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;


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to