diff --git a/clang/Lex/MacroExpander.cpp b/clang/Lex/MacroExpander.cpp index dc7ddd271f4a..cec0501b2f7a 100644 --- a/clang/Lex/MacroExpander.cpp +++ b/clang/Lex/MacroExpander.cpp @@ -28,7 +28,7 @@ using namespace clang; /// MacroArgs ctor function - This destroys the vector passed in. MacroArgs *MacroArgs::create(const MacroInfo *MI, const LexerToken *UnexpArgTokens, - unsigned NumToks) { + unsigned NumToks, bool VarargsElided) { assert(MI->isFunctionLike() && "Can't have args for an object-like macro!"); @@ -36,7 +36,7 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI, MacroArgs *Result = (MacroArgs*)malloc(sizeof(MacroArgs) + NumToks*sizeof(LexerToken)); // Construct the macroargs object. - new (Result) MacroArgs(NumToks); + new (Result) MacroArgs(NumToks, VarargsElided); // Copy the actual unexpanded tokens to immediately after the result ptr. if (NumToks) @@ -410,8 +410,6 @@ void MacroExpander::ExpandFunctionArguments() { continue; } - // FIXME: Handle comma swallowing GNU extension. - // If an empty argument is on the LHS or RHS of a paste, the standard (C99 // 6.10.3.3p2,3) calls for a bunch of placemarker stuff to occur. We // implement this by eating ## operators when a LHS or RHS expands to @@ -430,6 +428,17 @@ void MacroExpander::ExpandFunctionArguments() { assert(PasteBefore && ResultToks.back().getKind() == tok::hashhash); NextTokGetsSpace |= ResultToks.back().hasLeadingSpace(); ResultToks.pop_back(); + + // If this is the __VA_ARGS__ token, and if the argument wasn't provided, + // and if the macro had at least one real argument, and if the token before + // the ## was a comma, remove the comma. + if ((unsigned)ArgNo == Macro->getNumArgs() && // is __VA_ARGS__ + ActualArgs->isVarargsElidedUse() && // Argument elided. + !ResultToks.empty() && ResultToks.back().getKind() == tok::comma) { + // Never add a space, even if the comma, ##, or arg had a space. + NextTokGetsSpace = false; + ResultToks.pop_back(); + } continue; } diff --git a/clang/Lex/Preprocessor.cpp b/clang/Lex/Preprocessor.cpp index c2c63f4c8c58..b6c6bc3610d9 100644 --- a/clang/Lex/Preprocessor.cpp +++ b/clang/Lex/Preprocessor.cpp @@ -785,6 +785,9 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(LexerToken &MacroName, // the count. MinArgsExpected += MI->isC99Varargs(); + // See MacroArgs instance var for description of this. + bool isVarargsElided = false; + if (NumActuals < MinArgsExpected) { // There are several cases where too few arguments is ok, handle them now. if (NumActuals+1 == MinArgsExpected && MI->isVariadic()) { @@ -792,6 +795,10 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(LexerToken &MacroName, // #define A(x, ...) // A("blah") Diag(Tok, diag::ext_missing_varargs_arg); + + // Remember this occurred if this is a C99 macro invocation with at least + // one actual argument. + isVarargsElided = (MI->isC99Varargs() && MI->getNumArgs()); } else if (MI->getNumArgs() == 1) { // #define A(x) // A() @@ -816,7 +823,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(LexerToken &MacroName, ArgTokens.push_back(Tok); } - return MacroArgs::create(MI, &ArgTokens[0], ArgTokens.size()); + return MacroArgs::create(MI, &ArgTokens[0], ArgTokens.size(),isVarargsElided); } /// ComputeDATE_TIME - Compute the current time, enter it into the specified diff --git a/clang/include/clang/Lex/MacroExpander.h b/clang/include/clang/Lex/MacroExpander.h index f5f802a0d68f..46fee5788187 100644 --- a/clang/include/clang/Lex/MacroExpander.h +++ b/clang/include/clang/Lex/MacroExpander.h @@ -40,15 +40,23 @@ class MacroArgs { /// StringifiedArgs - This contains arguments in 'stringified' form. If the /// stringified form of an argument has not yet been computed, this is empty. std::vector StringifiedArgs; + + /// VarargsElided - True if this is a C99 style varargs macro invocation and + /// there was no argument specified for the "..." argument. If the argument + /// was specified (even empty) or this isn't a C99 style varargs function, or + /// if in strict mode and the C99 varargs macro had only a ... argument, this + /// is false. + bool VarargsElided; - MacroArgs(unsigned NumToks) : NumUnexpArgTokens(NumToks) {} + MacroArgs(unsigned NumToks, bool varargsElided) + : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided) {} ~MacroArgs() {} public: /// MacroArgs ctor function - Create a new MacroArgs object with the specified /// macro and argument info. static MacroArgs *create(const MacroInfo *MI, const LexerToken *UnexpArgTokens, - unsigned NumArgTokens); + unsigned NumArgTokens, bool VarargsElided); /// destroy - Destroy and deallocate the memory for this object. /// @@ -80,6 +88,14 @@ public: /// getNumArguments - Return the number of arguments passed into this macro /// invocation. unsigned getNumArguments() const { return NumUnexpArgTokens; } + + + /// isVarargsElidedUse - Return true if this is a C99 style varargs macro + /// invocation and there was no argument specified for the "..." argument. If + /// the argument was specified (even empty) or this isn't a C99 style varargs + /// function, or if in strict mode and the C99 varargs macro had only a ... + /// argument, this returns false. + bool isVarargsElidedUse() const { return VarargsElided; } };