diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/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 (!LExpr) + LExpr = B.dyn_cast(); IsNullPtr = false; } @@ -6100,8 +6104,11 @@ if (!handleTrivialCopy(Info, MD->getParamDecl(0), Args[0], RHSValue, MD->getParent()->isUnion())) return false; + const Expr *LHS = This->getExpr(); + if (!LHS) + return false; if (Info.getLangOpts().CPlusPlus20 && MD->isTrivial() && - !HandleUnionActiveMemberChange(Info, Args[0], *This)) + !HandleUnionActiveMemberChange(Info, LHS, *This)) return false; if (!handleAssignment(Info, Args[0], *This, MD->getThisType(), RHSValue)) @@ -8058,10 +8065,20 @@ namespace { class LValueExprEvaluator : public LValueExprEvaluatorBase { + friend class LValueExprEvaluatorBase; + friend class ExprEvaluatorBase; + friend class ConstStmtVisitor; + friend class StmtVisitorBase; 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 +8140,7 @@ assert(!E->isValueDependent()); assert(E->isGLValue() || E->getType()->isFunctionType() || E->getType()->isVoidType() || isa(E)); - return LValueExprEvaluator(Info, Result, InvalidBaseOK).Visit(E); + return LValueExprEvaluator(Info, Result, InvalidBaseOK).Evaluate(E); } bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { @@ -8424,7 +8441,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 +8465,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; diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp --- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp @@ -1447,3 +1447,11 @@ 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); +} // namespace PR45879