summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-08-30 22:52:55 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-08-30 22:52:55 +0000
commit0c07d3746df825eed1a45bf91ddbd085dbbafe87 (patch)
tree60c33013dffd7786d67fee3a2d6621e20eb405d7
parentaf1bfac502bc3ddd1059f6072f0651f3ba926f9b (diff)
downloadclang-0c07d3746df825eed1a45bf91ddbd085dbbafe87.tar.gz
[c++20] Implement semantic restrictions for C++20 designated
initializers. This has some interesting interactions with our existing extensions to support C99 designated initializers as an extension in C++. Those are resolved as follows: * We continue to permit the full breadth of C99 designated initializers in C++, with the exception that we disallow a partial overwrite of an initializer with a non-trivially-destructible type. (Full overwrite is OK, because we won't run the first initializer at all.) * The C99 extensions are disallowed in SFINAE contexts and during overload resolution, where they could change the meaning of valid programs. * C++20 disallows reordering of initializers. We only check for that for the simple cases that the C++20 rules permit (designators of the form '.field_name =' and continue to allow reordering in other cases). It would be nice to improve this behavior in future. * All C99 designated initializer extensions produce a warning by default in C++20 mode. People are going to learn the C++ rules based on what Clang diagnoses, so it's important we diagnose these properly by default. * In C++ <= 17, we apply the C++20 rules rather than the C99 rules, and so still diagnose C99 extensions as described above. We continue to accept designated C++20-compatible initializers in C++ <= 17 silently by default (but naturally still reject under -pedantic-errors). This is not a complete implementation of P0329R4. In particular, that paper introduces new non-C99-compatible syntax { .field { init } }, and we do not support that yet. This is based on a previous patch by Don Hinton, though I've made substantial changes when addressing the above interactions. Differential Revision: https://reviews.llvm.org/D59754 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@370544 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticGroups.td11
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td38
-rw-r--r--include/clang/Sema/Sema.h7
-rw-r--r--lib/Sema/SemaExpr.cpp74
-rw-r--r--lib/Sema/SemaInit.cpp268
-rw-r--r--lib/Sema/SemaOverload.cpp6
-rw-r--r--lib/Sema/TreeTransform.h2
-rw-r--r--test/Analysis/globals.cpp2
-rw-r--r--test/CXX/expr/expr.const/p2-0x.cpp2
-rw-r--r--test/CodeGenObjCXX/designated-initializers.mm2
-rw-r--r--test/PCH/cxx1y-default-initializer.cpp4
-rw-r--r--test/Parser/cxx0x-lambda-expressions.cpp4
-rw-r--r--test/Parser/objc-init.m6
-rw-r--r--test/Sema/designated-initializers.c14
-rw-r--r--test/Sema/static-assert.c7
-rw-r--r--test/SemaCXX/aggregate-initialization.cpp7
-rw-r--r--test/SemaCXX/c99.cpp69
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp6
-rw-r--r--test/SemaCXX/constexpr-printing.cpp6
-rw-r--r--test/SemaCXX/cxx0x-initializer-constructor.cpp2
-rw-r--r--test/SemaCXX/cxx2a-initializer-aggregates.cpp109
-rw-r--r--test/SemaCXX/decltype.cpp10
-rw-r--r--test/SemaCXX/designated-initializers-base-class.cpp3
-rw-r--r--test/SemaCXX/designated-initializers.cpp4
-rw-r--r--test/SemaCXX/eval-crashes.cpp2
-rw-r--r--test/SemaCXX/member-init.cpp2
-rw-r--r--test/SemaObjCXX/message.mm2
-rw-r--r--test/SemaTemplate/instantiate-c99.cpp6
-rw-r--r--test/SemaTemplate/instantiate-init.cpp4
29 files changed, 513 insertions, 166 deletions
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 02be30e1b4..3391f371dc 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -100,7 +100,6 @@ def GNUComplexInteger : DiagGroup<"gnu-complex-integer">;
def GNUConditionalOmittedOperand : DiagGroup<"gnu-conditional-omitted-operand">;
def ConfigMacros : DiagGroup<"config-macros">;
def : DiagGroup<"ctor-dtor-privacy">;
-def GNUDesignator : DiagGroup<"gnu-designator">;
def GNUStringLiteralOperatorTemplate :
DiagGroup<"gnu-string-literal-operator-template">;
def UndefinedVarTemplate : DiagGroup<"undefined-var-template">;
@@ -146,6 +145,12 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAttributes,
DeprecatedWritableStr]>,
DiagCategory<"Deprecations">;
+def CXX2aDesignator : DiagGroup<"c++20-designator">;
+// Allow -Wno-c99-designator to be used to turn off all warnings on valid C99
+// designators (including the warning controlled by -Wc++20-designator).
+def C99Designator : DiagGroup<"c99-designator", [CXX2aDesignator]>;
+def GNUDesignator : DiagGroup<"gnu-designator">;
+
def DynamicExceptionSpec
: DiagGroup<"dynamic-exception-spec", [DeprecatedDynamicExceptionSpec]>;
@@ -896,7 +901,7 @@ def CXX17 : DiagGroup<"c++17-extensions">;
// A warning group for warnings about using C++2a features as extensions in
// earlier C++ versions.
-def CXX2a : DiagGroup<"c++2a-extensions">;
+def CXX2a : DiagGroup<"c++2a-extensions", [CXX2aDesignator]>;
def : DiagGroup<"c++0x-extensions", [CXX11]>;
def : DiagGroup<"c++1y-extensions", [CXX14]>;
@@ -909,7 +914,7 @@ def DelegatingCtorCycles :
def C11 : DiagGroup<"c11-extensions">;
// A warning group for warnings about using C99 features as extensions.
-def C99 : DiagGroup<"c99-extensions">;
+def C99 : DiagGroup<"c99-extensions", [C99Designator]>;
// A warning group for warnings about GCC extensions.
def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct,
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 7d380338c2..8b52dd8ae5 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -154,7 +154,7 @@ def err_variably_modified_new_type : Error<
// C99 Designated Initializers
def ext_designated_init : Extension<
- "designated initializers are a C99 feature">, InGroup<C99>;
+ "designated initializers are a C99 feature">, InGroup<C99Designator>;
def err_array_designator_negative : Error<
"array designator value '%0' is negative">;
def err_array_designator_empty_range : Error<
@@ -173,15 +173,17 @@ def err_field_designator_nonfield : Error<
def note_field_designator_found : Note<"field designator refers here">;
def err_designator_for_scalar_init : Error<
"designator in initializer for scalar type %0">;
-def warn_subobject_initializer_overrides : Warning<
- "subobject initialization overrides initialization of other fields "
- "within its enclosing subobject">, InGroup<InitializerOverrides>;
def warn_initializer_overrides : Warning<
- "initializer overrides prior initialization of this subobject">,
- InGroup<InitializerOverrides>;
+ "initializer %select{partially |}0overrides prior initialization of "
+ "this subobject">, InGroup<InitializerOverrides>;
+def ext_initializer_overrides : ExtWarn<warn_initializer_overrides.Text>,
+ InGroup<InitializerOverrides>, SFINAEFailure;
+def err_initializer_overrides_destructed : Error<
+ "initializer would partially override prior initialization of object of "
+ "type %1 with non-trivial destruction">;
def note_previous_initializer : Note<
"previous initialization %select{|with side effects }0is here"
- "%select{| (side effects may not occur at run time)}0">;
+ "%select{| (side effects will not occur at run time)}0">;
def err_designator_into_flexible_array_member : Error<
"designator into flexible array member subobject">;
def note_flexible_array_member : Note<
@@ -189,6 +191,28 @@ def note_flexible_array_member : Note<
def ext_flexible_array_init : Extension<
"flexible array initialization is a GNU extension">, InGroup<GNUFlexibleArrayInitializer>;
+// C++20 designated initializers
+def ext_cxx_designated_init : Extension<
+ "designated initializers are a C++20 extension">, InGroup<CXX2aDesignator>;
+def warn_cxx17_compat_designated_init : Warning<
+ "designated initializers are incompatible with C++ standards before C++20">,
+ InGroup<CXXPre2aCompatPedantic>, DefaultIgnore;
+def ext_designated_init_mixed : ExtWarn<
+ "mixture of designated and non-designated initializers in the same "
+ "initializer list is a C99 extension">, InGroup<C99Designator>;
+def note_designated_init_mixed : Note<
+ "first non-designated initializer is here">;
+def ext_designated_init_array : ExtWarn<
+ "array designators are a C99 extension">, InGroup<C99Designator>;
+def ext_designated_init_nested : ExtWarn<
+ "nested designators are a C99 extension">, InGroup<C99Designator>;
+def ext_designated_init_reordered : ExtWarn<
+ "ISO C++ requires field designators to be specified in declaration order; "
+ "field %1 will be initialized after field %0">, InGroup<Reorder>,
+ SFINAEFailure;
+def note_previous_field_init : Note<
+ "previous initialization for field %0 is here">;
+
// Declarations.
def ext_plain_complex : ExtWarn<
"plain '_Complex' requires a type specifier; assuming '_Complex double'">;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 624238c00e..0ca74e58e0 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2775,6 +2775,9 @@ public:
Expr *Value,
bool AllowNRVO = true);
+ bool CanPerformAggregateInitializationForOverloadResolution(
+ const InitializedEntity &Entity, InitListExpr *From);
+
bool CanPerformCopyInitialization(const InitializedEntity &Entity,
ExprResult Init);
ExprResult PerformCopyInitialization(const InitializedEntity &Entity,
@@ -4636,6 +4639,10 @@ public:
MultiExprArg InitArgList,
SourceLocation RBraceLoc);
+ ExprResult BuildInitList(SourceLocation LBraceLoc,
+ MultiExprArg InitArgList,
+ SourceLocation RBraceLoc);
+
ExprResult ActOnDesignatedInitializer(Designation &Desig,
SourceLocation Loc,
bool GNUSyntax,
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 43e61d3429..5f5f4c8d04 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -6107,6 +6107,77 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
ExprResult
Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
SourceLocation RBraceLoc) {
+ // Only produce each kind of designated initialization diagnostic once.
+ SourceLocation FirstDesignator;
+ bool DiagnosedArrayDesignator = false;
+ bool DiagnosedNestedDesignator = false;
+ bool DiagnosedMixedDesignator = false;
+
+ // Check that any designated initializers are syntactically valid in the
+ // current language mode.
+ for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) {
+ if (auto *DIE = dyn_cast<DesignatedInitExpr>(InitArgList[I])) {
+ if (FirstDesignator.isInvalid())
+ FirstDesignator = DIE->getBeginLoc();
+
+ if (!getLangOpts().CPlusPlus)
+ break;
+
+ if (!DiagnosedNestedDesignator && DIE->size() > 1) {
+ DiagnosedNestedDesignator = true;
+ Diag(DIE->getBeginLoc(), diag::ext_designated_init_nested)
+ << DIE->getDesignatorsSourceRange();
+ }
+
+ for (auto &Desig : DIE->designators()) {
+ if (!Desig.isFieldDesignator() && !DiagnosedArrayDesignator) {
+ DiagnosedArrayDesignator = true;
+ Diag(Desig.getBeginLoc(), diag::ext_designated_init_array)
+ << Desig.getSourceRange();
+ }
+ }
+
+ if (!DiagnosedMixedDesignator &&
+ !isa<DesignatedInitExpr>(InitArgList[0])) {
+ DiagnosedMixedDesignator = true;
+ Diag(DIE->getBeginLoc(), diag::ext_designated_init_mixed)
+ << DIE->getSourceRange();
+ Diag(InitArgList[0]->getBeginLoc(), diag::note_designated_init_mixed)
+ << InitArgList[0]->getSourceRange();
+ }
+ } else if (getLangOpts().CPlusPlus && !DiagnosedMixedDesignator &&
+ isa<DesignatedInitExpr>(InitArgList[0])) {
+ DiagnosedMixedDesignator = true;
+ auto *DIE = cast<DesignatedInitExpr>(InitArgList[0]);
+ Diag(DIE->getBeginLoc(), diag::ext_designated_init_mixed)
+ << DIE->getSourceRange();
+ Diag(InitArgList[I]->getBeginLoc(), diag::note_designated_init_mixed)
+ << InitArgList[I]->getSourceRange();
+ }
+ }
+
+ if (FirstDesignator.isValid()) {
+ // Only diagnose designated initiaization as a C++20 extension if we didn't
+ // already diagnose use of (non-C++20) C99 designator syntax.
+ if (getLangOpts().CPlusPlus && !DiagnosedArrayDesignator &&
+ !DiagnosedNestedDesignator && !DiagnosedMixedDesignator) {
+ Diag(FirstDesignator, getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_designated_init
+ : diag::ext_cxx_designated_init);
+ } else if (!getLangOpts().CPlusPlus && !getLangOpts().C99) {
+ Diag(FirstDesignator, diag::ext_designated_init);
+ }
+ }
+
+ return BuildInitList(LBraceLoc, InitArgList, RBraceLoc);
+}
+
+ExprResult
+Sema::BuildInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
+ SourceLocation RBraceLoc) {
+ // Semantic analysis for initializers is done by ActOnDeclarator() and
+ // CheckInitializer() - it requires knowledge of the object being initialized.
+
// Immediately handle non-overload placeholders. Overloads can be
// resolved contextually, but everything else here can't.
for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) {
@@ -6121,9 +6192,6 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
}
}
- // Semantic analysis for initializers is done by ActOnDeclarator() and
- // CheckInitializer() - it requires knowledge of the object being initialized.
-
InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitArgList,
RBraceLoc);
E->setType(Context.VoidTy); // FIXME: just a place holder for now.
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 0f83a71aff..297121381e 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -281,6 +281,7 @@ class InitListChecker {
bool hadError = false;
bool VerifyOnly; // No diagnostics.
bool TreatUnavailableAsInvalid; // Used only in VerifyOnly mode.
+ bool InOverloadResolution;
InitListExpr *FullyStructuredList = nullptr;
NoInitExpr *DummyExpr = nullptr;
@@ -372,6 +373,63 @@ class InitListChecker {
ExprResult PerformEmptyInit(SourceLocation Loc,
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:
//
// Assume we have the following definitions (Case#1):
@@ -410,9 +468,9 @@ class InitListChecker {
SourceLocation Loc);
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; }
// 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,
InitListExpr *IL, QualType &T, bool VerifyOnly,
- bool TreatUnavailableAsInvalid)
+ bool TreatUnavailableAsInvalid,
+ bool InOverloadResolution)
: SemaRef(S), VerifyOnly(VerifyOnly),
- TreatUnavailableAsInvalid(TreatUnavailableAsInvalid) {
+ TreatUnavailableAsInvalid(TreatUnavailableAsInvalid),
+ InOverloadResolution(InOverloadResolution) {
if (!VerifyOnly || hasAnyDesignatedInits(IL)) {
FullyStructuredList =
createInitListExpr(T, IL->getSourceRange(), IL->getNumInits());
@@ -1959,7 +2019,8 @@ void InitListChecker::CheckStructUnionTypes(
}
// 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)
return;
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
/// 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
/// 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()));
else if (InitListExpr *Result = dyn_cast<InitListExpr>(ExistingInit))
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()))
- FieldIndex = CXXRD->getNumBases();
+ NumBases = CXXRD->getNumBases();
+
+ unsigned FieldIndex = NumBases;
for (auto *FI : RT->getDecl()->fields()) {
if (FI->isUnnamedBitfield())
@@ -2504,15 +2556,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
&& "A union should never have more than one initializer!");
Expr *ExistingInit = StructuredList->getInit(0);
- if (ExistingInit && !VerifyOnly) {
+ if (ExistingInit) {
// 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
@@ -2535,6 +2582,54 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
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.
if (!VerifyOnly)
D->setField(*Field);
@@ -2875,7 +2970,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
if (!IsFullyOverwritten)
return Result;
- if (ExistingInit && !VerifyOnly) {
+ if (ExistingInit) {
// 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
@@ -2895,11 +2990,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
// struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
//
// 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;
@@ -2968,24 +3059,23 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
if (Expr *PrevInit = StructuredList->updateInit(SemaRef.Context,
StructuredIndex, expr)) {
// 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;
}
+/// 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
/// value. This is essentially just a wrapper around
/// VerifyIntegerConstantExpression that also checks for negative values
@@ -3019,6 +3109,7 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
bool Invalid = false;
SmallVector<ASTDesignator, 32> Designators;
SmallVector<Expr *, 32> InitExpressions;
+ bool HasArrayDesignator = false;
// Build designators and check array designator expressions.
for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) {
@@ -3042,6 +3133,7 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
D.getRBracketLoc()));
InitExpressions.push_back(Index);
}
+ HasArrayDesignator = true;
break;
}
@@ -3085,6 +3177,7 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
InitExpressions.push_back(EndIndex);
}
}
+ HasArrayDesignator = true;
break;
}
}
@@ -3096,17 +3189,8 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
// Clear out the expressions within the designation.
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>());
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 938606a847..4be7fce677 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -4920,13 +4920,11 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
// Type is an aggregate, argument is an init list. At this point it comes
// down to checking whether the initialization works.
// FIXME: Find out whether this parameter is consumed or not.
- // FIXME: Expose SemaInit's aggregate initialization code so that we don't
- // need to call into the initialization code here; overload resolution
- // should not be doing that.
InitializedEntity Entity =
InitializedEntity::InitializeParameter(S.Context, ToType,
/*Consumed=*/false);
- if (S.CanPerformCopyInitialization(Entity, From)) {
+ if (S.CanPerformAggregateInitializationForOverloadResolution(Entity,
+ From)) {
Result.setUserDefined();
Result.UserDefined.Before.setAsIdentityConversion();
// Initializer lists don't have a type.
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index de1339880b..c2a144a401 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -2416,7 +2416,7 @@ public:
ExprResult RebuildInitList(SourceLocation LBraceLoc,
MultiExprArg Inits,
SourceLocation RBraceLoc) {
- return SemaRef.ActOnInitList(LBraceLoc, Inits, RBraceLoc);
+ return SemaRef.BuildInitList(LBraceLoc, Inits, RBraceLoc);
}
/// Build a new designated initializer expression.
diff --git a/test/Analysis/globals.cpp b/test/Analysis/globals.cpp
index d3df6eb6d2..fc74161375 100644
--- a/test/Analysis/globals.cpp
+++ b/test/Analysis/globals.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify -std=c++2a %s
static const unsigned long long scull = 0;
diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
index f8db93b3eb..091ef09725 100644
--- a/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/test/CXX/expr/expr.const/p2-0x.cpp
@@ -360,7 +360,7 @@ namespace LValueToRValueUnion {
extern const U pu;
constexpr const int *pua = &pu.a;
constexpr const int *pub = &pu.b;
- constexpr U pu = { .b = 1 }; // expected-warning {{C99 feature}}
+ constexpr U pu = { .b = 1 }; // expected-warning {{C++20 extension}}
constexpr const int a2 = *pua; // expected-error {{constant expression}} expected-note {{read of member 'a' of union with active member 'b'}}
constexpr const int b2 = *pub; // ok
}
diff --git a/test/CodeGenObjCXX/designated-initializers.mm b/test/CodeGenObjCXX/designated-initializers.mm
index 71ffe1fbbd..1773f269fe 100644
--- a/test/CodeGenObjCXX/designated-initializers.mm
+++ b/test/CodeGenObjCXX/designated-initializers.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64 %s -verify -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple arm64 %s -verify -emit-llvm -o - -Wno-c99-designator | FileCheck %s
// expected-no-diagnostics
// Make sure we don't enter an infinite loop (rdar://21942503)
diff --git a/test/PCH/cxx1y-default-initializer.cpp b/test/PCH/cxx1y-default-initializer.cpp
index c9593a56d2..acb6337dea 100644
--- a/test/PCH/cxx1y-default-initializer.cpp
+++ b/test/PCH/cxx1y-default-initializer.cpp
@@ -37,8 +37,8 @@ C<int> ci;
static_assert(A{}.z == 3, "");
static_assert(A{1}.z == 4, "");
-static_assert(A{.y = 5}.z == 5, ""); // expected-warning {{C99}}
-static_assert(A{3, .y = 1}.z == 4, ""); // expected-warning {{C99}}
+static_assert(A{.y = 5}.z == 5, ""); // expected-warning {{C++20}}
+static_assert(A{3, .y = 1}.z == 4, ""); // expected-warning {{C99}} expected-note {{here}}
static_assert(make<int>().z == 3, "");
static_assert(make<int>(12).z == 15, "");
static_assert(C<int>().c == 0, "");
diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp
index 2acd8144b7..d509177784 100644
--- a/test/Parser/cxx0x-lambda-expressions.cpp
+++ b/test/Parser/cxx0x-lambda-expressions.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 %s
-// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++2a %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 -Wno-c99-designator %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++2a -Wno-c99-designator %s
enum E { e };
diff --git a/test/Parser/objc-init.m b/test/Parser/objc-init.m
index 088e385f95..04e0c823fc 100644
--- a/test/Parser/objc-init.m
+++ b/test/Parser/objc-init.m
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-fragile -verify -pedantic -Wno-objc-root-class %s
-// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-fragile -verify -x objective-c++ -Wno-objc-root-class %s
-// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-fragile -verify -x objective-c++ -Wno-objc-root-class -std=c++98 %s
-// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-fragile -verify -x objective-c++ -Wno-objc-root-class -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-fragile -verify -x objective-c++ -Wno-c99-designator -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-fragile -verify -x objective-c++ -Wno-c99-designator -Wno-objc-root-class -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-fragile -verify -x objective-c++ -Wno-c99-designator -Wno-objc-root-class -std=c++11 %s
// rdar://5707001
@interface NSNumber;
diff --git a/test/Sema/designated-initializers.c b/test/Sema/designated-initializers.c
index 0a72e8ff37..4239b5e6ae 100644
--- a/test/Sema/designated-initializers.c
+++ b/test/Sema/designated-initializers.c
@@ -130,10 +130,10 @@ int get8() { ++counter; return 8; }
void test() {
struct X xs[] = {
[0] = (struct X){1, 2}, // expected-note 2 {{previous initialization is here}}
- [0].c = 3, // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}}
+ [0].c = 3, // expected-warning{{initializer partially overrides prior initialization of this subobject}}
(struct X) {4, 5, 6}, // expected-note{{previous initialization is here}}
- [1].b = get8(), // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}}
- [0].b = 8 // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}}
+ [1].b = get8(), // expected-warning{{initializer partially overrides prior initialization of this subobject}}
+ [0].b = 8 // expected-warning{{initializer partially overrides prior initialization of this subobject}}
};
}
@@ -331,20 +331,20 @@ struct overwrite_string_struct {
char L[6];
int M;
} overwrite_string[] = {
- { { "foo" }, 1 }, // expected-note {{previous initialization is here}}
- [0].L[2] = 'x' // expected-warning{{subobject initialization overrides initialization of other fields}}
+ { { "foo" }, 1 }, // expected-note{{previous initialization is here}}
+ [0].L[2] = 'x' // expected-warning{{initializer partially overrides prior initialization of this subobject}}
};
struct overwrite_string_struct2 {
char L[6];
int M;
} overwrite_string2[] = {
{ { "foo" }, 1 }, // expected-note{{previous initialization is here}}
- [0].L[4] = 'x' // expected-warning{{subobject initialization overrides initialization of other fields}}
+ [0].L[4] = 'x' // expected-warning{{initializer partially overrides prior initialization of this subobject}}
};
struct overwrite_string_struct
overwrite_string3[] = {
"foo", 1, // expected-note{{previous initialization is here}}
- [0].L[4] = 'x' // expected-warning{{subobject initialization overrides initialization of other fields}}
+ [0].L[4] = 'x' // expected-warning{{initializer partially overrides prior initialization of this subobject}}
};
struct overwrite_string_struct
overwrite_string4[] = {
diff --git a/test/Sema/static-assert.c b/test/Sema/static-assert.c
index cdb227f825..f08e557fc8 100644
--- a/test/Sema/static-assert.c
+++ b/test/Sema/static-assert.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify %s
// RUN: %clang_cc1 -std=c99 -pedantic -fsyntax-only -verify=expected,ext %s
-// RUN: %clang_cc1 -xc++ -std=c++11 -pedantic -fsyntax-only -verify=expected,ext %s
+// RUN: %clang_cc1 -xc++ -std=c++11 -pedantic -fsyntax-only -verify=expected,ext,cxx %s
_Static_assert("foo", "string is nonzero"); // ext-warning {{'_Static_assert' is a C11 extension}}
#ifndef __cplusplus
@@ -42,10 +42,7 @@ struct A {
}
typedef UNION(unsigned, struct A) U1; // ext-warning 3 {{'_Static_assert' is a C11 extension}}
-UNION(char[2], short) u2 = { .one = { 'a', 'b' } }; // ext-warning 3 {{'_Static_assert' is a C11 extension}}
-#if defined(__cplusplus)
-// ext-warning@-2 {{designated initializers are a C99 feature}}
-#endif
+UNION(char[2], short) u2 = { .one = { 'a', 'b' } }; // ext-warning 3 {{'_Static_assert' is a C11 extension}} cxx-warning {{designated initializers are a C++20 extension}}
typedef UNION(char, short) U3; // expected-error {{static_assert failed due to requirement 'sizeof(char) == sizeof(short)' "type size mismatch"}} \
// ext-warning 3 {{'_Static_assert' is a C11 extension}}
typedef UNION(float, 0.5f) U4; // expected-error {{expected a type}} \
diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp
index bb03c6fb5c..c71a7449d3 100644
--- a/test/SemaCXX/aggregate-initialization.cpp
+++ b/test/SemaCXX/aggregate-initialization.cpp
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s
// Verify that using an initializer list for a non-aggregate looks for
// constructors..
diff --git a/test/SemaCXX/c99.cpp b/test/SemaCXX/c99.cpp
index 7afcdd509f..9fbc45bc20 100644
--- a/test/SemaCXX/c99.cpp
+++ b/test/SemaCXX/c99.cpp
@@ -1,9 +1,70 @@
-// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify=expected,cxx17 -std=c++17 %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify=expected,cxx20 -std=c++2a %s
+
+// cxx17-warning@* 0+{{designated initializers are a C++20 extension}}
+
void f1(int i[static 5]) { // expected-error{{C99}}
}
struct Point { int x; int y; int z[]; }; // expected-warning{{flexible array members are a C99 feature}}
-Point p1 = { .x = 17, // expected-warning{{designated initializers are a C99 feature}}
- y: 25 }; // expected-warning{{designated initializers are a C99 feature}} \
- // expected-warning{{use of GNU old-style field designator extension}}
+Point p1 = { .x = 17,
+ y: 25 }; // expected-warning{{use of GNU old-style field designator extension}}
+
+Point p2 = {
+ .x = 17, // expected-warning {{mixture of designated and non-designated initializers in the same initializer list is a C99 extension}}
+ 25 // expected-note {{first non-designated initializer}}
+};
+
+Point p3 = {
+ .x = 17, // expected-note {{previous initialization is here}}
+ .x = 18, // expected-warning {{initializer overrides prior initialization of this subobject}}
+};
+
+Point p4 = {
+ .x = 17, // expected-warning {{mixture of designated and non-designated initializers in the same initializer list is a C99 extension}}
+ 25, // expected-note {{first non-designated initializer}}
+ // expected-note@-1 {{previous initialization is here}}
+ .y = 18, // expected-warning {{initializer overrides prior initialization of this subobject}}
+};
+
+int arr[1] = {[0] = 0}; // expected-warning {{array designators are a C99 extension}}
+
+struct Pt { int x, y; };
+struct Rect { Pt tl, br; };
+Rect r = {
+ .tl.x = 0 // expected-warning {{nested designators are a C99 extension}}
+};
+
+struct NonTrivial {
+ NonTrivial();
+ ~NonTrivial();
+};
+struct S {
+ int a;
+ NonTrivial b;
+};
+struct T {
+ S s;
+};
+S f();
+
+T t1 = {
+ .s = f()
+};
+
+// It's important that we reject this; we would not destroy the existing
+// 'NonTrivial' object before overwriting it (and even calling its destructor
+// would not necessarily be correct).
+T t2 = {
+ .s = f(), // expected-note {{previous}}
+ .s.b = NonTrivial() // expected-error {{initializer would partially override prior initialization of object of type 'S' with non-trivial destruction}}
+ // expected-warning@-1 {{nested}}
+};
+
+// FIXME: It might be reasonable to accept this.
+T t3 = {
+ .s = f(), // expected-note {{previous}}
+ .s.a = 0 // expected-error {{initializer would partially override prior initialization of object of type 'S' with non-trivial destruction}}
+ // expected-warning@-1 {{nested}}
+};
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index e9e083950c..eaac64d21e 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -fsyntax-only -fcxx-exceptions -verify -std=c++11 -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion
+// RUN: %clang_cc1 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fsyntax-only -fcxx-exceptions -verify -std=c++11 -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion
namespace StaticAssertFoldTest {
@@ -566,7 +566,7 @@ static_assert(fail(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][2] - 2)) == 11, "
expected-error {{static_assert expression is not an integral constant expression}} \
expected-note {{in call to 'fail(zs[1][0][1][0])'}}
-constexpr int arr[40] = { 1, 2, 3, [8] = 4 }; // expected-warning {{C99 feature}}
+constexpr int arr[40] = { 1, 2, 3, [8] = 4 };
constexpr int SumNonzero(const int *p) {
return *p + (*p ? SumNonzero(p+1) : 0);
}
@@ -979,7 +979,7 @@ union U {
int b;
};
-constexpr U u[4] = { { .a = 0 }, { .b = 1 }, { .a = 2 }, { .b = 3 } }; // expected-warning 4{{C99 feature}}
+constexpr U u[4] = { { .a = 0 }, { .b = 1 }, { .a = 2 }, { .b = 3 } };
static_assert(u[0].a == 0, "");
static_assert(u[0].b, ""); // expected-error {{constant expression}} expected-note {{read of member 'b' of union with active member 'a'}}
static_assert(u[1].b == 1, "");
diff --git a/test/SemaCXX/constexpr-printing.cpp b/test/SemaCXX/constexpr-printing.cpp
index 7f6a9c6a82..ebd91b8a3c 100644
--- a/test/SemaCXX/constexpr-printing.cpp
+++ b/test/SemaCXX/constexpr-printing.cpp
@@ -41,11 +41,7 @@ expected-error {{constant expression}} \
expected-note {{in call to 'test_printing(12, 3.976200e+01, 3+4i, 1.290000e+01+3.600000e+00i, &u2.T::arr[4], u2.another.arr[2], {5, 1, 2, 3}, {{{}}, {{}}, &u1.T::arr[2]})'}}
struct V {
- // FIXME: when we can generate these as constexpr constructors, remove the
- // explicit definitions.
- constexpr V() : arr{[255] = 42} {}
- constexpr V(const V &v) : arr{[255] = 42} {}
- int arr[256];
+ int arr[256] = {[255] = 42}; // expected-warning {{C99}}
};
constexpr V v;
constexpr int get(const int *p) { return *p; } // expected-note {{read of dereferenced one-past-the-end pointer}}
diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp
index 07a233b56c..870bbe5ce3 100644
--- a/test/SemaCXX/cxx0x-initializer-constructor.cpp
+++ b/test/SemaCXX/cxx0x-initializer-constructor.cpp
@@ -406,6 +406,6 @@ namespace PR11410 {
0, 1
}; // expected-error {{ambiguous}} expected-note {{in implicit initialization of array element 2}}
C c2[3] = {
- [0] = 1, [2] = 3
+ [0] = 1, [2] = 3 // expected-warning {{C99}}
}; // expected-error {{ambiguous}} expected-note {{in implicit initialization of array element 1}}
}
diff --git a/test/SemaCXX/cxx2a-initializer-aggregates.cpp b/test/SemaCXX/cxx2a-initializer-aggregates.cpp
index 9c438d399b..a974f3d726 100644
--- a/test/SemaCXX/cxx2a-initializer-aggregates.cpp
+++ b/test/SemaCXX/cxx2a-initializer-aggregates.cpp
@@ -1,4 +1,9 @@
-// RUN: %clang_cc1 -std=c++2a %s -verify
+// RUN: %clang_cc1 -std=c++2a %s -verify=expected,pedantic,override,reorder -pedantic-errors
+// RUN: %clang_cc1 -std=c++2a %s -verify=expected,pedantic -Werror=c99-designator -Wno-reorder -Wno-initializer-overrides
+// RUN: %clang_cc1 -std=c++2a %s -verify=expected,reorder -Wno-c99-designator -Werror=reorder -Wno-initializer-overrides
+// RUN: %clang_cc1 -std=c++2a %s -verify=expected,override -Wno-c99-designator -Wno-reorder -Werror=initializer-overrides
+// RUN: %clang_cc1 -std=c++2a %s -verify -Wno-c99-designator -Wno-reorder -Wno-initializer-overrides
+
namespace class_with_ctor {
struct A { // expected-note 6{{candidate}}
@@ -21,3 +26,105 @@ namespace class_with_ctor {
C c1 = {{}, {}}; // ok, call default ctor twice
C c2 = {{1, 2}, {3, 4}}; // expected-error 2{{no matching constructor}}
}
+
+namespace designator {
+struct A { int x, y; };
+struct B { A a; };
+
+A a1 = {
+ .y = 1, // reorder-note {{previous initialization for field 'y' is here}}
+ .x = 2 // reorder-error {{ISO C++ requires field designators to be specified in declaration order; field 'y' will be initialized after field 'x'}}
+};
+int arr[3] = {[1] = 5}; // pedantic-error {{array designators are a C99 extension}}
+B b = {.a.x = 0}; // pedantic-error {{nested designators are a C99 extension}}
+A a2 = {
+ .x = 1, // pedantic-error {{mixture of designated and non-designated initializers in the same initializer list is a C99 extension}}
+ 2 // pedantic-note {{first non-designated initializer is here}}
+};
+A a3 = {
+ 1, // pedantic-note {{first non-designated initializer is here}}
+ .y = 2 // pedantic-error {{mixture of designated and non-designated initializers in the same initializer list is a C99 extension}}
+};
+A a4 = {
+ .x = 1, // override-note {{previous}}
+ .x = 1 // override-error {{overrides prior initialization}}
+};
+A a5 = {
+ .y = 1, // override-note {{previous}}
+ .y = 1 // override-error {{overrides prior initialization}}
+};
+struct C { int :0, x, :0, y, :0; };
+C c = {
+ .x = 1, // override-note {{previous}}
+ .x = 1, // override-error {{overrides prior initialization}} override-note {{previous}}
+ .y = 1, // override-note {{previous}}
+ .y = 1, // override-error {{overrides prior initialization}}
+ .x = 1, // reorder-error {{declaration order}} override-error {{overrides prior initialization}} override-note {{previous}}
+ .x = 1, // override-error {{overrides prior initialization}}
+};
+}
+
+namespace base_class {
+ struct base {
+ int x;
+ };
+ struct derived : base {
+ int y;
+ };
+ derived d = {.x = 1, .y = 2}; // expected-error {{'x' does not refer to any field}}
+}
+
+namespace union_ {
+ union U { int a, b; };
+ U u = {
+ .a = 1, // override-note {{here}}
+ .b = 2, // override-error {{overrides prior}}
+ };
+}
+
+namespace overload_resolution {
+ struct A { int x, y; };
+ union B { int x, y; };
+
+ void f(A a);
+ void f(B b) = delete;
+ void g() { f({.x = 1, .y = 2}); } // ok, calls non-union overload
+
+ // As an extension of the union case, overload resolution won't pick any
+ // candidate where a field initializer would be overridden.
+ struct A2 { int x, other, y; };
+ int f(A2);
+ void g2() { int k = f({.x = 1, 2, .y = 3}); (void)k; } // pedantic-error {{mixture of designated and non-designated}} pedantic-note {{here}}
+
+ struct C { int x; };
+ void h(A a); // expected-note {{candidate}}
+ void h(C c); // expected-note {{candidate}}
+ void i() {
+ h({.x = 1, .y = 2});
+ h({.y = 1, .x = 2}); // reorder-error {{declaration order}} reorder-note {{previous}}
+ h({.x = 1}); // expected-error {{ambiguous}}
+ }
+
+ struct D { int y, x; };
+ void j(A a); // expected-note {{candidate}}
+ void j(D d); // expected-note {{candidate}}
+ void k() {
+ j({.x = 1, .y = 2}); // expected-error {{ambiguous}}
+ }
+}
+
+namespace deduction {
+ struct A { int x, y; };
+ union B { int x, y; };
+
+ template<typename T, typename U> void f(decltype(T{.x = 1, .y = 2}) = {});
+ template<typename T, typename U> void f(decltype(U{.x = 1, .y = 2}) = {}) = delete;
+ void g() { f<A, B>(); } // ok, calls non-union overload
+
+ struct C { int y, x; };
+ template<typename T, typename U> void h(decltype(T{.y = 1, .x = 2}) = {}) = delete;
+ template<typename T, typename U> void h(decltype(U{.y = 1, .x = 2}) = {});
+ void i() {
+ h<A, C>(); // ok, selects C overload by SFINAE
+ }
+}
diff --git a/test/SemaCXX/decltype.cpp b/test/SemaCXX/decltype.cpp
index 2956f9a228..f06ca226bc 100644
--- a/test/SemaCXX/decltype.cpp
+++ b/test/SemaCXX/decltype.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Wno-c99-designator %s
// PR5290
int const f0();
@@ -80,22 +80,22 @@ namespace D5789 {
struct P1 { char x[6]; } g1 = { "foo" };
struct LP1 { struct P1 p1; };
- // expected-warning@+3 {{subobject initialization overrides}}
+ // expected-warning@+3 {{initializer partially overrides}}
// expected-note@+2 {{previous initialization}}
// expected-note@+1 {{previous definition}}
template<class T> void foo(decltype(T(LP1{ .p1 = g1, .p1.x[1] = 'x' }))) {}
- // expected-warning@+3 {{subobject initialization overrides}}
+ // expected-warning@+3 {{initializer partially overrides}}
// expected-note@+2 {{previous initialization}}
template<class T>
void foo(decltype(T(LP1{ .p1 = g1, .p1.x[1] = 'r' }))) {} // okay
- // expected-warning@+3 {{subobject initialization overrides}}
+ // expected-warning@+3 {{initializer partially overrides}}
// expected-note@+2 {{previous initialization}}
template<class T>
void foo(decltype(T(LP1{ .p1 = { "foo" }, .p1.x[1] = 'x'}))) {} // okay
- // expected-warning@+3 {{subobject initialization overrides}}
+ // expected-warning@+3 {{initializer partially overrides}}
// expected-note@+2 {{previous initialization}}
// expected-error@+1 {{redefinition of 'foo'}}
template<class T> void foo(decltype(T(LP1{ .p1 = g1, .p1.x[1] = 'x' }))) {}
diff --git a/test/SemaCXX/designated-initializers-base-class.cpp b/test/SemaCXX/designated-initializers-base-class.cpp
index 9c2e61ea2a..2aa9603e44 100644
--- a/test/SemaCXX/designated-initializers-base-class.cpp
+++ b/test/SemaCXX/designated-initializers-base-class.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 %s -std=c++1z -fsyntax-only -verify -Winitializer-overrides
-// expected-no-diagnostics
struct B {
int x;
@@ -9,4 +8,4 @@ struct D : B {
int y;
};
-void test() { D d = {1, .y = 2}; }
+void test() { D d = {1, .y = 2}; } // expected-warning {{C99 extension}} expected-note {{}}
diff --git a/test/SemaCXX/designated-initializers.cpp b/test/SemaCXX/designated-initializers.cpp
index 739817372e..a897e5a4e5 100644
--- a/test/SemaCXX/designated-initializers.cpp
+++ b/test/SemaCXX/designated-initializers.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Winitializer-overrides %s
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Woverride-init %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Wno-reorder -Wno-c99-designator -Winitializer-overrides %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Wno-reorder -Wno-c99-designator -Woverride-init %s
template <typename T> struct Foo {
struct SubFoo {
diff --git a/test/SemaCXX/eval-crashes.cpp b/test/SemaCXX/eval-crashes.cpp
index 60c2deed4d..3e59ad31c5 100644
--- a/test/SemaCXX/eval-crashes.cpp
+++ b/test/SemaCXX/eval-crashes.cpp
@@ -37,7 +37,7 @@ namespace pr33140_3 {
struct X {
Y_t a;
};
- struct X foo[2] = {[0 ... 1] = {.a = (Y_t){.c = 0}}};
+ struct X foo[2] = {[0 ... 1] = {.a = (Y_t){.c = 0}}}; // expected-warning {{C99 extension}}
}
namespace pr33140_6 {
diff --git a/test/SemaCXX/member-init.cpp b/test/SemaCXX/member-init.cpp
index 3fcee50e63..f2c0644626 100644
--- a/test/SemaCXX/member-init.cpp
+++ b/test/SemaCXX/member-init.cpp
@@ -184,7 +184,7 @@ void g() { f<int>(); } // expected-note {{in instantiation of function template
namespace PR22056 {
template <int N>
struct S {
- int x[3] = {[N] = 3};
+ int x[3] = {[N] = 3}; // expected-warning {{C99 extension}}
};
}
diff --git a/test/SemaObjCXX/message.mm b/test/SemaObjCXX/message.mm
index e2bdd1386f..aa364d5214 100644
--- a/test/SemaObjCXX/message.mm
+++ b/test/SemaObjCXX/message.mm
@@ -84,7 +84,7 @@ struct identity {
#if __cplusplus <= 199711L
// expected-warning@-2 {{'typename' occurs outside of a template}}
#endif
- int array[5] = {[3] = 2};
+ int array[5] = {[3] = 2}; // expected-warning {{C99 extension}}
return [super method];
}
@end
diff --git a/test/SemaTemplate/instantiate-c99.cpp b/test/SemaTemplate/instantiate-c99.cpp
index 07d3fc7920..b0183ff762 100644
--- a/test/SemaTemplate/instantiate-c99.cpp
+++ b/test/SemaTemplate/instantiate-c99.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -Wno-c99-extensions -Wno-reorder -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Wno-c99-extensions -Wno-reorder -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -Wno-c99-extensions -Wno-reorder -fsyntax-only -verify -std=c++11 %s
// Test template instantiation for C99-specific features.
diff --git a/test/SemaTemplate/instantiate-init.cpp b/test/SemaTemplate/instantiate-init.cpp
index b58ad3a157..99b29c77d5 100644
--- a/test/SemaTemplate/instantiate-init.cpp
+++ b/test/SemaTemplate/instantiate-init.cpp
@@ -151,8 +151,8 @@ namespace InitListUpdate {
// 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}}
+ g(AA{0, [0].n = N} ...); // expected-warning 3{{extension}} expected-note {{here}} expected-warning 3{{overrides prior init}} expected-note 3{{previous init}}
+ g(AA{N, [0].n = 0} ...); // expected-warning 3{{extension}} expected-note {{here}} expected-warning 3{{overrides prior init}} expected-note 3{{previous init}}
};
void g(AA, AA);