|
@@ -281,6 +281,7 @@ class InitListChecker {
|
|
bool hadError = false;
|
|
bool hadError = false;
|
|
bool VerifyOnly; // No diagnostics.
|
|
bool VerifyOnly; // No diagnostics.
|
|
bool TreatUnavailableAsInvalid; // Used only in VerifyOnly mode.
|
|
bool TreatUnavailableAsInvalid; // Used only in VerifyOnly mode.
|
|
|
|
+ bool InOverloadResolution;
|
|
InitListExpr *FullyStructuredList = nullptr;
|
|
InitListExpr *FullyStructuredList = nullptr;
|
|
NoInitExpr *DummyExpr = nullptr;
|
|
NoInitExpr *DummyExpr = nullptr;
|
|
|
|
|
|
@@ -372,6 +373,63 @@ class InitListChecker {
|
|
ExprResult PerformEmptyInit(SourceLocation Loc,
|
|
ExprResult PerformEmptyInit(SourceLocation Loc,
|
|
const InitializedEntity &Entity);
|
|
const InitializedEntity &Entity);
|
|
|
|
|
|
|
|
+ /// Diagnose that OldInit (or part thereof) has been overridden by NewInit.
|
|
|
|
+ void diagnoseInitOverride(Expr *OldInit, SourceRange NewInitRange,
|
|
|
|
+ bool FullyOverwritten = true) {
|
|
|
|
+ // Overriding an initializer via a designator is valid with C99 designated
|
|
|
|
+ // initializers, but ill-formed with C++20 designated initializers.
|
|
|
|
+ unsigned DiagID = SemaRef.getLangOpts().CPlusPlus
|
|
|
|
+ ? diag::ext_initializer_overrides
|
|
|
|
+ : diag::warn_initializer_overrides;
|
|
|
|
+
|
|
|
|
+ if (InOverloadResolution && SemaRef.getLangOpts().CPlusPlus) {
|
|
|
|
+ // In overload resolution, we have to strictly enforce the rules, and so
|
|
|
|
+ // don't allow any overriding of prior initializers. This matters for a
|
|
|
|
+ // case such as:
|
|
|
|
+ //
|
|
|
|
+ // union U { int a, b; };
|
|
|
|
+ // struct S { int a, b; };
|
|
|
|
+ // void f(U), f(S);
|
|
|
|
+ //
|
|
|
|
+ // Here, f({.a = 1, .b = 2}) is required to call the struct overload. For
|
|
|
|
+ // consistency, we disallow all overriding of prior initializers in
|
|
|
|
+ // overload resolution, not only overriding of union members.
|
|
|
|
+ hadError = true;
|
|
|
|
+ } else if (OldInit->getType().isDestructedType() && !FullyOverwritten) {
|
|
|
|
+ // If we'll be keeping around the old initializer but overwriting part of
|
|
|
|
+ // the object it initialized, and that object is not trivially
|
|
|
|
+ // destructible, this can leak. Don't allow that, not even as an
|
|
|
|
+ // extension.
|
|
|
|
+ //
|
|
|
|
+ // FIXME: It might be reasonable to allow this in cases where the part of
|
|
|
|
+ // the initializer that we're overriding has trivial destruction.
|
|
|
|
+ DiagID = diag::err_initializer_overrides_destructed;
|
|
|
|
+ } else if (!OldInit->getSourceRange().isValid()) {
|
|
|
|
+ // We need to check on source range validity because the previous
|
|
|
|
+ // initializer does not have to be an explicit initializer. e.g.,
|
|
|
|
+ //
|
|
|
|
+ // struct P { int a, b; };
|
|
|
|
+ // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
|
|
|
|
+ //
|
|
|
|
+ // There is an overwrite taking place because the first braced initializer
|
|
|
|
+ // list "{ .a = 2 }" already provides value for .p.b (which is zero).
|
|
|
|
+ //
|
|
|
|
+ // Such overwrites are harmless, so we don't diagnose them. (Note that in
|
|
|
|
+ // C++, this cannot be reached unless we've already seen and diagnosed a
|
|
|
|
+ // different conformance issue, such as a mixture of designated and
|
|
|
|
+ // non-designated initializers or a multi-level designator.)
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!VerifyOnly) {
|
|
|
|
+ SemaRef.Diag(NewInitRange.getBegin(), DiagID)
|
|
|
|
+ << NewInitRange << FullyOverwritten << OldInit->getType();
|
|
|
|
+ SemaRef.Diag(OldInit->getBeginLoc(), diag::note_previous_initializer)
|
|
|
|
+ << (OldInit->HasSideEffects(SemaRef.Context) && FullyOverwritten)
|
|
|
|
+ << OldInit->getSourceRange();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
// Explanation on the "FillWithNoInit" mode:
|
|
// Explanation on the "FillWithNoInit" mode:
|
|
//
|
|
//
|
|
// Assume we have the following definitions (Case#1):
|
|
// Assume we have the following definitions (Case#1):
|
|
@@ -410,9 +468,9 @@ class InitListChecker {
|
|
SourceLocation Loc);
|
|
SourceLocation Loc);
|
|
|
|
|
|
public:
|
|
public:
|
|
- InitListChecker(Sema &S, const InitializedEntity &Entity,
|
|
|
|
- InitListExpr *IL, QualType &T, bool VerifyOnly,
|
|
|
|
- bool TreatUnavailableAsInvalid);
|
|
|
|
|
|
+ InitListChecker(Sema &S, const InitializedEntity &Entity, InitListExpr *IL,
|
|
|
|
+ QualType &T, bool VerifyOnly, bool TreatUnavailableAsInvalid,
|
|
|
|
+ bool InOverloadResolution = false);
|
|
bool HadError() { return hadError; }
|
|
bool HadError() { return hadError; }
|
|
|
|
|
|
// Retrieves the fully-structured initializer list used for
|
|
// Retrieves the fully-structured initializer list used for
|
|
@@ -877,9 +935,11 @@ static bool hasAnyDesignatedInits(const InitListExpr *IL) {
|
|
|
|
|
|
InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
|
|
InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
|
|
InitListExpr *IL, QualType &T, bool VerifyOnly,
|
|
InitListExpr *IL, QualType &T, bool VerifyOnly,
|
|
- bool TreatUnavailableAsInvalid)
|
|
|
|
|
|
+ bool TreatUnavailableAsInvalid,
|
|
|
|
+ bool InOverloadResolution)
|
|
: SemaRef(S), VerifyOnly(VerifyOnly),
|
|
: SemaRef(S), VerifyOnly(VerifyOnly),
|
|
- TreatUnavailableAsInvalid(TreatUnavailableAsInvalid) {
|
|
|
|
|
|
+ TreatUnavailableAsInvalid(TreatUnavailableAsInvalid),
|
|
|
|
+ InOverloadResolution(InOverloadResolution) {
|
|
if (!VerifyOnly || hasAnyDesignatedInits(IL)) {
|
|
if (!VerifyOnly || hasAnyDesignatedInits(IL)) {
|
|
FullyStructuredList =
|
|
FullyStructuredList =
|
|
createInitListExpr(T, IL->getSourceRange(), IL->getNumInits());
|
|
createInitListExpr(T, IL->getSourceRange(), IL->getNumInits());
|
|
@@ -1959,7 +2019,8 @@ void InitListChecker::CheckStructUnionTypes(
|
|
}
|
|
}
|
|
|
|
|
|
// If there's a default initializer, use it.
|
|
// If there's a default initializer, use it.
|
|
- if (isa<CXXRecordDecl>(RD) && cast<CXXRecordDecl>(RD)->hasInClassInitializer()) {
|
|
|
|
|
|
+ if (isa<CXXRecordDecl>(RD) &&
|
|
|
|
+ cast<CXXRecordDecl>(RD)->hasInClassInitializer()) {
|
|
if (!StructuredList)
|
|
if (!StructuredList)
|
|
return;
|
|
return;
|
|
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
|
|
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
|
|
@@ -2276,7 +2337,9 @@ class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback {
|
|
///
|
|
///
|
|
/// @param NextField If non-NULL and the first designator in @p DIE is
|
|
/// @param NextField If non-NULL and the first designator in @p DIE is
|
|
/// a field, this will be set to the field declaration corresponding
|
|
/// a field, this will be set to the field declaration corresponding
|
|
-/// to the field named by the designator.
|
|
|
|
|
|
+/// to the field named by the designator. On input, this is expected to be
|
|
|
|
+/// the next field that would be initialized in the absence of designation,
|
|
|
|
+/// if the complete object being initialized is a struct.
|
|
///
|
|
///
|
|
/// @param NextElementIndex If non-NULL and the first designator in @p
|
|
/// @param NextElementIndex If non-NULL and the first designator in @p
|
|
/// DIE is an array designator or GNU array-range designator, this
|
|
/// DIE is an array designator or GNU array-range designator, this
|
|
@@ -2344,53 +2407,41 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
|
|
SourceRange(D->getBeginLoc(), DIE->getEndLoc()));
|
|
SourceRange(D->getBeginLoc(), DIE->getEndLoc()));
|
|
else if (InitListExpr *Result = dyn_cast<InitListExpr>(ExistingInit))
|
|
else if (InitListExpr *Result = dyn_cast<InitListExpr>(ExistingInit))
|
|
StructuredList = Result;
|
|
StructuredList = Result;
|
|
- else if (!VerifyOnly) {
|
|
|
|
- if (DesignatedInitUpdateExpr *E =
|
|
|
|
- dyn_cast<DesignatedInitUpdateExpr>(ExistingInit))
|
|
|
|
- StructuredList = E->getUpdater();
|
|
|
|
- else {
|
|
|
|
- DesignatedInitUpdateExpr *DIUE = new (SemaRef.Context)
|
|
|
|
- DesignatedInitUpdateExpr(SemaRef.Context, D->getBeginLoc(),
|
|
|
|
- ExistingInit, DIE->getEndLoc());
|
|
|
|
- StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE);
|
|
|
|
- StructuredList = DIUE->getUpdater();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // We need to check on source range validity because the previous
|
|
|
|
- // initializer does not have to be an explicit initializer. e.g.,
|
|
|
|
|
|
+ else {
|
|
|
|
+ // We are creating an initializer list that initializes the
|
|
|
|
+ // subobjects of the current object, but there was already an
|
|
|
|
+ // initialization that completely initialized the current
|
|
|
|
+ // subobject, e.g., by a compound literal:
|
|
//
|
|
//
|
|
- // struct P { int a, b; };
|
|
|
|
- // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
|
|
|
|
|
|
+ // struct X { int a, b; };
|
|
|
|
+ // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
|
|
//
|
|
//
|
|
- // There is an overwrite taking place because the first braced initializer
|
|
|
|
- // list "{ .a = 2 }" already provides value for .p.b (which is zero).
|
|
|
|
- if (ExistingInit->getSourceRange().isValid()) {
|
|
|
|
- // We are creating an initializer list that initializes the
|
|
|
|
- // subobjects of the current object, but there was already an
|
|
|
|
- // initialization that completely initialized the current
|
|
|
|
- // subobject, e.g., by a compound literal:
|
|
|
|
- //
|
|
|
|
- // struct X { int a, b; };
|
|
|
|
- // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
|
|
|
|
- //
|
|
|
|
- // Here, xs[0].a == 1 and xs[0].b == 3, since the second,
|
|
|
|
- // designated initializer re-initializes only its current object
|
|
|
|
- // subobject [0].b.
|
|
|
|
- SemaRef.Diag(D->getBeginLoc(),
|
|
|
|
- diag::warn_subobject_initializer_overrides)
|
|
|
|
- << SourceRange(D->getBeginLoc(), DIE->getEndLoc());
|
|
|
|
-
|
|
|
|
- SemaRef.Diag(ExistingInit->getBeginLoc(),
|
|
|
|
- diag::note_previous_initializer)
|
|
|
|
- << /*FIXME:has side effects=*/0 << ExistingInit->getSourceRange();
|
|
|
|
|
|
+ // Here, xs[0].a == 1 and xs[0].b == 3, since the second,
|
|
|
|
+ // designated initializer re-initializes only its current object
|
|
|
|
+ // subobject [0].b.
|
|
|
|
+ diagnoseInitOverride(ExistingInit,
|
|
|
|
+ SourceRange(D->getBeginLoc(), DIE->getEndLoc()),
|
|
|
|
+ /*FullyOverwritten=*/false);
|
|
|
|
+
|
|
|
|
+ if (!VerifyOnly) {
|
|
|
|
+ if (DesignatedInitUpdateExpr *E =
|
|
|
|
+ dyn_cast<DesignatedInitUpdateExpr>(ExistingInit))
|
|
|
|
+ StructuredList = E->getUpdater();
|
|
|
|
+ else {
|
|
|
|
+ DesignatedInitUpdateExpr *DIUE = new (SemaRef.Context)
|
|
|
|
+ DesignatedInitUpdateExpr(SemaRef.Context, D->getBeginLoc(),
|
|
|
|
+ ExistingInit, DIE->getEndLoc());
|
|
|
|
+ StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE);
|
|
|
|
+ StructuredList = DIUE->getUpdater();
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ // We don't need to track the structured representation of a
|
|
|
|
+ // designated init update of an already-fully-initialized object in
|
|
|
|
+ // verify-only mode. The only reason we would need the structure is
|
|
|
|
+ // to determine where the uninitialized "holes" are, and in this
|
|
|
|
+ // case, we know there aren't any and we can't introduce any.
|
|
|
|
+ StructuredList = nullptr;
|
|
}
|
|
}
|
|
- } else {
|
|
|
|
- // We don't need to track the structured representation of a designated
|
|
|
|
- // init update of an already-fully-initialized object in verify-only
|
|
|
|
- // mode. The only reason we would need the structure is to determine
|
|
|
|
- // where the uninitialized "holes" are, and in this case, we know there
|
|
|
|
- // aren't any and we can't introduce any.
|
|
|
|
- StructuredList = nullptr;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -2475,10 +2526,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- unsigned FieldIndex = 0;
|
|
|
|
-
|
|
|
|
|
|
+ unsigned NumBases = 0;
|
|
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
|
|
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
|
|
- FieldIndex = CXXRD->getNumBases();
|
|
|
|
|
|
+ NumBases = CXXRD->getNumBases();
|
|
|
|
+
|
|
|
|
+ unsigned FieldIndex = NumBases;
|
|
|
|
|
|
for (auto *FI : RT->getDecl()->fields()) {
|
|
for (auto *FI : RT->getDecl()->fields()) {
|
|
if (FI->isUnnamedBitfield())
|
|
if (FI->isUnnamedBitfield())
|
|
@@ -2504,15 +2556,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
|
|
&& "A union should never have more than one initializer!");
|
|
&& "A union should never have more than one initializer!");
|
|
|
|
|
|
Expr *ExistingInit = StructuredList->getInit(0);
|
|
Expr *ExistingInit = StructuredList->getInit(0);
|
|
- if (ExistingInit && !VerifyOnly) {
|
|
|
|
|
|
+ if (ExistingInit) {
|
|
// We're about to throw away an initializer, emit warning.
|
|
// We're about to throw away an initializer, emit warning.
|
|
- SemaRef.Diag(D->getFieldLoc(),
|
|
|
|
- diag::warn_initializer_overrides)
|
|
|
|
- << D->getSourceRange();
|
|
|
|
- SemaRef.Diag(ExistingInit->getBeginLoc(),
|
|
|
|
- diag::note_previous_initializer)
|
|
|
|
- << /*FIXME:has side effects=*/0
|
|
|
|
- << ExistingInit->getSourceRange();
|
|
|
|
|
|
+ diagnoseInitOverride(
|
|
|
|
+ ExistingInit, SourceRange(D->getBeginLoc(), DIE->getEndLoc()));
|
|
}
|
|
}
|
|
|
|
|
|
// remove existing initializer
|
|
// remove existing initializer
|
|
@@ -2535,6 +2582,54 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // C++20 [dcl.init.list]p3:
|
|
|
|
+ // The ordered identifiers in the designators of the designated-
|
|
|
|
+ // initializer-list shall form a subsequence of the ordered identifiers
|
|
|
|
+ // in the direct non-static data members of T.
|
|
|
|
+ //
|
|
|
|
+ // Note that this is not a condition on forming the aggregate
|
|
|
|
+ // initialization, only on actually performing initialization,
|
|
|
|
+ // so it is not checked in VerifyOnly mode.
|
|
|
|
+ //
|
|
|
|
+ // FIXME: This is the only reordering diagnostic we produce, and it only
|
|
|
|
+ // catches cases where we have a top-level field designator that jumps
|
|
|
|
+ // backwards. This is the only such case that is reachable in an
|
|
|
|
+ // otherwise-valid C++20 program, so is the only case that's required for
|
|
|
|
+ // conformance, but for consistency, we should diagnose all the other
|
|
|
|
+ // cases where a designator takes us backwards too.
|
|
|
|
+ if (IsFirstDesignator && !VerifyOnly && SemaRef.getLangOpts().CPlusPlus &&
|
|
|
|
+ NextField &&
|
|
|
|
+ (*NextField == RT->getDecl()->field_end() ||
|
|
|
|
+ (*NextField)->getFieldIndex() > Field->getFieldIndex() + 1)) {
|
|
|
|
+ // Find the field that we just initialized.
|
|
|
|
+ FieldDecl *PrevField = nullptr;
|
|
|
|
+ for (auto FI = RT->getDecl()->field_begin();
|
|
|
|
+ FI != RT->getDecl()->field_end(); ++FI) {
|
|
|
|
+ if (FI->isUnnamedBitfield())
|
|
|
|
+ continue;
|
|
|
|
+ if (*NextField != RT->getDecl()->field_end() &&
|
|
|
|
+ declaresSameEntity(*FI, **NextField))
|
|
|
|
+ break;
|
|
|
|
+ PrevField = *FI;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (PrevField &&
|
|
|
|
+ PrevField->getFieldIndex() > KnownField->getFieldIndex()) {
|
|
|
|
+ SemaRef.Diag(DIE->getBeginLoc(), diag::ext_designated_init_reordered)
|
|
|
|
+ << KnownField << PrevField << DIE->getSourceRange();
|
|
|
|
+
|
|
|
|
+ unsigned OldIndex = NumBases + PrevField->getFieldIndex();
|
|
|
|
+ if (StructuredList && OldIndex <= StructuredList->getNumInits()) {
|
|
|
|
+ if (Expr *PrevInit = StructuredList->getInit(OldIndex)) {
|
|
|
|
+ SemaRef.Diag(PrevInit->getBeginLoc(),
|
|
|
|
+ diag::note_previous_field_init)
|
|
|
|
+ << PrevField << PrevInit->getSourceRange();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
// Update the designator with the field declaration.
|
|
// Update the designator with the field declaration.
|
|
if (!VerifyOnly)
|
|
if (!VerifyOnly)
|
|
D->setField(*Field);
|
|
D->setField(*Field);
|
|
@@ -2875,7 +2970,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
|
|
if (!IsFullyOverwritten)
|
|
if (!IsFullyOverwritten)
|
|
return Result;
|
|
return Result;
|
|
|
|
|
|
- if (ExistingInit && !VerifyOnly) {
|
|
|
|
|
|
+ if (ExistingInit) {
|
|
// We are creating an initializer list that initializes the
|
|
// We are creating an initializer list that initializes the
|
|
// subobjects of the current object, but there was already an
|
|
// subobjects of the current object, but there was already an
|
|
// initialization that completely initialized the current
|
|
// initialization that completely initialized the current
|
|
@@ -2895,11 +2990,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
|
|
// struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
|
|
// struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
|
|
//
|
|
//
|
|
// This case is handled by CheckDesignatedInitializer.
|
|
// This case is handled by CheckDesignatedInitializer.
|
|
- SemaRef.Diag(InitRange.getBegin(),
|
|
|
|
- diag::warn_subobject_initializer_overrides)
|
|
|
|
- << InitRange;
|
|
|
|
- SemaRef.Diag(ExistingInit->getBeginLoc(), diag::note_previous_initializer)
|
|
|
|
- << /*FIXME:has side effects=*/0 << ExistingInit->getSourceRange();
|
|
|
|
|
|
+ diagnoseInitOverride(ExistingInit, InitRange);
|
|
}
|
|
}
|
|
|
|
|
|
unsigned ExpectedNumInits = 0;
|
|
unsigned ExpectedNumInits = 0;
|
|
@@ -2968,24 +3059,23 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
|
|
if (Expr *PrevInit = StructuredList->updateInit(SemaRef.Context,
|
|
if (Expr *PrevInit = StructuredList->updateInit(SemaRef.Context,
|
|
StructuredIndex, expr)) {
|
|
StructuredIndex, expr)) {
|
|
// This initializer overwrites a previous initializer. Warn.
|
|
// This initializer overwrites a previous initializer. Warn.
|
|
- // We need to check on source range validity because the previous
|
|
|
|
- // initializer does not have to be an explicit initializer.
|
|
|
|
- // struct P { int a, b; };
|
|
|
|
- // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
|
|
|
|
- // There is an overwrite taking place because the first braced initializer
|
|
|
|
- // list "{ .a = 2 }' already provides value for .p.b (which is zero).
|
|
|
|
- if (PrevInit->getSourceRange().isValid() && !VerifyOnly) {
|
|
|
|
- SemaRef.Diag(expr->getBeginLoc(), diag::warn_initializer_overrides)
|
|
|
|
- << expr->getSourceRange();
|
|
|
|
-
|
|
|
|
- SemaRef.Diag(PrevInit->getBeginLoc(), diag::note_previous_initializer)
|
|
|
|
- << /*FIXME:has side effects=*/0 << PrevInit->getSourceRange();
|
|
|
|
- }
|
|
|
|
|
|
+ diagnoseInitOverride(PrevInit, expr->getSourceRange());
|
|
}
|
|
}
|
|
|
|
|
|
++StructuredIndex;
|
|
++StructuredIndex;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/// Determine whether we can perform aggregate initialization for the purposes
|
|
|
|
+/// of overload resolution.
|
|
|
|
+bool Sema::CanPerformAggregateInitializationForOverloadResolution(
|
|
|
|
+ const InitializedEntity &Entity, InitListExpr *From) {
|
|
|
|
+ QualType Type = Entity.getType();
|
|
|
|
+ InitListChecker Check(*this, Entity, From, Type, /*VerifyOnly=*/true,
|
|
|
|
+ /*TreatUnavailableAsInvalid=*/false,
|
|
|
|
+ /*InOverloadResolution=*/true);
|
|
|
|
+ return !Check.HadError();
|
|
|
|
+}
|
|
|
|
+
|
|
/// Check that the given Index expression is a valid array designator
|
|
/// Check that the given Index expression is a valid array designator
|
|
/// value. This is essentially just a wrapper around
|
|
/// value. This is essentially just a wrapper around
|
|
/// VerifyIntegerConstantExpression that also checks for negative values
|
|
/// VerifyIntegerConstantExpression that also checks for negative values
|
|
@@ -3019,6 +3109,7 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
|
|
bool Invalid = false;
|
|
bool Invalid = false;
|
|
SmallVector<ASTDesignator, 32> Designators;
|
|
SmallVector<ASTDesignator, 32> Designators;
|
|
SmallVector<Expr *, 32> InitExpressions;
|
|
SmallVector<Expr *, 32> InitExpressions;
|
|
|
|
+ bool HasArrayDesignator = false;
|
|
|
|
|
|
// Build designators and check array designator expressions.
|
|
// Build designators and check array designator expressions.
|
|
for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) {
|
|
for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) {
|
|
@@ -3042,6 +3133,7 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
|
|
D.getRBracketLoc()));
|
|
D.getRBracketLoc()));
|
|
InitExpressions.push_back(Index);
|
|
InitExpressions.push_back(Index);
|
|
}
|
|
}
|
|
|
|
+ HasArrayDesignator = true;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3085,6 +3177,7 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
|
|
InitExpressions.push_back(EndIndex);
|
|
InitExpressions.push_back(EndIndex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ HasArrayDesignator = true;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -3096,17 +3189,8 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
|
|
// Clear out the expressions within the designation.
|
|
// Clear out the expressions within the designation.
|
|
Desig.ClearExprs(*this);
|
|
Desig.ClearExprs(*this);
|
|
|
|
|
|
- DesignatedInitExpr *DIE
|
|
|
|
- = DesignatedInitExpr::Create(Context,
|
|
|
|
- Designators,
|
|
|
|
- InitExpressions, Loc, GNUSyntax,
|
|
|
|
- Init.getAs<Expr>());
|
|
|
|
-
|
|
|
|
- if (!getLangOpts().C99)
|
|
|
|
- Diag(DIE->getBeginLoc(), diag::ext_designated_init)
|
|
|
|
- << DIE->getSourceRange();
|
|
|
|
-
|
|
|
|
- return DIE;
|
|
|
|
|
|
+ return DesignatedInitExpr::Create(Context, Designators, InitExpressions, Loc,
|
|
|
|
+ GNUSyntax, Init.getAs<Expr>());
|
|
}
|
|
}
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//===----------------------------------------------------------------------===//
|