Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -57,6 +57,8 @@ Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- Add ``-Wincomplete-array-initializer-list`` warning to detect missing + elements in initializer lists assigned to array types. Non-comprehensive list of changes in this release ------------------------------------------------- Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -732,6 +732,7 @@ def Uninitialized : DiagGroup<"uninitialized", [UninitializedSometimes, UninitializedStaticSelfInit, UninitializedConstReference]>; +def IncompleteArrayInitializerList : DiagGroup<"incomplete-array-initializer-list">; def IgnoredPragmaIntrinsic : DiagGroup<"ignored-pragma-intrinsic">; // #pragma optimize is often used to avoid to work around MSVC codegen bugs or // to disable inlining. It's not completely clear what alternative to suggest Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2213,6 +2213,9 @@ "reference %0 is not yet bound to a value when used within its own" " initialization">, InGroup; +def warn_incomplete_array_initializer_list : Warning< + "incomplete array initializer list">, + InGroup, DefaultIgnore; def warn_uninit_var : Warning< "variable %0 is uninitialized when %select{used here|captured by block}1">, InGroup, DefaultIgnore; Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -980,6 +980,21 @@ if (RequiresSecondPass && !hadError) FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass, nullptr, 0); + + if (T->isArrayType() && VerifyOnly) { + const auto *CAType = dyn_cast(T); + if (CAType && FullyStructuredList->getNumInits() < + CAType->getSize().getZExtValue()) { + S.Diag(IL->getBeginLoc(), diag::warn_incomplete_array_initializer_list) + << IL->getSourceRange(); + } else { + auto inits = FullyStructuredList->inits(); + if (llvm::find(inits, nullptr) != inits.end()) + S.Diag(IL->getBeginLoc(), + diag::warn_incomplete_array_initializer_list) + << IL->getSourceRange(); + } + } } if (hadError && FullyStructuredList) FullyStructuredList->markError(); Index: test/Sema/warn-incomplete-initializer-list.c =================================================================== --- /dev/null +++ test/Sema/warn-incomplete-initializer-list.c @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -fsyntax-only -Wincomplete-initializer-list -verify -std=c99 %s + +// missing array initializer in between +enum { + FOO1_A, + FOO1_MISSING, + FOO1_B, + FOO1_COUNT +}; +const char *foo1[] = { // expected-warning{{incomplete initializer list}} + [FOO1_A] = "a", + [FOO1_B] = "b", +}; + +// missing array initializer at end +enum { + FOO2_A, + FOO2_B, + FOO2_MISSING, + FOO2_COUNT +}; +const char *foo2[FOO2_COUNT] = { //expected-warning{{incomplete initializer list}} + [FOO2_A] = "a", + [FOO2_B] = "b", +}; + +// complete array initializer +int foo3[4] = { 1, 1, 1, 1 }; + +// missing struct initializer in between +struct { + int a, b, c, d; +} bar1 = { + .a = 1, + .b = 1, + .d = 1 +}; + +// missing struct initializer at end +struct { + int a, b, c, d; +} bar2 = { + .a = 1, + .b = 1, + .c = 1 +}; + +// complete struct initializer +struct { + int a, b, c, d; +} bar3 = { 1, 1, 1, 1 };