Skip to content

Commit faee39b

Browse files
committed
PR43762: when implicitly changing the active union member for an
assignment during constant evaluation, only start the lifetime of trivially-default-constructible union members.
1 parent 85a2146 commit faee39b

File tree

2 files changed

+52
-3
lines changed

2 files changed

+52
-3
lines changed

clang/lib/AST/ExprConstant.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5333,9 +5333,16 @@ static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr,
53335333
if (!FD || FD->getType()->isReferenceType())
53345334
break;
53355335

5336-
// ... and also contains A.B if B names a union member
5337-
if (FD->getParent()->isUnion())
5338-
UnionPathLengths.push_back({PathLength - 1, FD});
5336+
// ... and also contains A.B if B names a union member ...
5337+
if (FD->getParent()->isUnion()) {
5338+
// ... of a non-class, non-array type, or of a class type with a
5339+
// trivial default constructor that is not deleted, or an array of
5340+
// such types.
5341+
auto *RD =
5342+
FD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
5343+
if (!RD || RD->hasTrivialDefaultConstructor())
5344+
UnionPathLengths.push_back({PathLength - 1, FD});
5345+
}
53395346

53405347
E = ME->getBase();
53415348
--PathLength;

clang/test/SemaCXX/constant-expression-cxx2a.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,48 @@ namespace Union {
584584
r.b.r.b = 2; // expected-note {{read of member 'b' of union with active member 'a'}}
585585
return r.b.r.b;
586586
}
587+
588+
namespace PR43762 {
589+
struct A { int x = 1; constexpr int f() { return 1; } };
590+
struct B : A { int y = 1; constexpr int g() { return 2; } };
591+
struct C {
592+
int x;
593+
constexpr virtual int f() = 0;
594+
};
595+
struct D : C {
596+
int y;
597+
constexpr virtual int f() override { return 3; }
598+
};
599+
600+
union U {
601+
int n;
602+
B b;
603+
D d;
604+
};
605+
606+
constexpr int test(int which) {
607+
U u{.n = 5};
608+
switch (which) {
609+
case 0:
610+
u.b.x = 10; // expected-note {{active member 'n'}}
611+
return u.b.f();
612+
case 1:
613+
u.b.y = 10; // expected-note {{active member 'n'}}
614+
return u.b.g();
615+
case 2:
616+
u.d.x = 10; // expected-note {{active member 'n'}}
617+
return u.d.f();
618+
case 3:
619+
u.d.y = 10; // expected-note {{active member 'n'}}
620+
return u.d.f();
621+
}
622+
}
623+
624+
static_assert(test(0)); // expected-error {{}} expected-note {{in call}}
625+
static_assert(test(1)); // expected-error {{}} expected-note {{in call}}
626+
static_assert(test(2)); // expected-error {{}} expected-note {{in call}}
627+
static_assert(test(3)); // expected-error {{}} expected-note {{in call}}
628+
}
587629
}
588630

589631
namespace TwosComplementShifts {

0 commit comments

Comments
 (0)