@@ -268,12 +268,15 @@ bool Converter::VisitConstantArrayType(clang::ConstantArrayType *type) {
268268bool Converter::VisitIncompleteArrayType (clang::IncompleteArrayType *type) {
269269 StrCat (' [' );
270270 Convert (type->getElementType ());
271- StrCat (' ] ' );
271+ StrCat (" ; 0] " );
272272 return false ;
273273}
274274
275275bool Converter::VisitReferenceType (clang::ReferenceType *type) {
276276 auto pointee_type = type->getPointeeType ();
277+ if (pointee_type->isFunctionType ()) {
278+ return Convert (ctx_.getPointerType (pointee_type));
279+ }
277280 StrCat (pointee_type.isConstQualified () ? " *const" : " *mut" );
278281 return Convert (pointee_type);
279282}
@@ -429,6 +432,12 @@ void Converter::ConvertFunctionBody(clang::FunctionDecl *decl) {
429432 return ;
430433 }
431434 auto compound = clang::dyn_cast<clang::CompoundStmt>(decl->getBody ());
435+ if (decl->isMain () && compound &&
436+ (compound->body_empty () ||
437+ !clang::isa<clang::ReturnStmt>(compound->body_back ()))) {
438+ StrCat (' 0' );
439+ return ;
440+ }
432441 if (!compound || compound->body_empty ()) {
433442 return ;
434443 }
@@ -596,6 +605,14 @@ void Converter::EmitScopedDestructor(const clang::VarDecl *decl) {
596605 return ;
597606 }
598607 auto type = decl->getType ();
608+ if (auto lambda = AsLambdaClass (type);
609+ lambda && LambdaNeedsDestruction (lambda)) {
610+ StrCat (token::kSemiColon ,
611+ std::format (" let _dtor_{0} = ScopedDestructorUnsafe::new(&raw mut "
612+ " {0}, |__f| __f.destroy())" ,
613+ GetNamedDeclAsString (decl)));
614+ return ;
615+ }
599616 if (type->isReferenceType () || type->isArrayType () ||
600617 !TypeNeedsDestruction (type)) {
601618 return ;
@@ -981,7 +998,7 @@ void Converter::DefineImplicitMembers(clang::CXXRecordDecl *decl) {
981998 }
982999 if (ctor->isMoveConstructor () && !ctor->isUserProvided () &&
9831000 !ctor->doesThisDeclarationHaveABody () && !ctor->isDeleted () &&
984- !HasDefaultedCopyConstructor (decl)) {
1001+ (decl-> isLambda () || !HasDefaultedCopyConstructor (decl) )) {
9851002 sema_->DefineImplicitMoveConstructor (decl->getLocation (), ctor);
9861003 }
9871004 }
@@ -1134,8 +1151,7 @@ bool Converter::VisitCXXConstructorDecl(clang::CXXConstructorDecl *decl) {
11341151 }
11351152 PushCurrFunction push_fn (*this , decl);
11361153
1137- if (decl->isCopyOrMoveConstructor () &&
1138- !decl->doesThisDeclarationHaveABody ()) {
1154+ if (decl->isCopyOrMoveConstructor () && !decl->hasBody ()) {
11391155 return false ;
11401156 }
11411157
@@ -1338,7 +1354,8 @@ bool Converter::VisitCompoundStmt(clang::CompoundStmt *stmt) {
13381354
13391355bool Converter::VisitDeclStmt (clang::DeclStmt *stmt) {
13401356 for (auto *decl : stmt->decls ()) {
1341- if (clang::isa<clang::TagDecl>(decl)) {
1357+ auto *var = clang::dyn_cast<clang::VarDecl>(decl);
1358+ if (clang::isa<clang::TagDecl>(decl) || (var && var->isStaticLocal ())) {
13421359 Buffer buf (*this );
13431360 Convert (decl);
13441361 hoisted_records_ += std::move (buf).str ();
@@ -1382,13 +1399,15 @@ bool Converter::VisitIfStmt(clang::IfStmt *stmt) {
13821399 stmt->setInit (init);
13831400 return false ;
13841401 }
1385- StrCat (keyword:: kIf ) ;
1386- if ( auto *cond = clang::dyn_cast<clang::ConstantExpr>( stmt->getCond ());
1387- cond && stmt->isConstexpr ()) {
1388- StrCat (cond-> getResultAsAPSInt () != 0 ? keyword:: kTrue : keyword:: kFalse );
1389- } else {
1390- ConvertCondition (stmt-> getCond ()) ;
1402+ if ( bool taken = false ;
1403+ !stmt-> getConditionVariable () && ! stmt->isConsteval () &&
1404+ ! stmt->getCond ()-> isValueDependent () &&
1405+ stmt-> getCond ()-> EvaluateAsBooleanCondition (taken, ctx_)) {
1406+ ConvertBody (taken ? stmt-> getThen () : stmt-> getElse ());
1407+ return false ;
13911408 }
1409+ StrCat (keyword::kIf );
1410+ ConvertCondition (stmt->getCond ());
13921411 ConvertBody (stmt->getThen ());
13931412 if (stmt->hasElseStorage ()) {
13941413 StrCat (keyword::kElse );
@@ -2406,6 +2425,37 @@ Converter::GetCodeUnitArrayLiteral(const clang::StringLiteral *expr) {
24062425 return out;
24072426}
24082427
2428+ std::string Converter::GetSourceFileAsString (clang::QualType type) {
2429+ return std::format (" concat!(file!(), \"\\ 0\" ).as_ptr() as {}" ,
2430+ ToString (type));
2431+ }
2432+
2433+ bool Converter::VisitSourceLocExpr (clang::SourceLocExpr *expr) {
2434+ switch (expr->getIdentKind ()) {
2435+ case clang::SourceLocIdentKind::Line:
2436+ StrCat (std::format (" line!() as {}" , ToString (expr->getType ())));
2437+ computed_expr_type_ = ComputedExprType::FreshValue;
2438+ return false ;
2439+ case clang::SourceLocIdentKind::File:
2440+ StrCat (GetSourceFileAsString (expr->getType ()));
2441+ computed_expr_type_ = ComputedExprType::FreshPointer;
2442+ return false ;
2443+ case clang::SourceLocIdentKind::Function: {
2444+ auto value = expr->EvaluateInContext (ctx_, nullptr );
2445+ auto *str = clang::cast<clang::StringLiteral>(
2446+ value.getLValueBase ().get <const clang::Expr *>());
2447+ Convert (clang::ImplicitCastExpr::Create (
2448+ ctx_, expr->getType (), clang::CK_ArrayToPointerDecay,
2449+ const_cast <clang::StringLiteral *>(str), nullptr , clang::VK_PRValue,
2450+ clang::FPOptionsOverride ()));
2451+ return false ;
2452+ }
2453+ default :
2454+ assert (0 && " unsupported SourceLocExpr" );
2455+ return false ;
2456+ }
2457+ }
2458+
24092459bool Converter::VisitStringLiteral (clang::StringLiteral *expr) {
24102460 if (IsCodeUnitStringLiteral (expr)) {
24112461 StrCat (GetCodeUnitArrayLiteral (expr));
@@ -3264,6 +3314,11 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) {
32643314 ConvertDeclRefValue (expr, member);
32653315 return false ;
32663316 }
3317+ if (auto field = clang::dyn_cast<clang::FieldDecl>(member);
3318+ field && AsLambdaCapture (field)) {
3319+ ConvertDeclRefValue (expr, member);
3320+ return false ;
3321+ }
32673322 if (auto *method = clang::dyn_cast<clang::CXXMethodDecl>(member);
32683323 method && IsMethodOnPtr (method) && !Mapper::Contains (ctx_, expr)) {
32693324 SetUFCSReceiver (expr->getBase (), expr->isArrow (), method);
@@ -3433,6 +3488,11 @@ bool Converter::VisitInitListExpr(clang::InitListExpr *expr) {
34333488 if (auto form = expr->getSemanticForm ())
34343489 expr = form;
34353490
3491+ if (expr->isTransparent ()) {
3492+ Convert (expr->getInit (0 ));
3493+ return false ;
3494+ }
3495+
34363496 auto qual_type = expr->getType ();
34373497 if (qual_type->isScalarType ()) {
34383498 assert (expr->getNumInits () < 2 && " Excess elements in scalar initializer" );
@@ -3710,6 +3770,12 @@ bool Converter::VisitCXXConstructExpr(clang::CXXConstructExpr *expr) {
37103770 }
37113771
37123772 auto *ctor = expr->getConstructor ();
3773+ if (IsLambdaCopyOrMoveConstructor (ctor)) {
3774+ Convert (expr->getArg (0 ));
3775+ StrCat (std::format (" .{}()" , GetCopyOrMoveName (ctor)));
3776+ SetFreshType (expr->getType ());
3777+ return false ;
3778+ }
37133779 if (IsPassThroughConstructor (ctor)) {
37143780 // Take suppress before recursing into the child.
37153781 bool suppress = PushSuppressIteratorClone::take (*this );
@@ -3875,6 +3941,12 @@ bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) {
38753941 }
38763942 StrCat (token::kComma );
38773943 ConvertLambdaClosure (decl);
3944+ ConvertLambdaCopyAndMove (decl);
3945+ if (LambdaNeedsDestruction (decl)) {
3946+ StrCat (token::kComma , " destroy" , token::kAssign );
3947+ PushBrace destroy (*this );
3948+ StrCat (DestroyMembers (decl));
3949+ }
38783950 computed_expr_type_ = ComputedExprType::FreshValue;
38793951 return false ;
38803952}
@@ -3918,6 +3990,25 @@ void Converter::ConvertLambdaClosure(const clang::CXXRecordDecl *decl) {
39183990 ConvertFunctionBody (curr_function_);
39193991}
39203992
3993+ void Converter::ConvertLambdaCopyAndMove (clang::CXXRecordDecl *decl) {
3994+ DefineImplicitMembers (decl);
3995+ for (auto ctor : decl->ctors ()) {
3996+ if (!ctor->isCopyOrMoveConstructor () || ctor->isDeleted ()) {
3997+ continue ;
3998+ }
3999+ StrCat (token::kComma , GetCopyOrMoveName (ctor));
4000+ PushBrace brace (*this );
4001+ PushCurrFunction push_fn (*this , ctor);
4002+ for (auto init : ctor->inits ()) {
4003+ assert (init->isMemberInitializer ());
4004+ auto field = init->getMember ();
4005+ StrCat (GetNamedDeclAsString (field), token::kColon );
4006+ ConvertVarInit (field->getType (), init->getInit ());
4007+ StrCat (token::kComma );
4008+ }
4009+ }
4010+ }
4011+
39214012bool Converter::VisitImplicitValueInitExpr (clang::ImplicitValueInitExpr *expr) {
39224013 if (auto arr_ty = clang::dyn_cast<clang::ArrayType>(
39234014 expr->getType ()->getCanonicalTypeInternal ().getTypePtr ())) {
@@ -4082,9 +4173,8 @@ std::string Converter::GetArrayDefaultAsString(clang::QualType qual_type) {
40824173 return std::format (" [{}; {}]" , element_type_as_string,
40834174 size_as_string.c_str ());
40844175 }
4085- if (auto *array_type =
4086- clang::dyn_cast<clang::IncompleteArrayType>(qual_type)) {
4087- return GetDefaultAsString (array_type->getElementType ());
4176+ if (clang::isa<clang::IncompleteArrayType>(qual_type)) {
4177+ return " []" ;
40884178 }
40894179 if (Printer::ToString (ctx_, qual_type).contains (" std::array" )) {
40904180 assert (GetTemplateArgs (qual_type).has_value ());
@@ -4268,6 +4358,12 @@ std::string Converter::GetUnsafeTypeAsString(clang::QualType qual_type) const {
42684358}
42694359
42704360void Converter::ConvertVarInit (clang::QualType qual_type, clang::Expr *expr) {
4361+ if (qual_type->isFunctionReferenceType ()) {
4362+ PushExprKind push (*this , ExprKind::AddrOf);
4363+ PushInitType init_type (*this , qual_type);
4364+ Convert (expr);
4365+ return ;
4366+ }
42714367 if (qual_type->isReferenceType () && !IsReferenceType (expr)) {
42724368 if (llvm::isa<clang::MaterializeTemporaryExpr>(expr->IgnoreImpCasts ())) {
42734369 StrCat (EmitMaterializedTempBinding (qual_type, expr));
@@ -4612,6 +4708,32 @@ std::string Converter::GetComparisonCall(const clang::FunctionDecl *op,
46124708 arg (0 , lhs), arg (1 , rhs));
46134709}
46144710
4711+ std::string Converter::GetComparisonBool (const clang::FunctionDecl *op,
4712+ const clang::CXXRecordDecl *decl,
4713+ std::string_view lhs,
4714+ std::string_view rhs) {
4715+ auto call = GetComparisonCall (op, decl, lhs, rhs);
4716+ auto ret = op->getReturnType ();
4717+ if (ret->isBooleanType ()) {
4718+ return call;
4719+ }
4720+ if (ret->isIntegerType ()) {
4721+ return std::format (" (({}) != 0)" , call);
4722+ }
4723+ const auto *record = ret->getAsCXXRecordDecl ();
4724+ assert (record && " unsupported comparison operator return type" );
4725+ for (const auto *found : record->getVisibleConversionFunctions ()) {
4726+ const auto *conversion = clang::dyn_cast<clang::CXXConversionDecl>(found);
4727+ if (conversion && conversion->getConversionType ()->isBooleanType ()) {
4728+ return std::format (" {{ let __cmp = &{}; {}::{}({}) }}" , call,
4729+ GetUFCSName (conversion), GetMethodName (conversion),
4730+ GetComparisonReceiver (conversion, record, " __cmp" ));
4731+ }
4732+ }
4733+ assert (0 && " comparison operator result has no conversion to bool" );
4734+ return call;
4735+ }
4736+
46154737std::string
46164738Converter::GetComparisonReferenceArg (const clang::CXXRecordDecl *decl,
46174739 std::string_view value) {
@@ -4639,19 +4761,19 @@ void Converter::ConvertOrdAndPartialOrdTraits(const clang::CXXRecordDecl *decl,
46394761 cmp_body = std::format (" if {} {{ std::cmp::Ordering::Less }} else if {} {{ "
46404762 " std::cmp::Ordering::Greater }} else {{ "
46414763 " std::cmp::Ordering::Equal }}" ,
4642- GetComparisonCall (lt, decl, " self" , " other" ),
4643- GetComparisonCall (lt, decl, " other" , " self" ));
4764+ GetComparisonBool (lt, decl, " self" , " other" ),
4765+ GetComparisonBool (lt, decl, " other" , " self" ));
46444766 }
46454767
46464768 if (eq) {
4647- eq_body = GetComparisonCall (eq, decl, " self" , " other" );
4769+ eq_body = GetComparisonBool (eq, decl, " self" , " other" );
46484770 } else if (cmp) {
46494771 eq_body = std::format (" {} == std::cmp::Ordering::Equal" ,
46504772 GetComparisonCall (cmp, decl, " self" , " other" ));
46514773 } else {
46524774 eq_body = std::format (" !({}) && !({})" ,
4653- GetComparisonCall (lt, decl, " self" , " other" ),
4654- GetComparisonCall (lt, decl, " other" , " self" ));
4775+ GetComparisonBool (lt, decl, " self" , " other" ),
4776+ GetComparisonBool (lt, decl, " other" , " self" ));
46554777 }
46564778
46574779 ConvertOrdAndPartialOrdTraitsBase (cmp_body, eq_body, GetRecordName (decl));
@@ -4666,6 +4788,10 @@ void Converter::AddOrdTrait(const clang::CXXRecordDecl *decl) {
46664788 fn->getDescribedFunctionTemplate () || !IsSameTypeComparison (fn, decl)) {
46674789 return ;
46684790 }
4791+ if (fn->getOverloadedOperator () == clang::OO_Spaceship &&
4792+ !ctx_.CompCategories .lookupInfoForType (fn->getReturnType ())) {
4793+ return ;
4794+ }
46694795 switch (fn->getOverloadedOperator ()) {
46704796 case clang::OO_EqualEqual:
46714797 eq = fn;
@@ -4967,9 +5093,9 @@ std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg,
49675093 }
49685094
49695095 if (ph_ctx.declared_in_rule_as_rust_ptr && arg->getType ()->isArrayType ()) {
4970- return std::format (
4971- " ({} as {})" , ConvertFreshPointer (arg),
4972- Mapper::GetParamType (ctx_, GetCalleeOrExpr (expr), ph_ctx. arg_idx ));
5096+ auto elem = ctx_. getAsArrayType (arg-> getType ())-> getElementType ();
5097+ return std::format ( " ({} as {})" , ConvertFreshPointer (arg),
5098+ ToStringBase (ctx_. getPointerType (elem) ));
49735099 }
49745100
49755101 if (ph_ctx.needs_materialization ()) {
0 commit comments