diff options
Diffstat (limited to 'clang/lib/Lex/Pragma.cpp')
-rw-r--r-- | clang/lib/Lex/Pragma.cpp | 125 |
1 files changed, 58 insertions, 67 deletions
diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index 286b863b354..1c87f3ecc09 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -144,84 +144,72 @@ void Preprocessor::HandlePragmaDirective(SourceLocation IntroducerLoc, DiscardUntilEndOfDirective(); } -namespace { - -/// Helper class for \see Preprocessor::Handle_Pragma. -class LexingFor_PragmaRAII { - Preprocessor &PP; - bool InMacroArgPreExpansion; - bool Failed = false; - Token &OutTok; - Token PragmaTok; - -public: - LexingFor_PragmaRAII(Preprocessor &PP, bool InMacroArgPreExpansion, - Token &Tok) - : PP(PP), InMacroArgPreExpansion(InMacroArgPreExpansion), OutTok(Tok) { - if (InMacroArgPreExpansion) { - PragmaTok = OutTok; - PP.EnableBacktrackAtThisPos(); - } - } - - ~LexingFor_PragmaRAII() { - if (InMacroArgPreExpansion) { - // When committing/backtracking the cached pragma tokens in a macro - // argument pre-expansion we want to ensure that either the tokens which - // have been committed will be removed from the cache or that the tokens - // over which we just backtracked won't remain in the cache after they're - // consumed and that the caching will stop after consuming them. - // Otherwise the caching will interfere with the way macro expansion - // works, because we will continue to cache tokens after consuming the - // backtracked tokens, which shouldn't happen when we're dealing with - // macro argument pre-expansion. - auto CachedTokenRange = PP.LastCachedTokenRange(); - if (Failed) { - PP.CommitBacktrackedTokens(); - } else { - PP.Backtrack(); - OutTok = PragmaTok; - } - PP.EraseCachedTokens(CachedTokenRange); - } - } - - void failed() { - Failed = true; - } -}; - -} // namespace - /// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then /// return the first token after the directive. The _Pragma token has just /// been read into 'Tok'. void Preprocessor::Handle_Pragma(Token &Tok) { - // This works differently if we are pre-expanding a macro argument. - // In that case we don't actually "activate" the pragma now, we only lex it - // until we are sure it is lexically correct and then we backtrack so that - // we activate the pragma whenever we encounter the tokens again in the token - // stream. This ensures that we will activate it in the correct location - // or that we will ignore it if it never enters the token stream, e.g: + // C11 6.10.3.4/3: + // all pragma unary operator expressions within [a completely + // macro-replaced preprocessing token sequence] are [...] processed [after + // rescanning is complete] // - // #define EMPTY(x) - // #define INACTIVE(x) EMPTY(x) - // INACTIVE(_Pragma("clang diagnostic ignored \"-Wconversion\"")) + // This means that we execute _Pragma operators in two cases: + // + // 1) on token sequences that would otherwise be produced as the output of + // phase 4 of preprocessing, and + // 2) on token sequences formed as the macro-replaced token sequence of a + // macro argument + // + // Case #2 appears to be a wording bug: only _Pragmas that would survive to + // the end of phase 4 should actually be executed. Discussion on the WG14 + // mailing list suggests that a _Pragma operator is notionally checked early, + // but only pragmas that survive to the end of phase 4 should be executed. + // + // 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; + SmallVector<Token, 3> 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 ( "string" ) tokens into the token stream. + auto Toks = llvm::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); + + // ... and return the _Pragma token unchanged. + Tok = *Tokens.begin(); + } + }; - LexingFor_PragmaRAII _PragmaLexing(*this, InMacroArgPreExpansion, Tok); + 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 _PragmaLexing.failed(); + return; } // Read the '"..."'. - Lex(Tok); + Toks.lex(); if (!tok::isStringLiteral(Tok.getKind())) { Diag(PragmaLoc, diag::err__Pragma_malformed); // Skip bad tokens, and the ')', if present. @@ -233,7 +221,7 @@ void Preprocessor::Handle_Pragma(Token &Tok) { Lex(Tok); if (Tok.is(tok::r_paren)) Lex(Tok); - return _PragmaLexing.failed(); + return; } if (Tok.hasUDSuffix()) { @@ -242,21 +230,24 @@ void Preprocessor::Handle_Pragma(Token &Tok) { Lex(Tok); if (Tok.is(tok::r_paren)) Lex(Tok); - return _PragmaLexing.failed(); + return; } // Remember the string. Token StrTok = Tok; // Read the ')'. - Lex(Tok); + Toks.lex(); if (Tok.isNot(tok::r_paren)) { Diag(PragmaLoc, diag::err__Pragma_malformed); - return _PragmaLexing.failed(); + return; } - if (InMacroArgPreExpansion) + // If we're expanding a macro argument, put the tokens back. + if (InMacroArgPreExpansion) { + Toks.revert(); return; + } SourceLocation RParenLoc = Tok.getLocation(); std::string StrVal = getSpelling(StrTok); |