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

[WIP] Experimental support for single-use C++14 generic lambdas

parent d0f84139
......@@ -577,6 +577,33 @@ exp_node FramacVisitor::make_initializer_list(
}
exp_node FramacVisitor::make_lambda_expr(const clang::LambdaExpr* lam) {
if (const clang::FunctionTemplateDecl* meths =
lam->getDependentCallOperator()) {
for (const clang::FunctionDecl *meth : meths->specializations()) {
qual_type lam_rt =
makeDefaultExternalNameType(
meth->getReturnTypeSourceRange().getBegin(),
meth->getReturnType());
/* arg_decl */ list lam_args = NULL;
auto args = meth->parameters();
for (auto it = args.rbegin(); it < args.rend(); it++) {
std::string name = (*it)->getNameAsString();
qual_type arg_type =
makeDefaultExternalNameType(
(*it)->getLocation(), (*it)->getOriginalType());
location l = makeLocation((*it)->getSourceRange());
lam_args =
cons_container(arg_decl_cons(arg_type, copy_string(name), l),lam_args);
}
/* closure */ list lam_closure =
_clangUtils->make_capture_list(lam->captures());
/* statement */ list lam_body =
makeCodeBlock(meth->getBody(), meth->getDeclContext(), meth);
return exp_node_LambdaExpr(lam_rt, lam_args, lam_closure, lam_body);
}
}
const clang::CXXMethodDecl* lam_meth = lam->getCallOperator();
qual_type lam_rt =
makeDefaultExternalNameType(
......
......@@ -164,10 +164,11 @@ compare_typ(typ t1, typ t2) {
result = compare_qualified_name(t1->cons_typ.Named.name,
t2->cons_typ.Named.name);
break;
case LAMBDA:
result =
compare_signature(
t1->cons_typ.Lambda.proto, t2->cons_typ.Lambda.proto);
case LAMBDA: {
auto get_signature = [](typ t) {
return (signature)t->cons_typ.Lambda.proto->element.container;
};
result = compare_signature(get_signature(t1), get_signature(t2));
if (result==0) {
/* capture */ list l1 = t1->cons_typ.Lambda.closure;
/* capture */ list l2 = t2->cons_typ.Lambda.closure;
......@@ -184,6 +185,7 @@ compare_typ(typ t1, typ t2) {
}
}
break;
}
default:
break;
}
......@@ -1410,6 +1412,11 @@ bool Clang_utils::is_lambda(const clang::RecordDecl* rec) const {
return cxx_rec && cxx_rec->isLambda();
}
bool Clang_utils::is_generic_lambda(const clang::RecordDecl* rec) const {
auto *cxx_rec = llvm::dyn_cast<const clang::CXXRecordDecl>(rec);
return cxx_rec && cxx_rec->isGenericLambda();
}
/* capture */ list Clang_utils::make_capture_list(
clang::CXXRecordDecl::capture_const_range captures) const {
list lam_closure = NULL;
......@@ -1450,11 +1457,27 @@ typ Clang_utils::make_lambda_type(
{
auto cxx_rec = llvm::dyn_cast<const clang::CXXRecordDecl>(record);
auto oper = cxx_rec->getLambdaCallOperator();
auto sig = makeSignature(*oper);
auto sig = cons_container(makeSignature(*oper), nullptr);
auto cap = make_capture_list(cxx_rec->captures());
return typ_Lambda(sig,cap);
}
typ Clang_utils::make_generic_lambda_type(
clang::SourceLocation const& loc, clang::RecordDecl const* record,
VirtualDeclRegistration* declRegistration) const
{
auto *cxx_rec = llvm::dyn_cast<const clang::CXXRecordDecl>(record);
clang::FunctionTemplateDecl *oper = cxx_rec->getDependentLambdaCallOperator();
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);
}
typ
Clang_utils::makePlainType(
clang::SourceLocation const & loc,
......@@ -1649,6 +1672,8 @@ Clang_utils::makePlainType(
const clang::RecordType*
recordType = static_cast<clang::RecordType const*>(type);
const clang::RecordDecl* record = recordType->getDecl();
if (is_generic_lambda(record))
return make_generic_lambda_type(loc,record,declRegistration);
if (is_lambda(record))
return make_lambda_type(loc,record,declRegistration);
if (declRegistration && declRegistration->doesRegisterDecl())
......
......@@ -664,6 +664,7 @@ public:
bool lvalHasRefType(clang::Expr const* expr) const;
bool is_lambda(clang::RecordDecl const* record) const;
bool is_generic_lambda(const clang::RecordDecl* rec) const;
/*capture*/ list make_capture_list(
clang::CXXRecordDecl::capture_const_range captures) const;
......@@ -672,6 +673,10 @@ public:
clang::SourceLocation const& loc, clang::RecordDecl const* record,
VirtualDeclRegistration* declRegistration=NULL) const;
typ make_generic_lambda_type(
clang::SourceLocation const& loc, clang::RecordDecl const* record,
VirtualDeclRegistration* declRegistration = nullptr) const;
typ makeBuiltinType(
clang::SourceLocation const& loc, clang::BuiltinType const* typ) const;
typ makeBuiltinTypeNoLoc(clang::BuiltinType const* typ) const
......
......@@ -410,7 +410,7 @@ let force_ptr_to_const p =
let make_lambda_type result args closure =
let parameter = List.map (fun x -> x.arg_type) args in
Lambda ({ result; parameter; variadic = false }, closure)
Lambda ([{ result; parameter; variadic = false }], closure)
let plain_obj_ptr t = Pointer (PDataPointer t)
......
......@@ -183,13 +183,7 @@ and pretty_type fmt typ =
-> Format.fprintf fmt "union %a"
pretty_qualified_name (name, tc)
| Named (qname, _) -> pretty_qualified_name fmt (qname, TStandard)
| Lambda (proto, cap) ->
let pp_sep fmt () = Format.pp_print_string fmt ", " in
Format.fprintf fmt "lambda %a [%a]-> %a"
(Format.pp_print_list ~pp_sep pretty_qual_type)
proto.parameter
(Format.pp_print_list ~pp_sep pretty_capture) cap
pretty_qual_type proto.result
| Lambda (protos, cap) -> pretty_generic_lambda fmt protos cap
and pretty_capture fmt cap =
match cap with
......@@ -208,6 +202,19 @@ and pretty_qual_type fmt { qualifier = specs; plain_type = typ} =
Format.fprintf fmt "%a (%a)"
(Pretty_utils.pp_list ~sep:" " pretty_specifier) specs
pretty_type typ
and pretty_lambda fmt proto cap =
let pp_sep fmt () = Format.pp_print_string fmt ", " in
Format.fprintf fmt "lambda %a [%a]-> %a"
(Format.pp_print_list ~pp_sep pretty_qual_type)
proto.parameter
(Format.pp_print_list ~pp_sep pretty_capture) cap
pretty_qual_type proto.result
and pretty_generic_lambda fmt protos cap =
match protos with
| [] -> ()
| p :: ps ->
pretty_lambda fmt p cap;
pretty_generic_lambda fmt ps cap
module Template_parameter =
Datatype.Make_with_collections(
......
......@@ -168,7 +168,7 @@ type typ =
(* body.ckind should be CUnion *)
| Named { name: qualified_name; is_extern_c_name : bool; } (* typedef *)
| Lambda {
proto : signature;
proto : signature list;
closure: capture list;
} (* a lambda object of the given signature.
Note that normally each anonymous lambda object should give rise
......
......@@ -203,10 +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 (proto,cap) ->
| Lambda (protos,cap) ->
(* 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 proto = (match protos with
| p :: _ -> p
| [] -> Frama_Clang_option.not_yet_implemented
"Initializer list without Compound initialization") in
"Ul" ^ mangle_parameter proto.parameter ^ "EUc" ^ mangle_captures cap ^ "E_"
(* not translated yet
| ArrayType(t,(DYN_SIZE | NO_SIZE)) ->
......
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