https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/198062
>From eec93dab61b36e06dac1a2a6b9634dbefae70a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]> Date: Wed, 13 May 2026 14:14:43 +0200 Subject: [PATCH] worken --- clang/lib/AST/ByteCode/Compiler.cpp | 19 ++++++++++++++ clang/lib/AST/ByteCode/Compiler.h | 2 ++ clang/lib/AST/ByteCode/Context.cpp | 7 ++++++ clang/lib/AST/ByteCode/Context.h | 1 + clang/lib/AST/ByteCode/EvalEmitter.cpp | 4 +++ clang/lib/AST/ByteCode/EvalEmitter.h | 2 ++ clang/lib/AST/ByteCode/InterpState.cpp | 12 +++++++++ clang/lib/AST/ByteCode/InterpState.h | 2 ++ clang/lib/AST/ByteCode/Program.cpp | 24 +++++++++++++++--- clang/lib/Serialization/ASTReaderDecl.cpp | 12 ++++++++- .../test/AST/ByteCode/Inputs/module.modulemap | 1 + clang/test/AST/ByteCode/Inputs/redecl1.h | 6 +++++ clang/test/AST/ByteCode/module-redecl1.cpp | 25 +++++++++++++++++++ clang/test/Modules/pr102360.cppm | 8 ++++++ clang/test/Modules/redecl-add-after-load.cpp | 4 +++ 15 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 clang/test/AST/ByteCode/Inputs/module.modulemap create mode 100644 clang/test/AST/ByteCode/Inputs/redecl1.h create mode 100644 clang/test/AST/ByteCode/module-redecl1.cpp diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 46762ed8291f9..e5bc3167f8789 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -6003,6 +6003,25 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, return false; } +template <class Emitter> +bool Compiler<Emitter>::registerRedecl(const VarDecl *VD, const APValue &Val) { + if (P.getGlobal(VD)) + return true; + + UnsignedOrNone GlobalIndex = P.createGlobal(VD, /*Init=*/nullptr); + if (!GlobalIndex) { + llvm_unreachable("Why didn't that work?"); + } + + assert(canClassify(VD->getType()) && + "registerRedecl should only be called with primitive values"); + + PrimType T = classifyPrim(VD->getType()); + if (!visitAPValue(Val, T, VD)) + return false; + return this->emitInitGlobal(T, *GlobalIndex, {}); +} + template <class Emitter> bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinID) { diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index a93fdd20b712f..6777610b2bb45 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -251,6 +251,8 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>, bool visitAttributedStmt(const AttributedStmt *S); bool visitCXXTryStmt(const CXXTryStmt *S); + bool registerRedecl(const VarDecl *VD, const APValue &V); + protected: bool visitStmt(const Stmt *S); bool visitExpr(const Expr *E, bool DestroyToplevelScope) override; diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 4ca76ce3669d3..2df01d4595bd3 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -179,6 +179,13 @@ bool Context::evaluateDestruction(State &Parent, const VarDecl *VD, return true; } +void Context::registerRedecl(const VarDecl *VD, const APValue &V) { + Expr::EvalStatus Status; + Compiler<EvalEmitter> C(*this, *P, Status, Stk); + + C.registerRedecl(VD, V); +} + template <typename ResultT> bool Context::evaluateStringRepr(State &Parent, const Expr *SizeExpr, const Expr *PtrExpr, ResultT &Result) { diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h index 47821a3e3a7f3..1e045484f8490 100644 --- a/clang/lib/AST/ByteCode/Context.h +++ b/clang/lib/AST/ByteCode/Context.h @@ -67,6 +67,7 @@ class Context final { /// Evaluates a toplevel initializer. bool evaluateAsInitializer(State &Parent, const VarDecl *VD, const Expr *Init, APValue &Result); + void registerRedecl(const VarDecl *VD, const APValue &V); /// Evaluates the destruction of a variable. bool evaluateDestruction(State &Parent, const VarDecl *VD, APValue Value); diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index 34c85c7c66bdd..db929968e9b3e 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -21,6 +21,10 @@ EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk) : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) {} +EvalEmitter::EvalEmitter(Context &Ctx, Program &P, Expr::EvalStatus &Status, + InterpStack &Stk) + : Ctx(Ctx), P(P), S(Status, P, Stk, Ctx, this), EvalResult(&Ctx) {} + EvalEmitter::~EvalEmitter() { for (auto &V : Locals) { Block *B = reinterpret_cast<Block *>(V.get()); diff --git a/clang/lib/AST/ByteCode/EvalEmitter.h b/clang/lib/AST/ByteCode/EvalEmitter.h index f939ef4839a19..b83613cb4813d 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.h +++ b/clang/lib/AST/ByteCode/EvalEmitter.h @@ -59,6 +59,8 @@ class EvalEmitter : public SourceMapper { protected: EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk); + EvalEmitter(Context &Ctx, Program &P, Expr::EvalStatus &Status, + InterpStack &Stk); virtual ~EvalEmitter(); diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp index f6338cda56e34..6aee438b4a4ca 100644 --- a/clang/lib/AST/ByteCode/InterpState.cpp +++ b/clang/lib/AST/ByteCode/InterpState.cpp @@ -30,6 +30,18 @@ InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk, EvalMode = Parent.EvalMode; } +InterpState::InterpState(Expr::EvalStatus &Status, Program &P, InterpStack &Stk, + Context &Ctx, SourceMapper *M) + : State(Ctx.getASTContext(), Status), M(M), P(P), Stk(Stk), Ctx(Ctx), + BottomFrame(*this), Current(&BottomFrame), + StepsLeft(Ctx.getLangOpts().ConstexprStepLimit), + InfiniteSteps(StepsLeft == 0), EvalID(Ctx.getEvalID()) { + InConstantContext = true; + CheckingPotentialConstantExpression = false; + CheckingForUndefinedBehavior = true; + EvalMode = EvaluationMode::ConstantExpression; +} + InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk, Context &Ctx, const Function *Func) : State(Ctx.getASTContext(), Parent.getEvalStatus()), M(nullptr), P(P), diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h index 050fa4c77cd2f..e30dd976746c3 100644 --- a/clang/lib/AST/ByteCode/InterpState.h +++ b/clang/lib/AST/ByteCode/InterpState.h @@ -44,6 +44,8 @@ class InterpState final : public State, public SourceMapper { public: InterpState(const State &Parent, Program &P, InterpStack &Stk, Context &Ctx, SourceMapper *M = nullptr); + InterpState(Expr::EvalStatus &Status, Program &P, InterpStack &Stk, + Context &Ctx, SourceMapper *M = nullptr); InterpState(const State &Parent, Program &P, InterpStack &Stk, Context &Ctx, const Function *Func); diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index d73011a8d8dc4..a3655823465b5 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -83,7 +83,26 @@ unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base) { Pointer Program::getPtrGlobal(unsigned Idx) const { assert(Idx < Globals.size()); - return Pointer(Globals[Idx]->block()); + + Block *B = Globals[Idx]->block(); + + // Force de-serialization of a redeclaration that might initialize this + // global. + if (B->getDescriptor()->getMetadataSize() != 0 && + B->getBlockDesc<GlobalInlineDescriptor>().InitState != + GlobalInitState::Initialized) { + if (const VarDecl *VD = B->getDescriptor()->asVarDecl()) { + const VarDecl *MD = VD->getMostRecentDecl(); + if (MD != VD && MD->hasInit() && !MD->getInit()->isValueDependent()) { + MD->evaluateValue(); + // Note that we need to get Globals[Idx] here again since the code block + // above might've actually changed what global Idx points to. + return Pointer(Globals[Idx]->block()); + } + } + } + + return Pointer(B); } UnsignedOrNone Program::getGlobal(const ValueDecl *VD) { @@ -201,8 +220,7 @@ UnsignedOrNone Program::createGlobal(const ValueDecl *VD, const Expr *Init, Global *NewGlobal = Globals[*Idx]; // Note that this loop has one iteration where Redecl == VD. - for (const Decl *Redecl : VD->redecls()) { - + for (const Decl *Redecl = VD; Redecl; Redecl = Redecl->getPreviousDecl()) { // If this redecl was registered as a dummy variable, it is now a proper // global variable and points to the block we just created. if (auto DummyIt = DummyVariables.find(Redecl); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index bd684b89e194f..ebecf1f9dc584 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "../AST/ByteCode/Context.h" #include "ASTCommon.h" #include "ASTReaderInternals.h" #include "clang/AST/ASTConcept.h" @@ -1701,6 +1702,7 @@ RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) { void ASTDeclReader::ReadVarDeclInit(VarDecl *VD) { if (uint64_t Val = Record.readInt()) { + ASTContext &Context = Reader.getContext(); EvaluatedStmt *Eval = VD->ensureEvaluatedStmt(); Eval->HasConstantInitialization = (Val & 2) != 0; Eval->HasConstantDestruction = (Val & 4) != 0; @@ -1710,7 +1712,15 @@ void ASTDeclReader::ReadVarDeclInit(VarDecl *VD) { if (Eval->WasEvaluated) { Eval->Evaluated = Record.readAPValue(); if (Eval->Evaluated.needsCleanup()) - Reader.getContext().addDestruction(&Eval->Evaluated); + Context.addDestruction(&Eval->Evaluated); + + // The bytecode interpreter has its own internal representation of global + // variables. Notify it that we just deserialized one and what its value + // is. This is important because this declaration might initialize a + // previously declared global (e.g. because that one is extern). + if (Context.getLangOpts().EnableNewConstInterp && + !VD->getType().isNull() && VD->getPreviousDecl() != nullptr) + Context.getInterpContext().registerRedecl(VD, Eval->Evaluated); } // Store the offset of the initializer. Don't deserialize it yet: it might diff --git a/clang/test/AST/ByteCode/Inputs/module.modulemap b/clang/test/AST/ByteCode/Inputs/module.modulemap new file mode 100644 index 0000000000000..6ba8d2e8a184b --- /dev/null +++ b/clang/test/AST/ByteCode/Inputs/module.modulemap @@ -0,0 +1 @@ +module redecl1 { header "redecl1.h" } diff --git a/clang/test/AST/ByteCode/Inputs/redecl1.h b/clang/test/AST/ByteCode/Inputs/redecl1.h new file mode 100644 index 0000000000000..6e02cab6b3133 --- /dev/null +++ b/clang/test/AST/ByteCode/Inputs/redecl1.h @@ -0,0 +1,6 @@ + +extern const int variable = 120; + + +struct S { int a; }; +extern constexpr S vars = {12}; diff --git a/clang/test/AST/ByteCode/module-redecl1.cpp b/clang/test/AST/ByteCode/module-redecl1.cpp new file mode 100644 index 0000000000000..90961eeae4aff --- /dev/null +++ b/clang/test/AST/ByteCode/module-redecl1.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -cc1 -xobjective-c++ %s -fmodules -fimplicit-module-maps -fmodules-cache-path=Inputs/ -I %S/Inputs -verify -std=c++11 +// RUN: %clang_cc1 -cc1 -xobjective-c++ %s -fmodules -fimplicit-module-maps -fmodules-cache-path=Inputs/ -I %S/Inputs -verify -std=c++11 -fexperimental-new-constant-interpreter + +// expected-no-diagnostics + +struct S { int a; }; + +extern const int variable; +extern const S vars; + +constexpr int test() { return variable; } +constexpr int test2() { return vars.a; } + +struct C { + static const int variable; + static const S vars; +}; + + + +/// The module contains a definition for 'variable', so the function call below +/// should work and return the correct value. +@import redecl1; +static_assert(test() == 120, ""); +static_assert(test2() == 12, ""); diff --git a/clang/test/Modules/pr102360.cppm b/clang/test/Modules/pr102360.cppm index e0dab1a031801..31109d6959512 100644 --- a/clang/test/Modules/pr102360.cppm +++ b/clang/test/Modules/pr102360.cppm @@ -10,6 +10,14 @@ // RUN: %clang_cc1 -std=c++20 %t/d.cpp -fsyntax-only -verify \ // RUN: -fprebuilt-module-path=%t +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/b.pcm \ +// RUN: -fprebuilt-module-path=%t -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -std=c++20 %t/c.cppm -emit-module-interface -o %t/c.pcm \ +// RUN: -fprebuilt-module-path=%t -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -std=c++20 %t/d.cpp -fsyntax-only -verify \ +// RUN: -fprebuilt-module-path=%t -fexperimental-new-constant-interpreter + //--- a.cppm export module a; diff --git a/clang/test/Modules/redecl-add-after-load.cpp b/clang/test/Modules/redecl-add-after-load.cpp index f888460f297e7..101be0b1fde4e 100644 --- a/clang/test/Modules/redecl-add-after-load.cpp +++ b/clang/test/Modules/redecl-add-after-load.cpp @@ -2,6 +2,10 @@ // RUN: %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11 // RUN: %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11 -DIMPORT_DECLS +// RUN: %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11 -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11 -DIMPORT_DECLS -fexperimental-new-constant-interpreter + + // expected-no-diagnostics #ifdef IMPORT_DECLS _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
