Skip to content

Commit ac47edd

Browse files
authored
[clang][Interp] Only zero-init first union member (#102744)
Zero-initializing all of them accidentally left the last member active. Only initialize the first one.
1 parent 5f26497 commit ac47edd

File tree

3 files changed

+56
-18
lines changed

3 files changed

+56
-18
lines changed

clang/lib/AST/Interp/Compiler.cpp

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,18 +1386,8 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
13861386

13871387
if (R->isUnion()) {
13881388
if (Inits.size() == 0) {
1389-
// Zero-initialize the first union field.
1390-
if (R->getNumFields() == 0)
1391-
return this->emitFinishInit(E);
1392-
const Record::Field *FieldToInit = R->getField(0u);
1393-
QualType FieldType = FieldToInit->Desc->getType();
1394-
if (std::optional<PrimType> T = classify(FieldType)) {
1395-
if (!this->visitZeroInitializer(*T, FieldType, E))
1396-
return false;
1397-
if (!this->emitInitField(*T, FieldToInit->Offset, E))
1398-
return false;
1399-
}
1400-
// FIXME: Non-primitive case?
1389+
if (!this->visitZeroRecordInitializer(R, E))
1390+
return false;
14011391
} else {
14021392
const Expr *Init = Inits[0];
14031393
const FieldDecl *FToInit = nullptr;
@@ -3374,6 +3364,8 @@ bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R,
33743364
return false;
33753365
if (!this->emitInitField(T, Field.Offset, E))
33763366
return false;
3367+
if (R->isUnion())
3368+
break;
33773369
continue;
33783370
}
33793371

@@ -3409,8 +3401,11 @@ bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R,
34093401
assert(false);
34103402
}
34113403

3412-
if (!this->emitPopPtr(E))
3404+
if (!this->emitFinishInitPop(E))
34133405
return false;
3406+
3407+
if (R->isUnion())
3408+
break;
34143409
}
34153410

34163411
for (const Record::Base &B : R->bases()) {

clang/test/AST/Interp/records.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -964,8 +964,6 @@ namespace TemporaryObjectExpr {
964964
static_assert(foo(F()) == 0, "");
965965
}
966966

967-
/// FIXME: This needs support for unions on the new interpreter.
968-
/// We diagnose an uninitialized object in c++14.
969967
#if __cplusplus > 201402L
970968
namespace Unions {
971969
struct F {
@@ -978,10 +976,10 @@ namespace TemporaryObjectExpr {
978976
};
979977

980978
constexpr int foo(F f) {
981-
return f.i + f.U.f; // ref-note {{read of member 'f' of union with active member 'a'}}
979+
return f.i + f.U.f; // both-note {{read of member 'f' of union with active member 'a'}}
982980
}
983-
static_assert(foo(F()) == 0, ""); // ref-error {{not an integral constant expression}} \
984-
// ref-note {{in call to}}
981+
static_assert(foo(F()) == 0, ""); // both-error {{not an integral constant expression}} \
982+
// both-note {{in call to}}
985983
}
986984
#endif
987985

clang/test/AST/Interp/unions.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,4 +253,49 @@ namespace Nested {
253253
// both-note {{in call to}}
254254

255255
}
256+
257+
258+
namespace Zeroing {
259+
struct non_trivial_constructor {
260+
constexpr non_trivial_constructor() : x(100) {}
261+
int x;
262+
};
263+
union U2 {
264+
int a{1000};
265+
non_trivial_constructor b;
266+
};
267+
268+
static_assert(U2().b.x == 100, ""); // both-error {{not an integral constant expression}} \
269+
// both-note {{read of member 'b' of union with active member 'a'}}
270+
271+
union { int a; int b; } constexpr u1{};
272+
static_assert(u1.a == 0, "");
273+
static_assert(u1.b == 0, ""); // both-error {{not an integral constant expression}} \
274+
// both-note {{read of member 'b' of union with active member 'a'}}
275+
276+
union U { int a; int b; } constexpr u2 = U();
277+
static_assert(u2.a == 0, "");
278+
static_assert(u2.b == 0, ""); // both-error {{not an integral constant expression}} \
279+
// both-note {{read of member 'b' of union with active member 'a'}}
280+
281+
282+
struct F {int x; int y; };
283+
union { F a; int b; } constexpr u3{};
284+
static_assert(u3.a.x == 0, "");
285+
286+
union U4 { F a; int b; } constexpr u4 = U4();
287+
static_assert(u4.a.x == 0, "");
288+
289+
union { int a[5]; int b; } constexpr u5{};
290+
static_assert(u5.a[0] == 0, "");
291+
static_assert(u5.a[4] == 0, "");
292+
static_assert(u5.b == 0, ""); // both-error {{not an integral constant expression}} \
293+
// both-note {{read of member 'b' of union with active member 'a'}}
294+
295+
union U6 { int a[5]; int b; } constexpr u6 = U6();
296+
static_assert(u6.a[0] == 0, "");
297+
static_assert(u6.a[4] == 0, "");
298+
static_assert(u6.b == 0, ""); // both-error {{not an integral constant expression}} \
299+
// both-note {{read of member 'b' of union with active member 'a'}}
300+
}
256301
#endif

0 commit comments

Comments
 (0)