diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Lex/Pragma.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Lex/Pragma.cpp | 211 |
1 files changed, 204 insertions, 7 deletions
diff --git a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp index f6532c2..e2a192b 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp @@ -115,10 +115,61 @@ void Preprocessor::HandlePragmaDirective(unsigned Introducer) { DiscardUntilEndOfDirective(); } +namespace { +/// \brief Helper class for \see Preprocessor::Handle_Pragma. +class LexingFor_PragmaRAII { + Preprocessor &PP; + bool InMacroArgPreExpansion; + bool Failed; + Token &OutTok; + Token PragmaTok; + +public: + LexingFor_PragmaRAII(Preprocessor &PP, bool InMacroArgPreExpansion, + Token &Tok) + : PP(PP), InMacroArgPreExpansion(InMacroArgPreExpansion), + Failed(false), OutTok(Tok) { + if (InMacroArgPreExpansion) { + PragmaTok = OutTok; + PP.EnableBacktrackAtThisPos(); + } + } + + ~LexingFor_PragmaRAII() { + if (InMacroArgPreExpansion) { + if (Failed) { + PP.CommitBacktrackedTokens(); + } else { + PP.Backtrack(); + OutTok = PragmaTok; + } + } + } + + void failed() { + Failed = true; + } +}; +} + /// 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: + // + // #define EMPTY(x) + // #define INACTIVE(x) EMPTY(x) + // INACTIVE(_Pragma("clang diagnostic ignored \"-Wconversion\"")) + + LexingFor_PragmaRAII _PragmaLexing(*this, InMacroArgPreExpansion, Tok); + // Remember the pragma token location. SourceLocation PragmaLoc = Tok.getLocation(); @@ -126,27 +177,45 @@ void Preprocessor::Handle_Pragma(Token &Tok) { Lex(Tok); if (Tok.isNot(tok::l_paren)) { Diag(PragmaLoc, diag::err__Pragma_malformed); - return; + return _PragmaLexing.failed(); } // Read the '"..."'. Lex(Tok); if (Tok.isNot(tok::string_literal) && Tok.isNot(tok::wide_string_literal)) { Diag(PragmaLoc, diag::err__Pragma_malformed); - return; + // Skip this token, and the ')', if present. + if (Tok.isNot(tok::r_paren)) + Lex(Tok); + if (Tok.is(tok::r_paren)) + Lex(Tok); + return _PragmaLexing.failed(); + } + + if (Tok.hasUDSuffix()) { + Diag(Tok, diag::err_invalid_string_udl); + // Skip this token, and the ')', if present. + Lex(Tok); + if (Tok.is(tok::r_paren)) + Lex(Tok); + return _PragmaLexing.failed(); } // Remember the string. - std::string StrVal = getSpelling(Tok); + Token StrTok = Tok; // Read the ')'. Lex(Tok); if (Tok.isNot(tok::r_paren)) { Diag(PragmaLoc, diag::err__Pragma_malformed); - return; + return _PragmaLexing.failed(); } + if (InMacroArgPreExpansion) + return; + SourceLocation RParenLoc = Tok.getLocation(); + std::string StrVal = getSpelling(StrTok); // The _Pragma is lexically sound. Destringize according to C99 6.10.9.1: // "The string literal is destringized by deleting the L prefix, if present, @@ -304,6 +373,8 @@ void Preprocessor::HandlePragmaPoison(Token &PoisonTok) { // Finally, poison it! II->setIsPoisoned(); + if (II->isFromAST()) + II->setChangedSinceDeserialization(); } } @@ -351,7 +422,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { return; // Reserve a buffer to get the spelling. - llvm::SmallString<128> FilenameBuffer; + SmallString<128> FilenameBuffer; bool Invalid = false; StringRef Filename = getSpelling(FilenameTok, FilenameBuffer, &Invalid); if (Invalid) @@ -440,6 +511,8 @@ void Preprocessor::HandlePragmaComment(Token &Tok) { // "foo " "bar" "Baz" SmallVector<Token, 4> StrToks; while (Tok.is(tok::string_literal)) { + if (Tok.hasUDSuffix()) + Diag(Tok, diag::err_invalid_string_udl); StrToks.push_back(Tok); Lex(Tok); } @@ -516,6 +589,8 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) { // "foo " "bar" "Baz" SmallVector<Token, 4> StrToks; while (Tok.is(tok::string_literal)) { + if (Tok.hasUDSuffix()) + Diag(Tok, diag::err_invalid_string_udl); StrToks.push_back(Tok); Lex(Tok); } @@ -575,6 +650,11 @@ IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) { return 0; } + if (Tok.hasUDSuffix()) { + Diag(Tok, diag::err_invalid_string_udl); + return 0; + } + // Remember the macro string. std::string StrVal = getSpelling(Tok); @@ -661,6 +741,111 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) { } } +void Preprocessor::HandlePragmaIncludeAlias(Token &Tok) { + // We will either get a quoted filename or a bracketed filename, and we + // have to track which we got. The first filename is the source name, + // and the second name is the mapped filename. If the first is quoted, + // the second must be as well (cannot mix and match quotes and brackets). + + // Get the open paren + Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::warn_pragma_include_alias_expected) << "("; + return; + } + + // We expect either a quoted string literal, or a bracketed name + Token SourceFilenameTok; + CurPPLexer->LexIncludeFilename(SourceFilenameTok); + if (SourceFilenameTok.is(tok::eod)) { + // The diagnostic has already been handled + return; + } + + StringRef SourceFileName; + SmallString<128> FileNameBuffer; + if (SourceFilenameTok.is(tok::string_literal) || + SourceFilenameTok.is(tok::angle_string_literal)) { + SourceFileName = getSpelling(SourceFilenameTok, FileNameBuffer); + } else if (SourceFilenameTok.is(tok::less)) { + // This could be a path instead of just a name + FileNameBuffer.push_back('<'); + SourceLocation End; + if (ConcatenateIncludeName(FileNameBuffer, End)) + return; // Diagnostic already emitted + SourceFileName = FileNameBuffer.str(); + } else { + Diag(Tok, diag::warn_pragma_include_alias_expected_filename); + return; + } + FileNameBuffer.clear(); + + // Now we expect a comma, followed by another include name + Lex(Tok); + if (Tok.isNot(tok::comma)) { + Diag(Tok, diag::warn_pragma_include_alias_expected) << ","; + return; + } + + Token ReplaceFilenameTok; + CurPPLexer->LexIncludeFilename(ReplaceFilenameTok); + if (ReplaceFilenameTok.is(tok::eod)) { + // The diagnostic has already been handled + return; + } + + StringRef ReplaceFileName; + if (ReplaceFilenameTok.is(tok::string_literal) || + ReplaceFilenameTok.is(tok::angle_string_literal)) { + ReplaceFileName = getSpelling(ReplaceFilenameTok, FileNameBuffer); + } else if (ReplaceFilenameTok.is(tok::less)) { + // This could be a path instead of just a name + FileNameBuffer.push_back('<'); + SourceLocation End; + if (ConcatenateIncludeName(FileNameBuffer, End)) + return; // Diagnostic already emitted + ReplaceFileName = FileNameBuffer.str(); + } else { + Diag(Tok, diag::warn_pragma_include_alias_expected_filename); + return; + } + + // Finally, we expect the closing paren + Lex(Tok); + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::warn_pragma_include_alias_expected) << ")"; + return; + } + + // Now that we have the source and target filenames, we need to make sure + // they're both of the same type (angled vs non-angled) + StringRef OriginalSource = SourceFileName; + + bool SourceIsAngled = + GetIncludeFilenameSpelling(SourceFilenameTok.getLocation(), + SourceFileName); + bool ReplaceIsAngled = + GetIncludeFilenameSpelling(ReplaceFilenameTok.getLocation(), + ReplaceFileName); + if (!SourceFileName.empty() && !ReplaceFileName.empty() && + (SourceIsAngled != ReplaceIsAngled)) { + unsigned int DiagID; + if (SourceIsAngled) + DiagID = diag::warn_pragma_include_alias_mismatch_angle; + else + DiagID = diag::warn_pragma_include_alias_mismatch_quote; + + Diag(SourceFilenameTok.getLocation(), DiagID) + << SourceFileName + << ReplaceFileName; + + return; + } + + // Now we can let the include handler know about this mapping + getHeaderSearchInfo().AddIncludeAlias(OriginalSource, ReplaceFileName); +} + /// AddPragmaHandler - Add the specified pragma handler to the preprocessor. /// If 'Namespace' is non-null, then it is a token required to exist on the /// pragma line before the pragma string starts, e.g. "STDC" or "GCC". @@ -712,8 +897,10 @@ void Preprocessor::RemovePragmaHandler(StringRef Namespace, // If this is a non-default namespace and it is now empty, remove // it. - if (NS != PragmaHandlers && NS->IsEmpty()) + if (NS != PragmaHandlers && NS->IsEmpty()) { PragmaHandlers->RemovePragmaHandler(NS); + delete NS; + } } bool Preprocessor::LexOnOffSwitch(tok::OnOffSwitch &Result) { @@ -939,6 +1126,15 @@ struct PragmaCommentHandler : public PragmaHandler { } }; +/// PragmaIncludeAliasHandler - "#pragma include_alias("...")". +struct PragmaIncludeAliasHandler : public PragmaHandler { + PragmaIncludeAliasHandler() : PragmaHandler("include_alias") {} + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &IncludeAliasTok) { + PP.HandlePragmaIncludeAlias(IncludeAliasTok); + } +}; + /// PragmaMessageHandler - "#pragma message("...")". struct PragmaMessageHandler : public PragmaHandler { PragmaMessageHandler() : PragmaHandler("message") {} @@ -1089,7 +1285,8 @@ void Preprocessor::RegisterBuiltinPragmas() { AddPragmaHandler("STDC", new PragmaSTDC_UnknownHandler()); // MS extensions. - if (Features.MicrosoftExt) { + if (LangOpts.MicrosoftExt) { AddPragmaHandler(new PragmaCommentHandler()); + AddPragmaHandler(new PragmaIncludeAliasHandler()); } } |