]> granicus.if.org Git - clang/commitdiff
Refactored duplicate string literal lexing code within Preprocessor, into a
authorAndy Gibbs <andyg1001@hotmail.co.uk>
Sat, 17 Nov 2012 19:15:38 +0000 (19:15 +0000)
committerAndy Gibbs <andyg1001@hotmail.co.uk>
Sat, 17 Nov 2012 19:15:38 +0000 (19:15 +0000)
common LexStringLiteral function.  In doing so, some consistency problems have
been ironed out (e.g. where the first token in the string literal was lexed
with macro expansion, but subsequent ones were not) and also an erroneous
diagnostic has been corrected.

LexStringLiteral is complemented by a FinishLexStringLiteral function which
can be used in the situation where the first token of the string literal has
already been lexed.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@168266 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticCommonKinds.td
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Lex/Preprocessor.h
lib/Lex/PPMacroExpansion.cpp
lib/Lex/Pragma.cpp
lib/Lex/Preprocessor.cpp
test/Preprocessor/invalid-__has_warning1.c
test/Preprocessor/invalid-__has_warning2.c
test/Preprocessor/pragma_diagnostic.c
test/Preprocessor/pragma_microsoft.c
test/Preprocessor/warning_tests.c

index a6ce9d4a2d212c40fd2a814f3efa1f146e407271..c2df5da11abcc50373cef676bb7b870602039e69 100644 (file)
@@ -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<
index 392d27607e6d3a0e38de741dee456bc185057c29..e1163cd46dae7f8db0b1461244d62ed510ab5f72 100644 (file)
@@ -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<
index e9095fbf44a94e5376e88611d19fe0abaaac1716..486dcd8e684536661f3ce98a7db5d18cd1222a4c 100644 (file)
@@ -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.
index 1f07a70d3a5592e15f62ab51503e4a4ae5293a4c..9f962b027fcbc788583b268111f3dc2c55296392 100644 (file)
@@ -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)
index e7e6c370537664964b03e5fe2cf3a1b1654bd009..0c1c9dbee51bf5944cab09617ae5754c0f544b56 100644 (file)
@@ -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);
   }
index 3b070ce049db704a8b9549eb2dedc5e70e78cd46..52d6bb6a83bb2ad0ed541d5260db4a88d755022b 100644 (file)
@@ -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) ==
index 40491d4767fe512e569ee5b9aa6a8587fcbcabde..b6a0b2e8ee3c9bc0aba6b233dc2b86106ad9d14a 100644 (file)
@@ -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(
index 7d85e5376f9dae009c202468ab04f9ab5188257e..8aba530c875a90c692bf77554e062d57c7052c19 100644 (file)
@@ -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();
index 818f02f0b90eef6ec9aeaae93978c35a802d3cab..5c91079619e621dc84a5fe51cfba538134ee5dbf 100644 (file)
@@ -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")}}
index e461c707a9a5f85950e8fb155a1e35c005f45031..782f986f7e63166782cc2ee3e66d8689ddf974d6 100644 (file)
@@ -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}}
index ac0b37b645ab8b06b491de9114bbafd475e9354f..77b84562694eb8db3d567bc8a6533168a9a9f546 100644 (file)
@@ -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
 #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