https://github.com/efriedma-quic updated https://github.com/llvm/llvm-project/pull/144970
>From b4235454f111a8d97b2d1d32ed63cf92a5151ca0 Mon Sep 17 00:00:00 2001 From: Eli Friedman <efrie...@quicinc.com> Date: Thu, 19 Jun 2025 18:29:49 -0700 Subject: [PATCH] [clang] Consistently handle consteval constructors for variables. 443377a9d1a8d4a69a317a1a892184c59dd0aec6 handled simple variables definitions, but it didn't handle uninitialized variables with a constexpr constructor, and it didn't handle template instantiation. Fixes #135281 . --- clang/include/clang/Sema/Sema.h | 1 + clang/lib/Parse/ParseDecl.cpp | 1 + clang/lib/Sema/SemaCoroutine.cpp | 3 +- clang/lib/Sema/SemaDecl.cpp | 6 ++++ clang/lib/Sema/SemaDeclCXX.cpp | 26 ++------------ clang/lib/Sema/SemaExpr.cpp | 19 +++++++++++ .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 3 +- .../SemaCXX/cxx2b-consteval-propagate.cpp | 34 +++++++++++++++++++ 8 files changed, 67 insertions(+), 26 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 9397546c8fc5d..e335814a910cc 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -6759,6 +6759,7 @@ class Sema final : public SemaBase { EK_Decltype, EK_TemplateArgument, EK_AttrArgument, + EK_VariableInit, EK_Other } ExprContext; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 7e739e09b15e8..c34a1fb6004a9 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2710,6 +2710,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( break; } case InitKind::Uninitialized: { + InitializerScopeRAII InitScope(*this, D, ThisDecl); Actions.ActOnUninitializedDecl(ThisDecl); break; } diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index a1389c6c034b1..d193a33f22393 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -783,7 +783,8 @@ static bool checkSuspensionContext(Sema &S, SourceLocation Loc, const auto ExprContext = S.currentEvaluationContext().ExprContext; const bool BadContext = S.isUnevaluatedContext() || - ExprContext != Sema::ExpressionEvaluationContextRecord::EK_Other; + (ExprContext != Sema::ExpressionEvaluationContextRecord::EK_Other && + ExprContext != Sema::ExpressionEvaluationContextRecord::EK_VariableInit); if (BadContext) { S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword; return false; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e1cccf068b5aa..74530b9fd4246 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -14400,6 +14400,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { Var->getType().getAddressSpace() == LangAS::hlsl_input) return; + if (getLangOpts().CPlusPlus) + ActOnCXXEnterDeclInitializer(nullptr, Var); + // C++03 [dcl.init]p9: // If no initializer is specified for an object, and the // object is of (possibly cv-qualified) non-POD class type (or @@ -14435,6 +14438,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { } CheckCompleteVariableDeclaration(Var); + + if (getLangOpts().CPlusPlus) + ActOnCXXExitDeclInitializer(nullptr, Var); } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 16645ecf411e5..d8e749276e85d 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -18937,7 +18937,8 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) { EnterDeclaratorContext(S, D->getDeclContext()); PushExpressionEvaluationContext( - ExpressionEvaluationContext::PotentiallyEvaluated, D); + ExpressionEvaluationContext::PotentiallyEvaluated, D, + ExpressionEvaluationContextRecord::EK_VariableInit); } void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) { @@ -18946,29 +18947,6 @@ void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) { if (S && D->isOutOfLine()) ExitDeclaratorContext(S); - if (getLangOpts().CPlusPlus23) { - // An expression or conversion is 'manifestly constant-evaluated' if it is: - // [...] - // - the initializer of a variable that is usable in constant expressions or - // has constant initialization. - if (auto *VD = dyn_cast<VarDecl>(D); - VD && (VD->isUsableInConstantExpressions(Context) || - VD->hasConstantInitialization())) { - // An expression or conversion is in an 'immediate function context' if it - // is potentially evaluated and either: - // [...] - // - it is a subexpression of a manifestly constant-evaluated expression - // or conversion. - ExprEvalContexts.back().InImmediateFunctionContext = true; - } - } - - // Unless the initializer is in an immediate function context (as determined - // above), this will evaluate all contained immediate function calls as - // constant expressions. If the initializer IS an immediate function context, - // the initializer has been determined to be a constant expression, and all - // such evaluations will be elided (i.e., as if we "knew the whole time" that - // it was a constant expression). PopExpressionEvaluationContext(); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index a3f534ee6712e..d74885491448a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -17935,6 +17935,25 @@ HandleImmediateInvocations(Sema &SemaRef, Rec.isImmediateFunctionContext() || SemaRef.RebuildingImmediateInvocation) return; + // An expression or conversion is 'manifestly constant-evaluated' if it is: + // [...] + // - the initializer of a variable that is usable in constant expressions or + // has constant initialization. + if (SemaRef.getLangOpts().CPlusPlus23 && + Rec.ExprContext == + Sema::ExpressionEvaluationContextRecord::EK_VariableInit) { + auto *VD = cast<VarDecl>(Rec.ManglingContextDecl); + if (VD->isUsableInConstantExpressions(SemaRef.Context) || + VD->hasConstantInitialization()) { + // An expression or conversion is in an 'immediate function context' if it + // is potentially evaluated and either: + // [...] + // - it is a subexpression of a manifestly constant-evaluated expression + // or conversion. + return; + } + } + /// When we have more than 1 ImmediateInvocationCandidates or previously /// failed immediate invocations, we need to check for nested /// ImmediateInvocationCandidates in order to avoid duplicate diagnostics. diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index a25bfd1c48dee..136fae78fd01f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -6103,7 +6103,8 @@ void Sema::InstantiateVariableInitializer( ContextRAII SwitchContext(*this, Var->getDeclContext()); EnterExpressionEvaluationContext Evaluated( - *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var); + *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var, + ExpressionEvaluationContextRecord::EK_VariableInit); currentEvaluationContext().InLifetimeExtendingContext = parentEvaluationContext().InLifetimeExtendingContext; currentEvaluationContext().RebuildDefaultArgOrDefaultInit = diff --git a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp index dd5063cb29c5b..c4cfd9398920a 100644 --- a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp +++ b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp @@ -576,3 +576,37 @@ int f() { //expected-note@-2 {{read of non-const variable 'a' is not allowed in a constant expression}} } } + +#if __cplusplus >= 202302L +namespace GH135281 { + struct B { + const void* p; + consteval B() : p{this} {} + }; + B b; + B b2{}; + B &&b3{}; + void f() { + static B b4; + B b5; // expected-error {{call to consteval function 'GH135281::B::B' is not a constant expression}} \ + // expected-note {{pointer to temporary is not a constant expression}} \ + // expected-note {{temporary created here}} + } + template<typename T> T temp_var_uninit; + template<typename T> T temp_var_brace_init{}; + B* b6 = &temp_var_uninit<B>; + B* b7 = &temp_var_brace_init<B>; + B* b8 = &temp_var_brace_init<B&&>; + template<typename T> void f2() { + static T b9; + T b10; // expected-error {{call to consteval function 'GH135281::B::B' is not a constant expression}} \ + // expected-note {{pointer to temporary is not a constant expression}} \ + // expected-note {{temporary created here}} + static B b11; + B b12; // expected-error 2 {{call to consteval function 'GH135281::B::B' is not a constant expression}} \ + // expected-note 2 {{pointer to temporary is not a constant expression}} \ + // expected-note 2 {{temporary created here}} + } + void (*ff)() = f2<B>; // expected-note {{instantiation of function template specialization}} +} +#endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits