<div dir="ltr"><div dir="ltr"></div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, 30 May 2019 at 04:31, Stephan Bergmann via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 22/05/2019 01:15, Richard Smith via cfe-commits wrote:<br>
> Author: rsmith<br>
> Date: Tue May 21 16:15:20 2019<br>
> New Revision: 361329<br>
> <br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=361329&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=361329&view=rev</a><br>
> Log:<br>
> [c++20] P1330R0: permit simple-assignments that change the active member<br>
> of a union within constant expression evaluation.<br>
[...]<br>
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)<br>
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Tue May 21 16:15:20 2019<br>
[...]> @@ -4888,6 +4916,159 @@ static bool HandleDynamicCast(EvalInfo &<br>
[...]<br>
> +/// Handle a builtin simple-assignment or a call to a trivial assignment<br>
> +/// operator whose left-hand side might involve a union member access. If it<br>
> +/// does, implicitly start the lifetime of any accessed union elements per<br>
> +/// C++20 [class.union]5.<br>
> +static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr,<br>
> +                                          const LValue &LHS) {<br>
> +  if (LHS.InvalidBase || LHS.Designator.Invalid)<br>
> +    return false;<br>
> +<br>
> +  llvm::SmallVector<std::pair<unsigned, const FieldDecl*>, 4> UnionPathLengths;<br>
> +  // C++ [class.union]p5:<br>
> +  //   define the set S(E) of subexpressions of E as follows:<br>
> +  const Expr *E = LHSExpr;<br>
> +  unsigned PathLength = LHS.Designator.Entries.size();<br>
> +  while (E) {<br>
> +    //   -- If E is of the form A.B, S(E) contains the elements of S(A)...<br>
> +    if (auto *ME = dyn_cast<MemberExpr>(E)) {<br>
> +      auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());<br>
> +      if (!FD)<br>
> +        break;<br>
> +<br>
> +      //    ... and also contains A.B if B names a union member<br>
> +      if (FD->getParent()->isUnion())<br>
> +        UnionPathLengths.push_back({PathLength - 1, FD});<br>
> +<br>
> +      E = ME->getBase();<br>
> +      --PathLength;<br>
> +      assert(declaresSameEntity(FD,<br>
> +                                LHS.Designator.Entries[PathLength]<br>
> +                                    .getAsBaseOrMember().getPointer()));<br>
> +<br>
> +      //   -- If E is of the form A[B] and is interpreted as a built-in array<br>
> +      //      subscripting operator, S(E) is [S(the array operand, if any)].<br>
> +    } else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) {<br>
> +      // Step over an ArrayToPointerDecay implicit cast.<br>
> +      auto *Base = ASE->getBase()->IgnoreImplicit();<br>
> +      if (!Base->getType()->isArrayType())<br>
> +        break;<br>
> +<br>
> +      E = Base;<br>
> +      --PathLength;<br>
> +<br>
> +    } else if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {<br>
> +      // Step over a derived-to-base conversion.<br>
> +      if (ICE->getCastKind() == CK_NoOp)<br>
> +        continue;<br>
> +      if (ICE->getCastKind() != CK_DerivedToBase &&<br>
> +          ICE->getCastKind() != CK_UncheckedDerivedToBase)<br>
> +        break;<br>
> +      for (const CXXBaseSpecifier *Elt : ICE->path()) {<br>
> +        --PathLength;<br>
> +        assert(declaresSameEntity(Elt->getType()->getAsCXXRecordDecl(),<br>
> +                                  LHS.Designator.Entries[PathLength]<br>
> +                                      .getAsBaseOrMember().getPointer()));<br>
<br>
the above assert fires for the below test.cc with `clang++ -std=c++2a <br>
-fsyntax-only test.cc`:<br>
<br>
> struct S1 { int n; };<br>
> struct S2: S1 {};<br>
> struct S3: S2 {};<br>
> void f() {<br>
>  S3 s;<br>
>  s.n = 0;<br>
> }<br></blockquote><div><br></div><div>Thanks for the great testcase, fixed in r362147.</div></div></div>