sepavloff updated this revision to Diff 386823.
sepavloff added a comment.

Update the patch

- Use more careful check for LHS expression,
- Make a bit more precise LHS expression tracking,
- Add comments,
- Add the test from discussion.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103395/new/

https://reviews.llvm.org/D103395

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
@@ -1447,3 +1447,22 @@
   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);
+
+struct sub {
+  char data;
+};
+struct main2 {
+  constexpr main2() {
+    member = {};
+  }
+  sub member;
+};
+constexpr main2 a{};
+} // namespace PR45879
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -1546,6 +1546,7 @@
     APValue::LValueBase Base;
     CharUnits Offset;
     SubobjectDesignator Designator;
+    const Expr *LExpr = nullptr;
     bool IsNullPtr : 1;
     bool InvalidBase : 1;
 
@@ -1554,6 +1555,7 @@
     const CharUnits &getLValueOffset() const { return Offset; }
     SubobjectDesignator &getLValueDesignator() { return Designator; }
     const SubobjectDesignator &getLValueDesignator() const { return Designator;}
+    const Expr *getExpr() const { return LExpr; }
     bool isNullPointer() const { return IsNullPtr;}
 
     unsigned getLValueCallIndex() const { return Base.getCallIndex(); }
@@ -1591,6 +1593,8 @@
       Offset = CharUnits::fromQuantity(0);
       InvalidBase = BInvalid;
       Designator = SubobjectDesignator(getType(B));
+      if (const Expr *E = B.dyn_cast<const Expr *>())
+        LExpr = E;
       IsNullPtr = false;
     }
 
@@ -5893,11 +5897,17 @@
 /// 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.
+/// Returns true if the assignment is OK and it may be processed further.
 static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr,
                                           const LValue &LHS) {
   if (LHS.InvalidBase || LHS.Designator.Invalid)
     return false;
 
+  // If no LHS expression was specified, assume the LHS cannot be an assignment
+  // to a union member.
+  if (!LHSExpr)
+    return true;
+
   llvm::SmallVector<std::pair<unsigned, const FieldDecl*>, 4> UnionPathLengths;
   // C++ [class.union]p5:
   //   define the set S(E) of subexpressions of E as follows:
@@ -6101,7 +6111,7 @@
                            MD->getParent()->isUnion()))
       return false;
     if (Info.getLangOpts().CPlusPlus20 && MD->isTrivial() &&
-        !HandleUnionActiveMemberChange(Info, Args[0], *This))
+        !HandleUnionActiveMemberChange(Info, This->getExpr(), *This))
       return false;
     if (!handleAssignment(Info, Args[0], *This, MD->getThisType(),
                           RHSValue))
@@ -8058,10 +8068,20 @@
 namespace {
 class LValueExprEvaluator
   : public LValueExprEvaluatorBase<LValueExprEvaluator> {
+  friend class LValueExprEvaluatorBase<LValueExprEvaluator>;
+  friend class ExprEvaluatorBase<LValueExprEvaluator>;
+  friend class ConstStmtVisitor<LValueExprEvaluator, bool>;
+  friend class StmtVisitorBase<llvm::make_const_ptr, LValueExprEvaluator, bool>;
 public:
   LValueExprEvaluator(EvalInfo &Info, LValue &Result, bool InvalidBaseOK) :
     LValueExprEvaluatorBaseTy(Info, Result, InvalidBaseOK) {}
 
+  bool Evaluate(const Expr *E) {
+    Result.LExpr = E;
+    return Visit(E);
+  }
+
+protected:
   bool VisitVarDecl(const Expr *E, const VarDecl *VD);
   bool VisitUnaryPreIncDec(const UnaryOperator *UO);
 
@@ -8123,7 +8143,7 @@
   assert(!E->isValueDependent());
   assert(E->isGLValue() || E->getType()->isFunctionType() ||
          E->getType()->isVoidType() || isa<ObjCSelectorExpr>(E));
-  return LValueExprEvaluator(Info, Result, InvalidBaseOK).Visit(E);
+  return LValueExprEvaluator(Info, Result, InvalidBaseOK).Evaluate(E);
 }
 
 bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
@@ -8424,7 +8444,7 @@
 
   // C++17 onwards require that we evaluate the RHS first.
   APValue RHS;
-  if (!Evaluate(RHS, this->Info, CAO->getRHS())) {
+  if (!::Evaluate(RHS, this->Info, CAO->getRHS())) {
     if (!Info.noteFailure())
       return false;
     Success = false;
@@ -8448,7 +8468,7 @@
 
   // C++17 onwards require that we evaluate the RHS first.
   APValue NewVal;
-  if (!Evaluate(NewVal, this->Info, E->getRHS())) {
+  if (!::Evaluate(NewVal, this->Info, E->getRHS())) {
     if (!Info.noteFailure())
       return false;
     Success = false;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to