Index: include/clang/Lex/MacroArgs.h =================================================================== --- include/clang/Lex/MacroArgs.h +++ include/clang/Lex/MacroArgs.h @@ -53,20 +53,24 @@ /// Preprocessor owns which we use to avoid thrashing malloc/free. MacroArgs *ArgCache; + /// ActualArgs - The number of arguments passed to this macro invocation. + unsigned NumActualArgs; + /// MacroArgs - The number of arguments the invoked macro expects. unsigned NumMacroArgs; - MacroArgs(unsigned NumToks, bool varargsElided, unsigned MacroArgs) + MacroArgs(unsigned NumToks, bool varargsElided, unsigned ActualArgs, + unsigned MacroArgs) : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided), - ArgCache(nullptr), NumMacroArgs(MacroArgs) {} + ArgCache(nullptr), NumActualArgs(ActualArgs), NumMacroArgs(MacroArgs) {} ~MacroArgs() = default; public: /// MacroArgs ctor function - Create a new MacroArgs object with the specified /// macro and argument info. - static MacroArgs *create(const MacroInfo *MI, - ArrayRef UnexpArgTokens, - bool VarargsElided, Preprocessor &PP); + static MacroArgs *create(const MacroInfo *MI, ArrayRef UnexpArgTokens, + bool VarargsElided, unsigned ActualArgs, + Preprocessor &PP); /// destroy - Destroy and deallocate the memory for this object. /// @@ -97,6 +101,10 @@ SourceLocation ExpansionLocStart, SourceLocation ExpansionLocEnd); + /// getNumActualArguments - Return the number of arguments passed into this + /// macro invocation. + unsigned getNumActualArguments() const { return NumActualArgs; } + /// getNumMacroArguments - Return the number of arguments the invoked macro /// expects. unsigned getNumMacroArguments() const { return NumMacroArgs; } @@ -108,17 +116,24 @@ /// argument, this returns false. bool isVarargsElidedUse() const { return VarargsElided; } + /// shouldOmitEmptyString - Return true if this is a MSVC Compatibility + /// situation, and this is a __VA_ARGS__ macro invocation where the variadic + /// argument was completely omitted. This permits the MSVC Extension where + /// omitted stringified __VA_ARGS__ result in no expansion, but an empty + /// __VA_ARGS__ results in the "" string literal. + bool shouldOmitEmptyString(const Preprocessor &PP); + /// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of /// tokens into the literal string token that should be produced by the C # /// preprocessor operator. If Charify is true, then it should be turned into - /// a character literal for the Microsoft charize (#@) extension. - /// - static Token StringifyArgument(const Token *ArgToks, - Preprocessor &PP, bool Charify, + /// a character literal for the Microsoft charize (#@) extension. If + /// OmitEmptyString is true, this function will omit result in a blank token + /// rather than two quote characters. + static Token StringifyArgument(const Token *ArgToks, Preprocessor &PP, + bool Charify, bool OmitEmptyString, SourceLocation ExpansionLocStart, SourceLocation ExpansionLocEnd); - - + /// deallocate - This should only be called by the Preprocessor when managing /// its freelist. MacroArgs *deallocate(); Index: lib/Lex/MacroArgs.cpp =================================================================== --- lib/Lex/MacroArgs.cpp +++ lib/Lex/MacroArgs.cpp @@ -23,8 +23,8 @@ /// MacroArgs ctor function - This destroys the vector passed in. MacroArgs *MacroArgs::create(const MacroInfo *MI, - ArrayRef UnexpArgTokens, - bool VarargsElided, Preprocessor &PP) { + ArrayRef UnexpArgTokens, bool VarargsElided, + unsigned ActualArgs, Preprocessor &PP) { assert(MI->isFunctionLike() && "Can't have args for an object-like macro!"); MacroArgs **ResultEnt = nullptr; @@ -51,14 +51,15 @@ Result = (MacroArgs *)malloc(sizeof(MacroArgs) + UnexpArgTokens.size() * sizeof(Token)); // Construct the MacroArgs object. - new (Result) - MacroArgs(UnexpArgTokens.size(), VarargsElided, MI->getNumArgs()); + new (Result) MacroArgs(UnexpArgTokens.size(), VarargsElided, ActualArgs, + MI->getNumArgs()); } else { Result = *ResultEnt; // Unlink this node from the preprocessors singly linked list. *ResultEnt = Result->ArgCache; Result->NumUnexpArgTokens = UnexpArgTokens.size(); Result->VarargsElided = VarargsElided; + Result->NumActualArgs = ActualArgs; Result->NumMacroArgs = MI->getNumArgs(); } @@ -187,14 +188,23 @@ return Result; } +/// shouldOmitEmptyString - Return true if this is a MSVC Compatibility +/// situation, and this is a __VA_ARGS__ macro invocation where the variadic +/// argument was completely omitted. This permits the MSVC Extension where +/// omitted stringified __VA_ARGS__ result in no expansion, but an empty +/// __VA_ARGS__ results in the "" string literal. +bool MacroArgs::shouldOmitEmptyString(const Preprocessor &PP) { + return PP.getLangOpts().MSVCCompat && isVarargsElidedUse() && + getNumActualArguments() < getNumMacroArguments(); +} /// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of /// tokens into the literal string token that should be produced by the C # /// preprocessor operator. If Charify is true, then it should be turned into /// a character literal for the Microsoft charize (#@) extension. /// -Token MacroArgs::StringifyArgument(const Token *ArgToks, - Preprocessor &PP, bool Charify, +Token MacroArgs::StringifyArgument(const Token *ArgToks, Preprocessor &PP, + bool Charify, bool OmitEmptyString, SourceLocation ExpansionLocStart, SourceLocation ExpansionLocEnd) { Token Tok; @@ -205,6 +215,13 @@ // Stringify all the tokens. SmallString<128> Result; + // In the MSVC omitted __VA_ARGS__ case, and where there are no tokens + // immediately return an empty string token. + if (OmitEmptyString && ArgToks->is(tok::eof)) { + PP.CreateString(Result, Tok, ExpansionLocStart, ExpansionLocEnd); + return Tok; + } + Result += "\""; bool isFirst = true; @@ -305,9 +322,9 @@ StringifiedArgs.resize(getNumMacroArguments(), {}); if (StringifiedArgs[ArgNo].isNot(tok::string_literal)) - StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP, - /*Charify=*/false, - ExpansionLocStart, - ExpansionLocEnd); + StringifiedArgs[ArgNo] = + StringifyArgument(getUnexpArgument(ArgNo), PP, + /*Charify=*/false, shouldOmitEmptyString(PP), + ExpansionLocStart, ExpansionLocEnd); return StringifiedArgs[ArgNo]; } Index: lib/Lex/PPMacroExpansion.cpp =================================================================== --- lib/Lex/PPMacroExpansion.cpp +++ lib/Lex/PPMacroExpansion.cpp @@ -1007,7 +1007,7 @@ return nullptr; } - return MacroArgs::create(MI, ArgTokens, isVarargsElided, *this); + return MacroArgs::create(MI, ArgTokens, isVarargsElided, NumActuals, *this); } /// \brief Keeps macro expanded tokens for TokenLexers. Index: lib/Lex/TokenLexer.cpp =================================================================== --- lib/Lex/TokenLexer.cpp +++ lib/Lex/TokenLexer.cpp @@ -202,10 +202,9 @@ ExpansionLocEnd); else { // 'charify': don't bother caching these. - Res = MacroArgs::StringifyArgument(ActualArgs->getUnexpArgument(ArgNo), - PP, true, - ExpansionLocStart, - ExpansionLocEnd); + Res = MacroArgs::StringifyArgument( + ActualArgs->getUnexpArgument(ArgNo), PP, true, + /*OmitEmptyString=*/false, ExpansionLocStart, ExpansionLocEnd); } Res.setFlag(Token::StringifiedInMacro); Index: test/Preprocessor/microsoft-ext.c =================================================================== --- test/Preprocessor/microsoft-ext.c +++ test/Preprocessor/microsoft-ext.c @@ -5,6 +5,9 @@ # define P(x, y) {x, y} # define M(x, y) M2(x, P(x, y)) M(a, b) // CHECK: a + {a, b} +#undef M +#undef P +#undef M2 // Regression test for PR13924 #define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) @@ -34,6 +37,9 @@ MAKE_FUNC(MAK, ER, int a, _COMMA, int b); // CHECK: void func(int a , int b) {} +#undef MAKE_FUNC +#undef MAKER +#undef _COMMA #define macro(a, b) (a - b) void function(int a); @@ -43,3 +49,17 @@ COMMA_ELIDER(); // CHECK: (x - ); // CHECK: function(x); +#undef COMMA_ELIDER +#undef macro + +// When expanding stringized __VA_ARGS__, MSVC expands omitted __VA_ARGS__ as nothing, +// and empty __VA_ARGS__ as the empty-string. +#define M(x, ...) #__VA_ARGS__ +Many is M(a,b,c)BAR +// CHECK: Many is "b,c"BAR +Empty is M(a,)BAR +// CHECK: Empty is ""BAR +Omitted is M(a)BAR +// CHECK: Omitted is BAR +#undef M +