diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -165,7 +165,6 @@ // // In Case #2, we check the syntax now, but then put the tokens back into the // token stream for later consumption. - struct TokenCollector { Preprocessor &Self; bool Collect; @@ -194,7 +193,6 @@ Tok = *Tokens.begin(); } }; - TokenCollector Toks = {*this, InMacroArgPreExpansion, {}, Tok}; // Remember the pragma token location. @@ -328,11 +326,41 @@ /// HandleMicrosoft__pragma - Like Handle_Pragma except the pragma text /// is not enclosed within a string literal. void Preprocessor::HandleMicrosoft__pragma(Token &Tok) { + struct TokenCollector { + Preprocessor &Self; + bool Collect; + SmallVector Tokens; + Token &Tok; + + void lex() { + if (Collect) + Tokens.push_back(Tok); + Self.Lex(Tok); + } + + void revert() { + assert(Collect && "did not collect tokens"); + assert(!Tokens.empty() && "collected unexpected number of tokens"); + + // Push the pragma content tokens into the token stream. + auto Toks = std::make_unique(Tokens.size()); + std::copy(Tokens.begin() + 1, Tokens.end(), Toks.get()); + Toks[Tokens.size() - 1] = Tok; + Self.EnterTokenStream(std::move(Toks), Tokens.size(), + /*DisableMacroExpansion*/ true, + /*IsReinject*/ true); + + // ... and return the _Pragma token unchanged. + Tok = *Tokens.begin(); + } + }; + TokenCollector Toks = {*this, InMacroArgPreExpansion, {}, Tok}; + // Remember the pragma token location. SourceLocation PragmaLoc = Tok.getLocation(); // Read the '('. - Lex(Tok); + Toks.lex(); if (Tok.isNot(tok::l_paren)) { Diag(PragmaLoc, diag::err__Pragma_malformed); return; @@ -341,14 +369,14 @@ // Get the tokens enclosed within the __pragma(), as well as the final ')'. SmallVector PragmaToks; int NumParens = 0; - Lex(Tok); + Toks.lex(); while (Tok.isNot(tok::eof)) { PragmaToks.push_back(Tok); if (Tok.is(tok::l_paren)) NumParens++; else if (Tok.is(tok::r_paren) && NumParens-- == 0) break; - Lex(Tok); + Toks.lex(); } if (Tok.is(tok::eof)) { @@ -356,6 +384,12 @@ return; } + // If we're expanding a macro argument, put the tokens back. + if (InMacroArgPreExpansion) { + Toks.revert(); + return; + } + PragmaToks.front().setFlag(Token::LeadingSpace); // Replace the ')' with an EOD to mark the end of the pragma. diff --git a/clang/test/Preprocessor/pragma_microsoft.c b/clang/test/Preprocessor/pragma_microsoft.c --- a/clang/test/Preprocessor/pragma_microsoft.c +++ b/clang/test/Preprocessor/pragma_microsoft.c @@ -51,6 +51,8 @@ __pragma(warning(pop)); \ } +#define __PRAGMA_IN_ARG(p) p + void f() { __pragma() // expected-warning{{unknown pragma ignored}} @@ -64,6 +66,10 @@ // CHECK: #pragma warning(disable: 10000) // CHECK: ; 1 + (2 > 3) ? 4 : 5; // CHECK: #pragma warning(pop) + + // Check that __pragma can be in a macro argument. + __PRAGMA_IN_ARG(__pragma(pack())) +// CHECK: #pragma pack() }