[clang] [Sema] Fix lifetime extension for temporaries in range-based for loops in C++23 (PR #145164)
Marco Vitale via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 26 10:30:01 PDT 2025
mrcvtl wrote:
> IMO, we have 2 options:
>
> 1. Add a flag variable into `ExpressionEvaluationContextRecord`. Represent that we are initializing the for-range __range variable.
> Eg.
>
> ```diff
> diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
> index 9397546c8fc5..c639a4b4af58 100644
> --- a/clang/include/clang/Sema/Sema.h
> +++ b/clang/include/clang/Sema/Sema.h
> @@ -6786,6 +6786,9 @@ public:
> /// Whether we should rebuild CXXDefaultArgExpr and CXXDefaultInitExpr.
> bool RebuildDefaultArgOrDefaultInit = false;
>
> + /// Whether we are initializing a C++ for-range implicit variable '__range'.
> + bool InitCXXForRangeVar = false;
> +
> // When evaluating immediate functions in the initializer of a default
> // argument or default member initializer, this is the declaration whose
> // default initializer is being evaluated and the location of the call
> diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
> index 060ba3166055..150e27f8acf7 100644
> --- a/clang/lib/Sema/CheckExprLifetime.cpp
> +++ b/clang/lib/Sema/CheckExprLifetime.cpp
> @@ -1341,6 +1341,8 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
> }
>
> if (IsGslPtrValueFromGslTempOwner && DiagLoc.isValid()) {
> + if (SemaRef.currentEvaluationContext().InitCXXForRangeVar)
> + return false;
> SemaRef.Diag(DiagLoc, diag::warn_dangling_lifetime_pointer)
> << DiagRange;
> return false;
> diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
> index 923a9e81fbd6..da97d34854ac 100644
> --- a/clang/lib/Sema/SemaStmt.cpp
> +++ b/clang/lib/Sema/SemaStmt.cpp
> @@ -2374,6 +2374,13 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
> SemaRef.ObjC().inferObjCARCLifetime(Decl))
> Decl->setInvalidDecl();
>
> + // EnterExpressionEvaluationContext ForRangeInitContext(
> + // SemaRef, Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
> + // /*LambdaContextDecl=*/nullptr,
> + // Sema::ExpressionEvaluationContextRecord::EK_Other,
> + // SemaRef.getLangOpts().CPlusPlus23);
> + if (SemaRef.getLangOpts().CPlusPlus23)
> + SemaRef.currentEvaluationContext().InitCXXForRangeVar = true;
> SemaRef.AddInitializerToDecl(Decl, Init, /*DirectInit=*/false);
> SemaRef.FinalizeDeclaration(Decl);
> SemaRef.CurContext->addHiddenDecl(Decl);
> ```
>
> 2. Introduce a bitfields into `clang::VarDecl::NonParmVarDeclBitfields`, like `CXXForRangeDecl`(Eg. `CXXForRangeImplicitVar`)
>
> CC @cor3ntin
I like option one! Maybe a stupid question, but why can’t we use `InLifetimeExtendingContext` flag here? It feels like it’s meant to capture the same kind of situation. Is there a subtle difference I’m missing?
I updated (locally) the PR to address the other feedbacks and I will push when I have the green light to use option 1!
https://github.com/llvm/llvm-project/pull/145164
More information about the cfe-commits
mailing list