Skip to content

Commit 91fbe3a

Browse files
author
git apple-llvm automerger
committed
Merge commit '2e7b95e4c080' from llvm.org/main into next
2 parents 6c4708b + 2e7b95e commit 91fbe3a

12 files changed

+477
-24
lines changed

clang/include/clang/Basic/SourceManager.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,6 +1681,11 @@ class SourceManager : public RefCountedBase<SourceManager> {
16811681
isInTheSameTranslationUnit(std::pair<FileID, unsigned> &LOffs,
16821682
std::pair<FileID, unsigned> &ROffs) const;
16831683

1684+
/// \param Loc a source location in a loaded AST (of a PCH/Module file).
1685+
/// \returns a FileID uniquely identifies the AST of a loaded
1686+
/// module/PCH where `Loc` is at.
1687+
FileID getUniqueLoadedASTFileID(SourceLocation Loc) const;
1688+
16841689
/// Determines whether the two decomposed source location is in the same TU.
16851690
bool isInTheSameTranslationUnitImpl(
16861691
const std::pair<FileID, unsigned> &LOffs,

clang/include/clang/Lex/Preprocessor.h

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2898,11 +2898,41 @@ class Preprocessor {
28982898
/// otherwise.
28992899
SourceLocation CurrentSafeBufferOptOutStart; // It is used to report the start location of an never-closed region.
29002900

2901-
// An ordered sequence of "-Wunsafe-buffer-usage" opt-out regions in one
2902-
// translation unit. Each region is represented by a pair of start and end
2903-
// locations. A region is "open" if its' start and end locations are
2904-
// identical.
2905-
SmallVector<std::pair<SourceLocation, SourceLocation>, 8> SafeBufferOptOutMap;
2901+
using SafeBufferOptOutRegionsTy =
2902+
SmallVector<std::pair<SourceLocation, SourceLocation>, 16>;
2903+
// An ordered sequence of "-Wunsafe-buffer-usage" opt-out regions in this
2904+
// translation unit. Each region is represented by a pair of start and
2905+
// end locations.
2906+
SafeBufferOptOutRegionsTy SafeBufferOptOutMap;
2907+
2908+
// The "-Wunsafe-buffer-usage" opt-out regions in loaded ASTs. We use the
2909+
// following structure to manage them by their ASTs.
2910+
struct {
2911+
// A map from unique IDs to region maps of loaded ASTs. The ID identifies a
2912+
// loaded AST. See `SourceManager::getUniqueLoadedASTID`.
2913+
llvm::DenseMap<FileID, SafeBufferOptOutRegionsTy> LoadedRegions;
2914+
2915+
// Returns a reference to the safe buffer opt-out regions of the loaded
2916+
// AST where `Loc` belongs to. (Construct if absent)
2917+
SafeBufferOptOutRegionsTy &
2918+
findAndConsLoadedOptOutMap(SourceLocation Loc, SourceManager &SrcMgr) {
2919+
return LoadedRegions[SrcMgr.getUniqueLoadedASTFileID(Loc)];
2920+
}
2921+
2922+
// Returns a reference to the safe buffer opt-out regions of the loaded
2923+
// AST where `Loc` belongs to. (This const function returns nullptr if
2924+
// absent.)
2925+
const SafeBufferOptOutRegionsTy *
2926+
lookupLoadedOptOutMap(SourceLocation Loc,
2927+
const SourceManager &SrcMgr) const {
2928+
FileID FID = SrcMgr.getUniqueLoadedASTFileID(Loc);
2929+
auto Iter = LoadedRegions.find(FID);
2930+
2931+
if (Iter == LoadedRegions.end())
2932+
return nullptr;
2933+
return &Iter->getSecond();
2934+
}
2935+
} LoadedSafeBufferOptOutMap;
29062936

29072937
public:
29082938
/// \return true iff the given `Loc` is in a "-Wunsafe-buffer-usage" opt-out
@@ -2933,6 +2963,18 @@ class Preprocessor {
29332963
/// opt-out region
29342964
bool isPPInSafeBufferOptOutRegion(SourceLocation &StartLoc);
29352965

2966+
/// \return a sequence of SourceLocations representing ordered opt-out regions
2967+
/// specified by
2968+
/// `\#pragma clang unsafe_buffer_usage begin/end`s of this translation unit.
2969+
SmallVector<SourceLocation, 64> serializeSafeBufferOptOutMap() const;
2970+
2971+
/// \param SrcLocSeqs a sequence of SourceLocations deserialized from a
2972+
/// record of code `PP_UNSAFE_BUFFER_USAGE`.
2973+
/// \return true iff the `Preprocessor` has been updated; false `Preprocessor`
2974+
/// is same as itself before the call.
2975+
bool setDeserializedSafeBufferOptOutMap(
2976+
const SmallVectorImpl<SourceLocation> &SrcLocSeqs);
2977+
29362978
private:
29372979
/// Helper functions to forward lexing to the actual lexer. They all share the
29382980
/// same signature.

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,9 @@ enum ASTRecordTypes {
705705
/// Record code for lexical and visible block for delayed namespace in
706706
/// reduced BMI.
707707
DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD = 68,
708+
709+
/// Record code for \#pragma clang unsafe_buffer_usage begin/end
710+
PP_UNSAFE_BUFFER_USAGE = 69,
708711
};
709712

710713
/// Record types used within a source manager block.

clang/lib/Basic/SourceManager.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1915,6 +1915,24 @@ SourceManager::getDecomposedIncludedLoc(FileID FID) const {
19151915
return DecompLoc;
19161916
}
19171917

1918+
FileID SourceManager::getUniqueLoadedASTFileID(SourceLocation Loc) const {
1919+
assert(isLoadedSourceLocation(Loc) &&
1920+
"Must be a source location in a loaded PCH/Module file");
1921+
1922+
auto [FID, Ignore] = getDecomposedLoc(Loc);
1923+
// `LoadedSLocEntryAllocBegin` stores the sorted lowest FID of each loaded
1924+
// allocation. Later allocations have lower FileIDs. The call below is to find
1925+
// the lowest FID of a loaded allocation from any FID in the same allocation.
1926+
// The lowest FID is used to identify a loaded allocation.
1927+
const FileID *FirstFID =
1928+
llvm::lower_bound(LoadedSLocEntryAllocBegin, FID, std::greater<FileID>{});
1929+
1930+
assert(FirstFID &&
1931+
"The failure to find the first FileID of a "
1932+
"loaded AST from a loaded source location was unexpected.");
1933+
return *FirstFID;
1934+
}
1935+
19181936
bool SourceManager::isInTheSameTranslationUnitImpl(
19191937
const std::pair<FileID, unsigned> &LOffs,
19201938
const std::pair<FileID, unsigned> &ROffs) const {

clang/lib/Lex/Preprocessor.cpp

Lines changed: 91 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#include "llvm/ADT/SmallString.h"
5959
#include "llvm/ADT/SmallVector.h"
6060
#include "llvm/ADT/StringRef.h"
61+
#include "llvm/ADT/iterator_range.h"
6162
#include "llvm/Support/Capacity.h"
6263
#include "llvm/Support/ErrorHandling.h"
6364
#include "llvm/Support/MemoryBuffer.h"
@@ -1489,26 +1490,56 @@ void Preprocessor::emitFinalMacroWarning(const Token &Identifier,
14891490
}
14901491

14911492
bool Preprocessor::isSafeBufferOptOut(const SourceManager &SourceMgr,
1492-
const SourceLocation &Loc) const {
1493-
// Try to find a region in `SafeBufferOptOutMap` where `Loc` is in:
1494-
auto FirstRegionEndingAfterLoc = llvm::partition_point(
1495-
SafeBufferOptOutMap,
1496-
[&SourceMgr,
1497-
&Loc](const std::pair<SourceLocation, SourceLocation> &Region) {
1498-
return SourceMgr.isBeforeInTranslationUnit(Region.second, Loc);
1499-
});
1493+
const SourceLocation &Loc) const {
1494+
// The lambda that tests if a `Loc` is in an opt-out region given one opt-out
1495+
// region map:
1496+
auto TestInMap = [&SourceMgr](const SafeBufferOptOutRegionsTy &Map,
1497+
const SourceLocation &Loc) -> bool {
1498+
// Try to find a region in `SafeBufferOptOutMap` where `Loc` is in:
1499+
auto FirstRegionEndingAfterLoc = llvm::partition_point(
1500+
Map, [&SourceMgr,
1501+
&Loc](const std::pair<SourceLocation, SourceLocation> &Region) {
1502+
return SourceMgr.isBeforeInTranslationUnit(Region.second, Loc);
1503+
});
1504+
1505+
if (FirstRegionEndingAfterLoc != Map.end()) {
1506+
// To test if the start location of the found region precedes `Loc`:
1507+
return SourceMgr.isBeforeInTranslationUnit(
1508+
FirstRegionEndingAfterLoc->first, Loc);
1509+
}
1510+
// If we do not find a region whose end location passes `Loc`, we want to
1511+
// check if the current region is still open:
1512+
if (!Map.empty() && Map.back().first == Map.back().second)
1513+
return SourceMgr.isBeforeInTranslationUnit(Map.back().first, Loc);
1514+
return false;
1515+
};
15001516

1501-
if (FirstRegionEndingAfterLoc != SafeBufferOptOutMap.end()) {
1502-
// To test if the start location of the found region precedes `Loc`:
1503-
return SourceMgr.isBeforeInTranslationUnit(FirstRegionEndingAfterLoc->first,
1504-
Loc);
1505-
}
1506-
// If we do not find a region whose end location passes `Loc`, we want to
1507-
// check if the current region is still open:
1508-
if (!SafeBufferOptOutMap.empty() &&
1509-
SafeBufferOptOutMap.back().first == SafeBufferOptOutMap.back().second)
1510-
return SourceMgr.isBeforeInTranslationUnit(SafeBufferOptOutMap.back().first,
1511-
Loc);
1517+
// What the following does:
1518+
//
1519+
// If `Loc` belongs to the local TU, we just look up `SafeBufferOptOutMap`.
1520+
// Otherwise, `Loc` is from a loaded AST. We look up the
1521+
// `LoadedSafeBufferOptOutMap` first to get the opt-out region map of the
1522+
// loaded AST where `Loc` is at. Then we find if `Loc` is in an opt-out
1523+
// region w.r.t. the region map. If the region map is absent, it means there
1524+
// is no opt-out pragma in that loaded AST.
1525+
//
1526+
// Opt-out pragmas in the local TU or a loaded AST is not visible to another
1527+
// one of them. That means if you put the pragmas around a `#include
1528+
// "module.h"`, where module.h is a module, it is not actually suppressing
1529+
// warnings in module.h. This is fine because warnings in module.h will be
1530+
// reported when module.h is compiled in isolation and nothing in module.h
1531+
// will be analyzed ever again. So you will not see warnings from the file
1532+
// that imports module.h anyway. And you can't even do the same thing for PCHs
1533+
// because they can only be included from the command line.
1534+
1535+
if (SourceMgr.isLocalSourceLocation(Loc))
1536+
return TestInMap(SafeBufferOptOutMap, Loc);
1537+
1538+
const SafeBufferOptOutRegionsTy *LoadedRegions =
1539+
LoadedSafeBufferOptOutMap.lookupLoadedOptOutMap(Loc, SourceMgr);
1540+
1541+
if (LoadedRegions)
1542+
return TestInMap(*LoadedRegions, Loc);
15121543
return false;
15131544
}
15141545

@@ -1557,6 +1588,47 @@ bool Preprocessor::isPPInSafeBufferOptOutRegion(SourceLocation &StartLoc) {
15571588
return InSafeBufferOptOutRegion;
15581589
}
15591590

1591+
SmallVector<SourceLocation, 64>
1592+
Preprocessor::serializeSafeBufferOptOutMap() const {
1593+
assert(!InSafeBufferOptOutRegion &&
1594+
"Attempt to serialize safe buffer opt-out regions before file being "
1595+
"completely preprocessed");
1596+
1597+
SmallVector<SourceLocation, 64> SrcSeq;
1598+
1599+
for (const auto &[begin, end] : SafeBufferOptOutMap) {
1600+
SrcSeq.push_back(begin);
1601+
SrcSeq.push_back(end);
1602+
}
1603+
// Only `SafeBufferOptOutMap` gets serialized. No need to serialize
1604+
// `LoadedSafeBufferOptOutMap` because if this TU loads a pch/module, every
1605+
// pch/module in the pch-chain/module-DAG will be loaded one by one in order.
1606+
// It means that for each loading pch/module m, it just needs to load m's own
1607+
// `SafeBufferOptOutMap`.
1608+
return SrcSeq;
1609+
}
1610+
1611+
bool Preprocessor::setDeserializedSafeBufferOptOutMap(
1612+
const SmallVectorImpl<SourceLocation> &SourceLocations) {
1613+
if (SourceLocations.size() == 0)
1614+
return false;
1615+
1616+
assert(SourceLocations.size() % 2 == 0 &&
1617+
"ill-formed SourceLocation sequence");
1618+
1619+
auto It = SourceLocations.begin();
1620+
SafeBufferOptOutRegionsTy &Regions =
1621+
LoadedSafeBufferOptOutMap.findAndConsLoadedOptOutMap(*It, SourceMgr);
1622+
1623+
do {
1624+
SourceLocation Begin = *It++;
1625+
SourceLocation End = *It++;
1626+
1627+
Regions.emplace_back(Begin, End);
1628+
} while (It != SourceLocations.end());
1629+
return true;
1630+
}
1631+
15601632
ModuleLoader::~ModuleLoader() = default;
15611633

15621634
CommentHandler::~CommentHandler() = default;

clang/lib/Serialization/ASTReader.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3632,6 +3632,17 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
36323632
break;
36333633
}
36343634

3635+
case PP_UNSAFE_BUFFER_USAGE: {
3636+
if (!Record.empty()) {
3637+
SmallVector<SourceLocation, 64> SrcLocs;
3638+
unsigned Idx = 0;
3639+
while (Idx < Record.size())
3640+
SrcLocs.push_back(ReadSourceLocation(F, Record, Idx));
3641+
PP.setDeserializedSafeBufferOptOutMap(SrcLocs);
3642+
}
3643+
break;
3644+
}
3645+
36353646
case PP_CONDITIONAL_STACK:
36363647
if (!Record.empty()) {
36373648
unsigned Idx = 0, End = Record.size() - 1;

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,7 @@ void ASTWriter::WriteBlockInfoBlock() {
927927
RECORD(PP_CONDITIONAL_STACK);
928928
RECORD(DECLS_TO_CHECK_FOR_DEFERRED_DIAGS);
929929
RECORD(PP_ASSUME_NONNULL_LOC);
930+
RECORD(PP_UNSAFE_BUFFER_USAGE);
930931

931932
// SourceManager Block.
932933
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -2555,6 +2556,12 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
25552556
Record.clear();
25562557
}
25572558

2559+
// Write the safe buffer opt-out region map in PP
2560+
for (SourceLocation &S : PP.serializeSafeBufferOptOutMap())
2561+
AddSourceLocation(S, Record);
2562+
Stream.EmitRecord(PP_UNSAFE_BUFFER_USAGE, Record);
2563+
Record.clear();
2564+
25582565
// Enter the preprocessor block.
25592566
Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 3);
25602567

0 commit comments

Comments
 (0)