diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index f739fe688c110..d1491e1f9e426 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -13,7 +13,9 @@ #ifndef LLVM_CLANG_SERIALIZATION_ASTREADER_H #define LLVM_CLANG_SERIALIZATION_ASTREADER_H +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Type.h" +#include "clang/Basic/AttributeCommonInfo.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/IdentifierTable.h" @@ -1156,6 +1158,19 @@ class ASTReader SmallVector, 16> PendingDeducedVarTypes; + struct PendingPreferredNameAttribute { + Decl *D; + AttributeCommonInfo Info; + serialization::TypeID TypeID; + bool isInherited; + bool isImplicit; + bool isPackExpansion; + SourceLocation ElaboratedTypedefSL; + NestedNameSpecifierLoc NestedNameSL; + SourceLocation TypedefSL; + }; + std::deque PendingPreferredNameAttributes; + /// The list of redeclaration chains that still need to be /// reconstructed, and the local offset to the corresponding list /// of redeclarations. diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h index 2561418b78ca7..10ea3e497d6c3 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -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. + 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(readAttr()); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index ec85fad3389a1..fae9440d27449 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -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()) { + Loc.setElaboratedKeywordLoc( + PendingPreferredNameAttributes[I].ElaboratedTypedefSL); + Loc.setQualifierLoc(PendingPreferredNameAttributes[I].NestedNameSL); + if (auto TypedefLoc = Loc.getNextTypeLoc().getAs()) + TypedefLoc.setNameLoc(PendingPreferredNameAttributes[I].TypedefSL); + } + } + + AttrVec &Attrs = getContext().getDeclAttrs(D); + PreferredNameAttr *New = new (Context) PreferredNameAttr( + Context, PendingPreferredNameAttributes[I].Info, TInfo); + cast(New)->setInherited( + PendingPreferredNameAttributes[I].isInherited); + New->setImplicit(PendingPreferredNameAttributes[I].isImplicit); + 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) { diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 6ece3ba7af9f4..b9b73d1646bb7 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -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 T *readDeclAs() { return Reader.readDeclAs(); } + + 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 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(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(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(); + 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(); + 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 //===----------------------------------------------------------------------===// diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index a52d59c61c4ce..370b05eb1bc16 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -4720,8 +4720,7 @@ void ASTRecordWriter::AddAttr(const Attr *A) { // FIXME: Clang can't handle the serialization/deserialization of // preferred_name properly now. See // https://github.com/llvm/llvm-project/issues/56490 for example. - if (!A || (isa(A) && - Writer->isWritingStdCXXNamedModules())) + if (!A) return Record.push_back(0); Record.push_back(A->getKind() + 1); // FIXME: stable encoding, target attrs diff --git a/clang/test/Modules/preferred_name.cppm b/clang/test/Modules/preferred_name.cppm index 806781a81c5ca..7f280ca74bb31 100644 --- a/clang/test/Modules/preferred_name.cppm +++ b/clang/test/Modules/preferred_name.cppm @@ -53,10 +53,17 @@ import A; export using ::foo_templ; //--- Use1.cpp -import A; // expected-warning@foo.h:8 {{attribute declaration must precede definition}} -#include "foo.h" // expected-note@foo.h: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'}}