akhuang created this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Avoid parsing __pragma into an annotation token when macro arguments are
pre-expanded.
This is what clang currently does when parsing _Pragmas.
Fixes https://bugs.llvm.org/show_bug.cgi?id=41128, where clang crashed
when trying to get the length of an annotation token.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D68114
Files:
clang/lib/Lex/Pragma.cpp
clang/test/Preprocessor/pragma_microsoft.c
Index: clang/test/Preprocessor/pragma_microsoft.c
===================================================================
--- clang/test/Preprocessor/pragma_microsoft.c
+++ 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()
}
Index: clang/lib/Lex/Pragma.cpp
===================================================================
--- clang/lib/Lex/Pragma.cpp
+++ 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<Token, 32> 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<Token[]>(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<Token, 32> 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.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits