-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[Modules] Delay deserialization of preferred_name attribute at r… #122726
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b611109
e701387
eb6b915
f57f83f
1d8676b
f685717
9174328
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1205,6 +1205,24 @@ class ASTReader | |
/// been completed. | ||
std::deque<PendingDeclContextInfo> PendingDeclContextInfos; | ||
|
||
/// Deserialization of some attributes must be deferred since they refer | ||
/// to themselves in their type (e.g., preferred_name attribute refers to the | ||
/// typedef that refers back to the template specialization of the template | ||
/// that the attribute is attached to). | ||
/// More attributes that store TypeSourceInfo might be potentially affected, | ||
/// see https://github.com/llvm/llvm-project/issues/56490 for details. | ||
struct DeferredAttribute { | ||
// Index of the deferred attribute in the Record of the TargetedDecl. | ||
uint64_t RecordIdx; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Add a comment to the field. e.g., something like the Index of the delayed attribute in the Record of the targeted decl. |
||
// Decl to attach a deferred attribute to. | ||
Decl *TargetedDecl; | ||
}; | ||
|
||
/// The collection of Decls that have been loaded but some of their attributes | ||
/// have been deferred, paired with the index inside the record pointing | ||
/// at the skipped attribute. | ||
SmallVector<DeferredAttribute> PendingDeferredAttributes; | ||
|
||
template <typename DeclTy> | ||
using DuplicateObjCDecls = std::pair<DeclTy *, DeclTy *>; | ||
|
||
|
@@ -1551,6 +1569,7 @@ class ASTReader | |
void loadPendingDeclChain(Decl *D, uint64_t LocalOffset); | ||
void loadObjCCategories(GlobalDeclID ID, ObjCInterfaceDecl *D, | ||
unsigned PreviousGeneration = 0); | ||
void loadDeferredAttribute(const DeferredAttribute &DA); | ||
|
||
RecordLocation getLocalBitOffset(uint64_t GlobalOffset); | ||
uint64_t getGlobalBitOffset(ModuleFile &M, uint64_t LocalOffset); | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -10079,6 +10079,11 @@ void ASTReader::finishPendingActions() { | |||||||||||||||||||||
} | ||||||||||||||||||||||
PendingDeducedVarTypes.clear(); | ||||||||||||||||||||||
|
||||||||||||||||||||||
// Load the delayed preferred name attributes. | ||||||||||||||||||||||
for (unsigned I = 0; I != PendingDeferredAttributes.size(); ++I) | ||||||||||||||||||||||
loadDeferredAttribute(PendingDeferredAttributes[I]); | ||||||||||||||||||||||
PendingDeferredAttributes.clear(); | ||||||||||||||||||||||
Comment on lines
+10082
to
+10085
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Technically, it is possible to update There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. The original snippet seems more concise though, so it might be preferable to stick to it for now. |
||||||||||||||||||||||
|
||||||||||||||||||||||
// For each decl chain that we wanted to complete while deserializing, mark | ||||||||||||||||||||||
// it as "still needs to be completed". | ||||||||||||||||||||||
for (unsigned I = 0; I != PendingIncompleteDeclChains.size(); ++I) { | ||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -612,7 +612,7 @@ void ASTDeclReader::VisitDecl(Decl *D) { | |
|
||
if (HasAttrs) { | ||
AttrVec Attrs; | ||
Record.readAttributes(Attrs); | ||
Record.readAttributes(Attrs, D); | ||
// Avoid calling setAttrs() directly because it uses Decl::getASTContext() | ||
// internally which is unsafe during derialization. | ||
D->setAttrsImpl(Attrs, Reader.getContext()); | ||
|
@@ -3088,6 +3088,8 @@ class AttrReader { | |
return Reader.readInt(); | ||
} | ||
|
||
uint64_t peekInts(unsigned N) { return Reader.peekInts(N); } | ||
|
||
bool readBool() { return Reader.readBool(); } | ||
|
||
SourceRange readSourceRange() { | ||
|
@@ -3118,18 +3120,29 @@ class AttrReader { | |
return Reader.readVersionTuple(); | ||
} | ||
|
||
void skipInt() { Reader.skipInts(1); } | ||
|
||
void skipInts(unsigned N) { Reader.skipInts(N); } | ||
|
||
unsigned getCurrentIdx() { return Reader.getIdx(); } | ||
|
||
OMPTraitInfo *readOMPTraitInfo() { return Reader.readOMPTraitInfo(); } | ||
|
||
template <typename T> T *readDeclAs() { return Reader.readDeclAs<T>(); } | ||
}; | ||
} | ||
|
||
/// Reads one attribute from the current stream position, advancing Idx. | ||
Attr *ASTRecordReader::readAttr() { | ||
AttrReader Record(*this); | ||
auto V = Record.readInt(); | ||
if (!V) | ||
return nullptr; | ||
|
||
// Read and ignore the skip count, since attribute deserialization is not | ||
// deferred on this pass. | ||
Record.skipInt(); | ||
|
||
Attr *New = nullptr; | ||
// Kind is stored as a 1-based integer because 0 is used to indicate a null | ||
// Attr pointer. | ||
|
@@ -3159,13 +3172,28 @@ Attr *ASTRecordReader::readAttr() { | |
return New; | ||
} | ||
|
||
/// Reads attributes from the current stream position. | ||
void ASTRecordReader::readAttributes(AttrVec &Attrs) { | ||
/// Reads attributes from the current stream position, advancing Idx. | ||
/// For some attributes (where type depends on itself recursively), defer | ||
/// reading the attribute until the type has been read. | ||
void ASTRecordReader::readAttributes(AttrVec &Attrs, Decl *D) { | ||
for (unsigned I = 0, E = readInt(); I != E; ++I) | ||
if (auto *A = readAttr()) | ||
if (auto *A = readOrDeferAttrFor(D)) | ||
Attrs.push_back(A); | ||
} | ||
|
||
/// Reads one attribute from the current stream position, advancing Idx. | ||
/// For some attributes (where type depends on itself recursively), defer | ||
/// reading the attribute until the type has been read. | ||
Attr *ASTRecordReader::readOrDeferAttrFor(Decl *D) { | ||
AttrReader Record(*this); | ||
unsigned SkipCount = Record.peekInts(1); | ||
if (!SkipCount) | ||
return readAttr(); | ||
Reader->PendingDeferredAttributes.push_back({Record.getCurrentIdx(), D}); | ||
Record.skipInts(SkipCount); | ||
return nullptr; | ||
} | ||
|
||
//===----------------------------------------------------------------------===// | ||
// ASTReader Implementation | ||
//===----------------------------------------------------------------------===// | ||
|
@@ -4424,6 +4452,49 @@ void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) { | |
ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent); | ||
} | ||
|
||
void ASTReader::loadDeferredAttribute(const DeferredAttribute &DA) { | ||
Decl *D = DA.TargetedDecl; | ||
ModuleFile *M = getOwningModuleFile(D); | ||
|
||
unsigned LocalDeclIndex = D->getGlobalID().getLocalDeclIndex(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought we might need to store the indices separately, but having the declaration around we actually have enough to look up the bitstream position. Nice trick, kudos for coming up with this! |
||
const DeclOffset &DOffs = M->DeclOffsets[LocalDeclIndex]; | ||
RecordLocation Loc(M, DOffs.getBitOffset(M->DeclsBlockStartOffset)); | ||
|
||
llvm::BitstreamCursor &Cursor = Loc.F->DeclsCursor; | ||
SavedStreamPosition SavedPosition(Cursor); | ||
if (llvm::Error Err = Cursor.JumpToBit(Loc.Offset)) { | ||
Error(std::move(Err)); | ||
} | ||
|
||
Expected<unsigned> MaybeCode = Cursor.ReadCode(); | ||
if (!MaybeCode) { | ||
llvm::report_fatal_error( | ||
Twine("ASTReader::loadPreferredNameAttribute failed reading code: ") + | ||
toString(MaybeCode.takeError())); | ||
} | ||
unsigned Code = MaybeCode.get(); | ||
|
||
ASTRecordReader Record(*this, *Loc.F); | ||
Expected<unsigned> MaybeRecCode = Record.readRecord(Cursor, Code); | ||
if (!MaybeRecCode) { | ||
llvm::report_fatal_error( | ||
Twine( | ||
"ASTReader::loadPreferredNameAttribute failed reading rec code: ") + | ||
toString(MaybeCode.takeError())); | ||
} | ||
unsigned RecCode = MaybeRecCode.get(); | ||
if (RecCode < DECL_TYPEDEF || RecCode > DECL_LAST) { | ||
llvm::report_fatal_error( | ||
Twine("ASTReader::loadPreferredNameAttribute failed reading rec code: " | ||
"expected valid DeclCode") + | ||
toString(MaybeCode.takeError())); | ||
} | ||
|
||
Record.skipInts(DA.RecordIdx); | ||
Attr *A = Record.readAttr(); | ||
getContext().getDeclAttrs(D).push_back(A); | ||
} | ||
|
||
namespace { | ||
|
||
/// Given an ObjC interface, goes through the modules and links to the | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,10 +53,16 @@ import A; | |
export using ::foo_templ; | ||
|
||
//--- Use1.cpp | ||
import A; // expected-[email protected]:8 {{attribute declaration must precede definition}} | ||
#include "foo.h" // [email protected]:9 {{previous definition is here}} | ||
|
||
// expected-no-diagnostics | ||
import A; | ||
#include "foo.h" | ||
//--- Use2.cpp | ||
// expected-no-diagnostics | ||
#include "foo.h" | ||
import A; | ||
|
||
//--- Use3.cpp | ||
#include "foo.h" | ||
import A; | ||
foo test; | ||
int size = test.size(); // expected-error {{no member named 'size' in 'foo'}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it is better to add comment here to explain why we want to defer PreferredName.