sepavloff created this revision.
sepavloff added a reviewer: rsmith.
sepavloff requested review of this revision.
Herald added a project: clang.

The function HandleUnionActiveMemberChange determined union members that
become active by analyzing LHS expression. It works for assignment
operator but in the case of C++ assignment operator LHS is not easily
available. Actually RHS was used instead, wich resulted in crash
reported in PR45879.

This change uses LValue object to find union members.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D101429

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

Index: clang/test/SemaCXX/constant-expression-cxx2a.cpp
===================================================================
--- clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -379,10 +379,10 @@
     return *p; // expected-note {{read of uninitialized object}}
   }
   static_assert(read_uninitialized() == 0); // expected-error {{constant}} expected-note {{in call}}
-  constexpr void write_wrong_member_indirect() { // expected-error {{never produces a constant}}
+  constexpr void write_wrong_member_indirect() {
     B b = {.b = 1};
     int *p = &b.a.y;
-    *p = 1; // expected-note {{assignment to member 'a' of union with active member 'b'}}
+    *p = 1;
   }
   constexpr int write_uninitialized() {
     B b = {.b = 1};
@@ -1447,3 +1447,9 @@
   constexpr bool b = [a = S(), b = S()] { return a.p == b.p; }();
   static_assert(!b);
 }
+
+namespace PR45879 {
+  struct Base { int m; };
+  struct Derived : Base {};
+  constexpr int k = ((Base{} = Derived{}), 0);
+}
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -5871,7 +5871,7 @@
 /// operator whose left-hand side might involve a union member access. If it
 /// does, implicitly start the lifetime of any accessed union elements per
 /// C++20 [class.union]5.
-static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr,
+static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *E,
                                           const LValue &LHS) {
   if (LHS.InvalidBase || LHS.Designator.Invalid)
     return false;
@@ -5879,11 +5879,11 @@
   llvm::SmallVector<std::pair<unsigned, const FieldDecl*>, 4> UnionPathLengths;
   // C++ [class.union]p5:
   //   define the set S(E) of subexpressions of E as follows:
-  unsigned PathLength = LHS.Designator.Entries.size();
-  for (const Expr *E = LHSExpr; E != nullptr;) {
+  for (unsigned PathLength = LHS.Designator.Entries.size(); PathLength;
+       --PathLength) {
+    SubobjectDesignator::PathEntry PE = LHS.Designator.Entries[PathLength - 1];
     //   -- If E is of the form A.B, S(E) contains the elements of S(A)...
-    if (auto *ME = dyn_cast<MemberExpr>(E)) {
-      auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
+    if (auto *FD = PE.getAsFieldOrNull()) {
       // Note that we can't implicitly start the lifetime of a reference,
       // so we don't need to proceed any further if we reach one.
       if (!FD || FD->getType()->isReferenceType())
@@ -5900,41 +5900,10 @@
           UnionPathLengths.push_back({PathLength - 1, FD});
       }
 
-      E = ME->getBase();
-      --PathLength;
-      assert(declaresSameEntity(
-          FD, LHS.Designator.Entries[PathLength].getAsBaseOrMember()));
-
       //   -- If E is of the form A[B] and is interpreted as a built-in array
       //      subscripting operator, S(E) is [S(the array operand, if any)].
-    } else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
-      // Step over an ArrayToPointerDecay implicit cast.
-      auto *Base = ASE->getBase()->IgnoreImplicit();
-      if (!Base->getType()->isArrayType())
-        break;
-
-      E = Base;
-      --PathLength;
-
-    } else if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
-      // Step over a derived-to-base conversion.
-      E = ICE->getSubExpr();
-      if (ICE->getCastKind() == CK_NoOp)
-        continue;
-      if (ICE->getCastKind() != CK_DerivedToBase &&
-          ICE->getCastKind() != CK_UncheckedDerivedToBase)
-        break;
-      // Walk path backwards as we walk up from the base to the derived class.
-      for (const CXXBaseSpecifier *Elt : llvm::reverse(ICE->path())) {
-        --PathLength;
-        (void)Elt;
-        assert(
-            declaresSameEntity(Elt->getType()->getAsCXXRecordDecl(),
-                               LHS.Designator.Entries[PathLength].getAsBase()));
-      }
-
-    //   -- Otherwise, S(E) is empty.
-    } else {
+      //   -- Otherwise, S(E) is empty.
+    } else if (!PE.isArrayIndex() && !PE.isAnyBase()) {
       break;
     }
   }
@@ -5946,7 +5915,7 @@
   //   if modification of X [would access an inactive union member], an object
   //   of the type of X is implicitly created
   CompleteObject Obj =
-      findCompleteObject(Info, LHSExpr, AK_Assign, LHS, LHSExpr->getType());
+      findCompleteObject(Info, E, AK_Assign, LHS, E->getType());
   if (!Obj)
     return false;
   for (std::pair<unsigned, const FieldDecl *> LengthAndField :
@@ -5958,8 +5927,8 @@
     bool DuringInit = Info.isEvaluatingCtorDtor(LHS.Base, D.Entries) ==
                       ConstructionPhase::AfterBases;
     StartLifetimeOfUnionMemberHandler StartLifetime{
-        Info, LHSExpr, LengthAndField.second, DuringInit};
-    if (!findSubobject(Info, LHSExpr, Obj, D, StartLifetime))
+        Info, E, LengthAndField.second, DuringInit};
+    if (!findSubobject(Info, E, Obj, D, StartLifetime))
       return false;
   }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D101429: ... Serge Pavlov via Phabricator via cfe-commits

Reply via email to