diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 9e4088f94015..163109bf7c9f 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -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. diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp index 88c20c8d1bc6..4aaf6328aaf6 100644 --- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp @@ -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}} +}