[clang] Enable AST mutation in the constant evaluator (PR #115168)
Vlad Serebrennikov via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 8 07:20:47 PST 2024
https://github.com/Endilll updated https://github.com/llvm/llvm-project/pull/115168
>From 5ca48e03412b1b8e9253f13356b9cc957f6fd9e5 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Wed, 6 Nov 2024 17:58:43 +0300
Subject: [PATCH 1/6] Add EvalASTMutator interface with
`InstantiateFunctionDefinition` function
---
clang/include/clang/AST/ASTContext.h | 2 +-
clang/include/clang/AST/Decl.h | 22 ++++++++++---
clang/include/clang/AST/Expr.h | 3 +-
clang/include/clang/Sema/Sema.h | 17 ++++++++++
clang/lib/AST/ASTContext.cpp | 4 +--
clang/lib/AST/Decl.cpp | 16 +++++-----
clang/lib/AST/ExprConstant.cpp | 24 +++++++++++---
clang/lib/Sema/Sema.cpp | 11 ++++++-
clang/lib/Sema/SemaDecl.cpp | 5 +--
.../constexpr-function-instantiation.cpp | 31 +++++++++++++++++++
10 files changed, 113 insertions(+), 22 deletions(-)
create mode 100644 clang/test/SemaCXX/constexpr-function-instantiation.cpp
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index a4d36f2eacd5d1..d143591de9f2cd 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -3258,7 +3258,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
///
/// \returns true if the function/var must be CodeGen'ed/deserialized even if
/// it is not used.
- bool DeclMustBeEmitted(const Decl *D);
+ bool DeclMustBeEmitted(const Decl *D, EvalASTMutator *ASTMutator = nullptr);
/// Visits all versions of a multiversioned function with the passed
/// predicate.
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 7ff35d73df5997..89a2833c82194d 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -78,6 +78,18 @@ class UnresolvedSetImpl;
class VarTemplateDecl;
enum class ImplicitParamKind;
+/// Interface that allows constant evaluator to mutate AST.
+/// When constant evaluation is triggered by Sema, it can supply a proper
+/// implementation of this interface.
+struct EvalASTMutator {
+ virtual ~EvalASTMutator() = default;
+
+ virtual void
+ InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
+ FunctionDecl *Function, bool Recursive,
+ bool DefinitionRequired, bool AtEndOfTU) = 0;
+};
+
/// The top declaration context.
class TranslationUnitDecl : public Decl,
public DeclContext,
@@ -1355,11 +1367,12 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
/// Attempt to evaluate the value of the initializer attached to this
/// declaration, and produce notes explaining why it cannot be evaluated.
/// Returns a pointer to the value if evaluation succeeded, 0 otherwise.
- APValue *evaluateValue() const;
+ APValue *evaluateValue(EvalASTMutator *ASTMutator = nullptr) const;
private:
APValue *evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
- bool IsConstantInitialization) const;
+ bool IsConstantInitialization,
+ EvalASTMutator *ASTMutator = nullptr) const;
public:
/// Return the already-evaluated value of this variable's
@@ -1391,8 +1404,9 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
/// Evaluate the initializer of this variable to determine whether it's a
/// constant initializer. Should only be called once, after completing the
/// definition of the variable.
- bool checkForConstantInitialization(
- SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
+ bool
+ checkForConstantInitialization(SmallVectorImpl<PartialDiagnosticAt> &Notes,
+ EvalASTMutator *ASTMutator = nullptr) 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 466c65a9685ad3..ccf7fd226b5a8f 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -734,7 +734,8 @@ class Expr : public ValueStmt {
bool EvaluateAsInitializer(APValue &Result, const ASTContext &Ctx,
const VarDecl *VD,
SmallVectorImpl<PartialDiagnosticAt> &Notes,
- bool IsConstantInitializer) const;
+ bool IsConstantInitializer,
+ EvalASTMutator *ASTMutator = nullptr) const;
/// EvaluateWithSubstitution - Evaluate an expression as if from the context
/// of a call to the given function with the given arguments, inside an
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 93d98e1cbb9c81..1c0c6949573335 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -153,6 +153,7 @@ enum class OverloadCandidateParamOrder : char;
enum OverloadCandidateRewriteKind : unsigned;
class OverloadCandidateSet;
class Preprocessor;
+class Sema;
class SemaAMDGPU;
class SemaARM;
class SemaAVR;
@@ -352,6 +353,15 @@ struct SkipBodyInfo {
NamedDecl *New = nullptr;
};
+/// Implementation of EvalASTMutator interface that enables constant evaluator
+/// to modify AST, e.g. to instantiate templates.
+struct SemaASTMutator : EvalASTMutator {
+ Sema &SemaRef;
+ SemaASTMutator(Sema &SemaRef) void InstantiateFunctionDefinition(
+ SourceLocation PointOfInstantiation, FunctionDecl *Function,
+ bool Recursive, bool DefinitionRequired, bool AtEndOfTU) override;
+};
+
/// Describes the result of template argument deduction.
///
/// The TemplateDeductionResult enumeration describes the result of
@@ -1042,6 +1052,9 @@ class Sema final : public SemaBase {
/// CurContext - This is the current declaration context of parsing.
DeclContext *CurContext;
+ /// Get a Sema implementation of EvalASTMutator interface.
+ SemaASTMutator *getASTMutator() { return &ASTMutator; }
+
SemaAMDGPU &AMDGPU() {
assert(AMDGPUPtr);
return *AMDGPUPtr;
@@ -1199,6 +1212,10 @@ class Sema final : public SemaBase {
mutable IdentifierInfo *Ident_super;
+ /// EvalASTMutator implementation that can be passed to constant evaluator
+ /// to enable it to do AST mutations, e.g. template instantiation.
+ SemaASTMutator ASTMutator;
+
std::unique_ptr<SemaAMDGPU> AMDGPUPtr;
std::unique_ptr<SemaARM> ARMPtr;
std::unique_ptr<SemaAVR> AVRPtr;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 69892bda42b256..0aaf23af28d3d6 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -12522,7 +12522,7 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) const {
basicGVALinkageForVariable(*this, VD)));
}
-bool ASTContext::DeclMustBeEmitted(const Decl *D) {
+bool ASTContext::DeclMustBeEmitted(const Decl *D, EvalASTMutator *ASTMutator) {
if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl())
return false;
@@ -12627,7 +12627,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
// Variables that have initialization with side-effects are required.
if (VD->getInit() && VD->getInit()->HasSideEffects(*this) &&
// We can get a value-dependent initializer during error recovery.
- (VD->getInit()->isValueDependent() || !VD->evaluateValue()))
+ (VD->getInit()->isValueDependent() || !VD->evaluateValue(ASTMutator)))
return true;
// Likewise, variables with tuple-like bindings are required if their
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 86913763ef9ff5..f49ef66cb43aea 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2546,13 +2546,14 @@ EvaluatedStmt *VarDecl::getEvaluatedStmt() const {
return Init.dyn_cast<EvaluatedStmt *>();
}
-APValue *VarDecl::evaluateValue() const {
+APValue *VarDecl::evaluateValue(EvalASTMutator *ASTMutator) const {
SmallVector<PartialDiagnosticAt, 8> Notes;
- return evaluateValueImpl(Notes, hasConstantInitialization());
+ return evaluateValueImpl(Notes, hasConstantInitialization(), ASTMutator);
}
APValue *VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
- bool IsConstantInitialization) const {
+ bool IsConstantInitialization,
+ EvalASTMutator *ASTMutator) const {
EvaluatedStmt *Eval = ensureEvaluatedStmt();
const auto *Init = getInit();
@@ -2572,8 +2573,8 @@ APValue *VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
Eval->IsEvaluating = true;
ASTContext &Ctx = getASTContext();
- bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, Ctx, this, Notes,
- IsConstantInitialization);
+ bool Result = Init->EvaluateAsInitializer(
+ Eval->Evaluated, Ctx, this, Notes, IsConstantInitialization, ASTMutator);
// In C++, or in C23 if we're initialising a 'constexpr' variable, this isn't
// a constant initializer if we produced notes. In that case, we can't keep
@@ -2636,7 +2637,8 @@ bool VarDecl::hasConstantInitialization() const {
}
bool VarDecl::checkForConstantInitialization(
- SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+ SmallVectorImpl<PartialDiagnosticAt> &Notes,
+ EvalASTMutator *ASTMutator) 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
@@ -2651,7 +2653,7 @@ bool VarDecl::checkForConstantInitialization(
// Evaluate the initializer to check whether it's a constant expression.
Eval->HasConstantInitialization =
- evaluateValueImpl(Notes, true) && Notes.empty();
+ evaluateValueImpl(Notes, true, ASTMutator) && 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/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index d664c503655ba6..b9a075154b6d6f 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1004,6 +1004,11 @@ namespace {
EM_IgnoreSideEffects,
} EvalMode;
+ /// Implementation of an interface for AST mutation.
+ /// Basically something backed by Sema,
+ /// or nullptr if Sema is not available.
+ EvalASTMutator *ASTMutator;
+
/// Are we checking whether the expression is a potential constant
/// expression?
bool checkingPotentialConstantExpression() const override {
@@ -1017,7 +1022,8 @@ namespace {
return CheckingForUndefinedBehavior;
}
- EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
+ EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode,
+ EvalASTMutator *ASTMutator = nullptr)
: Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
CallStackDepth(0), NextCallIndex(1),
StepsLeft(C.getLangOpts().ConstexprStepLimit),
@@ -1027,13 +1033,15 @@ namespace {
/*CallExpr=*/nullptr, CallRef()),
EvaluatingDecl((const ValueDecl *)nullptr),
EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
- HasFoldFailureDiagnostic(false), EvalMode(Mode) {}
+ HasFoldFailureDiagnostic(false), EvalMode(Mode),
+ ASTMutator(ASTMutator) {}
~EvalInfo() {
discardCleanups();
}
ASTContext &getASTContext() const override { return Ctx; }
+ EvalASTMutator *getASTMutator() const { return ASTMutator; }
void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value,
EvaluatingDeclKind EDK = EvaluatingDeclKind::Ctor) {
@@ -8328,6 +8336,12 @@ class ExprEvaluatorBase
const FunctionDecl *Definition = nullptr;
Stmt *Body = FD->getBody(Definition);
+ if (!Definition && FD->getTemplateInstantiationPattern()) {
+ Info.getASTMutator()->InstantiateFunctionDefinition(
+ E->getExprLoc(), const_cast<FunctionDecl *>(FD),
+ /*Recursive=*/true, /*DefinitionRequired=*/true, /*AtEndOfTU=*/false);
+ Body = FD->getBody(Definition);
+ }
if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body) ||
!HandleFunctionCall(E->getExprLoc(), Definition, This, E, Args, Call,
@@ -16669,7 +16683,8 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
const VarDecl *VD,
SmallVectorImpl<PartialDiagnosticAt> &Notes,
- bool IsConstantInitialization) const {
+ bool IsConstantInitialization,
+ EvalASTMutator *ASTMutator) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
@@ -16687,7 +16702,8 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
(IsConstantInitialization &&
(Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23))
? EvalInfo::EM_ConstantExpression
- : EvalInfo::EM_ConstantFold);
+ : EvalInfo::EM_ConstantFold,
+ ASTMutator);
Info.setEvaluatingDecl(VD, Value);
Info.InConstantContext = IsConstantInitialization;
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 2b51765e80864a..328a8f7912a8ea 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -208,6 +208,8 @@ class SemaPPCallbacks : public PPCallbacks {
} // end namespace sema
} // end namespace clang
+SemaASTMutator::SemaASTMutator(Sema &SemaRef) : SemaRef(SemaRef) {}
+
const unsigned Sema::MaxAlignmentExponent;
const uint64_t Sema::MaximumAlignment;
@@ -221,7 +223,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr),
OpaqueParser(nullptr), CurContext(nullptr), ExternalSource(nullptr),
StackHandler(Diags), CurScope(nullptr), Ident_super(nullptr),
- AMDGPUPtr(std::make_unique<SemaAMDGPU>(*this)),
+ ASTMutator(*this), AMDGPUPtr(std::make_unique<SemaAMDGPU>(*this)),
ARMPtr(std::make_unique<SemaARM>(*this)),
AVRPtr(std::make_unique<SemaAVR>(*this)),
BPFPtr(std::make_unique<SemaBPF>(*this)),
@@ -2798,3 +2800,10 @@ Attr *Sema::CreateAnnotationAttr(const ParsedAttr &AL) {
return CreateAnnotationAttr(AL, Str, Args);
}
+
+void SemaASTMutator::InstantiateFunctionDefinition(
+ SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive,
+ bool DefinitionRequired, bool AtEndOfTU) {
+ SemaRef.InstantiateFunctionDefinition(
+ PointOfInstantiation, Function, Recursive, DefinitionRequired, AtEndOfTU);
+}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index f8e5f3c6d309d6..ea6ca66f8c69e9 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14441,7 +14441,8 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
} else {
// Evaluate the initializer to see if it's a constant initializer.
- HasConstInit = var->checkForConstantInitialization(Notes);
+ HasConstInit =
+ var->checkForConstantInitialization(Notes, getASTMutator());
}
if (HasConstInit) {
@@ -14549,7 +14550,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// If this variable must be emitted, add it as an initializer for the current
// module.
- if (Context.DeclMustBeEmitted(var) && !ModuleScopes.empty())
+ if (Context.DeclMustBeEmitted(var, getASTMutator()) && !ModuleScopes.empty())
Context.addModuleInitializer(ModuleScopes.back().Module, var);
// Build the bindings if this is a structured binding declaration.
diff --git a/clang/test/SemaCXX/constexpr-function-instantiation.cpp b/clang/test/SemaCXX/constexpr-function-instantiation.cpp
new file mode 100644
index 00000000000000..43c2ced137474d
--- /dev/null
+++ b/clang/test/SemaCXX/constexpr-function-instantiation.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++2c -fsyntax-only -verify %s
+
+namespace GH73232 {
+namespace ex1 {
+template <typename T>
+constexpr void g(T);
+
+constexpr int f() {
+ g(0);
+ return 0;
+}
+
+template <typename T>
+constexpr void g(T) {}
+
+constexpr auto z = f();
+} // namespace ex1
+
+namespace ex2 {
+template <typename> constexpr static void fromType();
+
+void registerConverter() { fromType<int>(); }
+template <typename> struct QMetaTypeId {};
+template <typename T> constexpr void fromType() {
+ (void)QMetaTypeId<T>{};
+} // #1
+template <> struct QMetaTypeId<int> {}; // #20428
+} // namespace ex2
+} // namespace GH73232
\ No newline at end of file
>From 57de67a735c40557ba203ad1c3e46c6791dff706 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Wed, 6 Nov 2024 18:00:39 +0300
Subject: [PATCH 2/6] Add missing newline
---
clang/test/SemaCXX/constexpr-function-instantiation.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/SemaCXX/constexpr-function-instantiation.cpp b/clang/test/SemaCXX/constexpr-function-instantiation.cpp
index 43c2ced137474d..6c7e43f85cf6f9 100644
--- a/clang/test/SemaCXX/constexpr-function-instantiation.cpp
+++ b/clang/test/SemaCXX/constexpr-function-instantiation.cpp
@@ -28,4 +28,4 @@ template <typename T> constexpr void fromType() {
} // #1
template <> struct QMetaTypeId<int> {}; // #20428
} // namespace ex2
-} // namespace GH73232
\ No newline at end of file
+} // namespace GH73232
>From 548298c8e2d1030b5d4edb8b548609b55aeba7f0 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Wed, 6 Nov 2024 18:14:45 +0300
Subject: [PATCH 3/6] Add missing semicolon
---
clang/include/clang/Sema/Sema.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 1c0c6949573335..61114b7107c650 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -357,7 +357,8 @@ struct SkipBodyInfo {
/// to modify AST, e.g. to instantiate templates.
struct SemaASTMutator : EvalASTMutator {
Sema &SemaRef;
- SemaASTMutator(Sema &SemaRef) void InstantiateFunctionDefinition(
+ SemaASTMutator(Sema &SemaRef);
+ void InstantiateFunctionDefinition(
SourceLocation PointOfInstantiation, FunctionDecl *Function,
bool Recursive, bool DefinitionRequired, bool AtEndOfTU) override;
};
>From 33092200cb15b3e095ee82d9001dd0e50eda668f Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Thu, 7 Nov 2024 19:35:41 +0300
Subject: [PATCH 4/6] Put ASTMutator inside ASTContext
---
clang/include/clang/AST/ASTContext.h | 21 ++++++++++++++++++-
clang/include/clang/AST/Decl.h | 20 +++---------------
clang/include/clang/AST/Expr.h | 3 +--
clang/lib/AST/ASTContext.cpp | 4 ++--
clang/lib/AST/Decl.cpp | 14 ++++++-------
clang/lib/AST/ExprConstant.cpp | 7 +++----
clang/lib/Sema/Sema.cpp | 6 ++++++
clang/lib/Sema/SemaDecl.cpp | 4 ++--
.../constexpr-function-instantiation.cpp | 20 +++++++++++-------
9 files changed, 56 insertions(+), 43 deletions(-)
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index d143591de9f2cd..487b1647012ca8 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -98,6 +98,7 @@ class ParentMapContext;
struct ParsedTargetAttr;
class Preprocessor;
class ProfileList;
+class Sema;
class StoredDeclsMap;
class TargetAttr;
class TargetInfo;
@@ -182,6 +183,18 @@ struct TypeInfoChars {
}
};
+// Interface that allows constant evaluator to mutate AST.
+// When constant evaluation is triggered by Sema, it can supply a proper
+// implementation of this interface.
+struct EvalASTMutator {
+ virtual ~EvalASTMutator() = default;
+
+ virtual void
+ InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
+ FunctionDecl *Function, bool Recursive,
+ bool DefinitionRequired, bool AtEndOfTU) = 0;
+};
+
/// Holds long-lived AST nodes (such as types and decls) that can be
/// referred to throughout the semantic analysis of a file.
class ASTContext : public RefCountedBase<ASTContext> {
@@ -671,7 +684,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// Keeps track of the deallocated DeclListNodes for future reuse.
DeclListNode *ListNodeFreeList = nullptr;
+ EvalASTMutator *ASTMutator = nullptr;
+
public:
+ EvalASTMutator *getASTMutator() const { return ASTMutator; }
+
IdentifierTable &Idents;
SelectorTable &Selectors;
Builtin::Context &BuiltinInfo;
@@ -3258,7 +3275,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
///
/// \returns true if the function/var must be CodeGen'ed/deserialized even if
/// it is not used.
- bool DeclMustBeEmitted(const Decl *D, EvalASTMutator *ASTMutator = nullptr);
+ bool DeclMustBeEmitted(const Decl *D);
/// Visits all versions of a multiversioned function with the passed
/// predicate.
@@ -3509,6 +3526,8 @@ OPT_LIST(V)
void ReleaseDeclContextMaps();
+ friend void injectASTMutatorIntoASTContext(Sema &, ASTContext &);
+
public:
enum PragmaSectionFlag : unsigned {
PSF_None = 0,
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 89a2833c82194d..83a4a2f4863fab 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -78,18 +78,6 @@ class UnresolvedSetImpl;
class VarTemplateDecl;
enum class ImplicitParamKind;
-/// Interface that allows constant evaluator to mutate AST.
-/// When constant evaluation is triggered by Sema, it can supply a proper
-/// implementation of this interface.
-struct EvalASTMutator {
- virtual ~EvalASTMutator() = default;
-
- virtual void
- InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
- FunctionDecl *Function, bool Recursive,
- bool DefinitionRequired, bool AtEndOfTU) = 0;
-};
-
/// The top declaration context.
class TranslationUnitDecl : public Decl,
public DeclContext,
@@ -1367,12 +1355,11 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
/// Attempt to evaluate the value of the initializer attached to this
/// declaration, and produce notes explaining why it cannot be evaluated.
/// Returns a pointer to the value if evaluation succeeded, 0 otherwise.
- APValue *evaluateValue(EvalASTMutator *ASTMutator = nullptr) const;
+ APValue *evaluateValue() const;
private:
APValue *evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
- bool IsConstantInitialization,
- EvalASTMutator *ASTMutator = nullptr) const;
+ bool IsConstantInitialization) const;
public:
/// Return the already-evaluated value of this variable's
@@ -1405,8 +1392,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,
- EvalASTMutator *ASTMutator = nullptr) const;
+ checkForConstantInitialization(SmallVectorImpl<PartialDiagnosticAt> &Notes) 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 ccf7fd226b5a8f..466c65a9685ad3 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -734,8 +734,7 @@ class Expr : public ValueStmt {
bool EvaluateAsInitializer(APValue &Result, const ASTContext &Ctx,
const VarDecl *VD,
SmallVectorImpl<PartialDiagnosticAt> &Notes,
- bool IsConstantInitializer,
- EvalASTMutator *ASTMutator = nullptr) const;
+ bool IsConstantInitializer) const;
/// EvaluateWithSubstitution - Evaluate an expression as if from the context
/// of a call to the given function with the given arguments, inside an
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 0aaf23af28d3d6..69892bda42b256 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -12522,7 +12522,7 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) const {
basicGVALinkageForVariable(*this, VD)));
}
-bool ASTContext::DeclMustBeEmitted(const Decl *D, EvalASTMutator *ASTMutator) {
+bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl())
return false;
@@ -12627,7 +12627,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D, EvalASTMutator *ASTMutator) {
// Variables that have initialization with side-effects are required.
if (VD->getInit() && VD->getInit()->HasSideEffects(*this) &&
// We can get a value-dependent initializer during error recovery.
- (VD->getInit()->isValueDependent() || !VD->evaluateValue(ASTMutator)))
+ (VD->getInit()->isValueDependent() || !VD->evaluateValue()))
return true;
// Likewise, variables with tuple-like bindings are required if their
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index f49ef66cb43aea..d264441fe74e7e 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2546,14 +2546,13 @@ EvaluatedStmt *VarDecl::getEvaluatedStmt() const {
return Init.dyn_cast<EvaluatedStmt *>();
}
-APValue *VarDecl::evaluateValue(EvalASTMutator *ASTMutator) const {
+APValue *VarDecl::evaluateValue() const {
SmallVector<PartialDiagnosticAt, 8> Notes;
- return evaluateValueImpl(Notes, hasConstantInitialization(), ASTMutator);
+ return evaluateValueImpl(Notes, hasConstantInitialization());
}
APValue *VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
- bool IsConstantInitialization,
- EvalASTMutator *ASTMutator) const {
+ bool IsConstantInitialization) const {
EvaluatedStmt *Eval = ensureEvaluatedStmt();
const auto *Init = getInit();
@@ -2574,7 +2573,7 @@ APValue *VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
ASTContext &Ctx = getASTContext();
bool Result = Init->EvaluateAsInitializer(
- Eval->Evaluated, Ctx, this, Notes, IsConstantInitialization, ASTMutator);
+ Eval->Evaluated, Ctx, this, Notes, IsConstantInitialization);
// In C++, or in C23 if we're initialising a 'constexpr' variable, this isn't
// a constant initializer if we produced notes. In that case, we can't keep
@@ -2637,8 +2636,7 @@ bool VarDecl::hasConstantInitialization() const {
}
bool VarDecl::checkForConstantInitialization(
- SmallVectorImpl<PartialDiagnosticAt> &Notes,
- EvalASTMutator *ASTMutator) const {
+ SmallVectorImpl<PartialDiagnosticAt> &Notes) 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
@@ -2653,7 +2651,7 @@ bool VarDecl::checkForConstantInitialization(
// Evaluate the initializer to check whether it's a constant expression.
Eval->HasConstantInitialization =
- evaluateValueImpl(Notes, true, ASTMutator) && Notes.empty();
+ evaluateValueImpl(Notes, 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/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index b9a075154b6d6f..c167e6fa8e92a4 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -8336,7 +8336,7 @@ class ExprEvaluatorBase
const FunctionDecl *Definition = nullptr;
Stmt *Body = FD->getBody(Definition);
- if (!Definition && FD->getTemplateInstantiationPattern()) {
+ if (Info.Ctx.getLangOpts().CPlusPlus26 && Info.getASTMutator() && !Definition && FD->getTemplateInstantiationPattern()) {
Info.getASTMutator()->InstantiateFunctionDefinition(
E->getExprLoc(), const_cast<FunctionDecl *>(FD),
/*Recursive=*/true, /*DefinitionRequired=*/true, /*AtEndOfTU=*/false);
@@ -16683,8 +16683,7 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
const VarDecl *VD,
SmallVectorImpl<PartialDiagnosticAt> &Notes,
- bool IsConstantInitialization,
- EvalASTMutator *ASTMutator) const {
+ bool IsConstantInitialization) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
@@ -16703,7 +16702,7 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
(Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23))
? EvalInfo::EM_ConstantExpression
: EvalInfo::EM_ConstantFold,
- ASTMutator);
+ Ctx.getASTMutator());
Info.setEvaluatingDecl(VD, Value);
Info.InConstantContext = IsConstantInitialization;
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 328a8f7912a8ea..ab58a54541c628 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -208,6 +208,10 @@ class SemaPPCallbacks : public PPCallbacks {
} // end namespace sema
} // end namespace clang
+void clang::injectASTMutatorIntoASTContext(Sema &S, ASTContext &Context) {
+ Context.ASTMutator = S.getASTMutator();
+}
+
SemaASTMutator::SemaASTMutator(Sema &SemaRef) : SemaRef(SemaRef) {}
const unsigned Sema::MaxAlignmentExponent;
@@ -300,6 +304,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
SemaPPCallbackHandler->set(*this);
CurFPFeatures.setFPEvalMethod(PP.getCurrentFPEvalMethod());
+
+ injectASTMutatorIntoASTContext(*this, Context);
}
// Anchor Sema's type info to this TU.
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index ea6ca66f8c69e9..3d95fd7013fbdd 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14442,7 +14442,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
} else {
// Evaluate the initializer to see if it's a constant initializer.
HasConstInit =
- var->checkForConstantInitialization(Notes, getASTMutator());
+ var->checkForConstantInitialization(Notes);
}
if (HasConstInit) {
@@ -14550,7 +14550,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// If this variable must be emitted, add it as an initializer for the current
// module.
- if (Context.DeclMustBeEmitted(var, getASTMutator()) && !ModuleScopes.empty())
+ if (Context.DeclMustBeEmitted(var) && !ModuleScopes.empty())
Context.addModuleInitializer(ModuleScopes.back().Module, var);
// Build the bindings if this is a structured binding declaration.
diff --git a/clang/test/SemaCXX/constexpr-function-instantiation.cpp b/clang/test/SemaCXX/constexpr-function-instantiation.cpp
index 6c7e43f85cf6f9..aec14e938be9f5 100644
--- a/clang/test/SemaCXX/constexpr-function-instantiation.cpp
+++ b/clang/test/SemaCXX/constexpr-function-instantiation.cpp
@@ -1,21 +1,27 @@
-// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c++2c -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=cxx20-23 %s
+// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify=cxx20-23 %s
+// RUN: %clang_cc1 -std=c++2c -fsyntax-only -verify=cxx26 %s
+
+// cxx26-no-diagnostics
namespace GH73232 {
namespace ex1 {
template <typename T>
-constexpr void g(T);
+constexpr void g(T); // #ex1-g-decl
constexpr int f() {
- g(0);
- return 0;
+ g(0); // #ex1-g-call
+ return 0;
}
template <typename T>
constexpr void g(T) {}
-constexpr auto z = f();
+constexpr auto z = f(); // #ex1-z-defn
+// cxx20-23-error at -1 {{constexpr variable 'z' must be initialized by a constant expression}}
+// cxx20-23-note@#ex1-g-call {{undefined function 'g<int>' cannot be used in a constant expression}}
+// cxx20-23-note@#ex1-z-defn {{in call to 'f()'}}
+// cxx20-23-note@#ex1-g-decl {{declared here}}
} // namespace ex1
namespace ex2 {
>From 54da0e85a0095e6b1c40a6bb51446c4feb20e67b Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Thu, 7 Nov 2024 20:08:04 +0300
Subject: [PATCH 5/6] Don't store `ASTMutator` inside `EvalInfo`
---
clang/include/clang/AST/ASTContext.h | 11 +++++++++--
clang/include/clang/AST/Decl.h | 4 ++--
clang/lib/AST/Decl.cpp | 4 ++--
clang/lib/AST/ExprConstant.cpp | 19 ++++++-------------
clang/lib/Sema/Sema.cpp | 3 +++
clang/lib/Sema/SemaDecl.cpp | 3 +--
6 files changed, 23 insertions(+), 21 deletions(-)
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 487b1647012ca8..b5895627213d10 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -184,8 +184,7 @@ struct TypeInfoChars {
};
// Interface that allows constant evaluator to mutate AST.
-// When constant evaluation is triggered by Sema, it can supply a proper
-// implementation of this interface.
+// Sema is the only entity that can implement this.
struct EvalASTMutator {
virtual ~EvalASTMutator() = default;
@@ -684,9 +683,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// Keeps track of the deallocated DeclListNodes for future reuse.
DeclListNode *ListNodeFreeList = nullptr;
+ /// Implementation of the interface that Sema provides during its
+ /// construction.
EvalASTMutator *ASTMutator = nullptr;
public:
+ /// Returns an object that is capable of modifying AST,
+ /// or nullptr if it's not available. The latter happens when
+ /// Sema is not available.
EvalASTMutator *getASTMutator() const { return ASTMutator; }
IdentifierTable &Idents;
@@ -3526,6 +3530,9 @@ OPT_LIST(V)
void ReleaseDeclContextMaps();
+ /// This is a function that is implemented in the Sema layer,
+ /// that needs friendship to initialize ASTMutator without this capability
+ /// being available in the public interface of ASTContext.
friend void injectASTMutatorIntoASTContext(Sema &, ASTContext &);
public:
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 83a4a2f4863fab..7ff35d73df5997 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -1391,8 +1391,8 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
/// Evaluate the initializer of this variable to determine whether it's a
/// constant initializer. Should only be called once, after completing the
/// definition of the variable.
- bool
- checkForConstantInitialization(SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
+ bool checkForConstantInitialization(
+ SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
void setInitStyle(InitializationStyle Style) {
VarDeclBits.InitStyle = Style;
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index d264441fe74e7e..86913763ef9ff5 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2572,8 +2572,8 @@ APValue *VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
Eval->IsEvaluating = true;
ASTContext &Ctx = getASTContext();
- bool Result = Init->EvaluateAsInitializer(
- Eval->Evaluated, Ctx, this, Notes, IsConstantInitialization);
+ bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, Ctx, this, Notes,
+ IsConstantInitialization);
// In C++, or in C23 if we're initialising a 'constexpr' variable, this isn't
// a constant initializer if we produced notes. In that case, we can't keep
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index c167e6fa8e92a4..701dca6bf373ee 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1004,11 +1004,6 @@ namespace {
EM_IgnoreSideEffects,
} EvalMode;
- /// Implementation of an interface for AST mutation.
- /// Basically something backed by Sema,
- /// or nullptr if Sema is not available.
- EvalASTMutator *ASTMutator;
-
/// Are we checking whether the expression is a potential constant
/// expression?
bool checkingPotentialConstantExpression() const override {
@@ -1022,8 +1017,7 @@ namespace {
return CheckingForUndefinedBehavior;
}
- EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode,
- EvalASTMutator *ASTMutator = nullptr)
+ EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
: Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
CallStackDepth(0), NextCallIndex(1),
StepsLeft(C.getLangOpts().ConstexprStepLimit),
@@ -1033,15 +1027,14 @@ namespace {
/*CallExpr=*/nullptr, CallRef()),
EvaluatingDecl((const ValueDecl *)nullptr),
EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
- HasFoldFailureDiagnostic(false), EvalMode(Mode),
- ASTMutator(ASTMutator) {}
+ HasFoldFailureDiagnostic(false), EvalMode(Mode) {}
~EvalInfo() {
discardCleanups();
}
ASTContext &getASTContext() const override { return Ctx; }
- EvalASTMutator *getASTMutator() const { return ASTMutator; }
+ EvalASTMutator *getASTMutator() const { return Ctx.getASTMutator(); }
void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value,
EvaluatingDeclKind EDK = EvaluatingDeclKind::Ctor) {
@@ -8336,7 +8329,8 @@ class ExprEvaluatorBase
const FunctionDecl *Definition = nullptr;
Stmt *Body = FD->getBody(Definition);
- if (Info.Ctx.getLangOpts().CPlusPlus26 && Info.getASTMutator() && !Definition && FD->getTemplateInstantiationPattern()) {
+ if (Info.Ctx.getLangOpts().CPlusPlus26 && Info.getASTMutator() &&
+ !Definition && FD->getTemplateInstantiationPattern()) {
Info.getASTMutator()->InstantiateFunctionDefinition(
E->getExprLoc(), const_cast<FunctionDecl *>(FD),
/*Recursive=*/true, /*DefinitionRequired=*/true, /*AtEndOfTU=*/false);
@@ -16701,8 +16695,7 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
(IsConstantInitialization &&
(Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23))
? EvalInfo::EM_ConstantExpression
- : EvalInfo::EM_ConstantFold,
- Ctx.getASTMutator());
+ : EvalInfo::EM_ConstantFold);
Info.setEvaluatingDecl(VD, Value);
Info.InConstantContext = IsConstantInitialization;
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index ab58a54541c628..41eff868a3fafb 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -305,6 +305,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
CurFPFeatures.setFPEvalMethod(PP.getCurrentFPEvalMethod());
+ /// Initialize ASTMutator within ASTContext.
+ /// This is very intentionally not a part of public interface
+ /// of ASTContext.
injectASTMutatorIntoASTContext(*this, Context);
}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 3d95fd7013fbdd..f8e5f3c6d309d6 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14441,8 +14441,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
} else {
// Evaluate the initializer to see if it's a constant initializer.
- HasConstInit =
- var->checkForConstantInitialization(Notes);
+ HasConstInit = var->checkForConstantInitialization(Notes);
}
if (HasConstInit) {
>From 4d91ede45c51acc0dee61695ef19e1b8f0fcfb72 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Fri, 8 Nov 2024 18:20:22 +0300
Subject: [PATCH 6/6] Remove `Sema` from `ASTContext`
---
clang/include/clang/AST/ASTContext.h | 3 +--
clang/lib/Sema/Sema.cpp | 7 ++++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index b5895627213d10..d2d4e13ee9b7e3 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -98,7 +98,6 @@ class ParentMapContext;
struct ParsedTargetAttr;
class Preprocessor;
class ProfileList;
-class Sema;
class StoredDeclsMap;
class TargetAttr;
class TargetInfo;
@@ -3533,7 +3532,7 @@ OPT_LIST(V)
/// This is a function that is implemented in the Sema layer,
/// that needs friendship to initialize ASTMutator without this capability
/// being available in the public interface of ASTContext.
- friend void injectASTMutatorIntoASTContext(Sema &, ASTContext &);
+ friend void injectASTMutatorIntoASTContext(ASTContext &, EvalASTMutator *);
public:
enum PragmaSectionFlag : unsigned {
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 41eff868a3fafb..9469be0ba1e8cc 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -208,8 +208,9 @@ class SemaPPCallbacks : public PPCallbacks {
} // end namespace sema
} // end namespace clang
-void clang::injectASTMutatorIntoASTContext(Sema &S, ASTContext &Context) {
- Context.ASTMutator = S.getASTMutator();
+void clang::injectASTMutatorIntoASTContext(ASTContext &Context,
+ EvalASTMutator *ASTMutator) {
+ Context.ASTMutator = ASTMutator;
}
SemaASTMutator::SemaASTMutator(Sema &SemaRef) : SemaRef(SemaRef) {}
@@ -308,7 +309,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
/// Initialize ASTMutator within ASTContext.
/// This is very intentionally not a part of public interface
/// of ASTContext.
- injectASTMutatorIntoASTContext(*this, Context);
+ injectASTMutatorIntoASTContext(Context, getASTMutator());
}
// Anchor Sema's type info to this TU.
More information about the cfe-commits
mailing list