Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2999,6 +2999,10 @@ def warn_objc_string_literal_comparison : Warning< "direct comparison of a string literal has undefined behavior">, InGroup; +def warn_concatenated_literal_array_init : Warning< + "concatenated literal in a string array initialization - " + "possibly missing a comma">, + InGroup>; def warn_concatenated_nsarray_literal : Warning< "concatenated NSString literal for an NSArray expression - " "possibly missing a comma">, Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -6907,6 +6907,19 @@ << DIE->getSourceRange(); Diag(InitArgList[I]->getBeginLoc(), diag::note_designated_init_mixed) << InitArgList[I]->getSourceRange(); + } else if (StringLiteral *SL = dyn_cast(InitArgList[I])) { + unsigned numConcat = SL->getNumConcatenated(); + // Diagnose missing comma in string array initialization. + if (numConcat > 1) { + bool hasMacro = false; + for (unsigned i = 0; i < numConcat; ++i) + if (SL->getStrTokenLoc(i).isMacroID()) { + hasMacro = true; + break; + } + if (!hasMacro) + Diag(SL->getBeginLoc(), diag::warn_concatenated_literal_array_init); + } } } Index: clang/test/Sema/string-concat.c =================================================================== --- /dev/null +++ clang/test/Sema/string-concat.c @@ -9,13 +9,7 @@ "optional", "packaged_task" // expected-warning{{concatenated literal in a string array initialization - possibly missing a comma}} "promise", - "shared_future", - "shared_lock", - "shared_ptr", - "thread", - "unique_ptr", - "unique_lock", - "weak_ptr", + "shared_future" }; const char *test2[] = {"basic_filebuf", @@ -32,10 +26,30 @@ "future", "optional", "packaged_task", "promise"}; +const char *test5[] = {"basic_filebuf", "future" "optional", "packaged_task"}; // expected-warning{{concatenated literal in a string array initialization - possibly missing a comma}} + + +// Do not warn for macros. + #define BASIC_IOS "basic_ios" #define FUTURE "future" -const char *test5[] = {"basic_filebuf", BASIC_IOS // expected-warning{{concatenated literal in a string array initialization - possibly missing a comma}} +const char *test6[] = {"basic_filebuf", BASIC_IOS FUTURE, "optional", "packaged_task", "promise"}; -const char *test6[] = {"basic_filebuf", "future" "optional", "packaged_task"}; // expected-warning{{concatenated literal in a string array initialization - possibly missing a comma}} +#define FOO(xx) xx "_normal", \ + xx "_movable", + +const char *test7[] = {"basic_filebuf", + "basic_ios" + FOO("future") + "optional", + "packaged_task"}; + +#define BAR(name) #name "_normal" + +const char *test8[] = {"basic_filebuf", + "basic_ios" + BAR(future), + "optional", + "packaged_task"};