aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Lex/Preprocessor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Lex/Preprocessor.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Lex/Preprocessor.cpp138
1 files changed, 117 insertions, 21 deletions
diff --git a/contrib/llvm-project/clang/lib/Lex/Preprocessor.cpp b/contrib/llvm-project/clang/lib/Lex/Preprocessor.cpp
index 7fdb5d4c0d7b..63e27e62cffc 100644
--- a/contrib/llvm-project/clang/lib/Lex/Preprocessor.cpp
+++ b/contrib/llvm-project/clang/lib/Lex/Preprocessor.cpp
@@ -58,6 +58,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Capacity.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -72,6 +73,9 @@
using namespace clang;
+/// Minimum distance between two check points, in tokens.
+static constexpr unsigned CheckPointStepSize = 1024;
+
LLVM_INSTANTIATE_REGISTRY(PragmaHandlerRegistry)
ExternalPreprocessorSource::~ExternalPreprocessorSource() = default;
@@ -756,7 +760,7 @@ void Preprocessor::HandlePoisonedIdentifier(Token & Identifier) {
Diag(Identifier,it->second) << Identifier.getIdentifierInfo();
}
-void Preprocessor::updateOutOfDateIdentifier(IdentifierInfo &II) const {
+void Preprocessor::updateOutOfDateIdentifier(const IdentifierInfo &II) const {
assert(II.isOutOfDate() && "not out of date");
getExternalSource()->updateOutOfDateIdentifier(II);
}
@@ -954,6 +958,11 @@ void Preprocessor::Lex(Token &Result) {
}
}
+ if (CurLexer && ++CheckPointCounter == CheckPointStepSize) {
+ CheckPoints[CurLexer->getFileID()].push_back(CurLexer->BufferPtr);
+ CheckPointCounter = 0;
+ }
+
LastTokenWasAt = Result.is(tok::at);
--LexLevel;
@@ -979,7 +988,7 @@ void Preprocessor::LexTokensUntilEOF(std::vector<Token> *Tokens) {
}
/// Lex a header-name token (including one formed from header-name-tokens if
-/// \p AllowConcatenation is \c true).
+/// \p AllowMacroExpansion is \c true).
///
/// \param FilenameTok Filled in with the next token. On success, this will
/// be either a header_name token. On failure, it will be whatever other
@@ -1475,26 +1484,56 @@ void Preprocessor::emitFinalMacroWarning(const Token &Identifier,
}
bool Preprocessor::isSafeBufferOptOut(const SourceManager &SourceMgr,
- const SourceLocation &Loc) const {
- // Try to find a region in `SafeBufferOptOutMap` where `Loc` is in:
- auto FirstRegionEndingAfterLoc = llvm::partition_point(
- SafeBufferOptOutMap,
- [&SourceMgr,
- &Loc](const std::pair<SourceLocation, SourceLocation> &Region) {
- return SourceMgr.isBeforeInTranslationUnit(Region.second, Loc);
- });
+ const SourceLocation &Loc) const {
+ // The lambda that tests if a `Loc` is in an opt-out region given one opt-out
+ // region map:
+ auto TestInMap = [&SourceMgr](const SafeBufferOptOutRegionsTy &Map,
+ const SourceLocation &Loc) -> bool {
+ // Try to find a region in `SafeBufferOptOutMap` where `Loc` is in:
+ auto FirstRegionEndingAfterLoc = llvm::partition_point(
+ Map, [&SourceMgr,
+ &Loc](const std::pair<SourceLocation, SourceLocation> &Region) {
+ return SourceMgr.isBeforeInTranslationUnit(Region.second, Loc);
+ });
+
+ if (FirstRegionEndingAfterLoc != Map.end()) {
+ // To test if the start location of the found region precedes `Loc`:
+ return SourceMgr.isBeforeInTranslationUnit(
+ FirstRegionEndingAfterLoc->first, Loc);
+ }
+ // If we do not find a region whose end location passes `Loc`, we want to
+ // check if the current region is still open:
+ if (!Map.empty() && Map.back().first == Map.back().second)
+ return SourceMgr.isBeforeInTranslationUnit(Map.back().first, Loc);
+ return false;
+ };
- if (FirstRegionEndingAfterLoc != SafeBufferOptOutMap.end()) {
- // To test if the start location of the found region precedes `Loc`:
- return SourceMgr.isBeforeInTranslationUnit(FirstRegionEndingAfterLoc->first,
- Loc);
- }
- // If we do not find a region whose end location passes `Loc`, we want to
- // check if the current region is still open:
- if (!SafeBufferOptOutMap.empty() &&
- SafeBufferOptOutMap.back().first == SafeBufferOptOutMap.back().second)
- return SourceMgr.isBeforeInTranslationUnit(SafeBufferOptOutMap.back().first,
- Loc);
+ // What the following does:
+ //
+ // If `Loc` belongs to the local TU, we just look up `SafeBufferOptOutMap`.
+ // Otherwise, `Loc` is from a loaded AST. We look up the
+ // `LoadedSafeBufferOptOutMap` first to get the opt-out region map of the
+ // loaded AST where `Loc` is at. Then we find if `Loc` is in an opt-out
+ // region w.r.t. the region map. If the region map is absent, it means there
+ // is no opt-out pragma in that loaded AST.
+ //
+ // Opt-out pragmas in the local TU or a loaded AST is not visible to another
+ // one of them. That means if you put the pragmas around a `#include
+ // "module.h"`, where module.h is a module, it is not actually suppressing
+ // warnings in module.h. This is fine because warnings in module.h will be
+ // reported when module.h is compiled in isolation and nothing in module.h
+ // will be analyzed ever again. So you will not see warnings from the file
+ // that imports module.h anyway. And you can't even do the same thing for PCHs
+ // because they can only be included from the command line.
+
+ if (SourceMgr.isLocalSourceLocation(Loc))
+ return TestInMap(SafeBufferOptOutMap, Loc);
+
+ const SafeBufferOptOutRegionsTy *LoadedRegions =
+ LoadedSafeBufferOptOutMap.lookupLoadedOptOutMap(Loc, SourceMgr);
+
+ if (LoadedRegions)
+ return TestInMap(*LoadedRegions, Loc);
return false;
}
@@ -1543,6 +1582,47 @@ bool Preprocessor::isPPInSafeBufferOptOutRegion(SourceLocation &StartLoc) {
return InSafeBufferOptOutRegion;
}
+SmallVector<SourceLocation, 64>
+Preprocessor::serializeSafeBufferOptOutMap() const {
+ assert(!InSafeBufferOptOutRegion &&
+ "Attempt to serialize safe buffer opt-out regions before file being "
+ "completely preprocessed");
+
+ SmallVector<SourceLocation, 64> SrcSeq;
+
+ for (const auto &[begin, end] : SafeBufferOptOutMap) {
+ SrcSeq.push_back(begin);
+ SrcSeq.push_back(end);
+ }
+ // Only `SafeBufferOptOutMap` gets serialized. No need to serialize
+ // `LoadedSafeBufferOptOutMap` because if this TU loads a pch/module, every
+ // pch/module in the pch-chain/module-DAG will be loaded one by one in order.
+ // It means that for each loading pch/module m, it just needs to load m's own
+ // `SafeBufferOptOutMap`.
+ return SrcSeq;
+}
+
+bool Preprocessor::setDeserializedSafeBufferOptOutMap(
+ const SmallVectorImpl<SourceLocation> &SourceLocations) {
+ if (SourceLocations.size() == 0)
+ return false;
+
+ assert(SourceLocations.size() % 2 == 0 &&
+ "ill-formed SourceLocation sequence");
+
+ auto It = SourceLocations.begin();
+ SafeBufferOptOutRegionsTy &Regions =
+ LoadedSafeBufferOptOutMap.findAndConsLoadedOptOutMap(*It, SourceMgr);
+
+ do {
+ SourceLocation Begin = *It++;
+ SourceLocation End = *It++;
+
+ Regions.emplace_back(Begin, End);
+ } while (It != SourceLocations.end());
+ return true;
+}
+
ModuleLoader::~ModuleLoader() = default;
CommentHandler::~CommentHandler() = default;
@@ -1558,3 +1638,19 @@ void Preprocessor::createPreprocessingRecord() {
Record = new PreprocessingRecord(getSourceManager());
addPPCallbacks(std::unique_ptr<PPCallbacks>(Record));
}
+
+const char *Preprocessor::getCheckPoint(FileID FID, const char *Start) const {
+ if (auto It = CheckPoints.find(FID); It != CheckPoints.end()) {
+ const SmallVector<const char *> &FileCheckPoints = It->second;
+ const char *Last = nullptr;
+ // FIXME: Do better than a linear search.
+ for (const char *P : FileCheckPoints) {
+ if (P > Start)
+ break;
+ Last = P;
+ }
+ return Last;
+ }
+
+ return nullptr;
+}