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