mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-26 05:18:46 +00:00
PR49020: Diagnose brace elision in designated initializers in C++.
This is a corner of the differences between C99 designators and C++20 designators that we'd previously overlooked. As with other such cases, this continues to be permitted as an extension and allowed by default, behind the -Wc99-designators warning flag, except in cases where it leads to a conformance difference (such as in overload resolution and in a SFINAE context).
This commit is contained in:
parent
1a13ee1efb
commit
b15cbaf5a0
@ -214,6 +214,9 @@ def ext_designated_init_reordered : ExtWarn<
|
|||||||
SFINAEFailure;
|
SFINAEFailure;
|
||||||
def note_previous_field_init : Note<
|
def note_previous_field_init : Note<
|
||||||
"previous initialization for field %0 is here">;
|
"previous initialization for field %0 is here">;
|
||||||
|
def ext_designated_init_brace_elision : ExtWarn<
|
||||||
|
"brace elision for designated initializer is a C99 extension">,
|
||||||
|
InGroup<C99Designator>, SFINAEFailure;
|
||||||
|
|
||||||
// Declarations.
|
// Declarations.
|
||||||
def ext_plain_complex : ExtWarn<
|
def ext_plain_complex : ExtWarn<
|
||||||
|
@ -315,7 +315,8 @@ class InitListChecker {
|
|||||||
InitListExpr *IList, QualType ElemType,
|
InitListExpr *IList, QualType ElemType,
|
||||||
unsigned &Index,
|
unsigned &Index,
|
||||||
InitListExpr *StructuredList,
|
InitListExpr *StructuredList,
|
||||||
unsigned &StructuredIndex);
|
unsigned &StructuredIndex,
|
||||||
|
bool DirectlyDesignated = false);
|
||||||
void CheckComplexType(const InitializedEntity &Entity,
|
void CheckComplexType(const InitializedEntity &Entity,
|
||||||
InitListExpr *IList, QualType DeclType,
|
InitListExpr *IList, QualType DeclType,
|
||||||
unsigned &Index,
|
unsigned &Index,
|
||||||
@ -1326,7 +1327,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
|
|||||||
QualType ElemType,
|
QualType ElemType,
|
||||||
unsigned &Index,
|
unsigned &Index,
|
||||||
InitListExpr *StructuredList,
|
InitListExpr *StructuredList,
|
||||||
unsigned &StructuredIndex) {
|
unsigned &StructuredIndex,
|
||||||
|
bool DirectlyDesignated) {
|
||||||
Expr *expr = IList->getInit(Index);
|
Expr *expr = IList->getInit(Index);
|
||||||
|
|
||||||
if (ElemType->isReferenceType())
|
if (ElemType->isReferenceType())
|
||||||
@ -1462,6 +1464,20 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
|
|||||||
CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList,
|
CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList,
|
||||||
StructuredIndex);
|
StructuredIndex);
|
||||||
++StructuredIndex;
|
++StructuredIndex;
|
||||||
|
|
||||||
|
// In C++20, brace elision is not permitted for a designated initializer.
|
||||||
|
if (DirectlyDesignated && SemaRef.getLangOpts().CPlusPlus && !hadError) {
|
||||||
|
if (InOverloadResolution)
|
||||||
|
hadError = true;
|
||||||
|
if (!VerifyOnly) {
|
||||||
|
SemaRef.Diag(expr->getBeginLoc(),
|
||||||
|
diag::ext_designated_init_brace_elision)
|
||||||
|
<< expr->getSourceRange()
|
||||||
|
<< FixItHint::CreateInsertion(expr->getBeginLoc(), "{")
|
||||||
|
<< FixItHint::CreateInsertion(
|
||||||
|
SemaRef.getLocForEndOfToken(expr->getEndLoc()), "}");
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!VerifyOnly) {
|
if (!VerifyOnly) {
|
||||||
// We cannot initialize this element, so let PerformCopyInitialization
|
// We cannot initialize this element, so let PerformCopyInitialization
|
||||||
@ -2413,8 +2429,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
|
|||||||
unsigned OldIndex = Index;
|
unsigned OldIndex = Index;
|
||||||
IList->setInit(OldIndex, DIE->getInit());
|
IList->setInit(OldIndex, DIE->getInit());
|
||||||
|
|
||||||
CheckSubElementType(Entity, IList, CurrentObjectType, Index,
|
CheckSubElementType(Entity, IList, CurrentObjectType, Index, StructuredList,
|
||||||
StructuredList, StructuredIndex);
|
StructuredIndex, /*DirectlyDesignated=*/true);
|
||||||
|
|
||||||
// Restore the designated initializer expression in the syntactic
|
// Restore the designated initializer expression in the syntactic
|
||||||
// form of the initializer list.
|
// form of the initializer list.
|
||||||
|
@ -54,6 +54,10 @@ A a5 = {
|
|||||||
.y = 1, // override-note {{previous}}
|
.y = 1, // override-note {{previous}}
|
||||||
.y = 1 // override-error {{overrides prior initialization}}
|
.y = 1 // override-error {{overrides prior initialization}}
|
||||||
};
|
};
|
||||||
|
B b2 = {.a = 1}; // pedantic-error {{brace elision for designated initializer is a C99 extension}}
|
||||||
|
B b3 = {.a = 1, 2}; // pedantic-error {{mixture of designated and non-designated}} pedantic-note {{first non-designated}} pedantic-error {{brace elision}}
|
||||||
|
B b4 = {.a = 1, 2, 3}; // pedantic-error {{mixture of designated and non-designated}} pedantic-note {{first non-designated}} pedantic-error {{brace elision}} expected-error {{excess elements}}
|
||||||
|
B b5 = {.a = nullptr}; // expected-error {{cannot initialize}}
|
||||||
struct C { int :0, x, :0, y, :0; };
|
struct C { int :0, x, :0, y, :0; };
|
||||||
C c = {
|
C c = {
|
||||||
.x = 1, // override-note {{previous}}
|
.x = 1, // override-note {{previous}}
|
||||||
@ -112,6 +116,15 @@ namespace overload_resolution {
|
|||||||
void k() {
|
void k() {
|
||||||
j({.x = 1, .y = 2}); // expected-error {{ambiguous}}
|
j({.x = 1, .y = 2}); // expected-error {{ambiguous}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct E { A a; };
|
||||||
|
struct F { int a; };
|
||||||
|
void l(E e); // expected-note {{candidate}}
|
||||||
|
int &l(F f); // expected-note {{candidate}}
|
||||||
|
void m() {
|
||||||
|
int &r = l({.a = 0}); // ok, l(E) is not viable
|
||||||
|
int &s = l({.a = {0}}); // expected-error {{ambiguous}}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace deduction {
|
namespace deduction {
|
||||||
@ -128,4 +141,18 @@ namespace deduction {
|
|||||||
void i() {
|
void i() {
|
||||||
h<A, C>(); // ok, selects C overload by SFINAE
|
h<A, C>(); // ok, selects C overload by SFINAE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct D { int n; };
|
||||||
|
struct E { D n; };
|
||||||
|
template<typename T, typename U> void j1(decltype(T{.n = 0}));
|
||||||
|
template<typename T, typename U> void j1(decltype(U{.n = 0})) = delete;
|
||||||
|
template<typename T, typename U> void j2(decltype(T{.n = {0}})); // expected-note {{candidate}}
|
||||||
|
template<typename T, typename U> void j2(decltype(U{.n = {0}})); // expected-note {{candidate}}
|
||||||
|
template<typename T, typename U> void j3(decltype(T{.n = {{0}}})) = delete;
|
||||||
|
template<typename T, typename U> void j3(decltype(U{.n = {{0}}}));
|
||||||
|
void k() {
|
||||||
|
j1<D, E>({}); // ok, selects D overload by SFINAE (too few braces for E)
|
||||||
|
j2<D, E>({}); // expected-error {{ambiguous}}
|
||||||
|
j3<D, E>({}); // ok, selects E overload by SFINAE (too many braces for D)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user