diff options
-rw-r--r-- | Parse/ParseObjc.cpp | 42 | ||||
-rw-r--r-- | Sema/Sema.h | 5 | ||||
-rw-r--r-- | Sema/SemaExpr.cpp | 11 | ||||
-rw-r--r-- | clang.xcodeproj/project.pbxproj | 1 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 4 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 6 | ||||
-rw-r--r-- | test/Sema/objc-string.m | 12 |
7 files changed, 65 insertions, 16 deletions
diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp index 05cbabd67c..d455a62199 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -1190,11 +1190,11 @@ Parser::DeclTy *Parser::ParseObjCMethodDefinition() { Parser::ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { switch (Tok.getKind()) { - case tok::string_literal: // primary-expression: string-literal - case tok::wide_string_literal: - return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc)); - default: - break; + case tok::string_literal: // primary-expression: string-literal + case tok::wide_string_literal: + return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc)); + default: + break; } switch (Tok.getIdentifierInfo()->getObjCKeywordID()) { @@ -1333,10 +1333,38 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() { Parser::ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { ExprResult Res = ParseStringLiteralExpression(); - if (Res.isInvalid) return Res; + + // @"foo" @"bar" is a valid concatenated string. Eat any subsequent string + // expressions. At this point, we know that the only valid thing that starts + // with '@' is an @"". + llvm::SmallVector<SourceLocation, 4> AtLocs; + llvm::SmallVector<ExprTy*, 4> AtStrings; + AtLocs.push_back(AtLoc); + AtStrings.push_back(Res.Val); + + while (Tok.is(tok::at)) { + AtLocs.push_back(ConsumeToken()); // eat the @. + + ExprResult Res(true); // Invalid unless there is a string literal. + if (isTokenStringLiteral()) + Res = ParseStringLiteralExpression(); + else + Diag(Tok, diag::err_objc_concat_string); + + if (Res.isInvalid) { + while (!AtStrings.empty()) { + Actions.DeleteExpr(AtStrings.back()); + AtStrings.pop_back(); + } + return Res; + } + + AtStrings.push_back(Res.Val); + } - return Actions.ParseObjCStringLiteral(AtLoc, Res.Val); + return Actions.ParseObjCStringLiteral(&AtLocs[0], &AtStrings[0], + AtStrings.size()); } /// objc-encode-expression: diff --git a/Sema/Sema.h b/Sema/Sema.h index 4c9f4788f8..d52d49b75c 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -465,8 +465,9 @@ public: tok::TokenKind Kind); // ParseObjCStringLiteral - Parse Objective-C string literals. - virtual ExprResult ParseObjCStringLiteral(SourceLocation AtLoc, - ExprTy *string); + virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, + ExprTy **Strings, + unsigned NumStrings); virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, SourceLocation EncodeLoc, SourceLocation LParenLoc, diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 808da1e55b..0f5fe8ad0f 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -2046,9 +2046,14 @@ Sema::ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, } // TODO: Move this to SemaObjC.cpp -Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation AtLoc, - ExprTy *string) { - StringLiteral* S = static_cast<StringLiteral *>(string); +Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, + ExprTy **Strings, + unsigned NumStrings) { + + // FIXME: This is passed in an ARRAY of strings which need to be concatenated. + // Handle this case here. For now we just ignore all but the first one. + SourceLocation AtLoc = AtLocs[0]; + StringLiteral* S = static_cast<StringLiteral *>(Strings[0]); if (CheckBuiltinCFStringArgument(S)) return true; diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index ed2ec876d3..789b272fa4 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -772,7 +772,6 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */; - compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; mainGroup = 08FB7794FE84155DC02AAC07 /* clang */; projectDirPath = ""; diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 25f1eea308..7fec38e800 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -414,6 +414,8 @@ DIAG(err_objc_protocol_optional, ERROR, "@optional may be specified in protocols only") DIAG(err_missing_catch_finally, ERROR, "@try statment without a @catch and @finally clause") +DIAG(err_objc_concat_string, ERROR, + "unexpected token after Objective-C string") DIAG(err_undef_superclass, ERROR, "cannot find interface declaration for '%0', superclass of '%1'") DIAG(err_duplicate_class_def, ERROR, @@ -465,7 +467,7 @@ DIAG(warn_previous_declaration, WARNING, DIAG(err_conflicting_aliasing_type, ERROR, "conflicting types for alias %0'") DIAG(err_statically_allocated_object, ERROR, - "statically allocated Objective-c object '%0'") + "statically allocated Objective-C object '%0'") DIAG(warn_method_not_found, WARNING, "method '%0%1' not found (return type defaults to 'id')") diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 5f6a1469e3..8de9a19011 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -643,8 +643,10 @@ public: //===----------------------- Obj-C Expressions --------------------------===// - virtual ExprResult ParseObjCStringLiteral(SourceLocation AtLoc, - ExprTy *string) { + + virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, + ExprTy **Strings, + unsigned NumStrings) { return 0; } diff --git a/test/Sema/objc-string.m b/test/Sema/objc-string.m new file mode 100644 index 0000000000..4fe4394164 --- /dev/null +++ b/test/Sema/objc-string.m @@ -0,0 +1,12 @@ +// RUN: clang %s -verify -fsyntax-only + +@class NSString; +@interface NSConstantString; +@end + + + +NSString *s = @"123"; // simple +NSString *t = @"123" @"456"; // concat +NSString *u = @"123" @ blah; // expected-error: {{unexpected token}} + |