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

Reply via email to