llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Daniel M. Katz (katzdm)

<details>
<summary>Changes</summary>

This PR is a rework of #<!-- -->173537, which was a rework of #<!-- -->115168; 
the sole goal remains to address #<!-- -->73232. I used #<!-- -->173537 as a 
starting point (for both code and tests), but attempted to follow the 
alternative design requested in the comments therein.

A quick design overview:
- A `SemaProxy` interface is introduced to `AST`, which defines a set of 
(possibly mutable) semantic operations that can be triggered by the evaluation 
of certain expressions; this class finds its implementation in 
`Sema/SemaEval.cpp`. `Sema` creates a unique `SemaProxy` to itself at 
construction time, which is made available via `Sema::getproxyForEval()`.
- Ordinary evaluation (e.g., via `Expr::EvaluateAsConstantExpr`) has no access 
to `SemaProxy`, and therefore cannot act on the AST: instead, variants of these 
functions (e.g., `Expr::EvaluateAsMandatedConstantExpr`) are introduced, which 
accept a `SemaProxy &amp;`. This makes clear from the call-side whether an 
operation can or cannot act on the AST (according to language semantic rules).
- Within the constant evaluator(s), a pointer to `SemaProxy` is stored in 
`interp::State`; this is `nullptr` if evaluation began through a non-`Mandated` 
evaluation function (again, e.g., `EvaluateAsConstantExpr`). The proxy, if 
present, is leveraged during evaluation to call back through to `Sema` (e.g., 
to instantiate a specialization of a templated function).
- Various callsites are updated to leverage the new 
`Expr::EvaluateAsMandatedConstant*` forms of evaluation. I'd appreciate help 
from reviewers in auditing whether I've made the correct choices here.

The tests are mostly from #<!-- -->173537, although I've added some to more 
explicitly cover certain kinds of manifestly constant-evaluated expressions 
(e.g., immediate invocations). I commented one test from #<!-- -->173537 that 
fails an assertion due to an unrelated issue (i.e., #<!-- -->199347). #<!-- 
-->17537 included some other changes to existing tests due to changes to 
diagnostic messages; I was able to avoid these changes by checking whether the 
template of a specialization has a definition, prior to trying to instantiate 
it (so the diagnostic continues to refer to "undefined function 
`f&lt;int&gt;`", rather than to an explicit specialization).

As with #<!-- -->173537, this PR neither addresses #<!-- -->59966 nor provides 
scaffolding for Reflection, though the scaffolding introduced here will help to 
address both use-cases. In particular, the availability of `Sema` through the 
constant evaluator will unblock the implementation of many of C++26 
Reflection's metafunctions, which can explicitly act on the AST during 
evaluation.

It was brought to my attention that the Clang 23 branch is scheduled for a few 
weeks from now; seeing as this is a fairly significant architectural change, I 
have no intention to target that release.

---

Patch is 65.01 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/205557.diff


27 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+1) 
- (modified) clang/include/clang/AST/ASTContext.h (+2-1) 
- (modified) clang/include/clang/AST/Decl.h (+12-1) 
- (modified) clang/include/clang/AST/Expr.h (+20) 
- (added) clang/include/clang/AST/SemaProxy.h (+40) 
- (modified) clang/include/clang/Sema/Sema.h (+26) 
- (modified) clang/lib/AST/ASTContext.cpp (+4-2) 
- (modified) clang/lib/AST/ByteCode/Context.cpp (+2-1) 
- (modified) clang/lib/AST/ByteCode/Context.h (+6-1) 
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+23-9) 
- (modified) clang/lib/AST/ByteCode/InterpState.cpp (+6-6) 
- (modified) clang/lib/AST/ByteCode/State.h (+5-2) 
- (modified) clang/lib/AST/Decl.cpp (+10-4) 
- (modified) clang/lib/AST/ExprConstShared.h (+4) 
- (modified) clang/lib/AST/ExprConstant.cpp (+233-96) 
- (modified) clang/lib/Sema/CMakeLists.txt (+1) 
- (modified) clang/lib/Sema/Sema.cpp (+2-1) 
- (modified) clang/lib/Sema/SemaConcept.cpp (+2-2) 
- (modified) clang/lib/Sema/SemaDecl.cpp (+3-2) 
- (modified) clang/lib/Sema/SemaDeclCXX.cpp (+2-2) 
- (added) clang/lib/Sema/SemaEval.cpp (+48) 
- (modified) clang/lib/Sema/SemaExpr.cpp (+8-5) 
- (modified) clang/lib/Sema/SemaOverload.cpp (+2-1) 
- (modified) clang/test/SemaCXX/constexpr-late-instantiation.cpp (+225-2) 
- (modified) clang/unittests/AST/ByteCode/Descriptor.cpp (+1-1) 
- (modified) clang/unittests/AST/ByteCode/Pointer.cpp (+2-2) 
- (modified) clang/unittests/AST/ByteCode/toAPValue.cpp (+4-4) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 42c5dc16ea2e1..d27ba186a98df 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -804,6 +804,7 @@ Bug Fixes to C++ Support
 - Fixed a crash in constant evaluation using placement new on an array which 
was later initialized. (#GH196450)
 - Fixed an issue where Clang incorrectly accepted invalid unqualified uses of 
local nested class names outside their declaring scope. (#GH184622)
 - Fixed a crash when parsing invalid friend declaration with storage-class 
specifier. (#GH186569)
+- Instantiate constexpr functions as needed before they are evaluated. 
(#GH73232) (#GH35052) (#GH100897)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index a4ed852d36442..6c157cc8755a5 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -129,6 +129,7 @@ class ParentMapContext;
 struct ParsedTargetAttr;
 class Preprocessor;
 class ProfileList;
+class SemaProxy;
 class StoredDeclsMap;
 class TargetAttr;
 class TargetInfo;
@@ -808,7 +809,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
   ASTMutationListener *Listener = nullptr;
 
   /// Returns the clang bytecode interpreter context.
-  interp::Context &getInterpContext() const;
+  interp::Context &getInterpContext(SemaProxy *Sema) const;
 
   struct CUDAConstantEvalContext {
     /// Do not allow wrong-sided variables in constant expressions.
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index e200b8f06ec4b..8c3effac13255 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -70,6 +70,7 @@ class Module;
 class NamespaceDecl;
 class ParmVarDecl;
 class RecordDecl;
+class SemaProxy;
 class Stmt;
 class StringLiteral;
 class TagDecl;
@@ -1435,6 +1436,7 @@ class VarDecl : public DeclaratorDecl, public 
Redeclarable<VarDecl> {
 
 private:
   APValue *evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> *Notes,
+                             SemaProxy *SP,
                              bool IsConstantInitialization) const;
 
 public:
@@ -1451,6 +1453,15 @@ class VarDecl : public DeclaratorDecl, public 
Redeclarable<VarDecl> {
   ///         not.
   bool evaluateDestruction(SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
 
+  /// Evaluate the destruction of this variable, the destruction of which is
+  /// required by language rules to be constant.
+  ///
+  /// \pre hasConstantInitialization()
+  /// \return \c true if this variable has constant destruction, \c false if
+  ///         not.
+  bool evaluateMandatedConstantDestruction(
+      SmallVectorImpl<PartialDiagnosticAt> &Notes, SemaProxy &SP) const;
+
   /// Determine whether this variable has constant initialization.
   ///
   /// This is only set in two cases: when the language semantics require
@@ -1468,7 +1479,7 @@ class VarDecl : public DeclaratorDecl, public 
Redeclarable<VarDecl> {
   /// constant initializer. Should only be called once, after completing the
   /// definition of the variable.
   bool checkForConstantInitialization(
-      SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
+      SmallVectorImpl<PartialDiagnosticAt> &Notes, SemaProxy *SP) const;
 
   void setInitStyle(InitializationStyle Style) {
     VarDeclBits.InitStyle = Style;
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 7c94c4d35641c..6ca1eb96b651a 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -55,6 +55,7 @@ namespace clang {
   class ObjCPropertyRefExpr;
   class OpaqueValueExpr;
   class ParmVarDecl;
+  class SemaProxy;
   class StringLiteral;
   class TargetInfo;
   class ValueDecl;
@@ -667,6 +668,13 @@ class Expr : public ValueStmt {
   bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx,
                         bool InConstantContext = false) const;
 
+  /// Evaluate an expression that is required by the language to be a constant
+  /// expression, and fold the resulting rvalue constant into Result. If the
+  /// expression is a glvalue, an lvalue-to-rvalue conversion will be applied.
+  bool EvaluateAsMandatedConstantRValue(EvalResult &Result,
+                                        const ASTContext &Ctx,
+                                        SemaProxy &SP) const;
+
   /// EvaluateAsBooleanCondition - Return true if this is a constant
   /// which we can fold and convert to a boolean condition using
   /// any crazy technique that we want to, even if the expression has
@@ -743,6 +751,12 @@ class Expr : public ValueStmt {
                              EvalResult &Result,
                              bool IsConstantInitializer) const;
 
+  /// Evaluate an expression that is required by the language to be a constant
+  /// expression.
+  bool EvaluateAsMandatedConstantInitializer(
+      EvalResult &Result, const ASTContext &Ctx, SemaProxy &SP,
+      const VarDecl *VD) const;
+
   /// EvaluateWithSubstitution - Evaluate an expression as if from the context
   /// of a call to the given function with the given arguments, inside an
   /// unevaluated context. Returns true if the expression could be folded to a
@@ -773,6 +787,12 @@ class Expr : public ValueStmt {
       EvalResult &Result, const ASTContext &Ctx,
       ConstantExprKind Kind = ConstantExprKind::Normal) const;
 
+  /// Evaluate an expression that is required by the language to be a constant
+  /// expression.
+  bool EvaluateAsMandatedConstantExpr(
+      EvalResult &Result, const ASTContext &Ctx, SemaProxy &SP,
+      ConstantExprKind Kind = ConstantExprKind::Normal) const;
+
   /// If the current Expr is a pointer, this will try to statically
   /// determine the number of bytes available where the pointer is pointing.
   /// Returns true if all of the above holds and we were able to figure out the
diff --git a/clang/include/clang/AST/SemaProxy.h 
b/clang/include/clang/AST/SemaProxy.h
new file mode 100644
index 0000000000000..ab6a87f1e32a5
--- /dev/null
+++ b/clang/include/clang/AST/SemaProxy.h
@@ -0,0 +1,40 @@
+//===--- SemaProxy.h - Interface to language semantics ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the SemaProxy interface, used during language-mandated
+//  constant evaluation to act on, and query, the representation of the program
+//  according to language-defined semantics.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_SEMA_PROXY_H
+#define LLVM_CLANG_AST_SEMA_PROXY_H
+
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+
+class FunctionDecl;
+
+/// Classes implementing SemaProxy present a restricted view of the (possibly
+/// mutating) actions and queries defined by language semantics against the
+/// representation of the program (i.e., the AST). Such a view is required in
+/// order to evaluate certain expressions (e.g., C++'s manifestly
+/// constant-evaluated expressions) according to language rules.
+class SemaProxy {
+public:
+  virtual ~SemaProxy() = default;
+
+  virtual void
+  instantiateFunctionDefinition(SourceLocation PointOfInstantiation,
+                                FunctionDecl *Function) = 0;
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_SEMA_PROXY_H
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index b8d760e7e0975..97b951bf6d672 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -30,6 +30,7 @@
 #include "clang/AST/ExternalASTSource.h"
 #include "clang/AST/NestedNameSpecifier.h"
 #include "clang/AST/OperationKinds.h"
+#include "clang/AST/SemaProxy.h"
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeLoc.h"
@@ -907,6 +908,7 @@ class Sema final : public SemaBase {
   // 33. Types (SemaType.cpp)
   // 34. FixIt Helpers (SemaFixItUtils.cpp)
   // 35. Function Effects (SemaFunctionEffects.cpp)
+  // 36. Language-Mandated Constant Evaluation (SemaEval.cpp)
 
   /// \name Semantic Analysis
   /// Implementations are in Sema.cpp
@@ -15811,6 +15813,30 @@ class Sema final : public SemaBase {
   void performFunctionEffectAnalysis(TranslationUnitDecl *TU);
 
   ///@}
+
+  //
+  //
+  // -------------------------------------------------------------------------
+  //
+  //
+
+  /// \name Language-Mandated Constant Evaluation
+  /// Implementations are in SemaEval.cpp
+  ///@{
+public:
+  SemaProxy &getProxyForEval() const {
+    assert(ProxyForEval);
+    return *ProxyForEval;
+  }
+
+private:
+  std::unique_ptr<SemaProxy> ProxyForEval;
+
+  static SemaProxy *makeProxyForEval(Sema &SemaRef);
+
+  ///@}
+public:
+
 };
 
 DeductionFailureInfo
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index abf0cd5e18c2b..f58e7c394ad18 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -40,6 +40,7 @@
 #include "clang/AST/ParentMapContext.h"
 #include "clang/AST/RawCommentList.h"
 #include "clang/AST/RecordLayout.h"
+#include "clang/AST/SemaProxy.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/TemplateBase.h"
 #include "clang/AST/TemplateName.h"
@@ -901,9 +902,10 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
   llvm_unreachable("Invalid CXXABI type!");
 }
 
-interp::Context &ASTContext::getInterpContext() const {
+interp::Context &ASTContext::getInterpContext(SemaProxy *Sema) const {
   if (!InterpContext) {
-    InterpContext.reset(new interp::Context(const_cast<ASTContext &>(*this)));
+    InterpContext.reset(
+        new interp::Context(const_cast<ASTContext &>(*this), Sema));
   }
   return *InterpContext;
 }
diff --git a/clang/lib/AST/ByteCode/Context.cpp 
b/clang/lib/AST/ByteCode/Context.cpp
index 4beb35a9a7b43..eaf077a3eae92 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -26,7 +26,8 @@
 using namespace clang;
 using namespace clang::interp;
 
-Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {
+Context::Context(ASTContext &Ctx, SemaProxy *Sema)
+    : Ctx(Ctx), Sema(Sema), P(new Program(*this)) {
   this->ShortWidth = Ctx.getTargetInfo().getShortWidth();
   this->IntWidth = Ctx.getTargetInfo().getIntWidth();
   this->LongWidth = Ctx.getTargetInfo().getLongWidth();
diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h
index 789f72ae34f73..085883b1d729d 100644
--- a/clang/lib/AST/ByteCode/Context.h
+++ b/clang/lib/AST/ByteCode/Context.h
@@ -25,6 +25,7 @@ class FunctionDecl;
 class VarDecl;
 class APValue;
 class BlockExpr;
+class SemaProxy;
 
 namespace interp {
 class Function;
@@ -47,7 +48,7 @@ class EvalIDScope;
 class Context final {
 public:
   /// Initialises the constexpr VM.
-  explicit Context(ASTContext &Ctx);
+  explicit Context(ASTContext &Ctx, SemaProxy *Sema);
 
   /// Cleans up the constexpr VM.
   ~Context();
@@ -99,6 +100,8 @@ class Context final {
 
   /// Returns the AST context.
   ASTContext &getASTContext() const { return Ctx; }
+  /// Returns the (possibly null) pointer to the language semantics proxy.
+  SemaProxy *getSemaProxy() const { return Sema; }
   /// Returns the language options.
   const LangOptions &getLangOpts() const;
   /// Returns CHAR_BIT.
@@ -191,6 +194,8 @@ class Context final {
 
   /// Current compilation context.
   ASTContext &Ctx;
+  /// Current proxy to language semantics.
+  SemaProxy *Sema;
   /// Interpreter stack, shared across invocations.
   InterpStack Stk;
   /// Constexpr program.
diff --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index 3772def47408f..13de84a26eedc 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -21,6 +21,7 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/SemaProxy.h"
 #include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/StringExtras.h"
@@ -1776,15 +1777,28 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, const 
Type *TargetType,
   return true;
 }
 
-static void compileFunction(InterpState &S, const Function *Func) {
-  const FunctionDecl *Definition;
-  if (!Func->getDecl()->getBody(Definition))
-    return;
-  if (!Definition)
+static void compileFunction(InterpState &S, const Function *Func,
+                            CodePtr OpPC) {
+  const FunctionDecl *Fn = Func->getDecl();
+
+  // [C++26] [temp.inst] p5
+  // [...] the function template specialization is implicitly instantiated
+  // when the specialization is referenced in a context that requires a 
function
+  // definition to exist or if the existence of the definition affects the
+  // semantics of the program.
+  if (FunctionDefinitionCanBeLazilyInstantiated(Fn) && S.inConstantContext()) {
+    SemaProxy *SP = S.getSemaProxy();
+    if (!SP)
+      return;
+    SP->instantiateFunctionDefinition(S.Current->getLocation(OpPC),
+                                      const_cast<FunctionDecl *>(Fn));
+  }
+  Fn = Fn->getDefinition();
+  if (!Fn)
     return;
 
   Compiler<ByteCodeEmitter>(S.getContext(), S.P)
-      .compileFunc(Definition, const_cast<Function *>(Func));
+      .compileFunc(Fn, const_cast<Function *>(Func));
 }
 
 bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
@@ -1811,7 +1825,7 @@ bool CallVar(InterpState &S, CodePtr OpPC, const Function 
*Func,
   }
 
   if (!Func->isFullyCompiled())
-    compileFunction(S, Func);
+    compileFunction(S, Func, OpPC);
 
   if (!CheckCallable(S, OpPC, Func))
     return false;
@@ -1898,7 +1912,7 @@ bool Call(InterpState &S, CodePtr OpPC, const Function 
*Func,
   }
 
   if (!Func->isFullyCompiled())
-    compileFunction(S, Func);
+    compileFunction(S, Func, OpPC);
 
   if (!CheckCallable(S, OpPC, Func))
     return cleanup();
@@ -2316,7 +2330,7 @@ bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t 
ArgSize,
   // because the Call/CallVirt below might access the instance pointer
   // but the Function's information about them is wrong.
   if (!F->isFullyCompiled())
-    compileFunction(S, F);
+    compileFunction(S, F, OpPC);
 
   if (!CheckCallable(S, OpPC, F))
     return false;
diff --git a/clang/lib/AST/ByteCode/InterpState.cpp 
b/clang/lib/AST/ByteCode/InterpState.cpp
index 2d6ed98e6b52c..ac6d45df2b9e6 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -19,9 +19,9 @@ using namespace clang::interp;
 
 InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk,
                          Context &Ctx, SourceMapper *M)
-    : State(Ctx.getASTContext(), Parent.getEvalStatus()), M(M), P(P), Stk(Stk),
-      Ctx(Ctx), BottomFrame(*this), Current(&BottomFrame),
-      StepsLeft(Ctx.getLangOpts().ConstexprStepLimit),
+    : State(Ctx.getASTContext(), Parent.getSemaProxy(), 
Parent.getEvalStatus()),
+      M(M), P(P), Stk(Stk), Ctx(Ctx), BottomFrame(*this),
+      Current(&BottomFrame), StepsLeft(Ctx.getLangOpts().ConstexprStepLimit),
       InfiniteSteps(StepsLeft == 0), EvalID(Ctx.getEvalID()) {
   InConstantContext = Parent.InConstantContext;
   CheckingPotentialConstantExpression =
@@ -32,9 +32,9 @@ InterpState::InterpState(const State &Parent, Program &P, 
InterpStack &Stk,
 
 InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk,
                          Context &Ctx, const Function *Func)
-    : State(Ctx.getASTContext(), Parent.getEvalStatus()), M(nullptr), P(P),
-      Stk(Stk), Ctx(Ctx), BottomFrame(*this), Current(&BottomFrame),
-      StepsLeft(Ctx.getLangOpts().ConstexprStepLimit),
+    : State(Ctx.getASTContext(), Parent.getSemaProxy(), 
Parent.getEvalStatus()),
+      M(nullptr), P(P), Stk(Stk), Ctx(Ctx), BottomFrame(*this),
+      Current(&BottomFrame), StepsLeft(Ctx.getLangOpts().ConstexprStepLimit),
       InfiniteSteps(StepsLeft == 0), EvalID(Ctx.getEvalID()) {
   InConstantContext = Parent.InConstantContext;
   CheckingPotentialConstantExpression =
diff --git a/clang/lib/AST/ByteCode/State.h b/clang/lib/AST/ByteCode/State.h
index df3afdf8cbc24..e9e94d4ffeb9b 100644
--- a/clang/lib/AST/ByteCode/State.h
+++ b/clang/lib/AST/ByteCode/State.h
@@ -20,6 +20,7 @@
 
 namespace clang {
 class OptionalDiagnostic;
+class SemaProxy;
 
 /// Kinds of access we can perform on an object, for diagnostics. Note that
 /// we consider a member function call to be a kind of access, even though
@@ -80,8 +81,8 @@ class SourceInfo;
 /// Interface for the VM to interact with the AST walker's context.
 class State {
 public:
-  State(ASTContext &ASTCtx, Expr::EvalStatus &EvalStatus)
-      : Ctx(ASTCtx), EvalStatus(EvalStatus) {}
+  State(ASTContext &ASTCtx, SemaProxy *Sema, Expr::EvalStatus &EvalStatus)
+      : Ctx(ASTCtx), Sema(Sema), EvalStatus(EvalStatus) {}
   virtual ~State();
 
   virtual const Frame *getCurrentFrame() = 0;
@@ -90,6 +91,7 @@ class State {
 
   Expr::EvalStatus &getEvalStatus() const { return EvalStatus; }
   ASTContext &getASTContext() const { return Ctx; }
+  SemaProxy *getSemaProxy() const { return Sema; }
   const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
 
   /// Note that we have had a side-effect, and determine whether we should
@@ -188,6 +190,7 @@ class State {
 
   EvaluationMode EvalMode;
   ASTContext &Ctx;
+  SemaProxy *Sema;
   Expr::EvalStatus &EvalStatus;
 
 private:
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 7ab4235717dde..0382a26f0f692 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -32,6 +32,7 @@
 #include "clang/AST/Randstruct.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/AST/Redeclarable.h"
+#include "clang/AST/SemaProxy.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/TemplateBase.h"
 #include "clang/AST/Type.h"
@@ -2552,10 +2553,12 @@ EvaluatedStmt *VarDecl::getEvaluatedStmt() const {
 }
 
 APValue *VarDecl::evaluateValue() const {
-  return evaluateValueImpl(/*Notes=*/nullptr, hasConstantInitialization());
+  return evaluateValueImpl(/*Notes=*/nullptr, /*Sema=*/nullptr,
+                           hasConstantInitialization());
 }
 
 APValue *VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> 
*Notes,
+                                    SemaProxy *SP,
                                     bool IsConstantInitialization) const {
   EvaluatedStmt *Eval = ensureEvaluatedStmt();
 
@@ -2579,7 +2582,10 @@ APValue 
*VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> *Notes,
   Expr::EvalResult EStatus;
   EStatus.Diag = Notes;
   bool Result =
-      Init->EvaluateAsInitializer(Ctx, this, EStatus, 
IsConstantInitialization);
+      isConstexpr() ?
+        Init->EvaluateAsMandatedConstantInitializer(EStatus, Ctx, *SP, this)
+      : Init->EvaluateAsInitializer(Ctx, this, EStatus,
+                                    IsConstantInitialization);
   Eval->Evaluated = std::move(EStatus.Val);
 
   // In C++, or in C23 if we're initialising a 'constexpr' variable, this isn't
@@ -2643,7 +2649,7 @@ bool VarDecl::hasConstantInitialization() const {
 }
 
 bool VarDecl::checkForConstantInitialization(
-    SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+    SmallVectorImpl<PartialDiagnosticAt> &Notes, SemaProxy *SP) const {
   EvaluatedStmt *Eval = ensureEvaluatedStmt();
   // If we ask for the value before we know whether we have a constant
   // initializer, we can compute the wrong value (for example, due to
@@ -2658,7 +2664,7 @@ bool VarDecl::checkForConstantInitialization(
 
   // Evaluate the initializer to check whether it's a constant expression.
   Eval->HasConstantInitialization =
-      evaluateValueImpl(&Notes, true) && Notes.empty();
+      evaluateValueImpl(&Notes, SP, true) && Notes.empty();
 
   // If evaluation as a constant initializer failed, allow re-evaluation as a
   // non-constant initializer if we later find we want the value.
diff --git a/clang/lib/AST/ExprConstShared.h b/clang/lib/AST/ExprConstShared.h
index 619c79a1408f3..45c7db846fc70 100644
--- a/clang/lib/AST/ExprConstShared.h
+++ b/clang/lib/AST/ExprConstShared.h
@@ -29,6 +29,7 @@ class LangOptions;
 class ASTContext;
 class CharUni...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/205557
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to