Skip to content

Commit 6a4cb0f

Browse files
author
git apple-llvm automerger
committed
Merge commit 'c20fe8b86f9c' from swift/release/6.0 into stable/20230725
2 parents 41ad0c4 + c20fe8b commit 6a4cb0f

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
@@ -1679,6 +1679,11 @@ class SourceManager : public RefCountedBase<SourceManager> {
16791679
isInTheSameTranslationUnit(std::pair<FileID, unsigned> &LOffs,
16801680
std::pair<FileID, unsigned> &ROffs) const;
16811681

1682+
/// \param Loc a source location in a loaded AST (of a PCH/Module file).
1683+
/// \returns a FileID uniquely identifies the AST of a loaded
1684+
/// module/PCH where `Loc` is at.
1685+
FileID getUniqueLoadedASTFileID(SourceLocation Loc) const;
1686+
16821687
/// Determines whether the two decomposed source location is in the same TU.
16831688
bool isInTheSameTranslationUnitImpl(
16841689
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
@@ -2876,11 +2876,41 @@ class Preprocessor {
28762876
/// otherwise.
28772877
SourceLocation CurrentSafeBufferOptOutStart; // It is used to report the start location of an never-closed region.
28782878

2879-
// An ordered sequence of "-Wunsafe-buffer-usage" opt-out regions in one
2880-
// translation unit. Each region is represented by a pair of start and end
2881-
// locations. A region is "open" if its' start and end locations are
2882-
// identical.
2883-
SmallVector<std::pair<SourceLocation, SourceLocation>, 8> SafeBufferOptOutMap;
2879+
using SafeBufferOptOutRegionsTy =
2880+
SmallVector<std::pair<SourceLocation, SourceLocation>, 16>;
2881+
// An ordered sequence of "-Wunsafe-buffer-usage" opt-out regions in this
2882+
// translation unit. Each region is represented by a pair of start and
2883+
// end locations.
2884+
SafeBufferOptOutRegionsTy SafeBufferOptOutMap;
2885+
2886+
// The "-Wunsafe-buffer-usage" opt-out regions in loaded ASTs. We use the
2887+
// following structure to manage them by their ASTs.
2888+
struct {
2889+
// A map from unique IDs to region maps of loaded ASTs. The ID identifies a
2890+
// loaded AST. See `SourceManager::getUniqueLoadedASTID`.
2891+
llvm::DenseMap<FileID, SafeBufferOptOutRegionsTy> LoadedRegions;
2892+
2893+
// Returns a reference to the safe buffer opt-out regions of the loaded
2894+
// AST where `Loc` belongs to. (Construct if absent)
2895+
SafeBufferOptOutRegionsTy &
2896+
findAndConsLoadedOptOutMap(SourceLocation Loc, SourceManager &SrcMgr) {
2897+
return LoadedRegions[SrcMgr.getUniqueLoadedASTFileID(Loc)];
2898+
}
2899+
2900+
// Returns a reference to the safe buffer opt-out regions of the loaded
2901+
// AST where `Loc` belongs to. (This const function returns nullptr if
2902+
// absent.)
2903+
const SafeBufferOptOutRegionsTy *
2904+
lookupLoadedOptOutMap(SourceLocation Loc,
2905+
const SourceManager &SrcMgr) const {
2906+
FileID FID = SrcMgr.getUniqueLoadedASTFileID(Loc);
2907+
auto Iter = LoadedRegions.find(FID);
2908+
2909+
if (Iter == LoadedRegions.end())
2910+
return nullptr;
2911+
return &Iter->getSecond();
2912+
}
2913+
} LoadedSafeBufferOptOutMap;
28842914

28852915
public:
28862916
/// \return true iff the given `Loc` is in a "-Wunsafe-buffer-usage" opt-out
@@ -2910,6 +2940,18 @@ class Preprocessor {
29102940
/// \return true iff this PP is currently in a "-Wunsafe-buffer-usage"
29112941
/// opt-out region
29122942
bool isPPInSafeBufferOptOutRegion(SourceLocation &StartLoc);
2943+
2944+
/// \return a sequence of SourceLocations representing ordered opt-out regions
2945+
/// specified by
2946+
/// `\#pragma clang unsafe_buffer_usage begin/end`s of this translation unit.
2947+
SmallVector<SourceLocation, 64> serializeSafeBufferOptOutMap() const;
2948+
2949+
/// \param SrcLocSeqs a sequence of SourceLocations deserialized from a
2950+
/// record of code `PP_UNSAFE_BUFFER_USAGE`.
2951+
/// \return true iff the `Preprocessor` has been updated; false `Preprocessor`
2952+
/// is same as itself before the call.
2953+
bool setDeserializedSafeBufferOptOutMap(
2954+
const SmallVectorImpl<SourceLocation> &SrcLocSeqs);
29132955
};
29142956

29152957
/// Abstract base class that describes a handler that will receive

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,9 @@ enum ASTRecordTypes {
709709
/// Record code for an unterminated \#pragma clang assume_nonnull begin
710710
/// recorded in a preamble.
711711
PP_ASSUME_NONNULL_LOC = 67,
712+
713+
/// Record code for \#pragma clang unsafe_buffer_usage begin/end
714+
PP_UNSAFE_BUFFER_USAGE = 68,
712715
};
713716

714717
/// 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
@@ -1917,6 +1917,24 @@ SourceManager::getDecomposedIncludedLoc(FileID FID) const {
19171917
return DecompLoc;
19181918
}
19191919

1920+
FileID SourceManager::getUniqueLoadedASTFileID(SourceLocation Loc) const {
1921+
assert(isLoadedSourceLocation(Loc) &&
1922+
"Must be a source location in a loaded PCH/Module file");
1923+
1924+
auto [FID, Ignore] = getDecomposedLoc(Loc);
1925+
// `LoadedSLocEntryAllocBegin` stores the sorted lowest FID of each loaded
1926+
// allocation. Later allocations have lower FileIDs. The call below is to find
1927+
// the lowest FID of a loaded allocation from any FID in the same allocation.
1928+
// The lowest FID is used to identify a loaded allocation.
1929+
const FileID *FirstFID =
1930+
llvm::lower_bound(LoadedSLocEntryAllocBegin, FID, std::greater<FileID>{});
1931+
1932+
assert(FirstFID &&
1933+
"The failure to find the first FileID of a "
1934+
"loaded AST from a loaded source location was unexpected.");
1935+
return *FirstFID;
1936+
}
1937+
19201938
bool SourceManager::isInTheSameTranslationUnitImpl(
19211939
const std::pair<FileID, unsigned> &LOffs,
19221940
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"
@@ -1497,26 +1498,56 @@ void Preprocessor::emitFinalMacroWarning(const Token &Identifier,
14971498
}
14981499

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

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

@@ -1565,6 +1596,47 @@ bool Preprocessor::isPPInSafeBufferOptOutRegion(SourceLocation &StartLoc) {
15651596
return InSafeBufferOptOutRegion;
15661597
}
15671598

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

15701642
CommentHandler::~CommentHandler() = default;

clang/lib/Serialization/ASTReader.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3584,6 +3584,17 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
35843584
break;
35853585
}
35863586

3587+
case PP_UNSAFE_BUFFER_USAGE: {
3588+
if (!Record.empty()) {
3589+
SmallVector<SourceLocation, 64> SrcLocs;
3590+
unsigned Idx = 0;
3591+
while (Idx < Record.size())
3592+
SrcLocs.push_back(ReadSourceLocation(F, Record, Idx));
3593+
PP.setDeserializedSafeBufferOptOutMap(SrcLocs);
3594+
}
3595+
break;
3596+
}
3597+
35873598
case PP_CONDITIONAL_STACK:
35883599
if (!Record.empty()) {
35893600
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
@@ -906,6 +906,7 @@ void ASTWriter::WriteBlockInfoBlock() {
906906
RECORD(PP_CONDITIONAL_STACK);
907907
RECORD(DECLS_TO_CHECK_FOR_DEFERRED_DIAGS);
908908
RECORD(PP_ASSUME_NONNULL_LOC);
909+
RECORD(PP_UNSAFE_BUFFER_USAGE);
909910

910911
// SourceManager Block.
911912
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -2473,6 +2474,12 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
24732474
Record.clear();
24742475
}
24752476

2477+
// Write the safe buffer opt-out region map in PP
2478+
for (SourceLocation &S : PP.serializeSafeBufferOptOutMap())
2479+
AddSourceLocation(S, Record);
2480+
Stream.EmitRecord(PP_UNSAFE_BUFFER_USAGE, Record);
2481+
Record.clear();
2482+
24762483
// Enter the preprocessor block.
24772484
Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 3);
24782485

0 commit comments

Comments
 (0)