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,
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);
}
}
} 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())
} 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);
}
}
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);
}
}
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;