[clang] [Clang] Instantiate functions from constant evaluation. (PR #205557)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 24 08:21:06 PDT 2026
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 &`. 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<int>`", 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
More information about the cfe-commits
mailing list