From e002fbea56c67a46385b651c72cdf6a2242e193a Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Wed, 12 Dec 2007 01:04:12 +0000 Subject: [PATCH] Add ObjC parser support for concatenated ObjC strings. Note that this is passed to sema and ignored there, so the second part of the string will not make it into the AST. Passing to Fariborz to finish Sema + AST construction. llvm-svn: 44898 --- clang/Parse/ParseObjc.cpp | 42 +++++++++++++++---- clang/Sema/Sema.h | 5 ++- clang/Sema/SemaExpr.cpp | 11 +++-- clang/clang.xcodeproj/project.pbxproj | 1 - clang/include/clang/Basic/DiagnosticKinds.def | 4 +- clang/include/clang/Parse/Action.h | 6 ++- clang/test/Sema/objc-string.m | 12 ++++++ 7 files changed, 65 insertions(+), 16 deletions(-) create mode 100644 clang/test/Sema/objc-string.m diff --git a/clang/Parse/ParseObjc.cpp b/clang/Parse/ParseObjc.cpp index 05cbabd67c5a..d455a621992a 100644 --- a/clang/Parse/ParseObjc.cpp +++ b/clang/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 AtLocs; + llvm::SmallVector AtStrings; + AtLocs.push_back(AtLoc); + AtStrings.push_back(Res.Val); + + while (Tok.is(tok::at)) { + AtLocs.push_back(ConsumeToken()); // eat the @. - return Actions.ParseObjCStringLiteral(AtLoc, Res.Val); + 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(&AtLocs[0], &AtStrings[0], + AtStrings.size()); } /// objc-encode-expression: diff --git a/clang/Sema/Sema.h b/clang/Sema/Sema.h index 4c9f4788f8e2..d52d49b75c65 100644 --- a/clang/Sema/Sema.h +++ b/clang/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/clang/Sema/SemaExpr.cpp b/clang/Sema/SemaExpr.cpp index 808da1e55bcf..0f5fe8ad0f26 100644 --- a/clang/Sema/SemaExpr.cpp +++ b/clang/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(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(Strings[0]); if (CheckBuiltinCFStringArgument(S)) return true; diff --git a/clang/clang.xcodeproj/project.pbxproj b/clang/clang.xcodeproj/project.pbxproj index ed2ec876d39c..789b272fa4e5 100644 --- a/clang/clang.xcodeproj/project.pbxproj +++ b/clang/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/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 25f1eea308db..7fec38e800d1 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/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/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 5f6a1469e384..8de9a1901117 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/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/clang/test/Sema/objc-string.m b/clang/test/Sema/objc-string.m new file mode 100644 index 000000000000..4fe439416486 --- /dev/null +++ b/clang/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}} +