Implement the GNU comma swallowing extension. This implements

test/Preprocessor/macro_fn_comma_swallow.c

llvm-svn: 38780
This commit is contained in:
Chris Lattner 2006-07-29 04:39:41 +00:00
parent d480b9c0ed
commit 775d832110
3 changed files with 39 additions and 7 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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<LexerToken> 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; }
};