Skip to content

Commit 6bdfe3a

Browse files
committedOct 7, 2019
Fix for expanding __pragmas in macro arguments
Summary: 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. Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D68114 llvm-svn: 373950
1 parent be52ff9 commit 6bdfe3a

File tree

2 files changed

+58
-33
lines changed

2 files changed

+58
-33
lines changed
 

‎clang/lib/Lex/Pragma.cpp

+47-32
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,40 @@ void PragmaNamespace::HandlePragma(Preprocessor &PP,
121121
// Preprocessor Pragma Directive Handling.
122122
//===----------------------------------------------------------------------===//
123123

124+
namespace {
125+
// TokenCollector provides the option to collect tokens that were "read"
126+
// and return them to the stream to be read later.
127+
// Currently used when reading _Pragma/__pragma directives.
128+
struct TokenCollector {
129+
Preprocessor &Self;
130+
bool Collect;
131+
SmallVector<Token, 3> Tokens;
132+
Token &Tok;
133+
134+
void lex() {
135+
if (Collect)
136+
Tokens.push_back(Tok);
137+
Self.Lex(Tok);
138+
}
139+
140+
void revert() {
141+
assert(Collect && "did not collect tokens");
142+
assert(!Tokens.empty() && "collected unexpected number of tokens");
143+
144+
// Push the ( "string" ) tokens into the token stream.
145+
auto Toks = std::make_unique<Token[]>(Tokens.size());
146+
std::copy(Tokens.begin() + 1, Tokens.end(), Toks.get());
147+
Toks[Tokens.size() - 1] = Tok;
148+
Self.EnterTokenStream(std::move(Toks), Tokens.size(),
149+
/*DisableMacroExpansion*/ true,
150+
/*IsReinject*/ true);
151+
152+
// ... and return the pragma token unchanged.
153+
Tok = *Tokens.begin();
154+
}
155+
};
156+
} // namespace
157+
124158
/// HandlePragmaDirective - The "\#pragma" directive has been parsed. Lex the
125159
/// rest of the pragma, passing it to the registered pragma handlers.
126160
void Preprocessor::HandlePragmaDirective(PragmaIntroducer Introducer) {
@@ -166,35 +200,6 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
166200
// In Case #2, we check the syntax now, but then put the tokens back into the
167201
// token stream for later consumption.
168202

169-
struct TokenCollector {
170-
Preprocessor &Self;
171-
bool Collect;
172-
SmallVector<Token, 3> Tokens;
173-
Token &Tok;
174-
175-
void lex() {
176-
if (Collect)
177-
Tokens.push_back(Tok);
178-
Self.Lex(Tok);
179-
}
180-
181-
void revert() {
182-
assert(Collect && "did not collect tokens");
183-
assert(!Tokens.empty() && "collected unexpected number of tokens");
184-
185-
// Push the ( "string" ) tokens into the token stream.
186-
auto Toks = std::make_unique<Token[]>(Tokens.size());
187-
std::copy(Tokens.begin() + 1, Tokens.end(), Toks.get());
188-
Toks[Tokens.size() - 1] = Tok;
189-
Self.EnterTokenStream(std::move(Toks), Tokens.size(),
190-
/*DisableMacroExpansion*/ true,
191-
/*IsReinject*/ true);
192-
193-
// ... and return the _Pragma token unchanged.
194-
Tok = *Tokens.begin();
195-
}
196-
};
197-
198203
TokenCollector Toks = {*this, InMacroArgPreExpansion, {}, Tok};
199204

200205
// Remember the pragma token location.
@@ -328,11 +333,15 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
328333
/// HandleMicrosoft__pragma - Like Handle_Pragma except the pragma text
329334
/// is not enclosed within a string literal.
330335
void Preprocessor::HandleMicrosoft__pragma(Token &Tok) {
336+
// During macro pre-expansion, check the syntax now but put the tokens back
337+
// into the token stream for later consumption. Same as Handle_Pragma.
338+
TokenCollector Toks = {*this, InMacroArgPreExpansion, {}, Tok};
339+
331340
// Remember the pragma token location.
332341
SourceLocation PragmaLoc = Tok.getLocation();
333342

334343
// Read the '('.
335-
Lex(Tok);
344+
Toks.lex();
336345
if (Tok.isNot(tok::l_paren)) {
337346
Diag(PragmaLoc, diag::err__Pragma_malformed);
338347
return;
@@ -341,21 +350,27 @@ void Preprocessor::HandleMicrosoft__pragma(Token &Tok) {
341350
// Get the tokens enclosed within the __pragma(), as well as the final ')'.
342351
SmallVector<Token, 32> PragmaToks;
343352
int NumParens = 0;
344-
Lex(Tok);
353+
Toks.lex();
345354
while (Tok.isNot(tok::eof)) {
346355
PragmaToks.push_back(Tok);
347356
if (Tok.is(tok::l_paren))
348357
NumParens++;
349358
else if (Tok.is(tok::r_paren) && NumParens-- == 0)
350359
break;
351-
Lex(Tok);
360+
Toks.lex();
352361
}
353362

354363
if (Tok.is(tok::eof)) {
355364
Diag(PragmaLoc, diag::err_unterminated___pragma);
356365
return;
357366
}
358367

368+
// If we're expanding a macro argument, put the tokens back.
369+
if (InMacroArgPreExpansion) {
370+
Toks.revert();
371+
return;
372+
}
373+
359374
PragmaToks.front().setFlag(Token::LeadingSpace);
360375

361376
// Replace the ')' with an EOD to mark the end of the pragma.

‎clang/test/Preprocessor/pragma_microsoft.c

+11-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ __pragma(comment(linker," bar=" BAR))
5151
__pragma(warning(pop)); \
5252
}
5353

54+
#define PRAGMA_IN_ARGS(p) p
55+
5456
void f()
5557
{
5658
__pragma() // expected-warning{{unknown pragma ignored}}
@@ -64,8 +66,16 @@ void f()
6466
// CHECK: #pragma warning(disable: 10000)
6567
// CHECK: ; 1 + (2 > 3) ? 4 : 5;
6668
// CHECK: #pragma warning(pop)
67-
}
6869

70+
// Check that macro arguments can contain __pragma.
71+
PRAGMA_IN_ARGS(MACRO_WITH__PRAGMA) // expected-warning {{lower precedence}} \
72+
// expected-note 2 {{place parentheses}} \
73+
// expected-warning {{expression result unused}}
74+
// CHECK: #pragma warning(push)
75+
// CHECK: #pragma warning(disable: 10000)
76+
// CHECK: ; 1 + (2 > 3) ? 4 : 5;
77+
// CHECK: #pragma warning(pop)
78+
}
6979

7080
// This should include macro_arg_directive even though the include
7181
// is looking for test.h This allows us to assign to "n"

0 commit comments

Comments
 (0)
Please sign in to comment.