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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
