Merged to 6.0 in r324719.
On Wed, Feb 7, 2018 at 11:25 PM, Richard Smith via cfe-commits <cfe-commits@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@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits