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