@@ -229,10 +229,11 @@ std::string Converter::ConvertFreshObject(clang::Expr *expr) {
229229 return ConvertFreshPointer (expr);
230230}
231231
232- std::string Converter::ConvertPointerReceiver (clang::Expr *arg,
233- std::string_view param_type) {
232+ std::string Converter::ConvertPointerReceiver (
233+ clang::Expr *arg, std::string_view param_type,
234+ std::optional<clang::QualType> implicit_convert_to) {
234235 auto ptr = clang::isa<clang::MaterializeTemporaryExpr>(arg->IgnoreImpCasts ())
235- ? ConvertTemporaryPointer (arg, std:: nullopt )
236+ ? ConvertTemporaryPointer (arg, implicit_convert_to )
236237 : ConvertFreshObject (arg);
237238 return std::format (" ({} as {})" , ptr, param_type);
238239}
@@ -3174,6 +3175,13 @@ bool Converter::ConvertCXXOperatorCallExpr(clang::CXXOperatorCallExpr *expr) {
31743175 case clang::OverloadedOperatorKind::OO_Subscript: {
31753176 auto *base = expr->getArg (0 );
31763177 auto *idx = expr->getArg (1 );
3178+ // A pointer to the element is a reference to it.
3179+ std::optional<PushExprKind> place;
3180+ if (isAddrOf ()) {
3181+ StrCat (token::kRef ,
3182+ expr->getType ().isConstQualified () ? " " : keyword_mut_);
3183+ place.emplace (*this , ExprKind::LValue);
3184+ }
31773185 // Rust borrows the container before computing the index, so an index that
31783186 // reads the container, or that has side effects through anything the
31793187 // container is reached through, is computed beforehand.
@@ -4940,15 +4948,8 @@ void Converter::ConvertCast(clang::QualType qual_type, int line) {
49404948Converter::TempMaterializationCtx
49414949Converter::CollectRefBindingTempArgs (clang::CallExpr *expr) {
49424950 TempMaterializationCtx ctx (expr->getNumArgs ());
4943- if (auto *fn = expr->getCalleeDecl () ? expr->getCalleeDecl ()->getAsFunction ()
4944- : nullptr ) {
4945- for (unsigned i = 0 ; i < expr->getNumArgs () && i < fn->getNumParams ();
4946- ++i) {
4947- auto param_type = fn->getParamDecl (i)->getType ();
4948- if (NeedsRefBindingTemp (ctx_, expr->getArg (i), param_type)) {
4949- ctx.materialized_args [i] = param_type;
4950- }
4951- }
4951+ for (unsigned i = 0 ; i < expr->getNumArgs (); ++i) {
4952+ ctx.materialized_args [i] = GetRefBindingTempType (ctx_, expr, i);
49524953 }
49534954 return ctx;
49544955}
@@ -5034,16 +5035,19 @@ std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg,
50345035 bool borrowed = ph_ctx.access == TranslationRule::Access::kBorrow ||
50355036 ph_ctx.access == TranslationRule::Access::kBorrowMut ;
50365037 PushExprKind push (*this , borrowed ? ExprKind::Object : ExprKind::XValue);
5037- return ConvertPointerReceiver (arg, param_type);
5038+ return ConvertPointerReceiver (arg, param_type, ph_ctx. implicit_convert_to );
50385039 }
50395040
5041+ // A container reached through a pointer, e.g., a reference, is indexed
5042+ // through an explicit reference to it.
5043+ ScopedValue autoref (
5044+ autoref_mut_,
5045+ ph_ctx.is_index_base
5046+ ? std::optional (ph_ctx.access == TranslationRule::Access::kBorrowMut )
5047+ : std::nullopt );
5048+
50405049 if (ph_ctx.needs_object_receiver ()) {
50415050 Buffer buf (*this );
5042- ScopedValue autoref (autoref_mut_,
5043- ph_ctx.is_index_base
5044- ? std::optional (ph_ctx.access ==
5045- TranslationRule::Access::kBorrowMut )
5046- : std::nullopt );
50475051 PushExprKind push (*this , ExprKind::RValue);
50485052 ConvertDeref (arg);
50495053 return std::move (buf).str ();
@@ -5110,10 +5114,10 @@ std::string Converter::ConvertTake(clang::Expr *arg) {
51105114
51115115std::string Converter::ConvertMappedMethodCall (
51125116 clang::Expr *expr, const TranslationRule::MethodCallFragment &mc,
5113- llvm::ArrayRef<clang::TemplateArgument> bindings, clang::Expr **args,
5114- unsigned num_args , TempMaterializationCtx *ctx) {
5115- return ConvertIRFragment (mc.receiver , bindings, expr, args, num_args, ctx) +
5116- ConvertIRFragment (mc.body , bindings, expr, args, num_args, ctx);
5117+ llvm::ArrayRef<clang::TemplateArgument> bindings,
5118+ llvm::ArrayRef<clang::Expr *> args , TempMaterializationCtx *ctx) {
5119+ return ConvertIRFragment (mc.receiver , bindings, expr, args, ctx) +
5120+ ConvertIRFragment (mc.body , bindings, expr, args, ctx);
51175121}
51185122
51195123std::string Converter::GetMappedAsString (clang::Expr *expr, clang::Expr **args,
@@ -5123,11 +5127,66 @@ std::string Converter::GetMappedAsString(clang::Expr *expr, clang::Expr **args,
51235127 if (!tgt_ir)
51245128 return {};
51255129
5130+ // The arguments that the rule would not evaluate once and in order are bound
5131+ // to variables by a match. A value is bound by value, unless the rule takes a
5132+ // pointer to it, and an object by a pointer to it. The temporaries that
5133+ // objects are bound to live until the end of the statement, like those of
5134+ // the C++ arguments.
5135+ auto all_args = BuildUnifiedArgs (expr, args, num_args);
5136+ auto bind = tgt_ir->argsToBind (ctx_, expr, all_args);
5137+ std::vector<std::string> values, names;
5138+ // The variables are local to the function.
5139+ for (size_t i = 0 ; curr_function_ && i < all_args.size (); ++i) {
5140+ if (!bind[i]) {
5141+ continue ;
5142+ }
5143+ // The rule takes the value of a transparent union.
5144+ auto *arg = IgnoreTransparentUnion (all_args[i]);
5145+ auto type = arg->getType ();
5146+ bool by_value = arg->isPRValue () && !tgt_ir->takesAddress (ctx_, i, arg);
5147+ if (!by_value && arg->isPRValue ()) {
5148+ arg = new (ctx_) clang::MaterializeTemporaryExpr (type, arg, false );
5149+ }
5150+ // A temporary is of the type of the parameter.
5151+ std::optional<clang::QualType> convert_to;
5152+ if (clang::isa<clang::MaterializeTemporaryExpr>(arg->IgnoreImpCasts ())) {
5153+ convert_to = GetParamImplicitConvertTarget (expr, i);
5154+ type = convert_to.value_or (type);
5155+ }
5156+ auto var_type = by_value ? type : ctx_.getLValueReferenceType (type);
5157+ auto loc = arg->getExprLoc ();
5158+ auto *var = clang::VarDecl::Create (
5159+ ctx_, curr_function_, loc, loc, &ctx_.Idents .get (NewTempName ()),
5160+ var_type, ctx_.getTrivialTypeSourceInfo (var_type, loc), clang::SC_None);
5161+ // The temporaries of a value, e.g., borrows, end with its block.
5162+ if (by_value) {
5163+ bound_values_.insert (var);
5164+ values.push_back (std::format (" {{ {} }}" , ConvertFreshRValue (arg)));
5165+ } else {
5166+ PushExprKind push (*this , ExprKind::Object);
5167+ values.push_back (ConvertPointerReceiver (
5168+ arg, ToString (ctx_.getPointerType (type)), convert_to));
5169+ }
5170+ names.push_back ((by_value ? " mut " : " " ) + GetNamedDeclAsString (var));
5171+ all_args[i] = clang::DeclRefExpr::Create (ctx_, {}, {}, var, false , loc,
5172+ type, clang::VK_LValue);
5173+ if (by_value && !type->isRecordType ()) {
5174+ all_args[i] = clang::ImplicitCastExpr::Create (
5175+ ctx_, type, clang::CK_LValueToRValue, all_args[i], nullptr ,
5176+ clang::VK_PRValue, clang::FPOptionsOverride ());
5177+ }
5178+ // The variable is passed instead of a temporary.
5179+ if (ctx && i >= HasReceiver (expr)) {
5180+ ctx->materialized_args [i - HasReceiver (expr)].reset ();
5181+ }
5182+ }
5183+
51265184 auto saved_borrows = std::exchange (mut_borrows_, {});
51275185 auto *operand = tgt_ir->refExprOperand ();
51285186 bool lvalue = operand && !isAddrOf ();
5129- auto result = ConvertIRFragment (lvalue ? *operand : tgt_ir->body , bindings,
5130- expr, args, num_args, ctx);
5187+ auto result =
5188+ ConvertIRFragment (lvalue && values.empty () ? *operand : tgt_ir->body ,
5189+ bindings, expr, all_args, ctx);
51315190 if (tgt_ir->multi_statement ) {
51325191 result = ' {' + result + ' }' ;
51335192 }
@@ -5136,20 +5195,25 @@ std::string Converter::GetMappedAsString(clang::Expr *expr, clang::Expr **args,
51365195 result = std::format (" {}.with_mut(|{}| {})" , place, name, result);
51375196 }
51385197 mut_borrows_ = std::move (saved_borrows);
5198+ // A place is reached through a reference to it, out of the match, so that it
5199+ // can be assigned.
5200+ if (!values.empty ()) {
5201+ result =
5202+ std::format (" match ({},) {{ ({},) => {{ {} }} }}" ,
5203+ llvm::join (values, " , " ), llvm::join (names, " , " ), result);
5204+ if (lvalue) {
5205+ result = std::format (" (*{})" , result);
5206+ }
5207+ }
51395208 return result;
51405209}
51415210
51425211std::string Converter::ConvertIRFragment (
51435212 const std::vector<TranslationRule::BodyFragment> &fragments,
51445213 llvm::ArrayRef<clang::TemplateArgument> bindings, clang::Expr *expr,
5145- clang::Expr **args, unsigned num_args , TempMaterializationCtx *ctx) {
5214+ llvm::ArrayRef< clang::Expr *> all_args , TempMaterializationCtx *ctx) {
51465215 using namespace TranslationRule ;
51475216
5148- std::vector<clang::Expr *> all_args;
5149- if (expr) {
5150- all_args = BuildUnifiedArgs (expr, args, num_args);
5151- }
5152-
51535217 std::string result;
51545218 for (auto &frag : fragments) {
51555219 if (auto *t = std::get_if<TextFragment>(&frag)) {
@@ -5191,31 +5255,27 @@ std::string Converter::ConvertIRFragment(
51915255 result += ConvertInitFragment (expr, all_args);
51925256 } else if (auto *mc =
51935257 std::get_if<std::unique_ptr<MethodCallFragment>>(&frag)) {
5194- result +=
5195- ConvertMappedMethodCall (expr, **mc, bindings, args, num_args, ctx);
5258+ result += ConvertMappedMethodCall (expr, **mc, bindings, all_args, ctx);
51965259 } else if (auto *re =
51975260 std::get_if<std::unique_ptr<RefExprFragment>>(&frag)) {
5198- result +=
5199- (*re)->prefix + ' ' +
5200- ConvertIRFragment ((*re)->inner , bindings, expr, args, num_args, ctx);
5261+ result += (*re)->prefix + ' ' +
5262+ ConvertIRFragment ((*re)->inner , bindings, expr, all_args, ctx);
52015263 } else if (auto *call =
52025264 std::get_if<std::unique_ptr<GenericCallFragment>>(&frag)) {
5203- result += ConvertGenericCall (**call, bindings, expr, args, num_args , ctx);
5265+ result += ConvertGenericCall (**call, bindings, expr, all_args , ctx);
52045266 }
52055267 }
52065268
52075269 return result;
52085270}
52095271
5210- std::string
5211- Converter::ConvertGenericCall (const TranslationRule::GenericCallFragment &call,
5212- llvm::ArrayRef<clang::TemplateArgument> bindings,
5213- clang::Expr *expr, clang::Expr **args,
5214- unsigned num_args, TempMaterializationCtx *ctx) {
5272+ std::string Converter::ConvertGenericCall (
5273+ const TranslationRule::GenericCallFragment &call,
5274+ llvm::ArrayRef<clang::TemplateArgument> bindings, clang::Expr *expr,
5275+ llvm::ArrayRef<clang::Expr *> args, TempMaterializationCtx *ctx) {
52155276 std::vector<std::string> call_args;
52165277 for (const auto &arg : call.args ) {
5217- call_args.push_back (
5218- ConvertIRFragment (arg, bindings, expr, args, num_args, ctx));
5278+ call_args.push_back (ConvertIRFragment (arg, bindings, expr, args, ctx));
52195279 }
52205280 clang::QualType type;
52215281 if (call.generic <= bindings.size () &&
@@ -5272,21 +5332,21 @@ std::string Converter::DerefPtrExpr(std::string_view ptr_expr,
52725332
52735333std::string
52745334Converter::ConvertVariadicTail (clang::Expr *expr,
5275- const std::vector <clang::Expr *> & all_args) {
5335+ llvm::ArrayRef <clang::Expr *> all_args) {
52765336 const auto *tgt_ir = RuleRegistry::GetExprRule (ctx_, expr);
52775337 unsigned fixed = tgt_ir ? tgt_ir->params .size () : 0 ;
52785338
52795339 Buffer buf (*this );
52805340 StrCat (" Box::<[VaArg]>::from([" );
5281- EmitVariadicArgs (llvm::ArrayRef ( all_args) .drop_front (fixed),
5341+ EmitVariadicArgs (all_args.drop_front (fixed),
52825342 /* into_va_arg=*/ true );
52835343 StrCat (" ])" );
52845344 return std::move (buf).str ();
52855345}
52865346
52875347std::string
52885348Converter::ConvertInitFragment (clang::Expr *expr,
5289- const std::vector <clang::Expr *> & all_args) {
5349+ llvm::ArrayRef <clang::Expr *> all_args) {
52905350 const auto *tgt_ir = RuleRegistry::GetExprRule (ctx_, expr);
52915351 if (!tgt_ir || !tgt_ir->usesInit ()) {
52925352 llvm::report_fatal_error (" expression rule does not use Init" );
@@ -5295,9 +5355,8 @@ Converter::ConvertInitFragment(clang::Expr *expr,
52955355
52965356 Buffer buf (*this );
52975357 PushExprKind push (*this , ExprKind::RValue);
5298- ConvertConstructFromArgs (
5299- type, llvm::ArrayRef (all_args).drop_front (tgt_ir->params .size ()),
5300- expr->getExprLoc ());
5358+ ConvertConstructFromArgs (type, all_args.drop_front (tgt_ir->params .size ()),
5359+ expr->getExprLoc ());
53015360 return std::move (buf).str ();
53025361}
53035362
0 commit comments