-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[WIP] [Modules] Delay reading type source info of the preferred_name attribute. #122250
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
0a61557
b967053
183a54d
bffc612
487f6d0
50f4ea7
7d92fb2
97220d3
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 |
---|---|---|
|
@@ -337,6 +337,14 @@ class ASTRecordReader | |
/// Reads attributes from the current stream position, advancing Idx. | ||
void readAttributes(AttrVec &Attrs); | ||
|
||
/// Reads one attribute from the current stream position, advancing Idx. | ||
/// Parent Decl is provided to delay attribute deserialization. | ||
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. The lazy deserialization is a subtle difference, could we name the functions appropriately and "scary", e.g. 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. Done in #122726. |
||
Attr *readAttr(Decl *D); | ||
|
||
/// Reads attributes from the current stream position, advancing Idx. | ||
/// Parent Decl is provided to delay attribute deserialization. | ||
void readAttributes(AttrVec &Attrs, Decl *D); | ||
|
||
/// Read an BTFTypeTagAttr object. | ||
BTFTypeTagAttr *readBTFTypeTagAttr() { | ||
return cast<BTFTypeTagAttr>(readAttr()); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9860,6 +9860,33 @@ void ASTReader::finishPendingActions() { | |
} | ||
PendingDeducedVarTypes.clear(); | ||
|
||
ASTContext &Context = getContext(); | ||
for (unsigned I = 0; I != PendingPreferredNameAttributes.size(); ++I) { | ||
auto *D = PendingPreferredNameAttributes[I].D; | ||
QualType InfoTy = GetType(PendingPreferredNameAttributes[I].TypeID); | ||
TypeSourceInfo *TInfo = nullptr; | ||
if (!InfoTy.isNull()) { | ||
TInfo = getContext().CreateTypeSourceInfo(InfoTy); | ||
if (auto Loc = TInfo->getTypeLoc().getAs<ElaboratedTypeLoc>()) { | ||
Loc.setElaboratedKeywordLoc( | ||
PendingPreferredNameAttributes[I].ElaboratedTypedefSL); | ||
Loc.setQualifierLoc(PendingPreferredNameAttributes[I].NestedNameSL); | ||
if (auto TypedefLoc = Loc.getNextTypeLoc().getAs<TypedefTypeLoc>()) | ||
TypedefLoc.setNameLoc(PendingPreferredNameAttributes[I].TypedefSL); | ||
} | ||
} | ||
|
||
AttrVec &Attrs = getContext().getDeclAttrs(D); | ||
PreferredNameAttr *New = new (Context) PreferredNameAttr( | ||
Context, PendingPreferredNameAttributes[I].Info, TInfo); | ||
cast<InheritableAttr>(New)->setInherited( | ||
PendingPreferredNameAttributes[I].isInherited); | ||
New->setImplicit(PendingPreferredNameAttributes[I].isImplicit); | ||
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. Duplicating the code here may lead to errors later. Could we ensure that's the only code path that's being used to read preferred_name attributes? That would entail asserting that the common 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. Obsolete with #122726. |
||
New->setPackExpansion(PendingPreferredNameAttributes[I].isPackExpansion); | ||
Attrs.push_back(New); | ||
} | ||
PendingPreferredNameAttributes.clear(); | ||
|
||
// 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 |
---|---|---|
|
@@ -638,7 +638,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()); | ||
|
@@ -3129,42 +3129,86 @@ class AttrReader { | |
OMPTraitInfo *readOMPTraitInfo() { return Reader.readOMPTraitInfo(); } | ||
|
||
template <typename T> T *readDeclAs() { return Reader.readDeclAs<T>(); } | ||
|
||
AttributeCommonInfo readAttributeCommonInfo() { | ||
IdentifierInfo *AttrName = readIdentifier(); | ||
IdentifierInfo *ScopeName = readIdentifier(); | ||
SourceRange AttrRange = readSourceRange(); | ||
SourceLocation ScopeLoc = readSourceLocation(); | ||
unsigned ParsedKind = readInt(); | ||
unsigned Syntax = readInt(); | ||
unsigned SpellingIndex = readInt(); | ||
bool IsAlignas = (ParsedKind == AttributeCommonInfo::AT_Aligned && | ||
Syntax == AttributeCommonInfo::AS_Keyword && | ||
SpellingIndex == AlignedAttr::Keyword_alignas); | ||
bool IsRegularKeywordAttribute = readBool(); | ||
|
||
AttributeCommonInfo Info(AttrName, ScopeName, AttrRange, ScopeLoc, | ||
AttributeCommonInfo::Kind(ParsedKind), | ||
{AttributeCommonInfo::Syntax(Syntax), | ||
SpellingIndex, IsAlignas, | ||
IsRegularKeywordAttribute}); | ||
return Info; | ||
} | ||
|
||
std::optional<attr::Kind> readAttrKind() { | ||
auto V = readInt(); | ||
if (!V) | ||
return {}; | ||
|
||
// Kind is stored as a 1-based integer because 0 is used to indicate a null | ||
// Attr pointer. | ||
return static_cast<attr::Kind>(V - 1); | ||
} | ||
|
||
Attr *createAttribute(attr::Kind Kind, AttributeCommonInfo Info) { | ||
ASTContext &Context = Reader.getContext(); | ||
Attr *New = nullptr; | ||
auto Record = *this; | ||
#include "clang/Serialization/AttrPCHRead.inc" | ||
|
||
assert(New && "Unable to decode attribute?"); | ||
return New; | ||
} | ||
}; | ||
} | ||
} // namespace | ||
|
||
Attr *ASTRecordReader::readAttr() { | ||
AttrReader Record(*this); | ||
auto V = Record.readInt(); | ||
if (!V) | ||
attr::Kind Kind; | ||
if (auto KindOpt = Record.readAttrKind(); !KindOpt) | ||
return nullptr; | ||
else | ||
Kind = *KindOpt; | ||
|
||
Attr *New = nullptr; | ||
// Kind is stored as a 1-based integer because 0 is used to indicate a null | ||
// Attr pointer. | ||
auto Kind = static_cast<attr::Kind>(V - 1); | ||
ASTContext &Context = getContext(); | ||
|
||
IdentifierInfo *AttrName = Record.readIdentifier(); | ||
IdentifierInfo *ScopeName = Record.readIdentifier(); | ||
SourceRange AttrRange = Record.readSourceRange(); | ||
SourceLocation ScopeLoc = Record.readSourceLocation(); | ||
unsigned ParsedKind = Record.readInt(); | ||
unsigned Syntax = Record.readInt(); | ||
unsigned SpellingIndex = Record.readInt(); | ||
bool IsAlignas = (ParsedKind == AttributeCommonInfo::AT_Aligned && | ||
Syntax == AttributeCommonInfo::AS_Keyword && | ||
SpellingIndex == AlignedAttr::Keyword_alignas); | ||
bool IsRegularKeywordAttribute = Record.readBool(); | ||
|
||
AttributeCommonInfo Info(AttrName, ScopeName, AttrRange, ScopeLoc, | ||
AttributeCommonInfo::Kind(ParsedKind), | ||
{AttributeCommonInfo::Syntax(Syntax), SpellingIndex, | ||
IsAlignas, IsRegularKeywordAttribute}); | ||
AttributeCommonInfo Info = Record.readAttributeCommonInfo(); | ||
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. Instead of doing this, could we have a single function (e.g. That way, we only have one copy of the code and 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, done in #122726. |
||
return Record.createAttribute(Kind, Info); | ||
} | ||
|
||
#include "clang/Serialization/AttrPCHRead.inc" | ||
Attr *ASTRecordReader::readAttr(Decl *D) { | ||
AttrReader Record(*this); | ||
attr::Kind Kind; | ||
if (auto KindOpt = Record.readAttrKind(); !KindOpt) | ||
return nullptr; | ||
else | ||
Kind = *KindOpt; | ||
|
||
AttributeCommonInfo Info = Record.readAttributeCommonInfo(); | ||
if (Kind == attr::PreferredName) { | ||
bool isInherited = Record.readInt(); | ||
bool isImplicit = Record.readInt(); | ||
bool isPackExpansion = Record.readInt(); | ||
serialization::TypeID TypeID = getGlobalTypeID(Record.readInt()); | ||
SourceLocation ElaboratedTypedefSL = Record.readSourceLocation(); | ||
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. This code assumes a specific structure of the We could probably make the code here more robust by also updating serialization so that it writes only the source locations we read here, rather than call the generic method for serializing Could we instead try postponing reading the whole attribute? I bet this approach would end up being much simpler and will allow avoiding the duplication of serialization/deseriazliation logic. Moreover, it can be generalized to more attribute if the need arises. 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. Thank you for the suggestion, the draft implementation is in #122726. |
||
NestedNameSpecifierLoc NestedNameSL = readNestedNameSpecifierLoc(); | ||
SourceLocation TypedefSL = Record.readSourceLocation(); | ||
Reader->PendingPreferredNameAttributes.push_back( | ||
{D, Info, TypeID, isInherited, isImplicit, isPackExpansion, | ||
ElaboratedTypedefSL, NestedNameSL, TypedefSL}); | ||
return nullptr; | ||
} | ||
|
||
assert(New && "Unable to decode attribute?"); | ||
return New; | ||
return Record.createAttribute(Kind, Info); | ||
} | ||
|
||
/// Reads attributes from the current stream position. | ||
|
@@ -3174,6 +3218,12 @@ void ASTRecordReader::readAttributes(AttrVec &Attrs) { | |
Attrs.push_back(A); | ||
} | ||
|
||
void ASTRecordReader::readAttributes(AttrVec &Attrs, Decl *D) { | ||
for (unsigned I = 0, E = readInt(); I != E; ++I) | ||
if (auto *A = readAttr(D)) | ||
Attrs.push_back(A); | ||
} | ||
|
||
//===----------------------------------------------------------------------===// | ||
// ASTReader Implementation | ||
//===----------------------------------------------------------------------===// | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,10 +53,17 @@ import A; | |
export using ::foo_templ; | ||
|
||
//--- Use1.cpp | ||
import A; // [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.
Why not
SmallVector
like the above?For a slightly higher efficiency and for consistency with the code above?
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.
Exactly. But I'm not sure if this matters much.