@@ -234,9 +234,25 @@ std::string Converter::ConvertFreshRValue(
234234std::pair<std::string, std::string>
235235Converter::MaterializeTemp (const std::string &binding_name,
236236 clang::QualType param_type, clang::Expr *expr) {
237- return {std::format (" let mut {} = {} ;" , binding_name,
238- ConvertRValue (expr, param_type.getNonReferenceType ())),
239- std::format (" & mut {}" , binding_name)};
237+ auto pointee = param_type.getNonReferenceType ();
238+ auto value = ConvertRValue (expr, pointee);
239+ auto type_str = ToStringBase (pointee);
240+ const auto *decl = in_const_initializer_ ? keyword::kStatic : keyword::kLet ;
241+
242+ auto binding =
243+ std::format (" {} mut {} : {} = {};" , decl, binding_name, type_str, value);
244+ auto ref = std::format (" & mut {}" , binding_name);
245+ return {binding, ref};
246+ }
247+
248+ std::string Converter::EmitMaterializedTempBinding (clang::QualType param_type,
249+ clang::Expr *expr) {
250+ assert (materialized_temp_bindings_ && " materialized temp emitted outside a "
251+ " HoistMaterializedTempBindings scope" );
252+ auto [binding, ref] = MaterializeTemp (
253+ std::format (" __tmp_{}" , materialized_temp_id_++), param_type, expr);
254+ *materialized_temp_bindings_ += std::move (binding);
255+ return ref;
240256}
241257
242258bool Converter::VisitConstantArrayType (clang::ConstantArrayType *type) {
@@ -254,7 +270,7 @@ bool Converter::VisitIncompleteArrayType(clang::IncompleteArrayType *type) {
254270 return false ;
255271}
256272
257- bool Converter::VisitLValueReferenceType (clang::LValueReferenceType *type) {
273+ bool Converter::VisitReferenceType (clang::ReferenceType *type) {
258274 auto pointee_type = type->getPointeeType ();
259275 StrCat (pointee_type.isConstQualified () ? " *const" : " *mut" );
260276 return Convert (pointee_type);
@@ -393,6 +409,7 @@ void Converter::EmitHoistedDecls(clang::CompoundStmt *body) {
393409}
394410
395411void Converter::ConvertGotoBlock (clang::CompoundStmt *body) {
412+ HoistMaterializedTempBindings hoist_temps (*this );
396413 PushHoistedDecls push (hoisted_decls_);
397414 EmitHoistedDecls (body);
398415
@@ -457,6 +474,17 @@ void Converter::ConvertVaListVarDecl(clang::VarDecl *decl) {
457474 StrCat (keyword_mut_, GetNamedDeclAsString (decl), token::kColon , " VaList" );
458475}
459476
477+ bool Converter::NeedsMut (const clang::VarDecl *decl, clang::QualType type,
478+ llvm::StringRef name) const {
479+ auto *method_or_null =
480+ curr_function_ ? clang::dyn_cast<clang::CXXMethodDecl>(curr_function_)
481+ : nullptr ;
482+ return ((hoisted_decls_.contains (decl) ||
483+ (!type.isConstQualified () && !type->isReferenceType ())) &&
484+ ((method_or_null == nullptr ) || !method_or_null->isVirtual ()) &&
485+ !IsGlobalVar (decl) && name != " _" );
486+ }
487+
460488bool Converter::ConvertVarDeclSkipInit (clang::VarDecl *decl) {
461489 auto qual_type = decl->getType ();
462490 auto name = GetNamedDeclAsString (decl);
@@ -482,16 +510,10 @@ bool Converter::ConvertVarDeclSkipInit(clang::VarDecl *decl) {
482510 StrCat (keyword::kLet );
483511 }
484512
485- auto *method_or_null =
486- curr_function_ ? clang::dyn_cast<clang::CXXMethodDecl>(curr_function_)
487- : nullptr ;
488- if ((hoisted_decls_.contains (decl) || !qual_type.isConstQualified ()) &&
489- !qual_type->isReferenceType () &&
490- ((method_or_null == nullptr ) || !method_or_null->isVirtual ()) &&
491- !IsGlobalVar (decl) && name != " _" ) {
492- StrCat (keyword_mut_);
513+ if (NeedsMut (decl, qual_type, name)) {
514+ // If this decl requires 'mut', print it irregardless of the model
515+ StrCat (keyword::kMut );
493516 }
494-
495517 StrCat (name, token::kColon );
496518
497519 bool is_parm_with_default_value = false ;
@@ -545,6 +567,8 @@ void Converter::ConvertVarDecl(clang::VarDecl *decl) {
545567 EmitHoistedInArmAssignment (decl);
546568 return ;
547569 }
570+
571+ HoistMaterializedTempBindings hoist_temps (*this );
548572 if (!ConvertVarDeclSkipInit (decl)) {
549573 // Skip global variables declared extern
550574 return ;
@@ -557,6 +581,7 @@ void Converter::ConvertVarDecl(clang::VarDecl *decl) {
557581}
558582
559583void Converter::ConvertGlobalVarDecl (clang::VarDecl *decl) {
584+ HoistMaterializedTempBindings hoist_temps (*this );
560585 if (!ConvertVarDeclSkipInit (decl)) {
561586 // Skip global variables declared extern
562587 return ;
@@ -1124,6 +1149,7 @@ bool Converter::VisitDeclStmt(clang::DeclStmt *stmt) {
11241149bool Converter::VisitReturnStmt (clang::ReturnStmt *stmt) {
11251150 auto return_type = curr_function_->getReturnType ();
11261151 if (!return_type->isVoidType ()) {
1152+ HoistMaterializedTempBindings hoist_temps (*this );
11271153 StrCat (keyword::kReturn );
11281154 ConvertVarInit (return_type, stmt->getRetValue ());
11291155 } else {
@@ -1714,7 +1740,7 @@ Converter::CallInfo Converter::CollectCallInfo(clang::CallExpr *expr) {
17141740 : Kind::Hoisted,
17151741 };
17161742 bool is_materialize = clang::isa<clang::MaterializeTemporaryExpr>(arg);
1717- if (is_materialize && ca.param_type ->isLValueReferenceType ()) {
1743+ if (is_materialize && ca.param_type ->isReferenceType ()) {
17181744 ca.kind = Kind::Materialized;
17191745 } else if (is_materialize) {
17201746 ca.kind = Kind::Inline;
@@ -1750,7 +1776,7 @@ Converter::CallInfo Converter::CollectCallInfo(clang::CallExpr *expr) {
17501776}
17511777
17521778void Converter::ConvertParamTy (clang::QualType param_type, clang::Expr *expr) {
1753- if (param_type->isLValueReferenceType ()) {
1779+ if (param_type->isReferenceType ()) {
17541780 PushExprKind push (*this , ExprKind::AddrOf);
17551781 ConvertVarInit (param_type, expr);
17561782 } else {
@@ -3106,6 +3132,8 @@ void Converter::ConvertCXXConstructExprArgs(clang::CXXConstructExpr *expr) {
31063132
31073133 if (arg_idx < expr->getNumArgs ()) {
31083134 clang::Expr *arg = expr->getArg (arg_idx++);
3135+ PushBrace brace (*this );
3136+ HoistMaterializedTempBindings hoist_temps (*this );
31093137
31103138 if (has_default) {
31113139 StrCat (" Some(" );
@@ -3629,6 +3657,10 @@ std::string Converter::GetUnsafeTypeAsString(clang::QualType qual_type) const {
36293657
36303658void Converter::ConvertVarInit (clang::QualType qual_type, clang::Expr *expr) {
36313659 if (qual_type->isReferenceType () && !IsReferenceType (expr)) {
3660+ if (llvm::isa<clang::MaterializeTemporaryExpr>(expr->IgnoreImpCasts ())) {
3661+ StrCat (EmitMaterializedTempBinding (qual_type, expr));
3662+ return ;
3663+ }
36323664 StrCat (token::kRef );
36333665 if (IsMut (qual_type)) {
36343666 StrCat (keyword_mut_);
0 commit comments