diff options
-rw-r--r-- | include/clang/Lex/MacroInfo.h | 6 | ||||
-rw-r--r-- | lib/Lex/MacroInfo.cpp | 2 | ||||
-rw-r--r-- | lib/Lex/PPDirectives.cpp | 31 | ||||
-rw-r--r-- | lib/Lex/PPMacroExpansion.cpp | 11 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 2 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 1 | ||||
-rw-r--r-- | test/Preprocessor/macro_fn.c | 6 |
7 files changed, 55 insertions, 4 deletions
diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h index aba77d580d..aeedd735e3 100644 --- a/include/clang/Lex/MacroInfo.h +++ b/include/clang/Lex/MacroInfo.h @@ -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; } diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp index 904f04e4f8..d1875c79d0 100644 --- a/lib/Lex/MacroInfo.cpp +++ b/lib/Lex/MacroInfo.cpp @@ -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), diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index b7c1846e82..50b161a172 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -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); diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index eee4342e27..de98d5019d 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -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: diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index deba302e21..f64962e341 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -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()); } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index a2e8b71123..a34244d3f3 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -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) diff --git a/test/Preprocessor/macro_fn.c b/test/Preprocessor/macro_fn.c index f93d52c7ed..8ac9ed9a24 100644 --- a/test/Preprocessor/macro_fn.c +++ b/test/Preprocessor/macro_fn.c @@ -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) |