[llvm-branch-commits] [clang] 5b29638 - PR45879: Fix assert when constant evaluating union assignment.

Tom Stellard via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Jun 9 13:56:27 PDT 2022


Author: Richard Smith
Date: 2022-06-09T13:55:17-07:00
New Revision: 5b296385298f9ffb708d454ce107bc9a0cdea5de

URL: https://github.com/llvm/llvm-project/commit/5b296385298f9ffb708d454ce107bc9a0cdea5de
DIFF: https://github.com/llvm/llvm-project/commit/5b296385298f9ffb708d454ce107bc9a0cdea5de.diff

LOG: 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=`.

(cherry picked from commit 30baa5d2a450d5e302d8cba3fc7a26a59d4b7ae1)

Added: 
    

Modified: 
    clang/lib/AST/ExprConstant.cpp
    clang/test/SemaCXX/constant-expression-cxx2a.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 9e4088f94015c..163109bf7c9f5 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 @@ class ExprEvaluatorBase
         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 88c20c8d1bc69..4aaf6328aaf63 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}}
+}


        


More information about the llvm-branch-commits mailing list