diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index ec9c8eb08c3d..f1ab1e8dd758 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -552,6 +552,7 @@ def ObjCCocoaAPI : DiagGroup<"objc-cocoa-api", [ ]>; def ObjCStringComparison : DiagGroup<"objc-string-compare">; +def ObjCStringConcatenation : DiagGroup<"objc-string-concatenation">; def ObjCLiteralComparison : DiagGroup<"objc-literal-compare", [ ObjCStringComparison ]>; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 06053501fa63..5a2e6a9c6bf1 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1898,6 +1898,9 @@ def warn_missing_atsign_prefix : Warning< def warn_objc_string_literal_comparison : Warning< "direct comparison of a string literal has undefined behavior">, InGroup; +def warn_concatenated_nsarray_literal : Warning< + "concatenated nsstring literal for an nsarray expression">, + InGroup; def note_objc_literal_comparison_isequal : Note< "use 'isEqual:' instead">; diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index de0daca4b8bc..e3e91d140a06 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -324,7 +324,8 @@ ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation AtLoc, /// \brief Check that the given expression is a valid element of an Objective-C /// collection literal. static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element, - QualType T) { + QualType T, + bool ArrayLiteral = false) { // If the expression is type-dependent, there's nothing for us to do. if (Element->isTypeDependent()) return Element; @@ -401,14 +402,20 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element, Recovered = true; } } - + if (!Recovered) { S.Diag(Element->getLocStart(), diag::err_invalid_collection_element) << Element->getType(); return ExprError(); } } - + if (ArrayLiteral) + if (ObjCStringLiteral *getString = dyn_cast(OrigElement)) { + if (getString->getString() && getString->getString()->getNumConcatenated() > 1) + S.Diag(Element->getLocStart(), diag::warn_concatenated_nsarray_literal) + << Element->getType(); + } + // Make sure that the element has the type that the container factory // function expects. return S.PerformCopyInitialization( @@ -710,7 +717,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { for (unsigned I = 0, N = Elements.size(); I != N; ++I) { ExprResult Converted = CheckObjCCollectionLiteralElement(*this, ElementsBuffer[I], - RequiredType); + RequiredType, true); if (Converted.isInvalid()) return ExprError(); diff --git a/clang/test/SemaObjC/objc-array-literal.m b/clang/test/SemaObjC/objc-array-literal.m index 9f59316219c7..0d18d73c414c 100644 --- a/clang/test/SemaObjC/objc-array-literal.m +++ b/clang/test/SemaObjC/objc-array-literal.m @@ -39,3 +39,9 @@ int main() { const char *blah; NSArray *array2 = @[blah]; // expected-error{{collection element of type 'const char *' is not an Objective-C object}} } + +// rdar://14303083 +id Test14303083() { + id obj = @[ @"A", (@"B" @"C")]; + return @[ @"A", @"B" @"C"]; // expected-warning {{concatenated nsstring literal for an nsarray expression}} +}