[clang] [clang][Interp] Only zero-init first union member (PR #102744)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 10 07:55:32 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
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
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/102744
More information about the cfe-commits
mailing list