@@ -117,7 +117,7 @@ bool Converter::Convert(clang::QualType qual_type) {
117117 }
118118
119119 if (auto decl = qual_type->getAsRecordDecl ();
120- decl && IsUserDefinedDecl (decl)) {
120+ decl && IsUserDefinedDecl (decl) && ! AsLambdaClass (qual_type) ) {
121121 record_decls_.MarkReferenced (GetRecordName (decl));
122122 }
123123
@@ -165,19 +165,12 @@ bool Converter::VisitBuiltinType(clang::BuiltinType *type) {
165165
166166bool Converter::VisitRecordType (clang::RecordType *type) {
167167 auto *decl = type->getDecl ();
168- if (auto lambda = clang::dyn_cast<clang::CXXRecordDecl>(decl)) {
169- if (lambda->isLambda ()) {
170- if (in_function_formals_) {
171- StrCat (
172- ConvertFunctionPointerType (lambda->getLambdaCallOperator ()
173- ->getType ()
174- ->getAs <clang::FunctionProtoType>(),
175- FnProtoType::LambdaCallOperator));
176- } else {
177- StrCat (' _' );
178- }
179- return false ;
180- }
168+ if (auto lambda = AsLambdaClass (clang::QualType (type, 0 ))) {
169+ auto proto = lambda->getLambdaCallOperator ()
170+ ->getType ()
171+ ->castAs <clang::FunctionProtoType>();
172+ StrCat (std::format (" FnPtr<{}>" , ConvertFunctionPointerType (proto)));
173+ return false ;
181174 }
182175
183176 StrCat (GetRecordName (decl));
@@ -278,10 +271,8 @@ bool Converter::VisitReferenceType(clang::ReferenceType *type) {
278271}
279272
280273std::string
281- Converter::ConvertFunctionPointerType (const clang::FunctionProtoType *proto,
282- FnProtoType kind) {
283- std::string result =
284- (kind == FnProtoType::LambdaCallOperator ? " impl Fn(" : " fn(" );
274+ Converter::ConvertFunctionPointerType (const clang::FunctionProtoType *proto) {
275+ std::string result = " fn(" ;
285276 for (auto p_ty : proto->param_types ()) {
286277 result += ToString (p_ty);
287278 result += ' ,' ;
@@ -523,20 +514,6 @@ bool Converter::ConvertVarDeclSkipInit(clang::VarDecl *decl) {
523514 return true ;
524515}
525516
526- bool Converter::ConvertLambdaVarDecl (clang::VarDecl *decl) {
527- if (decl->getType ()->isFunctionPointerType ()) {
528- return false ;
529- }
530- if (decl->hasInit ()) {
531- if (clang::isa<clang::LambdaExpr>(
532- decl->getInit ()->IgnoreUnlessSpelledInSource ())) {
533- // Lambdas are inlined at the call site.
534- return true ;
535- }
536- }
537- return false ;
538- }
539-
540517void Converter::ConvertVarDeclInitializer (clang::VarDecl *decl) {
541518 if (decl->hasInit ()) {
542519 ConvertVarInit (decl->getType (), decl->getInit ());
@@ -594,9 +571,6 @@ bool Converter::VisitVarDecl(clang::VarDecl *decl) {
594571 if (clang::isa<clang::VarTemplatePartialSpecializationDecl>(decl)) {
595572 return false ;
596573 }
597- if (ConvertLambdaVarDecl (decl)) {
598- return false ;
599- }
600574
601575 if (IsGlobalVar (decl)) {
602576 ConvertGlobalVarDecl (decl);
@@ -651,6 +625,11 @@ bool Converter::RecordDerivesDefault(const clang::RecordDecl *decl) {
651625 }
652626 }
653627
628+ if (auto lambda = AsLambdaClass (f->getType ());
629+ lambda && lambda->captures ().empty ()) {
630+ return false ;
631+ }
632+
654633 // Records that contain std::array do not derive Default
655634 if (Printer::ToString (ctx_, f->getType ()).contains (" std::array" )) {
656635 return false ;
@@ -1785,6 +1764,14 @@ bool Converter::VisitCallExpr(clang::CallExpr *expr) {
17851764 return false ;
17861765 }
17871766
1767+ if (auto conversion = clang::dyn_cast_or_null<clang::CXXConversionDecl>(
1768+ expr->getCalleeDecl ());
1769+ conversion && conversion->getParent ()->isLambda ()) {
1770+ ConvertLambdaToFunctionPointer (clang::cast<clang::CXXMemberCallExpr>(expr)
1771+ ->getImplicitObjectArgument ());
1772+ return false ;
1773+ }
1774+
17881775 if (IsImplicitAssignmentCall (expr) &&
17891776 !Mapper::Contains (ctx_, expr->getCallee ())) {
17901777 auto *call = clang::cast<clang::CXXMemberCallExpr>(expr);
@@ -1862,7 +1849,18 @@ bool Converter::VisitCallExpr(clang::CallExpr *expr) {
18621849 return false ;
18631850}
18641851
1852+ void Converter::ConvertLambdaToFunctionPointer (clang::Expr *lambda) {
1853+ StrCat (" Some" );
1854+ PushParen paren (*this );
1855+ ConvertLambdaClosure (AsLambdaClass (lambda->getType ()));
1856+ computed_expr_type_ = ComputedExprType::FreshPointer;
1857+ }
1858+
18651859void Converter::EmitFnPtrCall (clang::Expr *callee) {
1860+ if (AsLambdaClass (callee->getType ())) {
1861+ StrCat (ConvertRValue (callee), " .call" );
1862+ return ;
1863+ }
18661864 {
18671865 PushParen paren (*this );
18681866 Convert (callee);
@@ -1931,7 +1929,7 @@ Converter::CallInfo Converter::CollectCallInfo(clang::CallExpr *expr) {
19311929 unsigned num_named_params =
19321930 function ? function->getNumParams () : proto->getNumParams ();
19331931 info.is_variadic = function ? function->isVariadic () : proto->isVariadic ();
1934- info.is_fn_ptr_call = !function;
1932+ info.is_fn_ptr_call = !function || AsLambdaClass (callee-> getType ()) ;
19351933 info.is_libc_passthrough =
19361934 RuleRegistry::IsLibcPassthrough (ctx_, GetCalleeOrExpr (expr));
19371935
@@ -2974,6 +2972,11 @@ bool Converter::VisitConditionalOperator(clang::ConditionalOperator *expr) {
29742972
29752973std::string Converter::ConvertDeclRef (clang::Expr *expr,
29762974 clang::ValueDecl *decl) {
2975+ if (auto field = AsLambdaCaptureField (curr_function_, expr)) {
2976+ return std::format (" {}.{}" , keyword::kSelfValue ,
2977+ GetNamedDeclAsString (field));
2978+ }
2979+
29772980 if (isAddrOf ()) {
29782981 clang::Expr *addrof_op = ToAddrOf (ctx_, expr);
29792982 if (auto str = GetMappedAsString (addrof_op); !str.empty ()) {
@@ -3017,16 +3020,21 @@ std::string Converter::ConvertDeclRef(clang::Expr *expr,
30173020}
30183021
30193022bool Converter::VisitDeclRefExpr (clang::DeclRefExpr *expr) {
3023+ if (auto init = AsLambdaUncapturedConstant (curr_function_, expr)) {
3024+ Convert (init);
3025+ return false ;
3026+ }
30203027 ConvertDeclRefValue (expr, expr->getDecl ());
30213028 return false ;
30223029}
30233030
30243031void Converter::ConvertDeclRefValue (clang::Expr *expr, clang::ValueDecl *decl) {
30253032 auto str = ConvertDeclRef (expr, decl);
3033+ auto type = GetDeclRefType (curr_function_, expr, decl);
30263034
3027- if (decl-> getType () ->getAs <clang::ReferenceType>() && !isAddrOf () &&
3035+ if (type ->getAs <clang::ReferenceType>() && !isAddrOf () &&
30283036 !map_iter_decls_.contains (clang::dyn_cast<clang::VarDecl>(decl))) {
3029- EmitDeref (std::move (str), decl-> getType () .getNonReferenceType ());
3037+ EmitDeref (std::move (str), type .getNonReferenceType ());
30303038 SetValueFreshness (expr->getType ());
30313039 return ;
30323040 }
@@ -3041,23 +3049,8 @@ void Converter::ConvertDeclRefValue(clang::Expr *expr, clang::ValueDecl *decl) {
30413049 return ;
30423050 }
30433051
3044- if (auto var_decl = clang::dyn_cast<clang::VarDecl>(decl)) {
3045- if (!var_decl->getType ()->isFunctionPointerType ()) {
3046- if (auto init = var_decl->getInit ()) {
3047- if (auto lambda = clang::dyn_cast<clang::LambdaExpr>(
3048- init->IgnoreUnlessSpelledInSource ())) {
3049- PushParen paren (*this );
3050- VisitLambdaExpr (lambda);
3051- computed_expr_type_ = ComputedExprType::FreshValue;
3052- return ;
3053- }
3054- }
3055- }
3056- }
3057-
3058- if (!decl->getType ()->getAs <clang::ReferenceType>() && isAddrOf ()) {
3059- StrCat (token::kRef , decl->getType ().isConstQualified () ? " " : keyword_mut_,
3060- str);
3052+ if (!type->getAs <clang::ReferenceType>() && isAddrOf ()) {
3053+ StrCat (token::kRef , type.isConstQualified () ? " " : keyword_mut_, str);
30613054 computed_expr_type_ = ComputedExprType::FreshPointer;
30623055 return ;
30633056 }
@@ -3209,7 +3202,8 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) {
32093202
32103203void Converter::SetUFCSReceiver (clang::Expr *base, bool is_arrow,
32113204 const clang::CXXMethodDecl *method) {
3212- if (clang::isa<clang::CXXThisExpr>(base->IgnoreParenImpCasts ())) {
3205+ if (clang::isa<clang::CXXThisExpr>(base->IgnoreParenImpCasts ()) &&
3206+ !AsLambdaOperatorCall (curr_function_)) {
32133207 bool in_ctor =
32143208 curr_function_ && clang::isa<clang::CXXConstructorDecl>(curr_function_);
32153209 ufcs_receiver_ = in_ctor ? " &mut this" : keyword::kSelfValue ;
@@ -3293,8 +3287,8 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) {
32933287 }
32943288
32953289 auto *base = expr->getBase ();
3296- bool base_is_this =
3297- clang::isa<clang::CXXThisExpr>(base-> IgnoreCasts ()) && !ThisIsRustPtr ( );
3290+ bool base_is_this = clang::isa<clang::CXXThisExpr>(base-> IgnoreCasts ()) &&
3291+ ! ThisIsRustPtr () && !AsLambdaOperatorCall (curr_function_ );
32983292 PushExprKind push (*this , isLValue () ? ExprKind::LValue : ExprKind::RValue);
32993293 if (base_is_this) {
33003294 StrCat (clang::isa<clang::CXXConstructorDecl>(curr_function_)
@@ -3319,6 +3313,14 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) {
33193313}
33203314
33213315bool Converter::VisitCXXThisExpr (clang::CXXThisExpr *expr) {
3316+ if (auto field = AsLambdaCaptureThis (curr_function_)) {
3317+ auto name = GetNamedDeclAsString (field);
3318+ StrCat (field->getType ()->isPointerType ()
3319+ ? std::format (" {}.{}" , keyword::kSelfValue , name)
3320+ : std::format (" (&raw mut {}.{})" , keyword::kSelfValue , name));
3321+ computed_expr_type_ = ComputedExprType::FreshPointer;
3322+ return false ;
3323+ }
33223324 if (clang::isa<clang::CXXConstructorDecl>(curr_function_)) {
33233325 StrCat (" &raw mut this" );
33243326 } else {
@@ -3774,22 +3776,63 @@ bool Converter::VisitConstantExpr(clang::ConstantExpr *expr) {
37743776}
37753777
37763778bool Converter::VisitLambdaExpr (clang::LambdaExpr *expr) {
3777- if (isAddrOf () && expr->capture_size () == 0 ) {
3778- StrCat (" Some" );
3779+ auto decl = expr->getLambdaClass ();
3780+ if (decl->captures ().empty ()) {
3781+ ConvertCapturelessLambda (decl);
3782+ return false ;
37793783 }
3784+ StrCat (LambdaMacro ());
37803785 PushParen paren (*this );
3786+ {
3787+ PushBrace captures (*this );
3788+ auto init = expr->capture_init_begin ();
3789+ for (auto field : decl->fields ()) {
3790+ ConvertLambdaCapture (field, *init++);
3791+ }
3792+ }
3793+ StrCat (token::kComma );
3794+ ConvertLambdaClosure (decl);
3795+ computed_expr_type_ = ComputedExprType::FreshValue;
3796+ return false ;
3797+ }
3798+
3799+ void Converter::ConvertCapturelessLambda (const clang::CXXRecordDecl *decl) {
3800+ auto proto = decl->getLambdaCallOperator ()
3801+ ->getType ()
3802+ ->castAs <clang::FunctionProtoType>();
3803+ StrCat (std::format (" FnPtr::<{}>::new" , ConvertFunctionPointerType (proto)));
3804+ PushParen paren (*this );
3805+ ConvertLambdaClosure (decl);
3806+ computed_expr_type_ = ComputedExprType::FreshValue;
3807+ }
3808+
3809+ void Converter::ConvertLambdaCapture (const clang::FieldDecl *field,
3810+ clang::Expr *init) {
3811+ StrCat (keyword::kLet , GetNamedDeclAsString (field), token::kColon );
3812+ Convert (field->getType ());
3813+ StrCat (token::kAssign );
3814+ ConvertVarInit (field->getType (), init);
3815+ StrCat (token::kSemiColon );
3816+ }
3817+
3818+ void Converter::ConvertLambdaClosure (const clang::CXXRecordDecl *decl) {
3819+ auto call_operator = decl->getLambdaCallOperator ();
37813820 StrCat (' |' );
3782- for (auto p : expr-> getLambdaClass ()-> getLambdaCallOperator () ->parameters ()) {
3821+ for (auto p : call_operator ->parameters ()) {
37833822 StrCat (GetNamedDeclAsString (p), token::kColon , ToString (p->getType ()),
37843823 token::kComma );
37853824 }
3786- StrCat (" | {" );
3787- EmitFunctionPreamble (expr->getLambdaClass ()->getLambdaCallOperator ());
3788- PushCurrFunction push_fn (*this ,
3789- expr->getLambdaClass ()->getLambdaCallOperator ());
3825+ StrCat (' |' );
3826+ ConvertFunctionReturnType (call_operator);
3827+ PushBrace body (*this );
3828+ std::optional<PushBrace> unsafe_brace;
3829+ if (decl->captures ().empty ()) {
3830+ StrCat (keyword_unsafe_);
3831+ unsafe_brace.emplace (*this );
3832+ }
3833+ EmitFunctionPreamble (call_operator);
3834+ PushCurrFunction push_fn (*this , call_operator);
37903835 ConvertFunctionBody (curr_function_);
3791- StrCat (' }' );
3792- return false ;
37933836}
37943837
37953838bool Converter::VisitImplicitValueInitExpr (clang::ImplicitValueInitExpr *expr) {
@@ -3991,6 +4034,17 @@ std::string Converter::GetArrayDefaultAsString(clang::QualType qual_type) {
39914034}
39924035
39934036std::string Converter::GetDefaultAsString (clang::QualType qual_type) {
4037+ if (auto lambda = AsLambdaClass (qual_type);
4038+ lambda && lambda->captures ().empty ()) {
4039+ if (HasStaticLocal (lambda->getLambdaCallOperator ()->getBody ())) {
4040+ llvm::report_fatal_error (
4041+ " default-constructed lambda with a static local is not supported" );
4042+ }
4043+ Buffer buf (*this );
4044+ ConvertCapturelessLambda (lambda);
4045+ return std::move (buf).str ();
4046+ }
4047+
39944048 if (IsVaListType (qual_type)) {
39954049 computed_expr_type_ = ComputedExprType::FreshValue;
39964050 return " VaList::default()" ;
@@ -4153,15 +4207,6 @@ void Converter::ConvertVarInit(clang::QualType qual_type, clang::Expr *expr) {
41534207 StrCat (keyword_mut_);
41544208 }
41554209 }
4156- if (qual_type->isFunctionPointerType ()) {
4157- if (auto *lambda = clang::dyn_cast<clang::LambdaExpr>(
4158- expr->IgnoreUnlessSpelledInSource ())) {
4159- PushExprKind push (*this , ExprKind::AddrOf);
4160- PushInitType init_type (*this , qual_type);
4161- VisitLambdaExpr (lambda);
4162- return ;
4163- }
4164- }
41654210 auto *ignore_casts = expr->IgnoreCasts ();
41664211 // FIXME: this looks very complicated
41674212 if (auto *ctor = clang::dyn_cast<clang::CXXConstructExpr>(ignore_casts);
0 commit comments