summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuanqi Xu <yedeng.yd@linux.alibaba.com>2024-05-10 15:36:31 +0800
committerChuanqi Xu <yedeng.yd@linux.alibaba.com>2024-05-27 14:27:31 +0800
commit8b7a650e128d6f2bfec9b0768169cf4aaa4af337 (patch)
treefd0eb18b2628da147eff891d072a172fd266144b
parentb590ba73a76609bace9949ea8195d2ee8213cb3f (diff)
[serialization] no transitive decl changeupstream/users/ChuanqiXu9/NoTransitiveDeclChange
-rw-r--r--clang/include/clang/AST/DeclBase.h17
-rw-r--r--clang/include/clang/AST/DeclID.h18
-rw-r--r--clang/include/clang/Serialization/ASTBitCodes.h6
-rw-r--r--clang/include/clang/Serialization/ASTReader.h36
-rw-r--r--clang/include/clang/Serialization/ModuleFile.h18
-rw-r--r--clang/include/clang/Serialization/ModuleManager.h2
-rw-r--r--clang/lib/AST/DeclBase.cpp40
-rw-r--r--clang/lib/Serialization/ASTReader.cpp159
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp12
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp7
-rw-r--r--clang/lib/Serialization/ModuleFile.cpp3
-rw-r--r--clang/test/Modules/no-transitive-decls-change.cppm112
12 files changed, 283 insertions, 147 deletions
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index e43e812cd945..4bdf27aa9940 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -701,10 +701,7 @@ public:
/// Set the owning module ID. This may only be called for
/// deserialized Decls.
- void setOwningModuleID(unsigned ID) {
- assert(isFromASTFile() && "Only works on a deserialized declaration");
- *((unsigned*)this - 2) = ID;
- }
+ void setOwningModuleID(unsigned ID);
public:
/// Determine the availability of the given declaration.
@@ -777,19 +774,11 @@ public:
/// Retrieve the global declaration ID associated with this
/// declaration, which specifies where this Decl was loaded from.
- GlobalDeclID getGlobalID() const {
- if (isFromASTFile())
- return (*((const GlobalDeclID *)this - 1));
- return GlobalDeclID();
- }
+ GlobalDeclID getGlobalID() const;
/// Retrieve the global ID of the module that owns this particular
/// declaration.
- unsigned getOwningModuleID() const {
- if (isFromASTFile())
- return *((const unsigned*)this - 2);
- return 0;
- }
+ unsigned getOwningModuleID() const;
private:
Module *getOwningModuleSlow() const;
diff --git a/clang/include/clang/AST/DeclID.h b/clang/include/clang/AST/DeclID.h
index 614ba06b6386..32d2ed41a374 100644
--- a/clang/include/clang/AST/DeclID.h
+++ b/clang/include/clang/AST/DeclID.h
@@ -19,6 +19,8 @@
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/iterator.h"
+#include <climits>
+
namespace clang {
/// Predefined declaration IDs.
@@ -107,12 +109,16 @@ public:
///
/// DeclID should only be used directly in serialization. All other users
/// should use LocalDeclID or GlobalDeclID.
- using DeclID = uint32_t;
+ using DeclID = uint64_t;
protected:
DeclIDBase() : ID(PREDEF_DECL_NULL_ID) {}
explicit DeclIDBase(DeclID ID) : ID(ID) {}
+ explicit DeclIDBase(unsigned LocalID, unsigned ModuleFileIndex) {
+ ID = (DeclID)LocalID | ((DeclID)ModuleFileIndex << 32);
+ }
+
public:
DeclID get() const { return ID; }
@@ -124,6 +130,10 @@ public:
bool isInvalid() const { return ID == PREDEF_DECL_NULL_ID; }
+ unsigned getModuleFileIndex() const { return ID >> 32; }
+
+ unsigned getLocalDeclIndex() const;
+
friend bool operator==(const DeclIDBase &LHS, const DeclIDBase &RHS) {
return LHS.ID == RHS.ID;
}
@@ -156,6 +166,9 @@ public:
LocalDeclID(PredefinedDeclIDs ID) : Base(ID) {}
explicit LocalDeclID(DeclID ID) : Base(ID) {}
+ explicit LocalDeclID(unsigned LocalID, unsigned ModuleFileIndex)
+ : Base(LocalID, ModuleFileIndex) {}
+
LocalDeclID &operator++() {
++ID;
return *this;
@@ -175,6 +188,9 @@ public:
GlobalDeclID() : Base() {}
explicit GlobalDeclID(DeclID ID) : Base(ID) {}
+ explicit GlobalDeclID(unsigned LocalID, unsigned ModuleFileIndex)
+ : Base(LocalID, ModuleFileIndex) {}
+
// For DeclIDIterator<GlobalDeclID> to be able to convert a GlobalDeclID
// to a LocalDeclID.
explicit operator LocalDeclID() const { return LocalDeclID(this->ID); }
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index fe1bd47348be..9e4b21baa7d2 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -255,6 +255,12 @@ public:
}
};
+// The unaligned decl ID used in the Blobs of bistreams.
+using unaligned_decl_id_t =
+ llvm::support::detail::packed_endian_specific_integral<
+ serialization::DeclID, llvm::endianness::native,
+ llvm::support::unaligned>;
+
/// The number of predefined preprocessed entity IDs.
const unsigned int NUM_PREDEF_PP_ENTITY_IDS = 1;
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index 4ece4593f073..a2e094354d96 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -501,12 +501,6 @@ private:
/// = I + 1 has already been loaded.
llvm::PagedVector<Decl *> DeclsLoaded;
- using GlobalDeclMapType = ContinuousRangeMap<GlobalDeclID, ModuleFile *, 4>;
-
- /// Mapping from global declaration IDs to the module in which the
- /// declaration resides.
- GlobalDeclMapType GlobalDeclMap;
-
using FileOffset = std::pair<ModuleFile *, uint64_t>;
using FileOffsetsTy = SmallVector<FileOffset, 2>;
using DeclUpdateOffsetsMap = llvm::DenseMap<GlobalDeclID, FileOffsetsTy>;
@@ -589,10 +583,11 @@ private:
struct FileDeclsInfo {
ModuleFile *Mod = nullptr;
- ArrayRef<LocalDeclID> Decls;
+ ArrayRef<serialization::unaligned_decl_id_t> Decls;
FileDeclsInfo() = default;
- FileDeclsInfo(ModuleFile *Mod, ArrayRef<LocalDeclID> Decls)
+ FileDeclsInfo(ModuleFile *Mod,
+ ArrayRef<serialization::unaligned_decl_id_t> Decls)
: Mod(Mod), Decls(Decls) {}
};
@@ -601,11 +596,7 @@ private:
/// An array of lexical contents of a declaration context, as a sequence of
/// Decl::Kind, DeclID pairs.
- using unaligned_decl_id_t =
- llvm::support::detail::packed_endian_specific_integral<
- serialization::DeclID, llvm::endianness::native,
- llvm::support::unaligned>;
- using LexicalContents = ArrayRef<unaligned_decl_id_t>;
+ using LexicalContents = ArrayRef<serialization::unaligned_decl_id_t>;
/// Map from a DeclContext to its lexical contents.
llvm::DenseMap<const DeclContext*, std::pair<ModuleFile*, LexicalContents>>
@@ -1486,10 +1477,11 @@ private:
unsigned ClientLoadCapabilities);
public:
- class ModuleDeclIterator : public llvm::iterator_adaptor_base<
- ModuleDeclIterator, const LocalDeclID *,
- std::random_access_iterator_tag, const Decl *,
- ptrdiff_t, const Decl *, const Decl *> {
+ class ModuleDeclIterator
+ : public llvm::iterator_adaptor_base<
+ ModuleDeclIterator, const serialization::unaligned_decl_id_t *,
+ std::random_access_iterator_tag, const Decl *, ptrdiff_t,
+ const Decl *, const Decl *> {
ASTReader *Reader = nullptr;
ModuleFile *Mod = nullptr;
@@ -1497,11 +1489,11 @@ public:
ModuleDeclIterator() : iterator_adaptor_base(nullptr) {}
ModuleDeclIterator(ASTReader *Reader, ModuleFile *Mod,
- const LocalDeclID *Pos)
+ const serialization::unaligned_decl_id_t *Pos)
: iterator_adaptor_base(Pos), Reader(Reader), Mod(Mod) {}
value_type operator*() const {
- return Reader->GetDecl(Reader->getGlobalDeclID(*Mod, *I));
+ return Reader->GetDecl(Reader->getGlobalDeclID(*Mod, (LocalDeclID)*I));
}
value_type operator->() const { return **this; }
@@ -1541,6 +1533,9 @@ private:
StringRef Arg2 = StringRef(), StringRef Arg3 = StringRef()) const;
void Error(llvm::Error &&Err) const;
+ /// Translate a \param GlobalDeclID to the index of DeclsLoaded array.
+ unsigned translateGlobalDeclIDToIndex(GlobalDeclID ID) const;
+
public:
/// Load the AST file and validate its contents against the given
/// Preprocessor.
@@ -1912,7 +1907,8 @@ public:
/// Retrieve the module file that owns the given declaration, or NULL
/// if the declaration is not from a module file.
- ModuleFile *getOwningModuleFile(const Decl *D);
+ ModuleFile *getOwningModuleFile(const Decl *D) const;
+ ModuleFile *getOwningModuleFile(GlobalDeclID ID) const;
/// Returns the source location for the decl \p ID.
SourceLocation getSourceLocationForDeclID(GlobalDeclID ID);
diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h
index 992d26a8b88c..56193d44dd6f 100644
--- a/clang/include/clang/Serialization/ModuleFile.h
+++ b/clang/include/clang/Serialization/ModuleFile.h
@@ -454,23 +454,11 @@ public:
/// by the declaration ID (-1).
const DeclOffset *DeclOffsets = nullptr;
- /// Base declaration ID for declarations local to this module.
- serialization::DeclID BaseDeclID = 0;
-
- /// Remapping table for declaration IDs in this module.
- ContinuousRangeMap<serialization::DeclID, int, 2> DeclRemap;
-
- /// Mapping from the module files that this module file depends on
- /// to the base declaration ID for that module as it is understood within this
- /// module.
- ///
- /// This is effectively a reverse global-to-local mapping for declaration
- /// IDs, so that we can interpret a true global ID (for this translation unit)
- /// as a local ID (for this module file).
- llvm::DenseMap<ModuleFile *, serialization::DeclID> GlobalToLocalDeclIDs;
+ /// Base declaration index in ASTReader for declarations local to this module.
+ unsigned BaseDeclIndex = 0;
/// Array of file-level DeclIDs sorted by file.
- const LocalDeclID *FileSortedDecls = nullptr;
+ const serialization::unaligned_decl_id_t *FileSortedDecls = nullptr;
unsigned NumFileSortedDecls = 0;
/// Array of category list location information within this
diff --git a/clang/include/clang/Serialization/ModuleManager.h b/clang/include/clang/Serialization/ModuleManager.h
index 3bd379acf7ed..097a1c16a057 100644
--- a/clang/include/clang/Serialization/ModuleManager.h
+++ b/clang/include/clang/Serialization/ModuleManager.h
@@ -46,7 +46,7 @@ namespace serialization {
/// Manages the set of modules loaded by an AST reader.
class ModuleManager {
/// The chain of AST files, in the order in which we started to load
- /// them (this order isn't really useful for anything).
+ /// them.
SmallVector<std::unique_ptr<ModuleFile>, 2> Chain;
/// The chain of non-module PCH files. The first entry is the one named
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 65d5eeb6354e..e74d69e05b28 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -74,18 +74,17 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Context,
GlobalDeclID ID, std::size_t Extra) {
// Allocate an extra 8 bytes worth of storage, which ensures that the
// resulting pointer will still be 8-byte aligned.
- static_assert(sizeof(unsigned) * 2 >= alignof(Decl),
- "Decl won't be misaligned");
+ static_assert(sizeof(uint64_t) >= alignof(Decl), "Decl won't be misaligned");
void *Start = Context.Allocate(Size + Extra + 8);
void *Result = (char*)Start + 8;
- unsigned *PrefixPtr = (unsigned *)Result - 2;
+ uint64_t *PrefixPtr = (uint64_t *)Result - 1;
- // Zero out the first 4 bytes; this is used to store the owning module ID.
- PrefixPtr[0] = 0;
+ *PrefixPtr = ID.get();
- // Store the global declaration ID in the second 4 bytes.
- PrefixPtr[1] = ID.get();
+ // We leave the upper 16 bits to store the module IDs. 48 bits should be
+ // sufficient to store a declaration ID.
+ assert(*PrefixPtr < llvm::maskTrailingOnes<uint64_t>(48));
return Result;
}
@@ -111,6 +110,29 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx,
return ::operator new(Size + Extra, Ctx);
}
+GlobalDeclID Decl::getGlobalID() const {
+ if (!isFromASTFile())
+ return GlobalDeclID();
+ // See the comments in `Decl::operator new` for details.
+ uint64_t ID = *((const uint64_t *)this - 1);
+ return GlobalDeclID(ID & llvm::maskTrailingOnes<uint64_t>(48));
+}
+
+unsigned Decl::getOwningModuleID() const {
+ if (!isFromASTFile())
+ return 0;
+
+ uint64_t ID = *((const uint64_t *)this - 1);
+ return ID >> 48;
+}
+
+void Decl::setOwningModuleID(unsigned ID) {
+ assert(isFromASTFile() && "Only works on a deserialized declaration");
+ uint64_t *IDAddress = (uint64_t *)this - 1;
+ assert(!((*IDAddress) >> 48) && "We should only set the module ID once");
+ *IDAddress |= (uint64_t)ID << 48;
+}
+
Module *Decl::getOwningModuleSlow() const {
assert(isFromASTFile() && "Not from AST file?");
return getASTContext().getExternalSource()->getModule(getOwningModuleID());
@@ -2163,3 +2185,7 @@ DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C,
return DD;
}
+
+unsigned DeclIDBase::getLocalDeclIndex() const {
+ return ID & llvm::maskTrailingOnes<DeclID>(32);
+}
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 4a6e1d23161b..7f17e09adc29 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -1656,7 +1656,7 @@ bool ASTReader::ReadSLocEntry(int ID) {
unsigned NumFileDecls = Record[7];
if (NumFileDecls && ContextObj) {
- const LocalDeclID *FirstDecl = F->FileSortedDecls + Record[6];
+ const unaligned_decl_id_t *FirstDecl = F->FileSortedDecls + Record[6];
assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?");
FileDeclIDs[FID] =
FileDeclsInfo(F, llvm::ArrayRef(FirstDecl, NumFileDecls));
@@ -3375,26 +3375,11 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
"duplicate DECL_OFFSET record in AST file");
F.DeclOffsets = (const DeclOffset *)Blob.data();
F.LocalNumDecls = Record[0];
- unsigned LocalBaseDeclID = Record[1];
- F.BaseDeclID = getTotalNumDecls();
-
- if (F.LocalNumDecls > 0) {
- // Introduce the global -> local mapping for declarations within this
- // module.
- GlobalDeclMap.insert(std::make_pair(
- GlobalDeclID(getTotalNumDecls() + NUM_PREDEF_DECL_IDS), &F));
-
- // Introduce the local -> global mapping for declarations within this
- // module.
- F.DeclRemap.insertOrReplace(
- std::make_pair(LocalBaseDeclID, F.BaseDeclID - LocalBaseDeclID));
-
- // Introduce the global -> local mapping for declarations within this
- // module.
- F.GlobalToLocalDeclIDs[&F] = LocalBaseDeclID;
+ F.BaseDeclIndex = getTotalNumDecls();
+ if (F.LocalNumDecls > 0)
DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls);
- }
+
break;
}
@@ -3629,7 +3614,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
break;
case FILE_SORTED_DECLS:
- F.FileSortedDecls = (const LocalDeclID *)Blob.data();
+ F.FileSortedDecls = (const unaligned_decl_id_t *)Blob.data();
F.NumFileSortedDecls = Record[0];
break;
@@ -4056,7 +4041,6 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const {
RemapBuilder PreprocessedEntityRemap(F.PreprocessedEntityRemap);
RemapBuilder SubmoduleRemap(F.SubmoduleRemap);
RemapBuilder SelectorRemap(F.SelectorRemap);
- RemapBuilder DeclRemap(F.DeclRemap);
RemapBuilder TypeRemap(F.TypeRemap);
auto &ImportedModuleVector = F.TransitiveImports;
@@ -4095,8 +4079,6 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const {
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t SelectorIDOffset =
endian::readNext<uint32_t, llvm::endianness::little>(Data);
- uint32_t DeclIDOffset =
- endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t TypeIndexOffset =
endian::readNext<uint32_t, llvm::endianness::little>(Data);
@@ -4114,11 +4096,7 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const {
PreprocessedEntityRemap);
mapOffset(SubmoduleIDOffset, OM->BaseSubmoduleID, SubmoduleRemap);
mapOffset(SelectorIDOffset, OM->BaseSelectorID, SelectorRemap);
- mapOffset(DeclIDOffset, OM->BaseDeclID, DeclRemap);
mapOffset(TypeIndexOffset, OM->BaseTypeIndex, TypeRemap);
-
- // Global -> local mappings.
- F.GlobalToLocalDeclIDs[OM] = DeclIDOffset;
}
}
@@ -7642,18 +7620,25 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
GlobalDeclID ASTReader::getGlobalDeclID(ModuleFile &F,
LocalDeclID LocalID) const {
- DeclID ID = LocalID.get();
- if (ID < NUM_PREDEF_DECL_IDS)
- return GlobalDeclID(ID);
+ if (LocalID.get() < NUM_PREDEF_DECL_IDS)
+ return GlobalDeclID(LocalID.get());
+
+ unsigned OwningModuleFileIndex = LocalID.getModuleFileIndex();
+ DeclID ID = LocalID.getLocalDeclIndex();
if (!F.ModuleOffsetMap.empty())
ReadModuleOffsetMap(F);
- ContinuousRangeMap<DeclID, int, 2>::iterator I =
- F.DeclRemap.find(ID - NUM_PREDEF_DECL_IDS);
- assert(I != F.DeclRemap.end() && "Invalid index into decl index remap");
+ ModuleFile *OwningModuleFile =
+ OwningModuleFileIndex == 0
+ ? &F
+ : F.TransitiveImports[OwningModuleFileIndex - 1];
+
+ if (OwningModuleFileIndex == 0)
+ ID -= NUM_PREDEF_DECL_IDS;
- return GlobalDeclID(ID + I->second);
+ uint64_t NewModuleFileIndex = OwningModuleFile->Index + 1;
+ return GlobalDeclID(ID, NewModuleFileIndex);
}
bool ASTReader::isDeclIDFromModule(GlobalDeclID ID, ModuleFile &M) const {
@@ -7661,31 +7646,33 @@ bool ASTReader::isDeclIDFromModule(GlobalDeclID ID, ModuleFile &M) const {
if (ID.get() < NUM_PREDEF_DECL_IDS)
return false;
- return ID.get() - NUM_PREDEF_DECL_IDS >= M.BaseDeclID &&
- ID.get() - NUM_PREDEF_DECL_IDS < M.BaseDeclID + M.LocalNumDecls;
+ unsigned ModuleFileIndex = ID.getModuleFileIndex();
+ return M.Index == ModuleFileIndex - 1;
+}
+
+ModuleFile *ASTReader::getOwningModuleFile(GlobalDeclID ID) const {
+ // Predefined decls aren't from any module.
+ if (ID.get() < NUM_PREDEF_DECL_IDS)
+ return nullptr;
+
+ uint64_t ModuleFileIndex = ID.getModuleFileIndex();
+ assert(ModuleFileIndex && "Untranslated Local Decl?");
+
+ return &getModuleManager()[ModuleFileIndex - 1];
}
-ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) {
+ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) const {
if (!D->isFromASTFile())
return nullptr;
- GlobalDeclMapType::const_iterator I =
- GlobalDeclMap.find(GlobalDeclID(D->getGlobalID()));
- assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
- return I->second;
+
+ return getOwningModuleFile(GlobalDeclID(D->getGlobalID()));
}
SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) {
if (ID.get() < NUM_PREDEF_DECL_IDS)
return SourceLocation();
- unsigned Index = ID.get() - NUM_PREDEF_DECL_IDS;
-
- if (Index > DeclsLoaded.size()) {
- Error("declaration ID out-of-range for AST file");
- return SourceLocation();
- }
-
- if (Decl *D = DeclsLoaded[Index])
+ if (Decl *D = GetExistingDecl(ID))
return D->getLocation();
SourceLocation Loc;
@@ -7752,8 +7739,19 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) {
llvm_unreachable("PredefinedDeclIDs unknown enum value");
}
+unsigned ASTReader::translateGlobalDeclIDToIndex(GlobalDeclID GlobalID) const {
+ ModuleFile *OwningModuleFile = getOwningModuleFile(GlobalID);
+ if (!OwningModuleFile) {
+ assert(GlobalID.get() < NUM_PREDEF_DECL_IDS && "Untransalted Global ID?");
+ return GlobalID.get();
+ }
+
+ return OwningModuleFile->BaseDeclIndex + GlobalID.getLocalDeclIndex();
+}
+
Decl *ASTReader::GetExistingDecl(GlobalDeclID ID) {
assert(ContextObj && "reading decl with no AST context");
+
if (ID.get() < NUM_PREDEF_DECL_IDS) {
Decl *D = getPredefinedDecl(*ContextObj, (PredefinedDeclIDs)ID);
if (D) {
@@ -7766,7 +7764,7 @@ Decl *ASTReader::GetExistingDecl(GlobalDeclID ID) {
return D;
}
- unsigned Index = ID.get() - NUM_PREDEF_DECL_IDS;
+ unsigned Index = translateGlobalDeclIDToIndex(ID);
if (Index >= DeclsLoaded.size()) {
assert(0 && "declaration ID out-of-range for AST file");
@@ -7781,7 +7779,7 @@ Decl *ASTReader::GetDecl(GlobalDeclID ID) {
if (ID.get() < NUM_PREDEF_DECL_IDS)
return GetExistingDecl(ID);
- unsigned Index = ID.get() - NUM_PREDEF_DECL_IDS;
+ unsigned Index = translateGlobalDeclIDToIndex(ID);
if (Index >= DeclsLoaded.size()) {
assert(0 && "declaration ID out-of-range for AST file");
@@ -7800,20 +7798,31 @@ Decl *ASTReader::GetDecl(GlobalDeclID ID) {
LocalDeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M,
GlobalDeclID GlobalID) {
- DeclID ID = GlobalID.get();
- if (ID < NUM_PREDEF_DECL_IDS)
+ if (GlobalID.get() < NUM_PREDEF_DECL_IDS)
+ return LocalDeclID(GlobalID.get());
+
+ if (!M.ModuleOffsetMap.empty())
+ ReadModuleOffsetMap(M);
+
+ ModuleFile *Owner = getOwningModuleFile(GlobalID);
+ DeclID ID = GlobalID.getLocalDeclIndex();
+
+ if (Owner == &M) {
+ ID += NUM_PREDEF_DECL_IDS;
return LocalDeclID(ID);
+ }
- GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(GlobalID);
- assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
- ModuleFile *Owner = I->second;
+ uint64_t OrignalModuleFileIndex = 0;
+ for (unsigned I = 0; I < M.TransitiveImports.size(); I++)
+ if (M.TransitiveImports[I] == Owner) {
+ OrignalModuleFileIndex = I + 1;
+ break;
+ }
- llvm::DenseMap<ModuleFile *, DeclID>::iterator Pos =
- M.GlobalToLocalDeclIDs.find(Owner);
- if (Pos == M.GlobalToLocalDeclIDs.end())
+ if (!OrignalModuleFileIndex)
return LocalDeclID();
- return LocalDeclID(ID - Owner->BaseDeclID + Pos->second);
+ return LocalDeclID(ID, OrignalModuleFileIndex);
}
GlobalDeclID ASTReader::ReadDeclID(ModuleFile &F, const RecordData &Record,
@@ -7892,32 +7901,34 @@ void ASTReader::FindExternalLexicalDecls(
namespace {
-class DeclIDComp {
+class UnalignedDeclIDComp {
ASTReader &Reader;
ModuleFile &Mod;
public:
- DeclIDComp(ASTReader &Reader, ModuleFile &M) : Reader(Reader), Mod(M) {}
+ UnalignedDeclIDComp(ASTReader &Reader, ModuleFile &M)
+ : Reader(Reader), Mod(M) {}
- bool operator()(LocalDeclID L, LocalDeclID R) const {
+ bool operator()(unaligned_decl_id_t L, unaligned_decl_id_t R) const {
SourceLocation LHS = getLocation(L);
SourceLocation RHS = getLocation(R);
return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
}
- bool operator()(SourceLocation LHS, LocalDeclID R) const {
+ bool operator()(SourceLocation LHS, unaligned_decl_id_t R) const {
SourceLocation RHS = getLocation(R);
return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
}
- bool operator()(LocalDeclID L, SourceLocation RHS) const {
+ bool operator()(unaligned_decl_id_t L, SourceLocation RHS) const {
SourceLocation LHS = getLocation(L);
return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
}
- SourceLocation getLocation(LocalDeclID ID) const {
+ SourceLocation getLocation(unaligned_decl_id_t ID) const {
return Reader.getSourceManager().getFileLoc(
- Reader.getSourceLocationForDeclID(Reader.getGlobalDeclID(Mod, ID)));
+ Reader.getSourceLocationForDeclID(
+ Reader.getGlobalDeclID(Mod, (LocalDeclID)ID)));
}
};
@@ -7940,8 +7951,8 @@ void ASTReader::FindFileRegionDecls(FileID File,
BeginLoc = SM.getLocForStartOfFile(File).getLocWithOffset(Offset);
SourceLocation EndLoc = BeginLoc.getLocWithOffset(Length);
- DeclIDComp DIDComp(*this, *DInfo.Mod);
- ArrayRef<LocalDeclID>::iterator BeginIt =
+ UnalignedDeclIDComp DIDComp(*this, *DInfo.Mod);
+ ArrayRef<unaligned_decl_id_t>::iterator BeginIt =
llvm::lower_bound(DInfo.Decls, BeginLoc, DIDComp);
if (BeginIt != DInfo.Decls.begin())
--BeginIt;
@@ -7950,17 +7961,18 @@ void ASTReader::FindFileRegionDecls(FileID File,
// to backtrack until we find it otherwise we will fail to report that the
// region overlaps with an objc container.
while (BeginIt != DInfo.Decls.begin() &&
- GetDecl(getGlobalDeclID(*DInfo.Mod, *BeginIt))
+ GetDecl(getGlobalDeclID(*DInfo.Mod, (LocalDeclID)(*BeginIt)))
->isTopLevelDeclInObjCContainer())
--BeginIt;
- ArrayRef<LocalDeclID>::iterator EndIt =
+ ArrayRef<unaligned_decl_id_t>::iterator EndIt =
llvm::upper_bound(DInfo.Decls, EndLoc, DIDComp);
if (EndIt != DInfo.Decls.end())
++EndIt;
- for (ArrayRef<LocalDeclID>::iterator DIt = BeginIt; DIt != EndIt; ++DIt)
- Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt)));
+ for (ArrayRef<unaligned_decl_id_t>::iterator DIt = BeginIt; DIt != EndIt;
+ ++DIt)
+ Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, (LocalDeclID)(*DIt))));
}
bool
@@ -8167,7 +8179,6 @@ LLVM_DUMP_METHOD void ASTReader::dump() {
dumpModuleIDMap("Global bit offset map", GlobalBitOffsetsMap);
dumpModuleIDMap("Global source location entry map", GlobalSLocEntryMap);
dumpModuleIDMap("Global type map", GlobalTypeMap);
- dumpModuleIDMap("Global declaration map", GlobalDeclMap);
dumpModuleIDMap("Global identifier map", GlobalIdentifierMap);
dumpModuleIDMap("Global macro map", GlobalMacroMap);
dumpModuleIDMap("Global submodule map", GlobalSubmoduleMap);
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 61cc99d4df68..519c7d5c20fd 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -3244,11 +3244,10 @@ bool ASTReader::isConsumerInterestedIn(Decl *D) {
/// Get the correct cursor and offset for loading a declaration.
ASTReader::RecordLocation ASTReader::DeclCursorForID(GlobalDeclID ID,
SourceLocation &Loc) {
- GlobalDeclMapType::iterator I = GlobalDeclMap.find(ID);
- assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
- ModuleFile *M = I->second;
- const DeclOffset &DOffs =
- M->DeclOffsets[ID.get() - M->BaseDeclID - NUM_PREDEF_DECL_IDS];
+ ModuleFile *M = getOwningModuleFile(ID);
+ assert(M);
+ unsigned LocalDeclIndex = ID.getLocalDeclIndex();
+ const DeclOffset &DOffs = M->DeclOffsets[LocalDeclIndex];
Loc = ReadSourceLocation(*M, DOffs.getRawLoc());
return RecordLocation(M, DOffs.getBitOffset(M->DeclsBlockStartOffset));
}
@@ -3791,7 +3790,6 @@ void ASTReader::markIncompleteDeclChain(Decl *D) {
/// Read the declaration at the given offset from the AST file.
Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) {
- unsigned Index = ID.get() - NUM_PREDEF_DECL_IDS;
SourceLocation DeclLoc;
RecordLocation Loc = DeclCursorForID(ID, DeclLoc);
llvm::BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
@@ -4122,7 +4120,7 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) {
}
assert(D && "Unknown declaration reading AST file");
- LoadedDecl(Index, D);
+ LoadedDecl(translateGlobalDeclIDToIndex(ID), D);
// Set the DeclContext before doing any deserialization, to make sure internal
// calls to Decl::getASTContext() by Decl's methods will find the
// TranslationUnitDecl without crashing.
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 00b0e4808321..b9f1a4cbca21 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -3358,12 +3358,10 @@ void ASTWriter::WriteTypeDeclOffsets() {
Abbrev = std::make_shared<BitCodeAbbrev>();
Abbrev->Add(BitCodeAbbrevOp(DECL_OFFSET));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of declarations
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base decl ID
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block
unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
{
- RecordData::value_type Record[] = {DECL_OFFSET, DeclOffsets.size(),
- FirstDeclID.get() - NUM_PREDEF_DECL_IDS};
+ RecordData::value_type Record[] = {DECL_OFFSET, DeclOffsets.size()};
Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, bytes(DeclOffsets));
}
}
@@ -5417,7 +5415,6 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
M.NumPreprocessedEntities);
writeBaseIDOrNone(M.BaseSubmoduleID, M.LocalNumSubmodules);
writeBaseIDOrNone(M.BaseSelectorID, M.LocalNumSelectors);
- writeBaseIDOrNone(M.BaseDeclID, M.LocalNumDecls);
writeBaseIDOrNone(M.BaseTypeIndex, M.LocalNumTypes);
}
}
@@ -6609,13 +6606,11 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) {
// Note, this will get called multiple times, once one the reader starts up
// and again each time it's done reading a PCH or module.
- FirstDeclID = LocalDeclID(NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls());
FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes();
FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers();
FirstMacroID = NUM_PREDEF_MACRO_IDS + Chain->getTotalNumMacros();
FirstSubmoduleID = NUM_PREDEF_SUBMODULE_IDS + Chain->getTotalNumSubmodules();
FirstSelectorID = NUM_PREDEF_SELECTOR_IDS + Chain->getTotalNumSelectors();
- NextDeclID = FirstDeclID;
NextTypeID = FirstTypeID;
NextIdentID = FirstIdentID;
NextMacroID = FirstMacroID;
diff --git a/clang/lib/Serialization/ModuleFile.cpp b/clang/lib/Serialization/ModuleFile.cpp
index 2c42d33a8f5d..f64a59bd9489 100644
--- a/clang/lib/Serialization/ModuleFile.cpp
+++ b/clang/lib/Serialization/ModuleFile.cpp
@@ -87,7 +87,6 @@ LLVM_DUMP_METHOD void ModuleFile::dump() {
<< " Number of types: " << LocalNumTypes << '\n';
dumpLocalRemap("Type index local -> global map", TypeRemap);
- llvm::errs() << " Base decl ID: " << BaseDeclID << '\n'
+ llvm::errs() << " Base decl index: " << BaseDeclIndex << '\n'
<< " Number of decls: " << LocalNumDecls << '\n';
- dumpLocalRemap("Decl ID local -> global map", DeclRemap);
}
diff --git a/clang/test/Modules/no-transitive-decls-change.cppm b/clang/test/Modules/no-transitive-decls-change.cppm
new file mode 100644
index 000000000000..42ac061bc90b
--- /dev/null
+++ b/clang/test/Modules/no-transitive-decls-change.cppm
@@ -0,0 +1,112 @@
+// Testing that changing a declaration in an unused module file won't change
+// the BMI of the current module file.
+//
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 %t/m-partA.cppm -emit-reduced-module-interface -o %t/m-partA.pcm
+// RUN: %clang_cc1 -std=c++20 %t/m-partA.v1.cppm -emit-reduced-module-interface -o \
+// RUN: %t/m-partA.v1.pcm
+// RUN: %clang_cc1 -std=c++20 %t/m-partB.cppm -emit-reduced-module-interface -o %t/m-partB.pcm
+// RUN: %clang_cc1 -std=c++20 %t/m.cppm -emit-reduced-module-interface -o %t/m.pcm \
+// RUN: -fmodule-file=m:partA=%t/m-partA.pcm -fmodule-file=m:partB=%t/m-partB.pcm
+// RUN: %clang_cc1 -std=c++20 %t/m.cppm -emit-reduced-module-interface -o %t/m.v1.pcm \
+// RUN: -fmodule-file=m:partA=%t/m-partA.v1.pcm -fmodule-file=m:partB=%t/m-partB.pcm
+//
+// RUN: %clang_cc1 -std=c++20 %t/useBOnly.cppm -emit-reduced-module-interface -o %t/useBOnly.pcm \
+// RUN: -fmodule-file=m=%t/m.pcm -fmodule-file=m:partA=%t/m-partA.pcm \
+// RUN: -fmodule-file=m:partB=%t/m-partB.pcm
+// RUN: %clang_cc1 -std=c++20 %t/useBOnly.cppm -emit-reduced-module-interface -o %t/useBOnly.v1.pcm \
+// RUN: -fmodule-file=m=%t/m.v1.pcm -fmodule-file=m:partA=%t/m-partA.v1.pcm \
+// RUN: -fmodule-file=m:partB=%t/m-partB.pcm
+// Since useBOnly only uses partB from module M, the change in partA shouldn't affect
+// useBOnly.
+// RUN: diff %t/useBOnly.pcm %t/useBOnly.v1.pcm &> /dev/null
+
+//--- m-partA.cppm
+export module m:partA;
+
+namespace A_Impl {
+ inline int getAImpl() {
+ return 43;
+ }
+
+ inline int getA2Impl() {
+ return 43;
+ }
+}
+
+namespace A {
+ using A_Impl::getAImpl;
+}
+
+export inline int getA() {
+ return 43;
+}
+
+export inline int getA2(int) {
+ return 88;
+}
+
+//--- m-partA.v1.cppm
+export module m:partA;
+
+namespace A_Impl {
+ inline int getAImpl() {
+ return 43;
+ }
+
+ inline int getA2Impl() {
+ return 43;
+ }
+}
+
+namespace A {
+ using A_Impl::getAImpl;
+ // Adding a new declaration without introducing a new declaration name.
+ using A_Impl::getA2Impl;
+}
+
+inline int getA() {
+ return 43;
+}
+
+inline int getA2(int) {
+ return 88;
+}
+
+// Now we add a new declaration without introducing new identifier and new types.
+// The consuming module which didn't use m:partA completely is expected to be
+// not changed.
+inline int getA(int) {
+ return 88;
+}
+
+//--- m-partB.cppm
+export module m:partB;
+
+export inline int getB() {
+ return 430;
+}
+
+//--- m.cppm
+export module m;
+export import :partA;
+export import :partB;
+
+//--- useBOnly.cppm
+export module useBOnly;
+import m;
+
+export inline int get() {
+ return getB();
+}
+
+//--- useAOnly.cppm
+export module useAOnly;
+import m;
+
+export inline int get() {
+ A<int> a;
+ return a.getValue();
+}