[clang] dc7c3c2 - [clang][bytecode] Disable location tracking for implicit field inits (#150190)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 5 04:14:05 PDT 2025
Author: Timm Baeder
Date: 2025-08-05T13:14:01+02:00
New Revision: dc7c3c2b2b1d0dfe20cd2b6783d7ab773054ad3d
URL: https://github.com/llvm/llvm-project/commit/dc7c3c2b2b1d0dfe20cd2b6783d7ab773054ad3d
DIFF: https://github.com/llvm/llvm-project/commit/dc7c3c2b2b1d0dfe20cd2b6783d7ab773054ad3d.diff
LOG: [clang][bytecode] Disable location tracking for implicit field inits (#150190)
Added:
Modified:
clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
clang/lib/AST/ByteCode/ByteCodeEmitter.h
clang/lib/AST/ByteCode/Compiler.cpp
clang/lib/AST/ByteCode/Compiler.h
clang/lib/AST/ByteCode/EvalEmitter.cpp
clang/lib/AST/ByteCode/EvalEmitter.h
clang/lib/AST/ByteCode/InterpFrame.cpp
clang/lib/AST/ByteCode/State.cpp
clang/test/AST/ByteCode/lifetimes.cpp
clang/test/AST/ByteCode/mutable.cpp
clang/test/AST/ByteCode/new-delete.cpp
clang/test/AST/ByteCode/unions.cpp
clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
index 8e7206eb3b032..1d71708799518 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 8a02911189748..d29db66325412 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 6b74b5ea1c973..4ab4dee5b853c 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
@@ -6017,6 +6042,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.
@@ -6043,6 +6070,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()) {
@@ -6071,6 +6103,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);
@@ -6149,6 +6185,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 408688c21fc5b..976b7c051bd3a 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;
More information about the cfe-commits
mailing list