Skip to content

[clang][Interp] Only zero-init first union member #102744

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 10, 2024
Merged

Conversation

tbaederr
Copy link
Contributor

@tbaederr tbaederr commented Aug 10, 2024

Zero-initializing all of them accidentally left the last member active. Only initialize the first one.

@tbaederr tbaederr changed the title [clang][Interp] Don't zero-init unions [clang][Interp] Only zero-init first union member Aug 10, 2024
@tbaederr tbaederr merged commit ac47edd into llvm:main Aug 10, 2024
8 checks passed
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Aug 10, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 10, 2024

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

Changes

Zero-initializing all of them accidentally left the last member active. Only initialize the first one.


Full diff: https://github.com/llvm/llvm-project/pull/102744.diff

3 Files Affected:

  • (modified) clang/lib/AST/Interp/Compiler.cpp (+8-13)
  • (modified) clang/test/AST/Interp/records.cpp (+3-5)
  • (modified) clang/test/AST/Interp/unions.cpp (+45)
diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp
index d0e4d409b6580..6c4d607706c6b 100644
--- a/clang/lib/AST/Interp/Compiler.cpp
+++ b/clang/lib/AST/Interp/Compiler.cpp
@@ -1386,18 +1386,8 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
 
     if (R->isUnion()) {
       if (Inits.size() == 0) {
-        // Zero-initialize the first union field.
-        if (R->getNumFields() == 0)
-          return this->emitFinishInit(E);
-        const Record::Field *FieldToInit = R->getField(0u);
-        QualType FieldType = FieldToInit->Desc->getType();
-        if (std::optional<PrimType> T = classify(FieldType)) {
-          if (!this->visitZeroInitializer(*T, FieldType, E))
-            return false;
-          if (!this->emitInitField(*T, FieldToInit->Offset, E))
-            return false;
-        }
-        // FIXME: Non-primitive case?
+        if (!this->visitZeroRecordInitializer(R, E))
+          return false;
       } else {
         const Expr *Init = Inits[0];
         const FieldDecl *FToInit = nullptr;
@@ -3374,6 +3364,8 @@ bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R,
         return false;
       if (!this->emitInitField(T, Field.Offset, E))
         return false;
+      if (R->isUnion())
+        break;
       continue;
     }
 
@@ -3409,8 +3401,11 @@ bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R,
       assert(false);
     }
 
-    if (!this->emitPopPtr(E))
+    if (!this->emitFinishInitPop(E))
       return false;
+
+    if (R->isUnion())
+      break;
   }
 
   for (const Record::Base &B : R->bases()) {
diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index 9c8c1c344e1e8..343665003c23e 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -964,8 +964,6 @@ namespace TemporaryObjectExpr {
     static_assert(foo(F()) == 0, "");
   }
 
-  /// FIXME: This needs support for unions on the new interpreter.
-  /// We diagnose an uninitialized object in c++14.
 #if __cplusplus > 201402L
   namespace Unions {
     struct F {
@@ -978,10 +976,10 @@ namespace TemporaryObjectExpr {
     };
 
     constexpr int foo(F f) {
-      return f.i + f.U.f; // ref-note {{read of member 'f' of union with active member 'a'}}
+      return f.i + f.U.f; // both-note {{read of member 'f' of union with active member 'a'}}
     }
-    static_assert(foo(F()) == 0, ""); // ref-error {{not an integral constant expression}} \
-                                      // ref-note {{in call to}}
+    static_assert(foo(F()) == 0, ""); // both-error {{not an integral constant expression}} \
+                                      // both-note {{in call to}}
   }
 #endif
 
diff --git a/clang/test/AST/Interp/unions.cpp b/clang/test/AST/Interp/unions.cpp
index a51f30cd9185b..6f6bc3d6891b4 100644
--- a/clang/test/AST/Interp/unions.cpp
+++ b/clang/test/AST/Interp/unions.cpp
@@ -253,4 +253,49 @@ namespace Nested {
                               // both-note {{in call to}}
 
 }
+
+
+namespace Zeroing {
+  struct non_trivial_constructor {
+      constexpr non_trivial_constructor() : x(100) {}
+      int x;
+  };
+  union U2 {
+      int a{1000};
+      non_trivial_constructor b;
+  };
+
+  static_assert(U2().b.x == 100, ""); // both-error {{not an integral constant expression}} \
+                                      // both-note {{read of member 'b' of union with active member 'a'}}
+
+  union { int a; int b; } constexpr u1{};
+  static_assert(u1.a == 0, "");
+  static_assert(u1.b == 0, ""); // both-error {{not an integral constant expression}} \
+                                // both-note {{read of member 'b' of union with active member 'a'}}
+
+  union U { int a; int b; } constexpr u2 = U();
+  static_assert(u2.a == 0, "");
+  static_assert(u2.b == 0, ""); // both-error {{not an integral constant expression}} \
+                                // both-note {{read of member 'b' of union with active member 'a'}}
+
+
+  struct F {int x; int y; };
+  union { F a; int b; } constexpr u3{};
+  static_assert(u3.a.x == 0, "");
+
+  union U4 { F a; int b; } constexpr u4 = U4();
+  static_assert(u4.a.x == 0, "");
+
+  union { int a[5]; int b; } constexpr u5{};
+  static_assert(u5.a[0] == 0, "");
+  static_assert(u5.a[4] == 0, "");
+  static_assert(u5.b == 0, ""); // both-error {{not an integral constant expression}} \
+                                // both-note {{read of member 'b' of union with active member 'a'}}
+
+  union U6 { int a[5]; int b; } constexpr u6 = U6();
+  static_assert(u6.a[0] == 0, "");
+  static_assert(u6.a[4] == 0, "");
+  static_assert(u6.b == 0, ""); // both-error {{not an integral constant expression}} \
+                                // both-note {{read of member 'b' of union with active member 'a'}}
+}
 #endif

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants