@@ -286,8 +286,7 @@ std::string Converter::EmitMaterializedTempBinding(clang::QualType param_type,
286286 clang::Expr *expr) {
287287 assert (materialized_temp_bindings_ && " materialized temp emitted outside a "
288288 " HoistMaterializedTempBindings scope" );
289- auto [binding, ref] = MaterializeTemp (
290- std::format (" __tmp_{}" , materialized_temp_id_++), param_type, expr);
289+ auto [binding, ref] = MaterializeTemp (NewTempName (), param_type, expr);
291290 *materialized_temp_bindings_ += std::move (binding);
292291 return ref;
293292}
@@ -1413,13 +1412,10 @@ void Converter::ConvertCondition(clang::Expr *cond) {
14131412}
14141413
14151414bool Converter::VisitIfStmt (clang::IfStmt *stmt) {
1415+ // The variables of the init statement are only visible in the if.
1416+ PushBrace scope (*this , stmt->getInit ());
14161417 if (auto *init = stmt->getInit ()) {
1417- PushBrace scope (*this );
14181418 Convert (init);
1419- stmt->setInit (nullptr );
1420- Convert (stmt);
1421- stmt->setInit (init);
1422- return false ;
14231419 }
14241420 if (bool taken = false ;
14251421 !stmt->getConditionVariable () && !stmt->isConsteval () &&
@@ -1500,14 +1496,12 @@ bool Converter::VisitCXXForRangeStmt(clang::CXXForRangeStmt *stmt) {
15001496 auto *begin =
15011497 clang::cast<clang::VarDecl>(stmt->getBeginStmt ()->getSingleDecl ());
15021498 auto *end = clang::cast<clang::VarDecl>(stmt->getEndStmt ()->getSingleDecl ());
1503- begin->setDeclName (
1504- clang::isa<clang::DecompositionDecl>(stmt->getLoopVariable ())
1505- ? clang::DeclarationName (
1506- &ctx_.Idents .get (GetNamedDeclAsString (stmt->getLoopVariable ())))
1507- : stmt->getLoopVariable ()->getDeclName ());
1499+ // The iterator is named after the loop variable, which shadows it.
1500+ auto name = GetNamedDeclAsString (stmt->getLoopVariable ());
1501+ range_iterator_names_[begin] = name;
15081502 StrCat (" 'loop_:" );
1509- StrCat (keyword::kFor , GetNamedDeclAsString (begin) , keyword::kIn ,
1510- " IterRange::new( " , ConvertFreshRValue (begin->getInit ()), token::kComma ,
1503+ StrCat (keyword::kFor , name , keyword::kIn , " IterRange::new( " ,
1504+ ConvertFreshRValue (begin->getInit ()), token::kComma ,
15111505 ConvertFreshRValue (end->getInit ()), ' )' );
15121506 {
15131507 PushBrace brace (*this );
@@ -1741,21 +1735,6 @@ void Converter::ConvertCallToOstream(clang::CallExpr *expr) {
17411735 assert (*fmt_trait == ' \0 ' && " Stream state was not restored after call" );
17421736}
17431737
1744- void Converter::ConvertPrintf (clang::CallExpr *expr) {
1745- bool is_fprintf = IsCDecl (expr->getDirectCallee (), " fprintf" );
1746-
1747- StrCat (" printf(" );
1748- for (unsigned i = is_fprintf; i < expr->getNumArgs (); ++i) {
1749- Convert (expr->getArg (i));
1750- // The format string
1751- if (i == is_fprintf) {
1752- StrCat (" as *const i8" );
1753- }
1754- StrCat (token::kComma );
1755- }
1756- StrCat (' )' );
1757- }
1758-
17591738void Converter::ConvertVariadicArg (clang::Expr *arg) {
17601739 PushExprKind push (*this , ExprKind::RValue);
17611740 if (arg->getType ()->isFunctionPointerType ()) {
@@ -1783,25 +1762,40 @@ void Converter::ConvertVAArgCall(clang::CallExpr *expr) {
17831762}
17841763
17851764bool Converter::VisitCallExpr (clang::CallExpr *expr) {
1765+ if (ConvertSpecialCall (expr)) {
1766+ return false ;
1767+ }
1768+ std::optional<TempMaterializationCtx> temps;
1769+ std::string str;
1770+ {
1771+ Buffer buf (*this );
1772+ temps = ConvertCallExpr (expr);
1773+ str = std::move (buf).str ();
1774+ }
1775+ EmitCallResult (expr, std::move (str), temps ? &*temps : nullptr );
1776+ return false ;
1777+ }
1778+
1779+ bool Converter::ConvertSpecialCall (clang::CallExpr *expr) {
17861780 if (IsBuiltinVaStart (expr) || IsBuiltinVaEnd (expr) || IsBuiltinVaCopy (expr)) {
17871781 ConvertVAArgCall (expr);
17881782 MarkFresh ();
1789- return false ;
1783+ return true ;
17901784 }
17911785
17921786 // p->~T() on a scalar is a no-op
17931787 if (clang::isa<clang::CXXPseudoDestructorExpr>(
17941788 expr->getCallee ()->IgnoreParenImpCasts ())) {
17951789 MarkFresh ();
1796- return false ;
1790+ return true ;
17971791 }
17981792
17991793 // p->~T() is a no-op when T has nothing to destruct
18001794 if (auto *dtor = clang::dyn_cast_or_null<clang::CXXDestructorDecl>(
18011795 expr->getCalleeDecl ());
18021796 dtor && !RecordNeedsDestruction (dtor->getParent ())) {
18031797 MarkFresh ();
1804- return false ;
1798+ return true ;
18051799 }
18061800
18071801 if (auto conversion = clang::dyn_cast_or_null<clang::CXXConversionDecl>(
@@ -1810,76 +1804,51 @@ bool Converter::VisitCallExpr(clang::CallExpr *expr) {
18101804 ConvertLambdaToFunctionPointer (clang::cast<clang::CXXMemberCallExpr>(expr)
18111805 ->getImplicitObjectArgument (),
18121806 conversion);
1813- return false ;
1807+ return true ;
18141808 }
18151809
1816- if (IsImplicitAssignmentCall (expr) && !Mapper::Contains (ctx_, expr)) {
1817- auto *call = clang::cast<clang::CXXMemberCallExpr>(expr);
1818- ConvertAssignment (call->getImplicitObjectArgument (), call->getArg (0 ), " =" );
1810+ // The remaining calls are converted as rules say, if there is one.
1811+ if (Mapper::Contains (ctx_, expr)) {
18191812 return false ;
18201813 }
18211814
1822- if (Mapper::Contains (ctx_, expr)) {
1823- if (RuleRegistry::IsLibcPassthrough (ctx_, expr)) {
1824- ConvertGenericCallExpr (expr);
1825- return false ;
1826- }
1827-
1828- bool deref_ref = (IsReferenceType (expr) ||
1829- GetReturnTypeOfFunction (expr)->isReferenceType ()) &&
1830- !isAddrOf () && !isVoid ();
1831-
1832- auto **args = expr->getArgs ();
1833- auto num_args = expr->getNumArgs ();
1834- auto ctx = CollectRefBindingTempArgs (expr);
1835- auto str = GetMappedAsString (expr, args, num_args, &ctx);
1836-
1837- if (deref_ref && !Mapper::IsRefExpr (ctx_, expr)) {
1838- Buffer buf (*this );
1839- EmitDeref (std::move (str), expr->getType ());
1840- str = std::move (buf).str ();
1841- }
1842-
1843- if (!ctx.temporary_bindings .empty ()) {
1844- str = std::format (" {{ {} {} }}" , ctx.temporary_bindings , str);
1845- }
1846-
1847- StrCat (str);
1848- if (deref_ref) {
1849- SetValueFreshness (expr->getType ());
1850- } else if (!IsPassThroughRule (expr)) {
1851- MarkFresh ();
1852- }
1853- return false ;
1815+ if (IsImplicitAssignmentCall (expr)) {
1816+ auto *call = clang::cast<clang::CXXMemberCallExpr>(expr);
1817+ ConvertAssignment (call->getImplicitObjectArgument (), call->getArg (0 ), " =" );
1818+ return true ;
18541819 }
18551820
18561821 if (IsTransparentStdCall (expr)) {
18571822 Convert (expr->getArg (0 ));
1858- return false ;
1823+ return true ;
18591824 }
18601825
18611826 if (auto *opcall = clang::dyn_cast<clang::CXXOperatorCallExpr>(expr);
1862- opcall && !IsUserOperatorCall (opcall) && !Mapper::Contains (ctx_, expr)) {
1863- return ConvertCXXOperatorCallExpr (opcall);
1827+ opcall && !IsUserOperatorCall (opcall)) {
1828+ ConvertCXXOperatorCallExpr (opcall);
1829+ return true ;
18641830 }
1831+ return false ;
1832+ }
18651833
1866- std::string str;
1867- {
1834+ void Converter::EmitCallResult (clang::CallExpr *expr, std::string str,
1835+ const TempMaterializationCtx *temps) {
1836+ bool deref = (GetReturnTypeOfFunction (expr)->isReferenceType () ||
1837+ (temps && IsReferenceType (expr))) &&
1838+ !isAddrOf () && !isVoid ();
1839+ // The dereference is in the block of the temporaries, so they are still
1840+ // alive.
1841+ if (deref && !(temps && Mapper::IsRefExpr (ctx_, expr))) {
18681842 Buffer buf (*this );
1869- Converter::ConvertCallExpr ( expr);
1843+ EmitDeref ( std::move (str), expr-> getType () );
18701844 str = std::move (buf).str ();
18711845 }
1872-
1873- auto ty = GetReturnTypeOfFunction (expr);
1874- auto ref = ty->getAs <clang::ReferenceType>();
1875-
1876- if (ref && !isAddrOf () && !isVoid ()) {
1877- EmitDeref (std::move (str), ref->getPointeeType ());
1878- return false ;
1846+ StrCat (temps ? temps->Wrap (std::move (str)) : str);
1847+ if (deref) {
1848+ SetValueFreshness (expr->getType ());
1849+ } else if (!temps || !IsPassThroughRule (expr)) {
1850+ MarkFresh ();
18791851 }
1880-
1881- EmitFresh (str);
1882- return false ;
18831852}
18841853
18851854void Converter::ConvertLambdaToFunctionPointer (
@@ -2212,14 +2181,7 @@ std::optional<Converter::TempMaterializationCtx>
22122181Converter::ConvertCallExpr (clang::CallExpr *expr) {
22132182 auto *callee = expr->getCallee ();
22142183
2215- bool is_printf = IsCDecl (expr->getDirectCallee (), " printf" );
2216- bool is_fprintf = IsCDecl (expr->getDirectCallee (), " fprintf" );
2217- unsigned format_arg = is_fprintf ? 1 : 0 ;
2218- if ((is_printf || is_fprintf) &&
2219- clang::isa<clang::StringLiteral>(
2220- expr->getArg (format_arg)->IgnoreImplicit ())) {
2221- ConvertPrintf (expr);
2222- } else if (IsBuiltinConstantP (callee)) {
2184+ if (IsBuiltinConstantP (callee)) {
22232185 clang::APValue V;
22242186 StrCat (expr->getArg (0 )->isCXX11ConstantExpr (ctx_
22252187#if CLANG_VERSION_MAJOR >= 24
@@ -2229,7 +2191,8 @@ Converter::ConvertCallExpr(clang::CallExpr *expr) {
22292191 )
22302192 ? token::kOne
22312193 : token::kZero );
2232- } else if (Mapper::Contains (ctx_, expr)) {
2194+ } else if (Mapper::Contains (ctx_, expr) &&
2195+ !RuleRegistry::IsLibcPassthrough (ctx_, expr)) {
22332196 auto **args = expr->getArgs ();
22342197 auto num_args = expr->getNumArgs ();
22352198 auto ctx = CollectRefBindingTempArgs (expr);
@@ -3090,6 +3053,10 @@ std::string Converter::ConvertDeclRef(clang::Expr *expr,
30903053 GetNamedDeclAsString (decl));
30913054 }
30923055
3056+ if (auto it = range_iterator_names_.find (decl);
3057+ it != range_iterator_names_.end ()) {
3058+ return it->second ;
3059+ }
30933060 return GetNamedDeclAsString (decl);
30943061}
30953062
@@ -3184,20 +3151,17 @@ bool Converter::ConvertCXXOperatorCallExpr(clang::CXXOperatorCallExpr *expr) {
31843151 // Rust borrows the container before computing the index, so an index that
31853152 // reads the container, or that has side effects through anything the
31863153 // container is reached through, is computed beforehand.
3187- std::unordered_set<const clang::ValueDecl *> base_vars;
3188- auto *inner = base->IgnoreParenImpCasts ();
3189- if (idx->HasSideEffects (ctx_)) {
3190- base_vars = GetAllVars (base);
3191- } else if (auto *ref = clang::dyn_cast<clang::DeclRefExpr>(inner)) {
3192- base_vars.insert (ref->getDecl ());
3193- } else if (auto *member = clang::dyn_cast<clang::MemberExpr>(inner)) {
3194- base_vars.insert (member->getMemberDecl ());
3195- } else {
3196- base_vars = GetAllVars (base);
3154+ const clang::ValueDecl *container = nullptr ;
3155+ if (!idx->HasSideEffects (ctx_)) {
3156+ auto *inner = base->IgnoreParenImpCasts ();
3157+ if (auto *ref = clang::dyn_cast<clang::DeclRefExpr>(inner)) {
3158+ container = ref->getDecl ();
3159+ } else if (auto *member = clang::dyn_cast<clang::MemberExpr>(inner)) {
3160+ container = member->getMemberDecl ();
3161+ }
31973162 }
3198- if (std::ranges::any_of (GetAllVars (idx), [&](const clang::ValueDecl *var) {
3199- return base_vars.contains (var);
3200- })) {
3163+ if (container ? GetAllVars (idx).contains (container)
3164+ : ReferToCommonVar (idx, base)) {
32013165 std::string idx_str;
32023166 {
32033167 ScopedValue no_autoref (autoref_mut_, std::nullopt );
@@ -4925,19 +4889,24 @@ Converter::CollectRefBindingTempArgs(clang::CallExpr *expr) {
49254889 return ctx;
49264890}
49274891
4892+ std::string Converter::TempMaterializationCtx::Wrap (std::string str) const {
4893+ if (temporary_bindings.empty ()) {
4894+ return str;
4895+ }
4896+ return std::format (" {{ {} {} }}" , temporary_bindings, str);
4897+ }
4898+
49284899const std::string &Converter::TempMaterializationCtx::GetOrMaterialize (
49294900 unsigned argument_num,
4930- std::function<std::pair<std::string, std::string>(const std::string &,
4931- clang::QualType)>
4901+ std::function<std::pair<std::string, std::string>(clang::QualType)>
49324902 materialize_fn) {
49334903 auto &str = materialized_refs_.at (argument_num);
49344904 if (!str.empty ()) {
49354905 return str;
49364906 }
49374907
49384908 if (auto m = materialized_args.at (argument_num)) {
4939- auto [binding, ref] =
4940- materialize_fn (std::format (" __tmp_{}" , argument_num), *m);
4909+ auto [binding, ref] = materialize_fn (*m);
49414910 temporary_bindings += std::move (binding);
49424911 str = std::move (ref);
49434912 return str;
@@ -4973,8 +4942,8 @@ std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg,
49734942 if (ph_ctx.needs_materialization ()) {
49744943 auto materialized = ph_ctx.materialize_ctx ->GetOrMaterialize (
49754944 static_cast <unsigned >(ph_ctx.materialize_idx ),
4976- [this , arg](const std::string &name, clang::QualType type) {
4977- return MaterializeTemp (name , type, arg);
4945+ [this , arg](clang::QualType type) {
4946+ return MaterializeTemp (NewTempName () , type, arg);
49784947 });
49794948 if (!materialized.empty ()) {
49804949 return materialized;
0 commit comments