r324537 - PR36055: fix computation of *-dependence in nested initializer lists.

Hans Wennborg via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 9 01:05:53 PST 2018


Merged to 6.0 in r324719.

On Wed, Feb 7, 2018 at 11:25 PM, Richard Smith via cfe-commits
<cfe-commits at lists.llvm.org> wrote:
> Author: rsmith
> Date: Wed Feb  7 14:25:16 2018
> New Revision: 324537
>
> URL: http://llvm.org/viewvc/llvm-project?rev=324537&view=rev
> Log:
> PR36055: fix computation of *-dependence in nested initializer lists.
>
> When we synthesize an implicit inner initializer list when analyzing an outer
> initializer list, we add it to the outer list immediately, and then fill in the
> inner list. This gives the outer list no chance to update its *-dependence bits
> with those of the completed inner list. To fix this, re-add the inner list to
> the outer list once it's completed.
>
> Note that we do not recompute the *-dependence bits from scratch when we
> complete an outer list; this would give the wrong result for the case where a
> designated initializer overwrites a dependent initializer with a non-dependent
> one. The resulting list in that case should still be dependent, even though all
> traces of the dependence were removed from the semantic form.
>
> Modified:
>     cfe/trunk/lib/Sema/SemaInit.cpp
>     cfe/trunk/test/SemaCXX/init-expr-crash.cpp
>     cfe/trunk/test/SemaTemplate/instantiate-init.cpp
>
> Modified: cfe/trunk/lib/Sema/SemaInit.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=324537&r1=324536&r2=324537&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaInit.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaInit.cpp Wed Feb  7 14:25:16 2018
> @@ -352,6 +352,7 @@ class InitListChecker {
>                                 bool FillWithNoInit = false);
>    void FillInEmptyInitializations(const InitializedEntity &Entity,
>                                    InitListExpr *ILE, bool &RequiresSecondPass,
> +                                  InitListExpr *OuterILE, unsigned OuterIndex,
>                                    bool FillWithNoInit = false);
>    bool CheckFlexibleArrayInit(const InitializedEntity &Entity,
>                                Expr *InitExpr, FieldDecl *Field,
> @@ -517,12 +518,13 @@ void InitListChecker::FillInEmptyInitFor
>      ILE->setInit(Init, BaseInit.getAs<Expr>());
>    } else if (InitListExpr *InnerILE =
>                   dyn_cast<InitListExpr>(ILE->getInit(Init))) {
> -    FillInEmptyInitializations(BaseEntity, InnerILE,
> -                               RequiresSecondPass, FillWithNoInit);
> +    FillInEmptyInitializations(BaseEntity, InnerILE, RequiresSecondPass,
> +                               ILE, Init, FillWithNoInit);
>    } else if (DesignatedInitUpdateExpr *InnerDIUE =
>                 dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) {
>      FillInEmptyInitializations(BaseEntity, InnerDIUE->getUpdater(),
> -                               RequiresSecondPass, /*FillWithNoInit =*/true);
> +                               RequiresSecondPass, ILE, Init,
> +                               /*FillWithNoInit =*/true);
>    }
>  }
>
> @@ -605,24 +607,43 @@ void InitListChecker::FillInEmptyInitFor
>    } else if (InitListExpr *InnerILE
>                 = dyn_cast<InitListExpr>(ILE->getInit(Init)))
>      FillInEmptyInitializations(MemberEntity, InnerILE,
> -                               RequiresSecondPass, FillWithNoInit);
> +                               RequiresSecondPass, ILE, Init, FillWithNoInit);
>    else if (DesignatedInitUpdateExpr *InnerDIUE
>                 = dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init)))
>      FillInEmptyInitializations(MemberEntity, InnerDIUE->getUpdater(),
> -                               RequiresSecondPass, /*FillWithNoInit =*/ true);
> +                               RequiresSecondPass, ILE, Init,
> +                               /*FillWithNoInit =*/true);
>  }
>
>  /// Recursively replaces NULL values within the given initializer list
>  /// with expressions that perform value-initialization of the
> -/// appropriate type.
> +/// appropriate type, and finish off the InitListExpr formation.
>  void
>  InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
>                                              InitListExpr *ILE,
>                                              bool &RequiresSecondPass,
> +                                            InitListExpr *OuterILE,
> +                                            unsigned OuterIndex,
>                                              bool FillWithNoInit) {
>    assert((ILE->getType() != SemaRef.Context.VoidTy) &&
>           "Should not have void type");
>
> +  // If this is a nested initializer list, we might have changed its contents
> +  // (and therefore some of its properties, such as instantiation-dependence)
> +  // while filling it in. Inform the outer initializer list so that its state
> +  // can be updated to match.
> +  // FIXME: We should fully build the inner initializers before constructing
> +  // the outer InitListExpr instead of mutating AST nodes after they have
> +  // been used as subexpressions of other nodes.
> +  struct UpdateOuterILEWithUpdatedInit {
> +    InitListExpr *Outer;
> +    unsigned OuterIndex;
> +    ~UpdateOuterILEWithUpdatedInit() {
> +      if (Outer)
> +        Outer->setInit(OuterIndex, Outer->getInit(OuterIndex));
> +    }
> +  } UpdateOuterRAII = {OuterILE, OuterIndex};
> +
>    // A transparent ILE is not performing aggregate initialization and should
>    // not be filled in.
>    if (ILE->isTransparent())
> @@ -769,11 +790,12 @@ InitListChecker::FillInEmptyInitializati
>      } else if (InitListExpr *InnerILE
>                   = dyn_cast_or_null<InitListExpr>(InitExpr))
>        FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass,
> -                                 FillWithNoInit);
> +                                 ILE, Init, FillWithNoInit);
>      else if (DesignatedInitUpdateExpr *InnerDIUE
>                   = dyn_cast_or_null<DesignatedInitUpdateExpr>(InitExpr))
>        FillInEmptyInitializations(ElementEntity, InnerDIUE->getUpdater(),
> -                                 RequiresSecondPass, /*FillWithNoInit =*/ true);
> +                                 RequiresSecondPass, ILE, Init,
> +                                 /*FillWithNoInit =*/true);
>    }
>  }
>
> @@ -795,10 +817,11 @@ InitListChecker::InitListChecker(Sema &S
>
>    if (!hadError && !VerifyOnly) {
>      bool RequiresSecondPass = false;
> -    FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass);
> +    FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass,
> +                               /*OuterILE=*/nullptr, /*OuterIndex=*/0);
>      if (RequiresSecondPass && !hadError)
>        FillInEmptyInitializations(Entity, FullyStructuredList,
> -                                 RequiresSecondPass);
> +                                 RequiresSecondPass, nullptr, 0);
>    }
>  }
>
> @@ -1162,10 +1185,12 @@ void InitListChecker::CheckSubElementTyp
>        if (!hadError && !VerifyOnly) {
>          bool RequiresSecondPass = false;
>          FillInEmptyInitializations(Entity, InnerStructuredList,
> -                                   RequiresSecondPass);
> +                                   RequiresSecondPass, StructuredList,
> +                                   StructuredIndex);
>          if (RequiresSecondPass && !hadError)
>            FillInEmptyInitializations(Entity, InnerStructuredList,
> -                                     RequiresSecondPass);
> +                                     RequiresSecondPass, StructuredList,
> +                                     StructuredIndex);
>        }
>        ++StructuredIndex;
>        ++Index;
>
> Modified: cfe/trunk/test/SemaCXX/init-expr-crash.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/init-expr-crash.cpp?rev=324537&r1=324536&r2=324537&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/init-expr-crash.cpp (original)
> +++ cfe/trunk/test/SemaCXX/init-expr-crash.cpp Wed Feb  7 14:25:16 2018
> @@ -29,3 +29,11 @@ template <class T> struct B {
>      return 0;
>    }
>  };
> +
> +// This test checks for a crash that resulted from us miscomputing the
> +// dependence of a nested initializer list.
> +template<int> struct X {
> +  static constexpr int n = 4;
> +  static constexpr int a[1][1] = {n};
> +};
> +
>
> Modified: cfe/trunk/test/SemaTemplate/instantiate-init.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-init.cpp?rev=324537&r1=324536&r2=324537&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaTemplate/instantiate-init.cpp (original)
> +++ cfe/trunk/test/SemaTemplate/instantiate-init.cpp Wed Feb  7 14:25:16 2018
> @@ -142,3 +142,17 @@ namespace ReturnStmtIsInitialization {
>    template<typename T> X f() { return {}; }
>    auto &&x = f<void>();
>  }
> +
> +namespace InitListUpdate {
> +  struct A { int n; };
> +  using AA = A[1];
> +
> +  // Check that an init list update doesn't "lose" the pack-ness of an expression.
> +  template <int... N> void f() {
> +    g(AA{0, [0].n = N} ...); // expected-warning 3{{overrides prior init}} expected-note 3{{previous init}}
> +    g(AA{N, [0].n = 0} ...); // expected-warning 3{{overrides prior init}} expected-note 3{{previous init}}
> +  };
> +
> +  void g(AA, AA);
> +  void h() { f<1, 2>(); } // expected-note {{instantiation of}}
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


More information about the cfe-commits mailing list