Changeset View
Changeset View
Standalone View
Standalone View
clang/lib/Lex/PPLexerChange.cpp
//===--- PPLexerChange.cpp - Handle changing lexers in the preprocessor ---===// | //===--- PPLexerChange.cpp - Handle changing lexers in the preprocessor ---===// | ||||||||
// | // | ||||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||||||
// See https://llvm.org/LICENSE.txt for license information. | // See https://llvm.org/LICENSE.txt for license information. | ||||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||||
// | // | ||||||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||||||
// | // | ||||||||
// This file implements pieces of the Preprocessor interface that manage the | // This file implements pieces of the Preprocessor interface that manage the | ||||||||
// current lexer stack. | // current lexer stack. | ||||||||
// | // | ||||||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||||||
#include "clang/Basic/FileManager.h" | #include "clang/Basic/FileManager.h" | ||||||||
#include "clang/Basic/SourceLocation.h" | |||||||||
#include "clang/Basic/SourceManager.h" | #include "clang/Basic/SourceManager.h" | ||||||||
#include "clang/Lex/HeaderSearch.h" | #include "clang/Lex/HeaderSearch.h" | ||||||||
#include "clang/Lex/LexDiagnostic.h" | #include "clang/Lex/LexDiagnostic.h" | ||||||||
#include "clang/Lex/MacroInfo.h" | #include "clang/Lex/MacroInfo.h" | ||||||||
#include "clang/Lex/Preprocessor.h" | #include "clang/Lex/Preprocessor.h" | ||||||||
#include "clang/Lex/PreprocessorOptions.h" | #include "clang/Lex/PreprocessorOptions.h" | ||||||||
#include "llvm/ADT/StringSwitch.h" | #include "llvm/ADT/StringSwitch.h" | ||||||||
#include "llvm/Support/FileSystem.h" | #include "llvm/Support/FileSystem.h" | ||||||||
#include "llvm/Support/MemoryBufferRef.h" | #include "llvm/Support/MemoryBufferRef.h" | ||||||||
#include "llvm/Support/Path.h" | #include "llvm/Support/Path.h" | ||||||||
using namespace clang; | using namespace clang; | ||||||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||||||
// Miscellaneous Methods. | // Miscellaneous Methods. | ||||||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||||||
/// isInPrimaryFile - Return true if we're in the top-level file, not in a | /// isInPrimaryFile - Return true if we're in the top-level file, not in a | ||||||||
/// \#include. This looks through macro expansions and active _Pragma lexers. | /// \#include. This looks through macro expansions and active _Pragma lexers. | ||||||||
▲ Show 20 Lines • Show All 261 Lines • ▼ Show 20 Lines | if (auto Header = getFileManager().getFile(Entry->path())) | ||||||||
computeRelativePath(FileMgr, Dir, *Header, RelativePath); | computeRelativePath(FileMgr, Dir, *Header, RelativePath); | ||||||||
Diag(ExpectedHeadersLoc, diag::warn_uncovered_module_header) | Diag(ExpectedHeadersLoc, diag::warn_uncovered_module_header) | ||||||||
<< Mod.getFullModuleName() << RelativePath; | << Mod.getFullModuleName() << RelativePath; | ||||||||
} | } | ||||||||
} | } | ||||||||
} | } | ||||||||
} | } | ||||||||
void Preprocessor::ResolvePragmaIncludeInstead( | |||||||||
const SourceLocation Location) const { | |||||||||
assert(Location.isValid()); | |||||||||
if (CurLexer == nullptr) | |||||||||
return; | |||||||||
if (SourceMgr.isInSystemHeader(Location)) | |||||||||
return; | |||||||||
auto IncludeHistory = CurLexer->getIncludeHistory(); | |||||||||
aaron.ballman: Please spell out the type instead of using `auto` or sink this into the `for` loop | |||||||||
for (const auto &Include : IncludeHistory) { | |||||||||
const StringRef Filename = Include.getKey(); | |||||||||
aaron.ballmanUnsubmitted
aaron.ballman: | |||||||||
const auto &IncludeInfo = Include.getValue(); | |||||||||
aaron.ballmanUnsubmitted Please spell out the type. aaron.ballman: Please spell out the type. | |||||||||
cjdbAuthorUnsubmitted The type's currently a private type (that was by design). Do you want me to make it a public type or pull it out into namespace clang? cjdb: The type's currently a private type (that was by design). Do you want me to make it a public… | |||||||||
aaron.ballmanUnsubmitted PreprocessorLexer already friends Preprocessor, so you can name it directly here (though please change the local variable name to be something different from the type name while you're at it). aaron.ballman: `PreprocessorLexer` already friends `Preprocessor`, so you can name it directly here (though… | |||||||||
const HeaderFileInfo &Info = HeaderInfo.getFileInfo(IncludeInfo.File); | |||||||||
if (Info.Aliases.empty()) | |||||||||
continue; | |||||||||
switch (Info.Aliases.size()) { | |||||||||
case 1: | |||||||||
Diag(IncludeInfo.Location, | |||||||||
diag::pp_pragma_include_instead_system_reserved) | |||||||||
<< Filename << 0 << Info.Aliases[0]; | |||||||||
continue; | |||||||||
case 2: | |||||||||
Diag(IncludeInfo.Location, | |||||||||
diag::pp_pragma_include_instead_system_reserved) | |||||||||
<< Filename << 1 << Info.Aliases[0] << Info.Aliases[1]; | |||||||||
continue; | |||||||||
default: { | |||||||||
std::string Aliases; | |||||||||
llvm::interleave( | |||||||||
aaron.ballmanUnsubmitted Can you use llvm::join() from StringExtras.h for this or does the insertion of the single quotes make that awkward? aaron.ballman: Can you use `llvm::join()` from `StringExtras.h` for this or does the insertion of the single… | |||||||||
Info.Aliases, | |||||||||
[&Aliases](const StringRef S) { Aliases += ("'" + S + "'").str(); }, | |||||||||
aaron.ballmanUnsubmitted
aaron.ballman: | |||||||||
[&Aliases] { Aliases += ", "; }); | |||||||||
Diag(IncludeInfo.Location, | |||||||||
diag::pp_pragma_include_instead_system_reserved) | |||||||||
<< Filename << 2 << ('{' + Aliases + '}'); | |||||||||
} | |||||||||
} | |||||||||
} | |||||||||
} | |||||||||
/// HandleEndOfFile - This callback is invoked when the lexer hits the end of | /// HandleEndOfFile - This callback is invoked when the lexer hits the end of | ||||||||
/// the current file. This either returns the EOF token or pops a level off | /// the current file. This either returns the EOF token or pops a level off | ||||||||
/// the include stack and keeps going. | /// the include stack and keeps going. | ||||||||
bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { | bool Preprocessor::HandleEndOfFile(Token &Result, SourceLocation EndLoc, | ||||||||
bool isEndOfMacro) { | |||||||||
assert(!CurTokenLexer && | assert(!CurTokenLexer && | ||||||||
"Ending a file when currently in a macro!"); | "Ending a file when currently in a macro!"); | ||||||||
// If we have an unclosed module region from a pragma at the end of a | // If we have an unclosed module region from a pragma at the end of a | ||||||||
// module, complain and close it now. | // module, complain and close it now. | ||||||||
const bool LeavingSubmodule = CurLexer && CurLexerSubmodule; | const bool LeavingSubmodule = CurLexer && CurLexerSubmodule; | ||||||||
if ((LeavingSubmodule || IncludeMacroStack.empty()) && | if ((LeavingSubmodule || IncludeMacroStack.empty()) && | ||||||||
!BuildingSubmoduleStack.empty() && | !BuildingSubmoduleStack.empty() && | ||||||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | if (const IdentifierInfo *ControllingMacro = | ||||||||
ControllingMacro->getName()); | ControllingMacro->getName()); | ||||||||
} | } | ||||||||
} | } | ||||||||
} | } | ||||||||
} | } | ||||||||
} | } | ||||||||
} | } | ||||||||
if (EndLoc.isValid()) | |||||||||
ResolvePragmaIncludeInstead(EndLoc); | |||||||||
// Complain about reaching a true EOF within arc_cf_code_audited. | // Complain about reaching a true EOF within arc_cf_code_audited. | ||||||||
// We don't want to complain about reaching the end of a macro | // We don't want to complain about reaching the end of a macro | ||||||||
// instantiation or a _Pragma. | // instantiation or a _Pragma. | ||||||||
if (PragmaARCCFCodeAuditedInfo.second.isValid() && !isEndOfMacro && | if (PragmaARCCFCodeAuditedInfo.second.isValid() && !isEndOfMacro && | ||||||||
!(CurLexer && CurLexer->Is_PragmaLexer)) { | !(CurLexer && CurLexer->Is_PragmaLexer)) { | ||||||||
Diag(PragmaARCCFCodeAuditedInfo.second, | Diag(PragmaARCCFCodeAuditedInfo.second, | ||||||||
diag::err_pp_eof_in_arc_cf_code_audited); | diag::err_pp_eof_in_arc_cf_code_audited); | ||||||||
Show All 35 Lines | if (!IncludeMacroStack.empty()) { | ||||||||
if (!isEndOfMacro && CurPPLexer && | if (!isEndOfMacro && CurPPLexer && | ||||||||
(SourceMgr.getIncludeLoc(CurPPLexer->getFileID()).isValid() || | (SourceMgr.getIncludeLoc(CurPPLexer->getFileID()).isValid() || | ||||||||
// Predefines file doesn't have a valid include location. | // Predefines file doesn't have a valid include location. | ||||||||
(PredefinesFileID.isValid() && | (PredefinesFileID.isValid() && | ||||||||
CurPPLexer->getFileID() == PredefinesFileID))) { | CurPPLexer->getFileID() == PredefinesFileID))) { | ||||||||
// Notify SourceManager to record the number of FileIDs that were created | // Notify SourceManager to record the number of FileIDs that were created | ||||||||
// during lexing of the #include'd file. | // during lexing of the #include'd file. | ||||||||
unsigned NumFIDs = | unsigned NumFIDs = | ||||||||
SourceMgr.local_sloc_entry_size() - | SourceMgr.local_sloc_entry_size() - | ||||||||
Can we use llvm::interleaveComma or interleave? zoecarver: Can we use `llvm::interleaveComma` or `interleave`? | |||||||||
Thanks, I was looking for join! cjdb: Thanks, I was looking for `join`! | |||||||||
CurPPLexer->getInitialNumSLocEntries() + 1/*#include'd file*/; | CurPPLexer->getInitialNumSLocEntries() + 1/*#include'd file*/; | ||||||||
SourceMgr.setNumCreatedFIDsForFileID(CurPPLexer->getFileID(), NumFIDs); | SourceMgr.setNumCreatedFIDsForFileID(CurPPLexer->getFileID(), NumFIDs); | ||||||||
} | } | ||||||||
bool ExitedFromPredefinesFile = false; | bool ExitedFromPredefinesFile = false; | ||||||||
FileID ExitedFID; | FileID ExitedFID; | ||||||||
if (!isEndOfMacro && CurPPLexer) { | if (!isEndOfMacro && CurPPLexer) { | ||||||||
ExitedFID = CurPPLexer->getFileID(); | ExitedFID = CurPPLexer->getFileID(); | ||||||||
I wasn't able to work out how to escape braces inside diagnostic files. Seems neither {{ nor \{ work :( cjdb: I wasn't able to work out how to escape braces inside diagnostic files. Seems neither `{{` nor… | |||||||||
assert(PredefinesFileID.isValid() && | assert(PredefinesFileID.isValid() && | ||||||||
"HandleEndOfFile is called before PredefinesFileId is set"); | "HandleEndOfFile is called before PredefinesFileId is set"); | ||||||||
ExitedFromPredefinesFile = (PredefinesFileID == ExitedFID); | ExitedFromPredefinesFile = (PredefinesFileID == ExitedFID); | ||||||||
} | } | ||||||||
if (LeavingSubmodule) { | if (LeavingSubmodule) { | ||||||||
// We're done with this submodule. | // We're done with this submodule. | ||||||||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | bool Preprocessor::HandleEndOfTokenLexer(Token &Result) { | ||||||||
// Delete or cache the now-dead macro expander. | // Delete or cache the now-dead macro expander. | ||||||||
if (NumCachedTokenLexers == TokenLexerCacheSize) | if (NumCachedTokenLexers == TokenLexerCacheSize) | ||||||||
CurTokenLexer.reset(); | CurTokenLexer.reset(); | ||||||||
else | else | ||||||||
TokenLexerCache[NumCachedTokenLexers++] = std::move(CurTokenLexer); | TokenLexerCache[NumCachedTokenLexers++] = std::move(CurTokenLexer); | ||||||||
// Handle this like a #include file being popped off the stack. | // Handle this like a #include file being popped off the stack. | ||||||||
return HandleEndOfFile(Result, true); | return HandleEndOfFile(Result, {}, true); | ||||||||
} | } | ||||||||
/// RemoveTopOfLexerStack - Pop the current lexer/macro exp off the top of the | /// RemoveTopOfLexerStack - Pop the current lexer/macro exp off the top of the | ||||||||
/// lexer stack. This should only be used in situations where the current | /// lexer stack. This should only be used in situations where the current | ||||||||
/// state of the top-of-stack lexer is unknown. | /// state of the top-of-stack lexer is unknown. | ||||||||
void Preprocessor::RemoveTopOfLexerStack() { | void Preprocessor::RemoveTopOfLexerStack() { | ||||||||
assert(!IncludeMacroStack.empty() && "Ran out of stack entries to load"); | assert(!IncludeMacroStack.empty() && "Ran out of stack entries to load"); | ||||||||
▲ Show 20 Lines • Show All 265 Lines • Show Last 20 Lines |
Please spell out the type instead of using auto or sink this into the for loop