@@ -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));
@@ -282,10 +275,8 @@ bool Converter::VisitReferenceType(clang::ReferenceType *type) {
282275}
283276
284277std::string
285- Converter::ConvertFunctionPointerType (const clang::FunctionProtoType *proto,
286- FnProtoType kind) {
287- std::string result =
288- (kind == FnProtoType::LambdaCallOperator ? " impl Fn(" : " fn(" );
278+ Converter::ConvertFunctionPointerType (const clang::FunctionProtoType *proto) {
279+ std::string result = " fn(" ;
289280 for (auto p_ty : proto->param_types ()) {
290281 result += ToString (p_ty);
291282 result += ' ,' ;
@@ -527,20 +518,6 @@ bool Converter::ConvertVarDeclSkipInit(clang::VarDecl *decl) {
527518 return true ;
528519}
529520
530- bool Converter::ConvertLambdaVarDecl (clang::VarDecl *decl) {
531- if (decl->getType ()->isFunctionPointerType ()) {
532- return false ;
533- }
534- if (decl->hasInit ()) {
535- if (clang::isa<clang::LambdaExpr>(
536- decl->getInit ()->IgnoreUnlessSpelledInSource ())) {
537- // Lambdas are inlined at the call site.
538- return true ;
539- }
540- }
541- return false ;
542- }
543-
544521void Converter::ConvertVarDeclInitializer (clang::VarDecl *decl) {
545522 if (decl->hasInit ()) {
546523 ConvertVarInit (decl->getType (), decl->getInit ());
@@ -599,9 +576,6 @@ bool Converter::VisitVarDecl(clang::VarDecl *decl) {
599576 decl->getDeclContext ()->isDependentContext ()) {
600577 return false ;
601578 }
602- if (ConvertLambdaVarDecl (decl)) {
603- return false ;
604- }
605579
606580 if (IsGlobalVar (decl)) {
607581 ConvertGlobalVarDecl (decl);
@@ -677,6 +651,11 @@ bool Converter::TypeDerivesDefault(clang::QualType qual_type) {
677651 }
678652 }
679653
654+ if (auto lambda = AsLambdaClass (qual_type);
655+ lambda && lambda->captures ().empty ()) {
656+ return false ;
657+ }
658+
680659 return true ;
681660}
682661
@@ -1846,6 +1825,14 @@ bool Converter::VisitCallExpr(clang::CallExpr *expr) {
18461825 return false ;
18471826 }
18481827
1828+ if (auto conversion = clang::dyn_cast_or_null<clang::CXXConversionDecl>(
1829+ expr->getCalleeDecl ());
1830+ conversion && conversion->getParent ()->isLambda ()) {
1831+ ConvertLambdaToFunctionPointer (clang::cast<clang::CXXMemberCallExpr>(expr)
1832+ ->getImplicitObjectArgument ());
1833+ return false ;
1834+ }
1835+
18491836 if (IsImplicitAssignmentCall (expr) &&
18501837 !Mapper::Contains (ctx_, expr->getCallee ())) {
18511838 auto *call = clang::cast<clang::CXXMemberCallExpr>(expr);
@@ -1923,7 +1910,18 @@ bool Converter::VisitCallExpr(clang::CallExpr *expr) {
19231910 return false ;
19241911}
19251912
1913+ void Converter::ConvertLambdaToFunctionPointer (clang::Expr *lambda) {
1914+ StrCat (" Some" );
1915+ PushParen paren (*this );
1916+ ConvertLambdaClosure (AsLambdaClass (lambda->getType ()));
1917+ computed_expr_type_ = ComputedExprType::FreshPointer;
1918+ }
1919+
19261920void Converter::EmitFnPtrCall (clang::Expr *callee) {
1921+ if (AsLambdaClass (callee->getType ())) {
1922+ StrCat (ConvertRValue (callee), " .call" );
1923+ return ;
1924+ }
19271925 {
19281926 PushParen paren (*this );
19291927 Convert (callee);
@@ -1992,7 +1990,7 @@ Converter::CallInfo Converter::CollectCallInfo(clang::CallExpr *expr) {
19921990 unsigned num_named_params =
19931991 function ? function->getNumParams () : proto->getNumParams ();
19941992 info.is_variadic = function ? function->isVariadic () : proto->isVariadic ();
1995- info.is_fn_ptr_call = !function;
1993+ info.is_fn_ptr_call = !function || AsLambdaClass (callee-> getType ()) ;
19961994 info.is_libc_passthrough =
19971995 RuleRegistry::IsLibcPassthrough (ctx_, GetCalleeOrExpr (expr));
19981996
@@ -3080,16 +3078,21 @@ std::string Converter::ConvertDeclRef(clang::Expr *expr,
30803078}
30813079
30823080bool Converter::VisitDeclRefExpr (clang::DeclRefExpr *expr) {
3081+ if (auto init = AsLambdaUncapturedConstant (curr_function_, expr)) {
3082+ Convert (init);
3083+ return false ;
3084+ }
30833085 ConvertDeclRefValue (expr, expr->getDecl ());
30843086 return false ;
30853087}
30863088
30873089void Converter::ConvertDeclRefValue (clang::Expr *expr, clang::ValueDecl *decl) {
30883090 auto str = ConvertDeclRef (expr, decl);
3091+ auto type = GetDeclRefType (curr_function_, expr, decl);
30893092
3090- if (decl-> getType () ->getAs <clang::ReferenceType>() && !isAddrOf () &&
3093+ if (type ->getAs <clang::ReferenceType>() && !isAddrOf () &&
30913094 !map_iter_decls_.contains (clang::dyn_cast<clang::VarDecl>(decl))) {
3092- EmitDeref (std::move (str), decl-> getType () .getNonReferenceType ());
3095+ EmitDeref (std::move (str), type .getNonReferenceType ());
30933096 SetValueFreshness (expr->getType ());
30943097 return ;
30953098 }
@@ -3104,23 +3107,8 @@ void Converter::ConvertDeclRefValue(clang::Expr *expr, clang::ValueDecl *decl) {
31043107 return ;
31053108 }
31063109
3107- if (auto var_decl = clang::dyn_cast<clang::VarDecl>(decl)) {
3108- if (!var_decl->getType ()->isFunctionPointerType ()) {
3109- if (auto init = var_decl->getInit ()) {
3110- if (auto lambda = clang::dyn_cast<clang::LambdaExpr>(
3111- init->IgnoreUnlessSpelledInSource ())) {
3112- PushParen paren (*this );
3113- VisitLambdaExpr (lambda);
3114- computed_expr_type_ = ComputedExprType::FreshValue;
3115- return ;
3116- }
3117- }
3118- }
3119- }
3120-
3121- if (!decl->getType ()->getAs <clang::ReferenceType>() && isAddrOf ()) {
3122- StrCat (token::kRef , decl->getType ().isConstQualified () ? " " : keyword_mut_,
3123- str);
3110+ if (!type->getAs <clang::ReferenceType>() && isAddrOf ()) {
3111+ StrCat (token::kRef , type.isConstQualified () ? " " : keyword_mut_, str);
31243112 computed_expr_type_ = ComputedExprType::FreshPointer;
31253113 return ;
31263114 }
@@ -3272,7 +3260,8 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) {
32723260
32733261void Converter::SetUFCSReceiver (clang::Expr *base, bool is_arrow,
32743262 const clang::CXXMethodDecl *method) {
3275- if (clang::isa<clang::CXXThisExpr>(base->IgnoreParenImpCasts ())) {
3263+ if (clang::isa<clang::CXXThisExpr>(base->IgnoreParenImpCasts ()) &&
3264+ !AsLambdaOperatorCall (curr_function_)) {
32763265 bool in_ctor =
32773266 curr_function_ && clang::isa<clang::CXXConstructorDecl>(curr_function_);
32783267 ufcs_receiver_ = in_ctor ? " &mut this" : keyword::kSelfValue ;
@@ -3356,8 +3345,8 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) {
33563345 }
33573346
33583347 auto *base = expr->getBase ();
3359- bool base_is_this =
3360- clang::isa<clang::CXXThisExpr>(base-> IgnoreCasts ()) && !ThisIsRustPtr ( );
3348+ bool base_is_this = clang::isa<clang::CXXThisExpr>(base-> IgnoreCasts ()) &&
3349+ ! ThisIsRustPtr () && !AsLambdaOperatorCall (curr_function_ );
33613350 PushExprKind push (*this , isLValue () ? ExprKind::LValue : ExprKind::RValue);
33623351 if (base_is_this) {
33633352 StrCat (clang::isa<clang::CXXConstructorDecl>(curr_function_)
@@ -3382,6 +3371,14 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) {
33823371}
33833372
33843373bool Converter::VisitCXXThisExpr (clang::CXXThisExpr *expr) {
3374+ if (auto field = AsLambdaCaptureThis (curr_function_)) {
3375+ auto name = GetNamedDeclAsString (field);
3376+ StrCat (field->getType ()->isPointerType ()
3377+ ? name
3378+ : std::format (" (&raw mut {})" , name));
3379+ computed_expr_type_ = ComputedExprType::FreshPointer;
3380+ return false ;
3381+ }
33853382 if (clang::isa<clang::CXXConstructorDecl>(curr_function_)) {
33863383 StrCat (" &raw mut this" );
33873384 } else {
@@ -3837,22 +3834,63 @@ bool Converter::VisitConstantExpr(clang::ConstantExpr *expr) {
38373834}
38383835
38393836bool Converter::VisitLambdaExpr (clang::LambdaExpr *expr) {
3840- if (isAddrOf () && expr->capture_size () == 0 ) {
3841- StrCat (" Some" );
3837+ auto decl = expr->getLambdaClass ();
3838+ if (decl->captures ().empty ()) {
3839+ ConvertCapturelessLambda (decl);
3840+ return false ;
3841+ }
3842+ StrCat (LambdaMacro ());
3843+ PushParen paren (*this );
3844+ {
3845+ PushBrace captures (*this );
3846+ auto init = expr->capture_init_begin ();
3847+ for (auto field : decl->fields ()) {
3848+ ConvertLambdaCapture (field, *init++);
3849+ }
38423850 }
3851+ StrCat (token::kComma );
3852+ ConvertLambdaClosure (decl);
3853+ computed_expr_type_ = ComputedExprType::FreshValue;
3854+ return false ;
3855+ }
3856+
3857+ void Converter::ConvertCapturelessLambda (const clang::CXXRecordDecl *decl) {
3858+ auto proto = decl->getLambdaCallOperator ()
3859+ ->getType ()
3860+ ->castAs <clang::FunctionProtoType>();
3861+ StrCat (std::format (" FnPtr::<{}>::new" , ConvertFunctionPointerType (proto)));
38433862 PushParen paren (*this );
3863+ ConvertLambdaClosure (decl);
3864+ computed_expr_type_ = ComputedExprType::FreshValue;
3865+ }
3866+
3867+ void Converter::ConvertLambdaCapture (const clang::FieldDecl *field,
3868+ clang::Expr *init) {
3869+ StrCat (keyword::kLet , GetNamedDeclAsString (field), token::kColon );
3870+ Convert (field->getType ());
3871+ StrCat (token::kAssign );
3872+ ConvertVarInit (field->getType (), init);
3873+ StrCat (token::kSemiColon );
3874+ }
3875+
3876+ void Converter::ConvertLambdaClosure (const clang::CXXRecordDecl *decl) {
3877+ auto call_operator = decl->getLambdaCallOperator ();
38443878 StrCat (' |' );
3845- for (auto p : expr-> getLambdaClass ()-> getLambdaCallOperator () ->parameters ()) {
3879+ for (auto p : call_operator ->parameters ()) {
38463880 StrCat (GetNamedDeclAsString (p), token::kColon , ToString (p->getType ()),
38473881 token::kComma );
38483882 }
3849- StrCat (" | {" );
3850- EmitFunctionPreamble (expr->getLambdaClass ()->getLambdaCallOperator ());
3851- PushCurrFunction push_fn (*this ,
3852- expr->getLambdaClass ()->getLambdaCallOperator ());
3883+ StrCat (' |' );
3884+ ConvertFunctionReturnType (call_operator);
3885+ PushBrace body (*this );
3886+ std::optional<PushBrace> unsafe_brace;
3887+ if (decl->captures ().empty ()) {
3888+ StrCat (keyword_unsafe_);
3889+ unsafe_brace.emplace (*this );
3890+ }
3891+ EmitFunctionPreamble (call_operator);
3892+ PushCurrFunction push_fn (*this , call_operator);
38533893 ConvertFunctionBody (curr_function_);
3854- StrCat (' }' );
3855- return false ;
38563894}
38573895
38583896bool Converter::VisitImplicitValueInitExpr (clang::ImplicitValueInitExpr *expr) {
@@ -4054,6 +4092,17 @@ std::string Converter::GetArrayDefaultAsString(clang::QualType qual_type) {
40544092}
40554093
40564094std::string Converter::GetDefaultAsString (clang::QualType qual_type) {
4095+ if (auto lambda = AsLambdaClass (qual_type);
4096+ lambda && lambda->captures ().empty ()) {
4097+ if (HasStaticLocal (lambda->getLambdaCallOperator ()->getBody ())) {
4098+ llvm::report_fatal_error (" default-constructed lambda with a static local "
4099+ " is not supported yet" );
4100+ }
4101+ Buffer buf (*this );
4102+ ConvertCapturelessLambda (lambda);
4103+ return std::move (buf).str ();
4104+ }
4105+
40574106 if (IsVaListType (qual_type)) {
40584107 computed_expr_type_ = ComputedExprType::FreshValue;
40594108 return " VaList::default()" ;
@@ -4161,7 +4210,7 @@ std::string Converter::GetRecordName(const clang::NamedDecl *decl) const {
41614210std::vector<const char *>
41624211Converter::GetStructAttributes (const clang::RecordDecl *decl) {
41634212 if (decl->isUnion ()) {
4164- return {" Copy" , " Clone" };
4213+ return {" Copy" , " Clone" , " FnPtrArg " };
41654214 }
41664215
41674216 std::vector<const char *> struct_attrs;
@@ -4176,6 +4225,7 @@ Converter::GetStructAttributes(const clang::RecordDecl *decl) {
41764225
41774226 if (RecordImplementsClone (decl)) {
41784227 struct_attrs.emplace_back (" VaArg" );
4228+ struct_attrs.emplace_back (" FnPtrArg" );
41794229 }
41804230
41814231 if (RecordDerivesDefault (decl)) {
@@ -4215,15 +4265,6 @@ void Converter::ConvertVarInit(clang::QualType qual_type, clang::Expr *expr) {
42154265 StrCat (keyword_mut_);
42164266 }
42174267 }
4218- if (qual_type->isFunctionPointerType ()) {
4219- if (auto *lambda = clang::dyn_cast<clang::LambdaExpr>(
4220- expr->IgnoreUnlessSpelledInSource ())) {
4221- PushExprKind push (*this , ExprKind::AddrOf);
4222- PushInitType init_type (*this , qual_type);
4223- VisitLambdaExpr (lambda);
4224- return ;
4225- }
4226- }
42274268 auto *ignore_casts = expr->IgnoreCasts ();
42284269 // FIXME: this looks very complicated
42294270 if (auto *ctor = clang::dyn_cast<clang::CXXConstructExpr>(ignore_casts);
0 commit comments