forked from OSchip/llvm-project
PR45879: Fix assert when constant evaluating union assignment.
Consider the form of the first operand of a class assignment not the second operand when implicitly starting the lifetimes of union members. Also add a missing check that the assignment call actually came from a syntactic assignment, not from a direct call to `operator=`.
This commit is contained in:
parent
4a6c9b5686
commit
30baa5d2a4
|
@ -6124,9 +6124,6 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
|
|||
if (!handleTrivialCopy(Info, MD->getParamDecl(0), Args[0], RHSValue,
|
||||
MD->getParent()->isUnion()))
|
||||
return false;
|
||||
if (Info.getLangOpts().CPlusPlus20 && MD->isTrivial() &&
|
||||
!HandleUnionActiveMemberChange(Info, Args[0], *This))
|
||||
return false;
|
||||
if (!handleAssignment(Info, Args[0], *This, MD->getThisType(),
|
||||
RHSValue))
|
||||
return false;
|
||||
|
@ -7638,6 +7635,15 @@ public:
|
|||
if (!EvaluateObjectArgument(Info, Args[0], ThisVal))
|
||||
return false;
|
||||
This = &ThisVal;
|
||||
|
||||
// If this is syntactically a simple assignment using a trivial
|
||||
// assignment operator, start the lifetimes of union members as needed,
|
||||
// per C++20 [class.union]5.
|
||||
if (Info.getLangOpts().CPlusPlus20 && OCE &&
|
||||
OCE->getOperator() == OO_Equal && MD->isTrivial() &&
|
||||
!HandleUnionActiveMemberChange(Info, Args[0], ThisVal))
|
||||
return false;
|
||||
|
||||
Args = Args.slice(1);
|
||||
} else if (MD && MD->isLambdaStaticInvoker()) {
|
||||
// Map the static invoker for the lambda back to the call operator.
|
||||
|
|
|
@ -1447,3 +1447,29 @@ namespace PR48582 {
|
|||
constexpr bool b = [a = S(), b = S()] { return a.p == b.p; }();
|
||||
static_assert(!b);
|
||||
}
|
||||
|
||||
namespace PR45879 {
|
||||
struct A { int n; };
|
||||
struct B { A a; };
|
||||
constexpr A a = (A() = B().a);
|
||||
|
||||
union C {
|
||||
int n;
|
||||
A a;
|
||||
};
|
||||
|
||||
constexpr bool f() {
|
||||
C c = {.n = 1};
|
||||
c.a = B{2}.a;
|
||||
return c.a.n == 2;
|
||||
}
|
||||
static_assert(f());
|
||||
|
||||
// Only syntactic assignments change the active union member.
|
||||
constexpr bool g() { // expected-error {{never produces a constant expression}}
|
||||
C c = {.n = 1};
|
||||
c.a.operator=(B{2}.a); // expected-note 2{{member call on member 'a' of union with active member 'n' is not allowed in a constant expression}}
|
||||
return c.a.n == 2;
|
||||
}
|
||||
static_assert(g()); // expected-error {{constant expression}} expected-note {{in call}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue