r361329 - [c++20] P1330R0: permit simple-assignments that change the active member
Stephan Bergmann via cfe-commits
cfe-commits at lists.llvm.org
Thu May 30 04:31:29 PDT 2019
On 22/05/2019 01:15, Richard Smith via cfe-commits wrote:
> Author: rsmith
> Date: Tue May 21 16:15:20 2019
> New Revision: 361329
>
> URL: http://llvm.org/viewvc/llvm-project?rev=361329&view=rev
> Log:
> [c++20] P1330R0: permit simple-assignments that change the active member
> of a union within constant expression evaluation.
[...]
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Tue May 21 16:15:20 2019
[...]> @@ -4888,6 +4916,159 @@ static bool HandleDynamicCast(EvalInfo &
[...]
> +/// Handle a builtin simple-assignment or a call to a trivial assignment
> +/// 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,
> + const LValue &LHS) {
> + if (LHS.InvalidBase || LHS.Designator.Invalid)
> + return false;
> +
> + llvm::SmallVector<std::pair<unsigned, const FieldDecl*>, 4> UnionPathLengths;
> + // C++ [class.union]p5:
> + // define the set S(E) of subexpressions of E as follows:
> + const Expr *E = LHSExpr;
> + unsigned PathLength = LHS.Designator.Entries.size();
> + while (E) {
> + // -- 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 (!FD)
> + break;
> +
> + // ... and also contains A.B if B names a union member
> + if (FD->getParent()->isUnion())
> + UnionPathLengths.push_back({PathLength - 1, FD});
> +
> + E = ME->getBase();
> + --PathLength;
> + assert(declaresSameEntity(FD,
> + LHS.Designator.Entries[PathLength]
> + .getAsBaseOrMember().getPointer()));
> +
> + // -- 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.
> + if (ICE->getCastKind() == CK_NoOp)
> + continue;
> + if (ICE->getCastKind() != CK_DerivedToBase &&
> + ICE->getCastKind() != CK_UncheckedDerivedToBase)
> + break;
> + for (const CXXBaseSpecifier *Elt : ICE->path()) {
> + --PathLength;
> + assert(declaresSameEntity(Elt->getType()->getAsCXXRecordDecl(),
> + LHS.Designator.Entries[PathLength]
> + .getAsBaseOrMember().getPointer()));
the above assert fires for the below test.cc with `clang++ -std=c++2a
-fsyntax-only test.cc`:
> struct S1 { int n; };
> struct S2: S1 {};
> struct S3: S2 {};
> void f() {
> S3 s;
> s.n = 0;
> }
More information about the cfe-commits
mailing list