Commit a1d04502 authored by Stefan Gränitz's avatar Stefan Gränitz
Browse files

[wip] Clang-mangled lambda names

parent a53e073c
Pipeline #37284 failed with stages
......@@ -24,8 +24,20 @@
#include "Clang_utils.h"
#include "ClangVisitor.h"
#include <clang/AST/Type.h>
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include <clang/AST/ASTContext.h>
#include <clang/AST/Mangle.h>
#include <clang/Basic/Diagnostic.h>
#include <clang/Basic/DiagnosticDriver.h>
#include <clang/Basic/DiagnosticFrontend.h>
#include <clang/Basic/DiagnosticIDs.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <llvm/Support/Casting.h>
#include <llvm/Support/FormatVariadic.h>
#include <llvm/Support/raw_ostream.h>
extern "C" {
......@@ -1451,6 +1463,49 @@ bool Clang_utils::is_generic_lambda(const clang::RecordDecl* rec) const {
return lam_closure;
}
// Clang generates rich diagnostics for failures. For now we render them into
// strings and dump them via stderr. Thus, one global static instance is fine.
//clang::DiagnosticsEngine &Clang_utils::get_diagnostics_engine() {
// static std::unique_ptr<clang::DiagnosticsEngine> global_inst = nullptr;
// if (!global_inst)
// global_inst = std::make_unique<clang::DiagnosticsEngine>(
// new clang::DiagnosticIDs, new clang::DiagnosticOptions,
// new clang::TextDiagnosticPrinter(llvm::errs(),
// new clang::DiagnosticOptions));
// return *global_inst;
//}
unsigned Clang_utils::get_lambda_id(const clang::CXXRecordDecl *inst) const {
const clang::DeclContext *scope = inst->getDeclContext();
auto it = TrackLambdasByScope.find(scope);
if (it == TrackLambdasByScope.end()) {
TrackLambdasByScope.insert(std::make_pair(scope, LamInstances_t{inst}));
return 0; // first lambda in this scope
}
LamInstances_t &insts = it->second;
for (unsigned i = 0; i < insts.size(); ++i)
if (inst == insts[i])
return i; // known lambda in this scope
insts.push_back(inst);
return insts.size() - 1; // new lambda in this scope
}
std::string
Clang_utils::get_lambda_name(const clang::FunctionDecl *inst) const {
clang::ASTNameGenerator mangler(inst->getASTContext());
std::string first_name = mangler.getName(inst);
size_t sep_pos = first_name.find('$');
assert(sep_pos != std::string::npos &&
"Lambda mangling always employs a dollar separator");
return first_name.substr(0, sep_pos);
}
std::string
Clang_utils::get_lambda_name(const clang::FunctionTemplateDecl *inst) const {
const clang::FunctionDecl *first_overload = *inst->spec_begin();
return get_lambda_name(first_overload);
}
typ Clang_utils::make_lambda_type(
clang::SourceLocation const& loc, clang::RecordDecl const* record,
VirtualDeclRegistration* declRegistration) const
......@@ -1459,7 +1514,12 @@ typ Clang_utils::make_lambda_type(
auto oper = cxx_rec->getLambdaCallOperator();
auto sig = cons_container(makeSignature(*oper), nullptr);
auto cap = make_capture_list(cxx_rec->captures());
return typ_Lambda(sig,cap);
unsigned id = get_lambda_id(cxx_rec);
std::string base_name = get_lambda_name(oper);
LambdaNames.push_back(llvm::formatv("{0}_{1}", base_name, id));
return typ_Lambda(sig, cap, LambdaNames.back().c_str());
}
typ Clang_utils::make_generic_lambda_type(
......@@ -1468,14 +1528,18 @@ typ Clang_utils::make_generic_lambda_type(
{
auto *cxx_rec = llvm::dyn_cast<const clang::CXXRecordDecl>(record);
clang::FunctionTemplateDecl *oper = cxx_rec->getDependentLambdaCallOperator();
list sigs = nullptr;
unsigned id = get_lambda_id(cxx_rec);
std::string base_name = get_lambda_name(oper);
LambdaNames.push_back(llvm::formatv("{0}_{1}", base_name, id));
list sigs = nullptr;
for (const clang::FunctionDecl *function : oper->specializations())
sigs = cons_container(makeSignature(*function), sigs);
assert(sigs && "Will unused generic lambdas appear in the AST? Possible.");
auto *cap = make_capture_list(cxx_rec->captures());
return typ_Lambda(sigs, cap);
return typ_Lambda(sigs, cap, LambdaNames.back().c_str());
}
typ
......
......@@ -814,6 +814,13 @@ public:
#endif
}
using LamInstances_t = std::vector<const clang::CXXRecordDecl *>;
using LamScopes_t = std::map<const clang::DeclContext *, LamInstances_t>;
mutable LamScopes_t TrackLambdasByScope;
mutable std::vector<std::string> LambdaNames;
unsigned get_lambda_id(const clang::CXXRecordDecl *inst) const;
std::string get_lambda_name(const clang::FunctionDecl *inst) const;
std::string get_lambda_name(const clang::FunctionTemplateDecl *inst) const;
};
class ForwardList;
......
......@@ -1713,7 +1713,7 @@ and convert_expr_node ?(drop_temp=false) env aux e does_remove_virtual =
mk_signature ovl.return_type params
in
let signatures = List.map make_signature overloads in
let lam_type = Lambda (signatures, closures) in
let lam_type = Lambda (signatures, closures, "") in
let lam_name = Convert_env.temp_name env "__fc_lambda_tmp" in
let (env, aux) =
create_lambda env aux lam_name lam_type overloads closures in
......
......@@ -183,9 +183,9 @@ and pretty_type fmt typ =
-> Format.fprintf fmt "union %a"
pretty_qualified_name (name, tc)
| Named (qname, _) -> pretty_qualified_name fmt (qname, TStandard)
| Lambda (sigs, caps) -> pretty_generic_lambda fmt sigs caps
| Lambda (sigs, caps, mangled) -> pretty_generic_lambda fmt sigs caps mangled
and pretty_generic_lambda fmt signatures captures =
and pretty_generic_lambda fmt signatures captures mangled =
let pretty_capture fmt cap =
match cap with
| Cap_id (s,typ,is_ref) ->
......@@ -196,7 +196,8 @@ and pretty_generic_lambda fmt signatures captures =
in
let pretty_lambda lam =
let pp_sep fmt () = Format.pp_print_string fmt ", " in
Format.fprintf fmt "lambda %a [%a]-> %a"
Format.fprintf fmt "lambda %s %a [%a]-> %a"
mangled
(Format.pp_print_list ~pp_sep pretty_capture) captures
(Format.pp_print_list ~pp_sep pretty_qual_type) lam.parameter
pretty_qual_type lam.result
......
......@@ -170,6 +170,7 @@ type typ =
| Lambda {
proto: signature list;
closure: capture list;
mangled: string;
} (* a lambda object of the given signature.
Note that normally each anonymous lambda object should give rise
to a different class. With this representation, we won't distinguish
......
......@@ -203,14 +203,14 @@ let rec mangle_cc_type = function
| Named (name,is_extern_c_name) ->
if is_extern_c_name then name.decl_name
else mangle_name_optt name TStandard
| Lambda (signatures,cap) ->
| Lambda (signatures, captures, mangled) ->
(* NB: we depart from standard mangling rules here, in order to have
a contextless mangling, whereas Itanium ABI mangles according to
the number of lambda classes found in each function. *)
let rec mangle_all = function
| [] -> ""
| s::sigs -> mangle_parameter s.parameter ^ mangle_all sigs in
"Ul" ^ mangle_all signatures ^ "EUc" ^ mangle_captures cap ^ "E_"
mangled ^ "$" ^ mangle_all signatures ^ "_" ^ mangle_captures captures
(* not translated yet
| ArrayType(t,(DYN_SIZE | NO_SIZE)) ->
"A_" ^ mangle_cc_type t *)
......
......@@ -9,7 +9,8 @@ int test_cxx11_lambda(int cap, int i) {
int test_cxx14_single_inst(int cap, int i) {
auto lam2 = [cap](auto val) { return cap - val; };
return lam2(i);
auto lam2b = [cap](auto val) { return cap - val; };
return lam2(i) + lam2b(i);
}
int test_cxx14_multi_inst(int cap, int i, float f) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment