diff options
Diffstat (limited to 'lib/Lex/Pragma.cpp')
| -rw-r--r-- | lib/Lex/Pragma.cpp | 211 | 
1 files changed, 204 insertions, 7 deletions
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index f6532c2175a1..e2a192b01f28 100644 --- a/lib/Lex/Pragma.cpp +++ b/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());    }  }  | 
