]> granicus.if.org Git - clang/commitdiff
Suppress elided variadic macro argument extension diagnostic for macros using
authorEli Friedman <eli.friedman@gmail.com>
Wed, 14 Nov 2012 02:18:46 +0000 (02:18 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Wed, 14 Nov 2012 02:18:46 +0000 (02:18 +0000)
the related comma pasting extension.

In certain cases, we used to get two diagnostics for what is essentially one
extension.  This change suppresses the first diagnostic in certain cases
where we know we're going to print the second diagnostic.  The
diagnostic is redundant, and it can't be suppressed in the definition
of the macro because it points at the use of the macro, so we want to
avoid printing it if possible.

The implementation works by detecting constructs which look like comma
pasting at the time of the definition of the macro; this information
is then used when the macro is used.  (We can't actually detect
whether we're using the comma pasting extension until the macro is
actually used, but we can detecting constructs which will be comma
pasting if the varargs argument is elided.)

<rdar://problem/12292192>

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

include/clang/Lex/MacroInfo.h
lib/Lex/MacroInfo.cpp
lib/Lex/PPDirectives.cpp
lib/Lex/PPMacroExpansion.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/Preprocessor/macro_fn.c

index aba77d580d9b31a11a24db5f1c5fc9cdfd09f7f7..aeedd735e399fc313897d13e6ae547032f07be80 100644 (file)
@@ -76,6 +76,9 @@ class MacroInfo {
   /// it has not yet been redefined or undefined.
   bool IsBuiltinMacro : 1;
 
+  /// \brief Whether this macro contains the sequence ", ## __VA_ARGS__"
+  bool HasCommaPasting : 1;
+
   /// \brief True if this macro was loaded from an AST file.
   bool IsFromAST : 1;
 
@@ -253,6 +256,9 @@ public:
   /// __LINE__, which requires processing before expansion.
   bool isBuiltinMacro() const { return IsBuiltinMacro; }
 
+  bool hasCommaPasting() const { return HasCommaPasting; }
+  void setHasCommaPasting() { HasCommaPasting = true; }
+
   /// isFromAST - Return true if this macro was loaded from an AST file.
   bool isFromAST() const { return IsFromAST; }
 
index 904f04e4f83674c1467e657226001beec9d1db6f..d1875c79d0d156ce8ac91f2363811a79d4eab8c7 100644 (file)
@@ -25,6 +25,7 @@ MacroInfo::MacroInfo(SourceLocation DefLoc)
     IsC99Varargs(false),
     IsGNUVarargs(false),
     IsBuiltinMacro(false),
+    HasCommaPasting(false),
     IsFromAST(false),
     ChangedAfterLoad(false),
     IsDisabled(false),
@@ -50,6 +51,7 @@ MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator)
     IsC99Varargs(MI.IsC99Varargs),
     IsGNUVarargs(MI.IsGNUVarargs),
     IsBuiltinMacro(MI.IsBuiltinMacro),
+    HasCommaPasting(MI.HasCommaPasting),
     IsFromAST(MI.IsFromAST),
     ChangedAfterLoad(MI.ChangedAfterLoad),
     IsDisabled(MI.IsDisabled),
index b7c1846e82bed7d1eafb12031ea630a65d1c3d2b..50b161a17236b19477ead31b5a28ef7517879054 100644 (file)
@@ -1809,7 +1809,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
     while (Tok.isNot(tok::eod)) {
       LastTok = Tok;
 
-      if (Tok.isNot(tok::hash)) {
+      if (Tok.isNot(tok::hash) && Tok.isNot(tok::hashhash)) {
         MI->AddTokenToBody(Tok);
 
         // Get the next token of the macro.
@@ -1817,6 +1817,35 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
         continue;
       }
 
+      if (Tok.is(tok::hashhash)) {
+        
+        // If we see token pasting, check if it looks like the gcc comma
+        // pasting extension.  We'll use this information to suppress
+        // diagnostics later on.
+        
+        // Get the next token of the macro.
+        LexUnexpandedToken(Tok);
+
+        if (Tok.is(tok::eod)) {
+          MI->AddTokenToBody(LastTok);
+          break;
+        }
+
+        unsigned NumTokens = MI->getNumTokens();
+        if (NumTokens && Tok.getIdentifierInfo() == Ident__VA_ARGS__ &&
+            MI->getReplacementToken(NumTokens-1).is(tok::comma))
+          MI->setHasCommaPasting();
+
+        // Things look ok, add the '##' and param name tokens to the macro.
+        MI->AddTokenToBody(LastTok);
+        MI->AddTokenToBody(Tok);
+        LastTok = Tok;
+
+        // Get the next token of the macro.
+        LexUnexpandedToken(Tok);
+        continue;
+      }
+
       // Get the next token of the macro.
       LexUnexpandedToken(Tok);
 
index eee4342e27ca95a4ad07867d10d1fd2634bd0dbc..de98d5019dad066c893e29930573400b6e56e2fa 100644 (file)
@@ -619,9 +619,14 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
       // Varargs where the named vararg parameter is missing: OK as extension.
       //   #define A(x, ...)
       //   A("blah")
-      Diag(Tok, diag::ext_missing_varargs_arg);
-      Diag(MI->getDefinitionLoc(), diag::note_macro_here)
-        << MacroName.getIdentifierInfo();
+      //
+      // If the macro contains the comma pasting extension, the diagnostic
+      // is suppressed; we know we'll get another diagnostic later.
+      if (!MI->hasCommaPasting()) {
+        Diag(Tok, diag::ext_missing_varargs_arg);
+        Diag(MI->getDefinitionLoc(), diag::note_macro_here)
+          << MacroName.getIdentifierInfo();
+      }
 
       // Remember this occurred, allowing us to elide the comma when used for
       // cases like:
index deba302e2138ef605c4ab1629c49f1224faea4d3..f64962e341c5efcd0c1052f986ff796d38383bf1 100644 (file)
@@ -1141,6 +1141,7 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset,
         // Decode function-like macro info.
         bool isC99VarArgs = Record[NextIndex++];
         bool isGNUVarArgs = Record[NextIndex++];
+        bool hasCommaPasting = Record[NextIndex++];
         MacroArgs.clear();
         unsigned NumArgs = Record[NextIndex++];
         for (unsigned i = 0; i != NumArgs; ++i)
@@ -1150,6 +1151,7 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset,
         MI->setIsFunctionLike();
         if (isC99VarArgs) MI->setIsC99Varargs();
         if (isGNUVarArgs) MI->setIsGNUVarargs();
+        if (hasCommaPasting) MI->setHasCommaPasting();
         MI->setArgumentList(MacroArgs.data(), MacroArgs.size(),
                             PP.getPreprocessorAllocator());
       }
index a2e8b71123b10d1c33ff1eba0a28a497d7ab5414..a34244d3f3cf687e399cbffe292c4f05cdc98c7a 100644 (file)
@@ -1855,6 +1855,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
 
         Record.push_back(MI->isC99Varargs());
         Record.push_back(MI->isGNUVarargs());
+        Record.push_back(MI->hasCommaPasting());
         Record.push_back(MI->getNumArgs());
         for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end();
              I != E; ++I)
index f93d52c7eda7b9c3697782110e711950cb5964ab..8ac9ed9a24873a77fdd10671473886987fbc110d 100644 (file)
@@ -44,3 +44,9 @@ one_dot()   /* empty first argument, elided ...: expected-warning {{must specify
 #define E() (i == 0)
 #if E
 #endif
+
+
+/* <rdar://problem/12292192> */
+#define NSAssert(condition, desc, ...) /* expected-warning {{variadic macros are a C99 feature}} */ \
+    SomeComplicatedStuff((desc), ##__VA_ARGS__) /* expected-warning {{token pasting of ',' and __VA_ARGS__ is a GNU extension}} */
+NSAssert(somecond, somedesc)