diff options
-rw-r--r-- | include/clang/Basic/DiagnosticCommonKinds.td | 1 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.td | 1 | ||||
-rw-r--r-- | include/clang/Lex/Preprocessor.h | 17 | ||||
-rw-r--r-- | lib/Lex/PPMacroExpansion.cpp | 96 | ||||
-rw-r--r-- | lib/Lex/Pragma.cpp | 99 | ||||
-rw-r--r-- | lib/Lex/Preprocessor.cpp | 39 | ||||
-rw-r--r-- | test/Preprocessor/invalid-__has_warning1.c | 2 | ||||
-rw-r--r-- | test/Preprocessor/invalid-__has_warning2.c | 2 | ||||
-rw-r--r-- | test/Preprocessor/pragma_diagnostic.c | 2 | ||||
-rw-r--r-- | test/Preprocessor/pragma_microsoft.c | 2 | ||||
-rw-r--r-- | test/Preprocessor/warning_tests.c | 25 |
11 files changed, 132 insertions, 154 deletions
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index a6ce9d4a2d..c2df5da11a 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -41,6 +41,7 @@ def err_expected_colon : Error<"expected ':'">; def err_expected_colon_after_setter_name : Error< "method name referenced in property setter attribute " "must end with ':'">; +def err_expected_string_literal : Error<"expected string literal">; def err_invalid_string_udl : Error< "string literal with user-defined suffix cannot be used here">; def err_invalid_character_udl : Error< diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 392d27607e..e1163cd46d 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -229,7 +229,6 @@ def err_label_end_of_compound_statement : Error< "label at end of compound statement: expected statement">; def err_address_of_label_outside_fn : Error< "use of address-of-label extension outside of a function body">; -def err_expected_string_literal : Error<"expected string literal">; def err_asm_operand_wide_string_literal : Error< "cannot use %select{unicode|wide}0 string literal in 'asm'">; def err_expected_selector_for_method : Error< diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index e9095fbf44..486dcd8e68 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -696,6 +696,23 @@ public: void LexAfterModuleImport(Token &Result); + /// \brief Lex a string literal, which may be the concatenation of multiple + /// string literals and may even come from macro expansion. + /// \returns true on success, false if a error diagnostic has been generated. + bool LexStringLiteral(Token &Result, std::string &String, + bool AllowMacroExpansion) { + if (AllowMacroExpansion) + Lex(Result); + else + LexUnexpandedToken(Result); + return FinishLexStringLiteral(Result, String, AllowMacroExpansion); + } + + /// \brief Complete the lexing of a string literal where the first token has + /// already been lexed (see LexStringLiteral). + bool FinishLexStringLiteral(Token &Result, std::string &String, + bool AllowMacroExpansion); + /// LexNonComment - Lex a token. If it's a comment, keep lexing until we get /// something not a comment. This is useful in -E -C mode where comments /// would foul up preprocessor directive handling. diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 1f07a70d3a..9f962b027f 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -21,7 +21,7 @@ #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/CodeCompletionHandler.h" #include "clang/Lex/ExternalPreprocessorSource.h" -#include "clang/Lex/LiteralSupport.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Config/llvm-config.h" @@ -1280,69 +1280,45 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { bool IsValid = false; bool Value = false; // Read the '('. - Lex(Tok); + LexUnexpandedToken(Tok); do { - if (Tok.is(tok::l_paren)) { - // Read the string. - Lex(Tok); - - // We need at least one string literal. - if (!Tok.is(tok::string_literal)) { - StartLoc = Tok.getLocation(); - IsValid = false; - // Eat tokens until ')'. - while (Tok.isNot(tok::r_paren) - && Tok.isNot(tok::eod) - && Tok.isNot(tok::eof)) - Lex(Tok); - break; - } - - // String concatenation allows multiple strings, which can even come - // from macro expansion. - SmallVector<Token, 4> StrToks; - while (Tok.is(tok::string_literal)) { - // Complain about, and drop, any ud-suffix. - if (Tok.hasUDSuffix()) - Diag(Tok, diag::err_invalid_string_udl); - StrToks.push_back(Tok); + if (Tok.isNot(tok::l_paren)) { + Diag(StartLoc, diag::err_warning_check_malformed); + break; + } + + LexUnexpandedToken(Tok); + std::string WarningName; + SourceLocation StrStartLoc = Tok.getLocation(); + if (!FinishLexStringLiteral(Tok, WarningName, /*MacroExpansion=*/false)) { + // Eat tokens until ')'. + while (Tok.isNot(tok::r_paren) + && Tok.isNot(tok::eod) + && Tok.isNot(tok::eof)) LexUnexpandedToken(Tok); - } - - // Is the end a ')'? - if (!(IsValid = Tok.is(tok::r_paren))) - break; - - // Concatenate and parse the strings. - StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this); - assert(Literal.isAscii() && "Didn't allow wide strings in"); - if (Literal.hadError) - break; - if (Literal.Pascal) { - Diag(Tok, diag::warn_pragma_diagnostic_invalid); - break; - } - - StringRef WarningName(Literal.GetString()); - - if (WarningName.size() < 3 || WarningName[0] != '-' || - WarningName[1] != 'W') { - Diag(StrToks[0].getLocation(), diag::warn_has_warning_invalid_option); - break; - } - - // Finally, check if the warning flags maps to a diagnostic group. - // We construct a SmallVector here to talk to getDiagnosticIDs(). - // Although we don't use the result, this isn't a hot path, and not - // worth special casing. - llvm::SmallVector<diag::kind, 10> Diags; - Value = !getDiagnostics().getDiagnosticIDs()-> - getDiagnosticsInGroup(WarningName.substr(2), Diags); + break; } + + // Is the end a ')'? + if (!(IsValid = Tok.is(tok::r_paren))) { + Diag(StartLoc, diag::err_warning_check_malformed); + break; + } + + if (WarningName.size() < 3 || WarningName[0] != '-' || + WarningName[1] != 'W') { + Diag(StrStartLoc, diag::warn_has_warning_invalid_option); + break; + } + + // Finally, check if the warning flags maps to a diagnostic group. + // We construct a SmallVector here to talk to getDiagnosticIDs(). + // Although we don't use the result, this isn't a hot path, and not + // worth special casing. + llvm::SmallVector<diag::kind, 10> Diags; + Value = !getDiagnostics().getDiagnosticIDs()-> + getDiagnosticsInGroup(WarningName.substr(2), Diags); } while (false); - - if (!IsValid) - Diag(StartLoc, diag::err_warning_check_malformed); OS << (int)Value; if (IsValid) diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index e7e6c37053..0c1c9dbee5 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -502,38 +502,9 @@ void Preprocessor::HandlePragmaComment(Token &Tok) { // Read the optional string if present. Lex(Tok); std::string ArgumentString; - if (Tok.is(tok::comma)) { - Lex(Tok); // eat the comma. - - // We need at least one string. - if (Tok.isNot(tok::string_literal)) { - Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); - return; - } - - // String concatenation allows multiple strings, which can even come from - // macro expansion. - // "foo " "bar" "Baz" - SmallVector<Token, 4> StrToks; - while (Tok.is(tok::string_literal)) { - if (Tok.hasUDSuffix()) - Diag(Tok, diag::err_invalid_string_udl); - StrToks.push_back(Tok); - Lex(Tok); - } - - // Concatenate and parse the strings. - StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this); - assert(Literal.isAscii() && "Didn't allow wide strings in"); - if (Literal.hadError) - return; - if (Literal.Pascal) { - Diag(StrToks[0].getLocation(), diag::err_pragma_comment_malformed); - return; - } - - ArgumentString = Literal.GetString(); - } + if (Tok.is(tok::comma) && !LexStringLiteral(Tok, ArgumentString, + /*MacroExpansion=*/true)) + return; // FIXME: If the kind is "compiler" warn if the string is present (it is // ignored). @@ -587,34 +558,9 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) { return; } - // We need at least one string. - if (Tok.isNot(tok::string_literal)) { - Diag(Tok.getLocation(), diag::err_pragma_message_malformed); - return; - } - - // String concatenation allows multiple strings, which can even come from - // macro expansion. - // "foo " "bar" "Baz" - SmallVector<Token, 4> StrToks; - while (Tok.is(tok::string_literal)) { - if (Tok.hasUDSuffix()) - Diag(Tok, diag::err_invalid_string_udl); - StrToks.push_back(Tok); - Lex(Tok); - } - - // Concatenate and parse the strings. - StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this); - assert(Literal.isAscii() && "Didn't allow wide strings in"); - if (Literal.hadError) - return; - if (Literal.Pascal) { - Diag(StrToks[0].getLocation(), diag::err_pragma_message_malformed); + std::string MessageString; + if (!FinishLexStringLiteral(Tok, MessageString, /*MacroExpansion=*/true)) return; - } - - StringRef MessageString(Literal.GetString()); if (ExpectClosingParen) { if (Tok.isNot(tok::r_paren)) { @@ -1090,50 +1036,27 @@ public: } PP.LexUnexpandedToken(Tok); + SourceLocation StringLoc = Tok.getLocation(); - // We need at least one string. - if (Tok.isNot(tok::string_literal)) { - PP.Diag(Tok.getLocation(), diag::warn_pragma_diagnostic_invalid_token); + std::string WarningName; + if (!PP.FinishLexStringLiteral(Tok, WarningName, /*MacroExpansion=*/false)) return; - } - - // String concatenation allows multiple strings, which can even come from - // macro expansion. - // "foo " "bar" "Baz" - SmallVector<Token, 4> StrToks; - while (Tok.is(tok::string_literal)) { - StrToks.push_back(Tok); - PP.LexUnexpandedToken(Tok); - } if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_diagnostic_invalid_token); return; } - // Concatenate and parse the strings. - StringLiteralParser Literal(&StrToks[0], StrToks.size(), PP); - assert(Literal.isAscii() && "Didn't allow wide strings in"); - if (Literal.hadError) - return; - if (Literal.Pascal) { - PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid); - return; - } - - StringRef WarningName(Literal.GetString()); - if (WarningName.size() < 3 || WarningName[0] != '-' || WarningName[1] != 'W') { - PP.Diag(StrToks[0].getLocation(), - diag::warn_pragma_diagnostic_invalid_option); + PP.Diag(StringLoc, diag::warn_pragma_diagnostic_invalid_option); return; } if (PP.getDiagnostics().setDiagnosticGroupMapping(WarningName.substr(2), Map, DiagLoc)) - PP.Diag(StrToks[0].getLocation(), - diag::warn_pragma_diagnostic_unknown_warning) << WarningName; + PP.Diag(StringLoc, diag::warn_pragma_diagnostic_unknown_warning) + << WarningName; else if (Callbacks) Callbacks->PragmaDiagnostic(DiagLoc, Namespace, Map, WarningName); } diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 3b070ce049..52d6bb6a83 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -37,6 +37,7 @@ #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/CodeCompletionHandler.h" #include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/LiteralSupport.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/TargetInfo.h" @@ -689,6 +690,44 @@ void Preprocessor::LexAfterModuleImport(Token &Result) { } } +bool Preprocessor::FinishLexStringLiteral(Token &Result, std::string &String, + bool AllowMacroExpansion) { + // We need at least one string literal. + if (Result.isNot(tok::string_literal)) { + Diag(Result, diag::err_expected_string_literal); + return false; + } + + // Lex string literal tokens, optionally with macro expansion. + SmallVector<Token, 4> StrToks; + do { + StrToks.push_back(Result); + + if (Result.hasUDSuffix()) + Diag(Result, diag::err_invalid_string_udl); + + if (AllowMacroExpansion) + Lex(Result); + else + LexUnexpandedToken(Result); + } while (Result.is(tok::string_literal)); + + // Concatenate and parse the strings. + StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this); + assert(Literal.isAscii() && "Didn't allow wide strings in"); + + if (Literal.hadError) + return false; + + if (Literal.Pascal) { + Diag(StrToks[0].getLocation(), diag::err_expected_string_literal); + return false; + } + + String = Literal.GetString(); + return true; +} + void Preprocessor::addCommentHandler(CommentHandler *Handler) { assert(Handler && "NULL comment handler"); assert(std::find(CommentHandlers.begin(), CommentHandlers.end(), Handler) == diff --git a/test/Preprocessor/invalid-__has_warning1.c b/test/Preprocessor/invalid-__has_warning1.c index 40491d4767..b6a0b2e8ee 100644 --- a/test/Preprocessor/invalid-__has_warning1.c +++ b/test/Preprocessor/invalid-__has_warning1.c @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -verify %s // These must be the last lines in this test. -// expected-error@+1{{requires a parenthesized string}} expected-error@+1 2{{expected}} +// expected-error@+1{{expected string literal}} expected-error@+1 2{{expected}} int i = __has_warning( diff --git a/test/Preprocessor/invalid-__has_warning2.c b/test/Preprocessor/invalid-__has_warning2.c index 7d85e5376f..8aba530c87 100644 --- a/test/Preprocessor/invalid-__has_warning2.c +++ b/test/Preprocessor/invalid-__has_warning2.c @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -verify %s // These must be the last lines in this test. -// expected-error@+1{{requires a parenthesized string}} expected-error@+1{{expected}} +// expected-error@+1{{expected string literal}} expected-error@+1{{expected}} int i = __has_warning(); diff --git a/test/Preprocessor/pragma_diagnostic.c b/test/Preprocessor/pragma_diagnostic.c index 818f02f0b9..5c91079619 100644 --- a/test/Preprocessor/pragma_diagnostic.c +++ b/test/Preprocessor/pragma_diagnostic.c @@ -23,7 +23,7 @@ #define foo error #pragma GCC diagnostic foo "-Wundef" // expected-warning {{pragma diagnostic expected 'error', 'warning', 'ignored', 'fatal', 'push', or 'pop'}} -#pragma GCC diagnostic error 42 // expected-warning {{unexpected token in pragma diagnostic}} +#pragma GCC diagnostic error 42 // expected-error {{expected string literal}} #pragma GCC diagnostic error "-Wundef" 42 // expected-warning {{unexpected token in pragma diagnostic}} #pragma GCC diagnostic error "invalid-name" // expected-warning {{pragma diagnostic expected option name (e.g. "-Wundef")}} diff --git a/test/Preprocessor/pragma_microsoft.c b/test/Preprocessor/pragma_microsoft.c index e461c707a9..782f986f7e 100644 --- a/test/Preprocessor/pragma_microsoft.c +++ b/test/Preprocessor/pragma_microsoft.c @@ -11,7 +11,7 @@ #pragma comment( user, "Compiled on " __DATE__ " at " __TIME__ ) #pragma comment(foo) // expected-error {{unknown kind of pragma comment}} -#pragma comment(compiler,) // expected-error {{pragma comment requires}} +#pragma comment(compiler,) // expected-error {{expected string literal}} #define foo compiler #pragma comment(foo) // macro expand kind. #pragma comment(foo) x // expected-error {{pragma comment requires}} diff --git a/test/Preprocessor/warning_tests.c b/test/Preprocessor/warning_tests.c index ac0b37b645..77b8456269 100644 --- a/test/Preprocessor/warning_tests.c +++ b/test/Preprocessor/warning_tests.c @@ -11,7 +11,7 @@ #warning Should have -Wparentheses #endif -// expected-error@+2 {{builtin warning check macro requires a parenthesized string}} +// expected-error@+2 {{expected string literal}} // expected-error@+1 {{expected value in expression}} #if __has_warning(-Wfoo) #endif @@ -21,3 +21,26 @@ #else #warning Not a valid warning flag #endif + +// expected-error@+2 {{builtin warning check macro requires a parenthesized string}} +// expected-error@+1 {{invalid token}} +#if __has_warning "not valid" +#endif + +// Macro expansion does not occur in the parameter to __has_warning +// (as is also expected behaviour for ordinary macros), so the +// following should not expand: + +#define MY_ALIAS "-Wparentheses" + +// expected-error@+1 2{{expected}} +#if __has_warning(MY_ALIAS) +#error Alias expansion not allowed +#endif + +// But deferring should expand: +#define HAS_WARNING(X) __has_warning(X) + +#if !HAS_WARNING(MY_ALIAS) +#error Expansion should have occurred +#endif |