[clang] 8031017 - [clang][bytecode] Mark fields as being initialized, even without running a ctor for them (#225295)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 22 01:13:54 PDT 2026
Author: Timm Baeder
Date: 2026-09-22T10:13:48+02:00
New Revision: 80310178c079fc4ec712ace6d72a97bb5c619a12
URL: https://github.com/llvm/llvm-project/commit/80310178c079fc4ec712ace6d72a97bb5c619a12
DIFF: https://github.com/llvm/llvm-project/commit/80310178c079fc4ec712ace6d72a97bb5c619a12.diff
LOG: [clang][bytecode] Mark fields as being initialized, even without running a ctor for them (#225295)
To fix the diagnostics.
Added:
Modified:
clang/lib/AST/ByteCode/Compiler.cpp
clang/lib/AST/ByteCode/Interp.h
clang/lib/AST/ByteCode/Opcodes.td
clang/test/AST/ByteCode/invalid.cpp
clang/test/SemaCXX/aggregate-default-member-initializers.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 38a095f8a1164..ecece6f08f3ab 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -2362,10 +2362,18 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
auto initPrimitiveField = [=](const Record::Field *FieldToInit,
const Expr *Init, PrimType T,
bool Activate = false) -> bool {
- InitStackScope<Emitter> ISS(this, isa<CXXDefaultInitExpr>(Init));
+ bool DefaultInit = isa<CXXDefaultInitExpr>(Init);
+ InitStackScope<Emitter> ISS(this, DefaultInit);
+
+ if (DefaultInit && !this->emitStartFieldInit(FieldToInit->Offset, Init))
+ return false;
+
if (!this->visit(Init))
return false;
+ if (DefaultInit && !this->emitEndInit(Init))
+ return false;
+
bool BitField = FieldToInit->isBitField();
if (BitField && Activate)
return this->emitInitBitFieldActivate(T, FieldToInit->Offset,
@@ -2392,7 +2400,10 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
if (Activate && !this->emitActivate(E))
return false;
- return this->visitInitializerPop(Init);
+ if (!this->emitStartInit(Init))
+ return false;
+
+ return this->visitInitializerPop(Init) && this->emitEndInit(Init);
};
if (R->isUnion()) {
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index f7d396b720767..d95d799288938 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -3738,6 +3738,12 @@ inline bool StartInit(InterpState &S) {
return true;
}
+inline bool StartFieldInit(InterpState &S, uint32_t FieldOffset) {
+ const Pointer &Ptr = S.Stk.peek<Pointer>();
+ S.InitializingPtrs.push_back(Ptr.view().atField(FieldOffset));
+ return true;
+}
+
inline bool EndInit(InterpState &S) {
S.InitializingPtrs.pop_back();
return true;
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index afed0014c1a10..78d99bf3c433f 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -190,6 +190,9 @@ def PushIgnoreDiags : SuccessOpcode;
def PopIgnoreDiags : SuccessOpcode;
def StartInit : SuccessOpcode;
+def StartFieldInit : SuccessOpcode {
+ let Args = [ArgUint32];
+}
def EndInit : SuccessOpcode;
def StartSpeculation : SuccessOpcode;
diff --git a/clang/test/AST/ByteCode/invalid.cpp b/clang/test/AST/ByteCode/invalid.cpp
index 3dd2dc91df9c1..565d65f60514a 100644
--- a/clang/test/AST/ByteCode/invalid.cpp
+++ b/clang/test/AST/ByteCode/invalid.cpp
@@ -282,3 +282,22 @@ namespace NonRecordNonArrayDesc {
F foo(42);
}
+
+namespace CompositeFieldInit {
+ struct S {
+ static consteval int decrement(int &x) {
+ return --x;
+ }
+
+ int a = 10;
+ int b = decrement(a); // both-error {{is not a constant expression}} \
+ // both-note {{declared here}} \
+ // both-note {{implicit use of 'this'}}
+ };
+
+ struct S2 {
+ const S s{10}; // both-note {{in the default initializer of 'b'}}
+ };
+
+ constexpr S2 s2{};
+}
diff --git a/clang/test/SemaCXX/aggregate-default-member-initializers.cpp b/clang/test/SemaCXX/aggregate-default-member-initializers.cpp
index 27fb4deab77d6..849e02e244bd4 100644
--- a/clang/test/SemaCXX/aggregate-default-member-initializers.cpp
+++ b/clang/test/SemaCXX/aggregate-default-member-initializers.cpp
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -std=c++20 -Wno-unused-value -verify=expected %s
-// RUN: %clang_cc1 -std=c++23 -Wno-unused-value -verify=expected %s
-// RUN: %clang_cc1 -std=c++20 -Wno-unused-value -verify=expected,bytecode %s \
-// RUN: -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++20 -Wno-unused-value -verify %s
+// RUN: %clang_cc1 -std=c++23 -Wno-unused-value -verify %s
+// RUN: %clang_cc1 -std=c++20 -Wno-unused-value -verify %s -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++23 -Wno-unused-value -verify %s -fexperimental-new-constant-interpreter
namespace lifetime {
@@ -69,25 +69,22 @@ namespace immediate {
struct Inner {
int a;
static consteval int decrement(int &x) {
- return --x; // bytecode-note {{modification of object of const-qualified type 'const int' is not allowed in a constant expression}}
+ return --x;
}
// FIXME: The aggregate result object does not exist yet when the immediate
// invocation is checked, so reading 'a' fails. This is long-standing and is
// independent of which full-expression the initializer belongs to.
int b = decrement(a); // expected-error {{call to consteval function 'immediate::Inner::decrement' is not a constant expression}} \
// expected-note {{implicit use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function}} \
- // expected-note {{declared here}} \
- // bytecode-note {{in call to 'decrement(Inner{1}.a)'}}
+ // expected-note {{declared here}}
};
struct Outer {
const Inner &inner = Inner{1}; // expected-note {{in the default initializer of 'b'}}
};
-constexpr int value = Outer{}.inner.a; // bytecode-error {{constexpr variable 'value' must be initialized by a constant expression}} \
- // bytecode-note {{declared here}}
-static_assert(value == 0); // bytecode-error {{static assertion expression is not an integral constant expression}} \
- // bytecode-note {{initializer of 'value' is not a constant expression}}
+constexpr int value = Outer{}.inner.a;
+static_assert(value == 0);
consteval unsigned currentLine(unsigned line = __builtin_LINE()) {
return line;
More information about the cfe-commits
mailing list