https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/150190
>From 11e636093500994024282cbab138fcd33d2afa03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Wed, 23 Jul 2025 09:01:22 +0200 Subject: [PATCH] [clang][bytecode] Disable location tracking for implicit field inits --- clang/lib/AST/ByteCode/ByteCodeEmitter.cpp | 4 +- clang/lib/AST/ByteCode/ByteCodeEmitter.h | 1 + clang/lib/AST/ByteCode/Compiler.cpp | 38 +++++++++++++++++++ clang/lib/AST/ByteCode/Compiler.h | 2 + clang/lib/AST/ByteCode/EvalEmitter.cpp | 1 + clang/lib/AST/ByteCode/EvalEmitter.h | 1 + clang/lib/AST/ByteCode/InterpFrame.cpp | 12 +++++- clang/lib/AST/ByteCode/State.cpp | 1 + clang/test/AST/ByteCode/lifetimes.cpp | 3 +- clang/test/AST/ByteCode/mutable.cpp | 8 ++++ clang/test/AST/ByteCode/new-delete.cpp | 5 +-- clang/test/AST/ByteCode/unions.cpp | 4 +- .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp | 3 ++ 13 files changed, 74 insertions(+), 9 deletions(-) diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp index d4746052c5cfe..0c003b21f35d6 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp @@ -216,7 +216,9 @@ bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &...Args, // The opcode is followed by arguments. The source info is // attached to the address after the opcode. emit(P, Code, Op, Success); - if (SI) + if (LocOverride) + SrcMap.emplace_back(Code.size(), *LocOverride); + else if (SI) SrcMap.emplace_back(Code.size(), SI); (..., emit(P, Code, Args, Success)); diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.h b/clang/lib/AST/ByteCode/ByteCodeEmitter.h index 9e9dd5e87cd7a..fafba3f68765c 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.h +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.h @@ -73,6 +73,7 @@ class ByteCodeEmitter { ParamOffset LambdaThisCapture{0, false}; /// Local descriptors. llvm::SmallVector<SmallVector<Local, 8>, 2> Descriptors; + std::optional<SourceInfo> LocOverride = std::nullopt; private: /// Current compilation context. diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 7a5bd4dfc0bed..f587be6afe4e4 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -185,6 +185,31 @@ template <class Emitter> class StmtExprScope final { bool OldFlag; }; +/// When generating code for e.g. implicit field initializers in constructors, +/// we don't have anything to point to in case the initializer causes an error. +/// In that case, we need to disable location tracking for the initializer so +/// we later point to the call range instead. +template <class Emitter> class LocOverrideScope final { +public: + LocOverrideScope(Compiler<Emitter> *Ctx, SourceInfo NewValue, + bool Enabled = true) + : Ctx(Ctx), OldFlag(Ctx->LocOverride), Enabled(Enabled) { + + if (Enabled) + Ctx->LocOverride = NewValue; + } + + ~LocOverrideScope() { + if (Enabled) + Ctx->LocOverride = OldFlag; + } + +private: + Compiler<Emitter> *Ctx; + std::optional<SourceInfo> OldFlag; + bool Enabled; +}; + } // namespace interp } // namespace clang @@ -6012,6 +6037,8 @@ bool Compiler<Emitter>::compileConstructor(const CXXConstructorDecl *Ctor) { bool IsUnion = R->isUnion(); if (IsUnion && Ctor->isCopyOrMoveConstructor()) { + LocOverrideScope<Emitter> LOS(this, SourceInfo{}); + if (R->getNumFields() == 0) return this->emitRetVoid(Ctor); // union copy and move ctors are special. @@ -6038,6 +6065,11 @@ bool Compiler<Emitter>::compileConstructor(const CXXConstructorDecl *Ctor) { if (const FieldDecl *Member = Init->getMember()) { const Record::Field *F = R->getField(Member); + LocOverrideScope<Emitter> LOS(this, SourceInfo{}, + !Init->isWritten() && + !Init->isInClassMemberInitializer() && + (!isa<CXXConstructExpr>(InitExpr) || + Member->isAnonymousStructOrUnion())); if (!emitFieldInitializer(F, F->Offset, InitExpr, IsUnion)) return false; } else if (const Type *Base = Init->getBaseClass()) { @@ -6066,6 +6098,10 @@ bool Compiler<Emitter>::compileConstructor(const CXXConstructorDecl *Ctor) { if (!this->emitFinishInitPop(InitExpr)) return false; } else if (const IndirectFieldDecl *IFD = Init->getIndirectMember()) { + LocOverrideScope<Emitter> LOS(this, SourceInfo{}, + !Init->isWritten() && + !Init->isInClassMemberInitializer() && + !isa<CXXConstructExpr>(InitExpr)); assert(IFD->getChainingSize() >= 2); @@ -6144,6 +6180,8 @@ bool Compiler<Emitter>::compileDestructor(const CXXDestructorDecl *Dtor) { assert(R); if (!R->isUnion()) { + + LocOverrideScope<Emitter> LOS(this, SourceInfo{}); // First, destroy all fields. for (const Record::Field &Field : llvm::reverse(R->fields())) { const Descriptor *D = Field.Desc; diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index 16f108fb5d141..ee8327d8fee1e 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -40,6 +40,7 @@ template <class Emitter> class LoopScope; template <class Emitter> class LabelScope; template <class Emitter> class SwitchScope; template <class Emitter> class StmtExprScope; +template <class Emitter> class LocOverrideScope; template <class Emitter> class Compiler; struct InitLink { @@ -333,6 +334,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>, friend class LabelScope<Emitter>; friend class SwitchScope<Emitter>; friend class StmtExprScope<Emitter>; + friend class LocOverrideScope<Emitter>; /// Emits a zero initializer. bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E); diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index fd7f3423c0f9b..8eaee09fea664 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -53,6 +53,7 @@ EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD, bool CheckFullyInitialized) { this->CheckFullyInitialized = CheckFullyInitialized; S.EvaluatingDecl = VD; + S.setEvalLocation(VD->getLocation()); EvalResult.setSource(VD); if (const Expr *Init = VD->getAnyInitializer()) { diff --git a/clang/lib/AST/ByteCode/EvalEmitter.h b/clang/lib/AST/ByteCode/EvalEmitter.h index 2fe7da608c739..85a0a99fbb4b0 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.h +++ b/clang/lib/AST/ByteCode/EvalEmitter.h @@ -95,6 +95,7 @@ class EvalEmitter : public SourceMapper { ParamOffset LambdaThisCapture{0, false}; /// Local descriptors. llvm::SmallVector<SmallVector<Local, 8>, 2> Descriptors; + std::optional<SourceInfo> LocOverride = std::nullopt; private: /// Current compilation context. diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp index d62a4f6275b50..14f99c7b76847 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.cpp +++ b/clang/lib/AST/ByteCode/InterpFrame.cpp @@ -202,7 +202,17 @@ SourceRange InterpFrame::getCallRange() const { return NullRange; return S.EvalLocation; } - return S.getRange(Caller->Func, RetPC - sizeof(uintptr_t)); + + // Move up to the frame that has a valid location for the caller. + for (const InterpFrame *C = this; C; C = C->Caller) { + if (!C->RetPC) + continue; + SourceRange CallRange = + S.getRange(C->Caller->Func, C->RetPC - sizeof(uintptr_t)); + if (CallRange.isValid()) + return CallRange; + } + return S.EvalLocation; } const FunctionDecl *InterpFrame::getCallee() const { diff --git a/clang/lib/AST/ByteCode/State.cpp b/clang/lib/AST/ByteCode/State.cpp index 3204d1a193a74..dc3d0da7a4a46 100644 --- a/clang/lib/AST/ByteCode/State.cpp +++ b/clang/lib/AST/ByteCode/State.cpp @@ -131,6 +131,7 @@ void State::addCallStack(unsigned Limit) { const Frame *Bottom = getBottomFrame(); for (const Frame *F = Top; F != Bottom; F = F->getCaller(), ++CallIdx) { SourceRange CallRange = F->getCallRange(); + assert(CallRange.isValid()); // Skip this call? if (CallIdx >= SkipStart && CallIdx < SkipEnd) { diff --git a/clang/test/AST/ByteCode/lifetimes.cpp b/clang/test/AST/ByteCode/lifetimes.cpp index 5e021387348b5..5c8d56291f079 100644 --- a/clang/test/AST/ByteCode/lifetimes.cpp +++ b/clang/test/AST/ByteCode/lifetimes.cpp @@ -31,8 +31,7 @@ struct S { // expected-note {{read of temporary whose lifetime has ended}} }; constexpr int k1 = S().t; // both-error {{must be initialized by a constant expression}} \ - // ref-note {{in call to}} \ - // expected-note {{in call to}} + // both-note {{in call to}} namespace MoveFnWorks { diff --git a/clang/test/AST/ByteCode/mutable.cpp b/clang/test/AST/ByteCode/mutable.cpp index 35c5a0389921e..16c8ce9125d5e 100644 --- a/clang/test/AST/ByteCode/mutable.cpp +++ b/clang/test/AST/ByteCode/mutable.cpp @@ -66,3 +66,11 @@ namespace MutableInConst { static_assert(mutableInConst() == 1, ""); } #endif + +struct D { mutable int y; }; // both-note {{declared here}} +constexpr D d1 = { 1 }; +constexpr D d2 = d1; // both-error {{must be initialized by a constant expression}} \ + // both-note {{read of mutable member 'y}} \ + // both-note {{in call to}} + + diff --git a/clang/test/AST/ByteCode/new-delete.cpp b/clang/test/AST/ByteCode/new-delete.cpp index 3c0bdbc8c99fe..c5f1878c41734 100644 --- a/clang/test/AST/ByteCode/new-delete.cpp +++ b/clang/test/AST/ByteCode/new-delete.cpp @@ -546,14 +546,13 @@ namespace FaultyDtorCalledByDelete { a = new int(13); IF.mem = new int(100); } - constexpr ~Foo() { delete a; } // expected-note {{in call to}} + constexpr ~Foo() { delete a; } }; constexpr int abc() { Foo *F = new Foo(); int n = *F->a; - delete F; // both-note {{in call to}} \ - // ref-note {{in call to}} + delete F; // both-note 2{{in call to}} return n; } diff --git a/clang/test/AST/ByteCode/unions.cpp b/clang/test/AST/ByteCode/unions.cpp index 139e318e1ba68..8ed76258b879a 100644 --- a/clang/test/AST/ByteCode/unions.cpp +++ b/clang/test/AST/ByteCode/unions.cpp @@ -849,14 +849,14 @@ namespace Activation2 { namespace CopyCtorMutable { struct E { - union { // expected-note {{read of mutable member 'b'}} + union { int a; mutable int b; // both-note {{here}} }; }; constexpr E e1 = {{1}}; constexpr E e2 = e1; // both-error {{constant}} \ - // ref-note {{read of mutable member 'b'}} \ + // both-note {{read of mutable member 'b'}} \ // both-note {{in call}} } diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp index 270bc3cb48be9..dd0f1fc3cba8e 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s // RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s -fexperimental-new-constant-interpreter + // A constexpr specifier used in an object declaration declares the object as // const. constexpr int a = 0; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits