@@ -1803,13 +1803,17 @@ void Converter::EmitCallResult(clang::CallExpr *expr, std::string str,
18031803 (temps && IsReferenceType (expr))) &&
18041804 !isAddrOf () && !isVoid ();
18051805 // The dereference is in the block of the temporaries, so they are still
1806- // alive.
1806+ // alive, as is the read of a field of the result .
18071807 if (deref && !(temps && Mapper::IsRefExpr (ctx_, expr))) {
18081808 Buffer buf (*this );
18091809 EmitDeref (std::move (str), expr->getType ());
18101810 str = std::move (buf).str ();
18111811 }
1812- StrCat (temps ? temps->Wrap (std::move (str)) : str);
1812+ if (deref && DeferTemporaries (expr, temps)) {
1813+ StrCat (str);
1814+ } else {
1815+ StrCat (temps ? temps->Wrap (std::move (str)) : str);
1816+ }
18131817 if (deref) {
18141818 SetValueFreshness (expr->getType ());
18151819 } else if (!temps || !IsPassThroughRule (expr)) {
@@ -3296,6 +3300,26 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) {
32963300 return ;
32973301 }
32983302
3303+ // A field of the result of a call is read in the block of the temporaries
3304+ // of the arguments of the call.
3305+ if (auto *call = GetFieldReadCall (expr);
3306+ call && (!field_read_call_ || field_read_call_->call != call)) {
3307+ FieldReadCall read{call, " " };
3308+ std::string str;
3309+ {
3310+ ScopedValue push_read (field_read_call_, &read);
3311+ Buffer buf (*this );
3312+ ConvertMemberExpr (expr);
3313+ str = std::move (buf).str ();
3314+ }
3315+ if (read.temporary_bindings .empty ()) {
3316+ StrCat (str);
3317+ } else {
3318+ StrCat (std::format (" {{ {} {} }}" , read.temporary_bindings , str));
3319+ }
3320+ return ;
3321+ }
3322+
32993323 auto *member = expr->getMemberDecl ();
33003324 auto *base = expr->getBase ();
33013325 bool base_is_this = clang::isa<clang::CXXThisExpr>(base->IgnoreCasts ()) &&
@@ -3319,6 +3343,27 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) {
33193343 }
33203344}
33213345
3346+ bool Converter::DeferTemporaries (const clang::Expr *call,
3347+ const TempMaterializationCtx *temps) {
3348+ if (!temps || !field_read_call_ || field_read_call_->call != call) {
3349+ return false ;
3350+ }
3351+ field_read_call_->temporary_bindings = temps->temporary_bindings ;
3352+ return true ;
3353+ }
3354+
3355+ // The call whose result expr reads a field of, through fields of fields.
3356+ const clang::Expr *Converter::GetFieldReadCall (const clang::MemberExpr *expr) {
3357+ const clang::Expr *base = expr;
3358+ while (auto *member = clang::dyn_cast<clang::MemberExpr>(base)) {
3359+ if (member->isArrow ()) {
3360+ return nullptr ;
3361+ }
3362+ base = member->getBase ()->IgnoreParenImpCasts ();
3363+ }
3364+ return clang::isa<clang::CallExpr>(base) ? base : nullptr ;
3365+ }
3366+
33223367bool Converter::VisitCXXThisExpr (clang::CXXThisExpr *expr) {
33233368 if (auto field = AsLambdaCaptureThis (curr_function_)) {
33243369 auto name = GetNamedDeclAsString (field);
@@ -3338,21 +3383,37 @@ bool Converter::VisitCXXThisExpr(clang::CXXThisExpr *expr) {
33383383}
33393384
33403385bool Converter::VisitOpaqueValueExpr (clang::OpaqueValueExpr *expr) {
3386+ // The common expression of an array init loop uses the indices of the
3387+ // loops outside it.
3388+ auto outer = array_init_outer_depth_.find (expr);
3389+ if (outer == array_init_outer_depth_.end ()) {
3390+ Convert (expr->getSourceExpr ());
3391+ return false ;
3392+ }
3393+ auto depth = std::exchange (array_init_depth_, outer->second );
33413394 Convert (expr->getSourceExpr ());
3395+ array_init_depth_ = depth;
33423396 return false ;
33433397}
33443398
3399+ std::string Converter::ArrayInitIndexName () const {
3400+ return array_init_depth_ == 1 ? " __i"
3401+ : std::format (" __i{}" , array_init_depth_);
3402+ }
3403+
33453404bool Converter::VisitArrayInitIndexExpr (clang::ArrayInitIndexExpr *expr) {
3346- EmitFresh (" __i " );
3405+ EmitFresh (ArrayInitIndexName () );
33473406 return false ;
33483407}
33493408
33503409bool Converter::VisitArrayInitLoopExpr (clang::ArrayInitLoopExpr *expr) {
33513410 StrCat (std::format (" std::array::from_fn::<_, {}, _>" ,
33523411 GetArraySize (expr->getType ())));
33533412 PushParen paren (*this );
3354- StrCat (" |__i: usize|" );
3413+ array_init_outer_depth_[expr->getCommonExpr ()] = array_init_depth_++;
3414+ StrCat (std::format (" |{}: usize|" , ArrayInitIndexName ()));
33553415 ConvertVarInit (expr->getSubExpr ()->getType (), expr->getSubExpr ());
3416+ --array_init_depth_;
33563417 MarkFresh ();
33573418 return false ;
33583419}
@@ -4466,19 +4527,15 @@ std::string Converter::GetComparisonCall(const clang::FunctionDecl *op,
44664527 const clang::CXXRecordDecl *decl,
44674528 std::string_view lhs,
44684529 std::string_view rhs) {
4469- auto arg = [&](unsigned i, std::string_view value) {
4470- if (op->getParamDecl (i)->getType ()->isReferenceType ()) {
4471- return GetComparisonReferenceArg (decl, value);
4472- }
4473- return std::format (" {}.clone()" , value);
4474- };
44754530 if (const auto *method = clang::dyn_cast<clang::CXXMethodDecl>(op)) {
44764531 return std::format (" {}::{}({}, {})" , GetUFCSName (method),
44774532 GetMethodName (method),
4478- GetComparisonReceiver (method, decl, lhs), arg (0 , rhs));
4533+ GetComparisonReceiver (method, lhs),
4534+ GetComparisonArg (op->getParamDecl (0 ), decl, rhs));
44794535 }
44804536 return std::format (" {}({}, {})" , GetNamedDeclAsString (op->getCanonicalDecl ()),
4481- arg (0 , lhs), arg (1 , rhs));
4537+ GetComparisonArg (op->getParamDecl (0 ), decl, lhs),
4538+ GetComparisonArg (op->getParamDecl (1 ), decl, rhs));
44824539}
44834540
44844541std::string Converter::GetComparisonBool (const clang::FunctionDecl *op,
@@ -4499,47 +4556,62 @@ std::string Converter::GetComparisonBool(const clang::FunctionDecl *op,
44994556 for (const auto *found : record->getVisibleConversionFunctions ()) {
45004557 const auto *conversion = clang::dyn_cast<clang::CXXConversionDecl>(found);
45014558 if (conversion && conversion->getConversionType ()->isBooleanType ()) {
4502- auto receiver =
4503- returns_ref
4504- ? GetComparisonReferenceReceiver (conversion, record, " __cmp" )
4505- : GetComparisonReceiver (conversion, record, " __cmp" );
4506- return std::format (" {{ let __cmp = {}{}; {}::{}({}) }}" ,
4507- returns_ref ? " " : " &" , call, GetUFCSName (conversion),
4508- GetMethodName (conversion), receiver);
4559+ return std::format (
4560+ " {{ let __cmp = {}; {}::{}({}) }}" , call, GetUFCSName (conversion),
4561+ GetMethodName (conversion),
4562+ GetComparisonResultReceiver (conversion, returns_ref, " __cmp" ));
45094563 }
45104564 }
45114565 assert (0 && " comparison operator result has no conversion to bool" );
45124566 return call;
45134567}
45144568
4515- std::string
4516- Converter::GetComparisonReferenceArg (const clang::CXXRecordDecl *decl,
4517- std::string_view value) {
4518- return std::format (" {} as *const {}" , value, GetRecordName (decl));
4569+ std::string Converter::GetComparisonArg (const clang::ParmVarDecl *param,
4570+ const clang::CXXRecordDecl *decl,
4571+ std::string_view value) {
4572+ if (param->getType ()->isReferenceType ()) {
4573+ return std::format (" {} as *const {}" , value, GetRecordName (decl));
4574+ }
4575+ return std::format (" {}.clone()" , value);
45194576}
45204577
45214578std::string
4522- Converter::GetComparisonReferenceReceiver (const clang::CXXMethodDecl *method,
4523- const clang::CXXRecordDecl *decl,
4524- std::string_view ptr) {
4525- return GetComparisonReceiver (method, decl, std::format (" &*{}" , ptr));
4579+ Converter::GetComparisonResultReceiver (const clang::CXXMethodDecl *method,
4580+ bool returns_ref,
4581+ std::string_view result) {
4582+ return GetComparisonReceiver (
4583+ method, std::format (" {}{}" , returns_ref ? " &*" : " &" , result));
45264584}
45274585
45284586std::string Converter::GetComparisonReceiver (const clang::CXXMethodDecl *method,
4529- const clang::CXXRecordDecl *,
45304587 std::string_view lhs) {
45314588 if (!MethodNeedsMutableReceiver (method)) {
45324589 return std::string (lhs);
45334590 }
45344591 return std::format (" &mut *(&raw const *{}).cast_mut()" , lhs);
45354592}
45364593
4594+ std::string Converter::GetEqBody (const clang::CXXRecordDecl *decl,
4595+ const clang::FunctionDecl *eq,
4596+ const clang::FunctionDecl *lt,
4597+ const clang::FunctionDecl *cmp,
4598+ std::string_view lhs, std::string_view rhs) {
4599+ if (eq) {
4600+ return GetComparisonBool (eq, decl, lhs, rhs);
4601+ }
4602+ if (cmp) {
4603+ return std::format (" {} == std::cmp::Ordering::Equal" ,
4604+ GetComparisonCall (cmp, decl, lhs, rhs));
4605+ }
4606+ return std::format (" !({}) && !({})" , GetComparisonBool (lt, decl, lhs, rhs),
4607+ GetComparisonBool (lt, decl, rhs, lhs));
4608+ }
4609+
45374610void Converter::ConvertOrdAndPartialOrdTraits (const clang::CXXRecordDecl *decl,
45384611 const clang::FunctionDecl *eq,
45394612 const clang::FunctionDecl *lt,
45404613 const clang::FunctionDecl *cmp) {
4541- std::string cmp_body, eq_body;
4542-
4614+ std::string cmp_body;
45434615 if (cmp) {
45444616 cmp_body = GetComparisonCall (cmp, decl, " self" , " other" );
45454617 } else if (lt) {
@@ -4549,19 +4621,9 @@ void Converter::ConvertOrdAndPartialOrdTraits(const clang::CXXRecordDecl *decl,
45494621 GetComparisonBool (lt, decl, " self" , " other" ),
45504622 GetComparisonBool (lt, decl, " other" , " self" ));
45514623 }
4552-
4553- if (eq) {
4554- eq_body = GetComparisonBool (eq, decl, " self" , " other" );
4555- } else if (cmp) {
4556- eq_body = std::format (" {} == std::cmp::Ordering::Equal" ,
4557- GetComparisonCall (cmp, decl, " self" , " other" ));
4558- } else {
4559- eq_body = std::format (" !({}) && !({})" ,
4560- GetComparisonBool (lt, decl, " self" , " other" ),
4561- GetComparisonBool (lt, decl, " other" , " self" ));
4562- }
4563-
4564- ConvertOrdAndPartialOrdTraitsBase (cmp_body, eq_body, GetRecordName (decl));
4624+ ConvertOrdAndPartialOrdTraitsBase (
4625+ cmp_body, GetEqBody (decl, eq, lt, cmp, " self" , " other" ),
4626+ GetRecordName (decl));
45654627}
45664628
45674629void Converter::AddOrdTrait (const clang::CXXRecordDecl *decl) {
0 commit comments