Skip to content

Commit b611109

Browse files
committed
[WIP][Modules] Delay deserialization of preferred_name attribute at record level.
1 parent 85ca551 commit b611109

File tree

6 files changed

+142
-13
lines changed

6 files changed

+142
-13
lines changed

clang/include/clang/Serialization/ASTReader.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,23 @@ class ASTReader
12051205
/// been completed.
12061206
std::deque<PendingDeclContextInfo> PendingDeclContextInfos;
12071207

1208+
/// Deserialization of some attributes must be deferred since they refer
1209+
/// to themselves in their type (e.g., preferred_name attribute refers to the
1210+
/// typedef that refers back to the template specialization of the template
1211+
/// that the attribute is attached to).
1212+
/// More attributes that store TypeSourceInfo might be potentially affected,
1213+
/// see https://github.com/llvm/llvm-project/issues/56490 for details.
1214+
struct DeferredAttribute {
1215+
uint64_t RecordIdx;
1216+
// Decl to attach a deferred attribute to.
1217+
Decl *ParentDecl;
1218+
};
1219+
1220+
/// The collection of Decls that have been loaded but some of their attributes
1221+
/// have been deferred, paired with the index inside the record pointing
1222+
/// at the skipped attribute.
1223+
SmallVector<DeferredAttribute> PendingDeferredAttributes;
1224+
12081225
template <typename DeclTy>
12091226
using DuplicateObjCDecls = std::pair<DeclTy *, DeclTy *>;
12101227

@@ -1551,6 +1568,7 @@ class ASTReader
15511568
void loadPendingDeclChain(Decl *D, uint64_t LocalOffset);
15521569
void loadObjCCategories(GlobalDeclID ID, ObjCInterfaceDecl *D,
15531570
unsigned PreviousGeneration = 0);
1571+
void loadDeferredAttribute(const DeferredAttribute &DA);
15541572

15551573
RecordLocation getLocalBitOffset(uint64_t GlobalOffset);
15561574
uint64_t getGlobalBitOffset(ModuleFile &M, uint64_t LocalOffset);

clang/include/clang/Serialization/ASTRecordReader.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,12 @@ class ASTRecordReader
337337
/// Reads attributes from the current stream position, advancing Idx.
338338
void readAttributes(AttrVec &Attrs);
339339

340+
/// Reads one attribute from the current stream position, advancing Idx.
341+
Attr *readOrDeferAttr(Decl *D);
342+
343+
/// Reads attributes from the current stream position, advancing Idx.
344+
void readOrDeferAttributes(AttrVec &Attrs, Decl *D);
345+
340346
/// Read an BTFTypeTagAttr object.
341347
BTFTypeTagAttr *readBTFTypeTagAttr() {
342348
return cast<BTFTypeTagAttr>(readAttr());
@@ -355,6 +361,10 @@ class ASTRecordReader
355361
SwitchCase *getSwitchCaseWithID(unsigned ID) {
356362
return Reader->getSwitchCaseWithID(ID);
357363
}
364+
365+
private:
366+
Attr *readOrDeferAttrImpl(Decl *D);
367+
void readOrDeferAttributesImpl(AttrVec &Attrs, Decl *D);
358368
};
359369

360370
/// Helper class that saves the current stream position and

clang/lib/Serialization/ASTReader.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10079,6 +10079,11 @@ void ASTReader::finishPendingActions() {
1007910079
}
1008010080
PendingDeducedVarTypes.clear();
1008110081

10082+
// Load the delayed preferred name attributes.
10083+
for (unsigned I = 0; I != PendingDeferredAttributes.size(); ++I)
10084+
loadDeferredAttribute(PendingDeferredAttributes[I]);
10085+
PendingDeferredAttributes.clear();
10086+
1008210087
// For each decl chain that we wanted to complete while deserializing, mark
1008310088
// it as "still needs to be completed".
1008410089
for (unsigned I = 0; I != PendingIncompleteDeclChains.size(); ++I) {

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 86 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ void ASTDeclReader::VisitDecl(Decl *D) {
612612

613613
if (HasAttrs) {
614614
AttrVec Attrs;
615-
Record.readAttributes(Attrs);
615+
Record.readOrDeferAttributes(Attrs, D);
616616
// Avoid calling setAttrs() directly because it uses Decl::getASTContext()
617617
// internally which is unsafe during derialization.
618618
D->setAttrsImpl(Attrs, Reader.getContext());
@@ -3118,13 +3118,18 @@ class AttrReader {
31183118
return Reader.readVersionTuple();
31193119
}
31203120

3121+
void skipInts(unsigned N) { Reader.skipInts(N); }
3122+
3123+
unsigned getCurrentIdx() { return Reader.getIdx(); }
3124+
31213125
OMPTraitInfo *readOMPTraitInfo() { return Reader.readOMPTraitInfo(); }
31223126

31233127
template <typename T> T *readDeclAs() { return Reader.readDeclAs<T>(); }
31243128
};
31253129
}
31263130

3127-
Attr *ASTRecordReader::readAttr() {
3131+
/// Reads one attribute from the current stream position, advancing Idx.
3132+
Attr *ASTRecordReader::readOrDeferAttrImpl(Decl *D) {
31283133
AttrReader Record(*this);
31293134
auto V = Record.readInt();
31303135
if (!V)
@@ -3134,6 +3139,20 @@ Attr *ASTRecordReader::readAttr() {
31343139
// Kind is stored as a 1-based integer because 0 is used to indicate a null
31353140
// Attr pointer.
31363141
auto Kind = static_cast<attr::Kind>(V - 1);
3142+
// Some attributes refer to themselves during deserialization, thus
3143+
// their deserialization must be deferred until their underlying type
3144+
// is resolved.
3145+
if (Kind == attr::PreferredName) {
3146+
if (D != nullptr) {
3147+
Reader->PendingDeferredAttributes.push_back(
3148+
{Record.getCurrentIdx() - 1, D});
3149+
auto SkipCount = Record.readInt();
3150+
Record.skipInts(SkipCount);
3151+
return nullptr;
3152+
}
3153+
// Ignore the skip count when resolving pending actions.
3154+
Record.readInt();
3155+
}
31373156
ASTContext &Context = getContext();
31383157

31393158
IdentifierInfo *AttrName = Record.readIdentifier();
@@ -3159,13 +3178,31 @@ Attr *ASTRecordReader::readAttr() {
31593178
return New;
31603179
}
31613180

3162-
/// Reads attributes from the current stream position.
3163-
void ASTRecordReader::readAttributes(AttrVec &Attrs) {
3181+
void ASTRecordReader::readOrDeferAttributesImpl(AttrVec &Attrs, Decl *D) {
31643182
for (unsigned I = 0, E = readInt(); I != E; ++I)
3165-
if (auto *A = readAttr())
3183+
if (auto *A = readOrDeferAttr(D))
31663184
Attrs.push_back(A);
31673185
}
31683186

3187+
Attr *ASTRecordReader::readAttr() { return readOrDeferAttrImpl(nullptr); }
3188+
3189+
/// Reads attributes from the current stream position.
3190+
void ASTRecordReader::readAttributes(AttrVec &Attrs) {
3191+
readOrDeferAttributesImpl(Attrs, nullptr);
3192+
}
3193+
3194+
/// Reads one attribute from the current stream position, advancing Idx.
3195+
/// For some attributes (where type depends on itself recursively), defer
3196+
/// reading the attribute until the type has been read.
3197+
Attr *ASTRecordReader::readOrDeferAttr(Decl *D) { return readOrDeferAttrImpl(D); }
3198+
3199+
/// Reads attributes from the current stream position, advancing Idx.
3200+
/// For some attributes (where type depends on itself recursively), defer
3201+
/// reading the attribute until the type has been read.
3202+
void ASTRecordReader::readOrDeferAttributes(AttrVec &Attrs, Decl *D) {
3203+
readOrDeferAttributesImpl(Attrs, D);
3204+
}
3205+
31693206
//===----------------------------------------------------------------------===//
31703207
// ASTReader Implementation
31713208
//===----------------------------------------------------------------------===//
@@ -4424,6 +4461,50 @@ void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) {
44244461
ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent);
44254462
}
44264463

4464+
void ASTReader::loadDeferredAttribute(
4465+
const DeferredAttribute &DA) {
4466+
Decl *D = DA.ParentDecl;
4467+
ModuleFile *M = getOwningModuleFile(D);
4468+
4469+
unsigned LocalDeclIndex = D->getGlobalID().getLocalDeclIndex();
4470+
const DeclOffset &DOffs = M->DeclOffsets[LocalDeclIndex];
4471+
RecordLocation Loc(M, DOffs.getBitOffset(M->DeclsBlockStartOffset));
4472+
4473+
llvm::BitstreamCursor &Cursor = Loc.F->DeclsCursor;
4474+
SavedStreamPosition SavedPosition(Cursor);
4475+
if (llvm::Error Err = Cursor.JumpToBit(Loc.Offset)) {
4476+
Error(std::move(Err));
4477+
}
4478+
4479+
Expected<unsigned> MaybeCode = Cursor.ReadCode();
4480+
if (!MaybeCode) {
4481+
llvm::report_fatal_error(
4482+
Twine("ASTReader::loadPreferredNameAttribute failed reading code: ") +
4483+
toString(MaybeCode.takeError()));
4484+
}
4485+
unsigned Code = MaybeCode.get();
4486+
4487+
ASTRecordReader Record(*this, *Loc.F);
4488+
Expected<unsigned> MaybeRecCode = Record.readRecord(Cursor, Code);
4489+
if (!MaybeRecCode) {
4490+
llvm::report_fatal_error(
4491+
Twine(
4492+
"ASTReader::loadPreferredNameAttribute failed reading rec code: ") +
4493+
toString(MaybeCode.takeError()));
4494+
}
4495+
unsigned RecCode = MaybeRecCode.get();
4496+
if (RecCode < DECL_TYPEDEF || RecCode > DECL_LAST) {
4497+
llvm::report_fatal_error(
4498+
Twine("ASTReader::loadPreferredNameAttribute failed reading rec code: "
4499+
"expected valid DeclCode") +
4500+
toString(MaybeCode.takeError()));
4501+
}
4502+
4503+
Record.skipInts(DA.RecordIdx);
4504+
Attr *A = Record.readOrDeferAttr(nullptr);
4505+
getContext().getDeclAttrs(D).push_back(A);
4506+
}
4507+
44274508
namespace {
44284509

44294510
/// Given an ObjC interface, goes through the modules and links to the

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "clang/AST/Type.h"
3838
#include "clang/AST/TypeLoc.h"
3939
#include "clang/AST/TypeLocVisitor.h"
40+
#include "clang/Basic/AttrKinds.h"
4041
#include "clang/Basic/Diagnostic.h"
4142
#include "clang/Basic/DiagnosticOptions.h"
4243
#include "clang/Basic/FileEntry.h"
@@ -4906,15 +4907,17 @@ void ASTWriter::WriteModuleFileExtension(Sema &SemaRef,
49064907

49074908
void ASTRecordWriter::AddAttr(const Attr *A) {
49084909
auto &Record = *this;
4909-
// FIXME: Clang can't handle the serialization/deserialization of
4910-
// preferred_name properly now. See
4911-
// https://github.com/llvm/llvm-project/issues/56490 for example.
4912-
if (!A || (isa<PreferredNameAttr>(A) &&
4913-
Writer->isWritingStdCXXNamedModules()))
4910+
if (!A)
49144911
return Record.push_back(0);
49154912

49164913
Record.push_back(A->getKind() + 1); // FIXME: stable encoding, target attrs
49174914

4915+
auto SkipIdx = Record.size();
4916+
if (A->getKind() == attr::PreferredName) {
4917+
// Add placeholder for the size of preferred_name attribute.
4918+
Record.push_back(0);
4919+
}
4920+
49184921
Record.AddIdentifierRef(A->getAttrName());
49194922
Record.AddIdentifierRef(A->getScopeName());
49204923
Record.AddSourceRange(A->getRange());
@@ -4925,6 +4928,12 @@ void ASTRecordWriter::AddAttr(const Attr *A) {
49254928
Record.push_back(A->isRegularKeywordAttribute());
49264929

49274930
#include "clang/Serialization/AttrPCHWrite.inc"
4931+
4932+
if (A->getKind() == attr::PreferredName) {
4933+
// Record the actual size of preferred_name attribute (-1 to count the
4934+
// placeholder).
4935+
Record[SkipIdx] = Record.size() - SkipIdx - 1;
4936+
}
49284937
}
49294938

49304939
/// Emit the list of attributes to the specified record.

clang/test/Modules/preferred_name.cppm

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,16 @@ import A;
5353
export using ::foo_templ;
5454

5555
//--- Use1.cpp
56-
import A; // expected-[email protected]:8 {{attribute declaration must precede definition}}
57-
#include "foo.h" // [email protected]:9 {{previous definition is here}}
58-
56+
// expected-no-diagnostics
57+
import A;
58+
#include "foo.h"
5959
//--- Use2.cpp
6060
// expected-no-diagnostics
6161
#include "foo.h"
6262
import A;
63+
64+
//--- Use3.cpp
65+
#include "foo.h"
66+
import A;
67+
foo test;
68+
int size = test.size(); // expected-error {{no member named 'size' in 'foo'}}

0 commit comments

Comments
 (0)