Skip to content

Commit

Permalink
[Serialization] Add a callback to register new created predefined dec…
Browse files Browse the repository at this point in the history
…ls for DeserializationListener (#102855)

Close #102684

The root cause of the issue is, it is possible that the predefined decl
is not registered at the beginning of writing a module file but got
created during the process of writing from reading.

This is incorrect. The predefined decls should always be predefined
decls.

Another deep thought about the issue is, we shouldn't read any new
things after we start to write the module file. But this is another
deeper question.
  • Loading branch information
ChuanqiXu9 authored Aug 12, 2024
1 parent a0241e7 commit 4915fdd
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 18 deletions.
1 change: 1 addition & 0 deletions clang/include/clang/Frontend/MultiplexConsumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class MultiplexASTDeserializationListener : public ASTDeserializationListener {
void MacroRead(serialization::MacroID ID, MacroInfo *MI) override;
void TypeRead(serialization::TypeIdx Idx, QualType T) override;
void DeclRead(GlobalDeclID ID, const Decl *D) override;
void PredefinedDeclBuilt(PredefinedDeclIDs ID, const Decl *D) override;
void SelectorRead(serialization::SelectorID iD, Selector Sel) override;
void MacroDefinitionRead(serialization::PreprocessedEntityID,
MacroDefinitionRecord *MD) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class ASTDeserializationListener {
virtual void TypeRead(serialization::TypeIdx Idx, QualType T) { }
/// A decl was deserialized from the AST file.
virtual void DeclRead(GlobalDeclID ID, const Decl *D) {}
/// A predefined decl was built during the serialization.
virtual void PredefinedDeclBuilt(PredefinedDeclIDs ID, const Decl *D) {}
/// A selector was read from the AST file.
virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) {}
/// A macro definition was read from the AST file.
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -1559,6 +1559,9 @@ class ASTReader
std::pair<ModuleFile *, unsigned>
translateTypeIDToIndex(serialization::TypeID ID) const;

/// Get a predefined Decl from ASTContext.
Decl *getPredefinedDecl(PredefinedDeclIDs ID);

public:
/// Load the AST file and validate its contents against the given
/// Preprocessor.
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Serialization/ASTWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,7 @@ class ASTWriter : public ASTDeserializationListener,
void IdentifierRead(serialization::IdentifierID ID, IdentifierInfo *II) override;
void MacroRead(serialization::MacroID ID, MacroInfo *MI) override;
void TypeRead(serialization::TypeIdx Idx, QualType T) override;
void PredefinedDeclBuilt(PredefinedDeclIDs ID, const Decl *D) override;
void SelectorRead(serialization::SelectorID ID, Selector Sel) override;
void MacroDefinitionRead(serialization::PreprocessedEntityID ID,
MacroDefinitionRecord *MD) override;
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Frontend/MultiplexConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ void MultiplexASTDeserializationListener::DeclRead(GlobalDeclID ID,
Listeners[i]->DeclRead(ID, D);
}

void MultiplexASTDeserializationListener::PredefinedDeclBuilt(PredefinedDeclIDs ID, const Decl *D) {
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->PredefinedDeclBuilt(ID, D);
}

void MultiplexASTDeserializationListener::SelectorRead(
serialization::SelectorID ID, Selector Sel) {
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Expand Down
91 changes: 73 additions & 18 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7787,7 +7787,10 @@ SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) {
return Loc;
}

static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) {
Decl *ASTReader::getPredefinedDecl(PredefinedDeclIDs ID) {
assert(ContextObj && "reading predefined decl without AST context");
ASTContext &Context = *ContextObj;
Decl *NewLoaded = nullptr;
switch (ID) {
case PREDEF_DECL_NULL_ID:
return nullptr;
Expand All @@ -7796,54 +7799,106 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) {
return Context.getTranslationUnitDecl();

case PREDEF_DECL_OBJC_ID_ID:
return Context.getObjCIdDecl();
if (Context.ObjCIdDecl)
return Context.ObjCIdDecl;
NewLoaded = Context.getObjCIdDecl();
break;

case PREDEF_DECL_OBJC_SEL_ID:
return Context.getObjCSelDecl();
if (Context.ObjCSelDecl)
return Context.ObjCSelDecl;
NewLoaded = Context.getObjCSelDecl();
break;

case PREDEF_DECL_OBJC_CLASS_ID:
return Context.getObjCClassDecl();
if (Context.ObjCClassDecl)
return Context.ObjCClassDecl;
NewLoaded = Context.getObjCClassDecl();
break;

case PREDEF_DECL_OBJC_PROTOCOL_ID:
return Context.getObjCProtocolDecl();
if (Context.ObjCProtocolClassDecl)
return Context.ObjCProtocolClassDecl;
NewLoaded = Context.getObjCProtocolDecl();
break;

case PREDEF_DECL_INT_128_ID:
return Context.getInt128Decl();
if (Context.Int128Decl)
return Context.Int128Decl;
NewLoaded = Context.getInt128Decl();
break;

case PREDEF_DECL_UNSIGNED_INT_128_ID:
return Context.getUInt128Decl();
if (Context.UInt128Decl)
return Context.UInt128Decl;
NewLoaded = Context.getUInt128Decl();
break;

case PREDEF_DECL_OBJC_INSTANCETYPE_ID:
return Context.getObjCInstanceTypeDecl();
if (Context.ObjCInstanceTypeDecl)
return Context.ObjCInstanceTypeDecl;
NewLoaded = Context.getObjCInstanceTypeDecl();
break;

case PREDEF_DECL_BUILTIN_VA_LIST_ID:
return Context.getBuiltinVaListDecl();
if (Context.BuiltinVaListDecl)
return Context.BuiltinVaListDecl;
NewLoaded = Context.getBuiltinVaListDecl();
break;

case PREDEF_DECL_VA_LIST_TAG:
return Context.getVaListTagDecl();
if (Context.VaListTagDecl)
return Context.VaListTagDecl;
NewLoaded = Context.getVaListTagDecl();
break;

case PREDEF_DECL_BUILTIN_MS_VA_LIST_ID:
return Context.getBuiltinMSVaListDecl();
if (Context.BuiltinMSVaListDecl)
return Context.BuiltinMSVaListDecl;
NewLoaded = Context.getBuiltinMSVaListDecl();
break;

case PREDEF_DECL_BUILTIN_MS_GUID_ID:
// ASTContext::getMSGuidTagDecl won't create MSGuidTagDecl conditionally.
return Context.getMSGuidTagDecl();

case PREDEF_DECL_EXTERN_C_CONTEXT_ID:
return Context.getExternCContextDecl();
if (Context.ExternCContext)
return Context.ExternCContext;
NewLoaded = Context.getExternCContextDecl();
break;

case PREDEF_DECL_MAKE_INTEGER_SEQ_ID:
return Context.getMakeIntegerSeqDecl();
if (Context.MakeIntegerSeqDecl)
return Context.MakeIntegerSeqDecl;
NewLoaded = Context.getMakeIntegerSeqDecl();
break;

case PREDEF_DECL_CF_CONSTANT_STRING_ID:
return Context.getCFConstantStringDecl();
if (Context.CFConstantStringTypeDecl)
return Context.CFConstantStringTypeDecl;
NewLoaded = Context.getCFConstantStringDecl();
break;

case PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID:
return Context.getCFConstantStringTagDecl();
if (Context.CFConstantStringTagDecl)
return Context.CFConstantStringTagDecl;
NewLoaded = Context.getCFConstantStringTagDecl();
break;

case PREDEF_DECL_TYPE_PACK_ELEMENT_ID:
return Context.getTypePackElementDecl();
if (Context.TypePackElementDecl)
return Context.TypePackElementDecl;
NewLoaded = Context.getTypePackElementDecl();
break;
}
llvm_unreachable("PredefinedDeclIDs unknown enum value");

assert(NewLoaded && "Failed to load predefined decl?");

if (DeserializationListener)
DeserializationListener->PredefinedDeclBuilt(ID, NewLoaded);

return NewLoaded;
}

unsigned ASTReader::translateGlobalDeclIDToIndex(GlobalDeclID GlobalID) const {
Expand All @@ -7860,7 +7915,7 @@ Decl *ASTReader::GetExistingDecl(GlobalDeclID ID) {
assert(ContextObj && "reading decl with no AST context");

if (ID < NUM_PREDEF_DECL_IDS) {
Decl *D = getPredefinedDecl(*ContextObj, (PredefinedDeclIDs)ID);
Decl *D = getPredefinedDecl((PredefinedDeclIDs)ID);
if (D) {
// Track that we have merged the declaration with ID \p ID into the
// pre-existing predefined declaration \p D.
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6754,6 +6754,12 @@ void ASTWriter::TypeRead(TypeIdx Idx, QualType T) {
StoredIdx = Idx;
}

void ASTWriter::PredefinedDeclBuilt(PredefinedDeclIDs ID, const Decl *D) {
assert(D->isCanonicalDecl() && "predefined decl is not canonical");
DeclIDs[D] = LocalDeclID(ID);
PredefinedDecls.insert(D);
}

void ASTWriter::SelectorRead(SelectorID ID, Selector S) {
// Always keep the highest ID. See \p TypeRead() for more information.
SelectorID &StoredID = SelectorIDs[S];
Expand Down
38 changes: 38 additions & 0 deletions clang/test/Modules/pr102684.cppm
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: split-file %s %t
//
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm
// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/b.pcm \
// RUN: -fprebuilt-module-path=%t
// RUN: %clang_cc1 -std=c++20 %t/test.cpp -fsyntax-only -verify \
// RUN: -fprebuilt-module-path=%t

//--- a.cppm
export module a;

namespace n {
template<typename, int...>
struct integer_sequence {

};

export template<typename>
using make_integer_sequence = __make_integer_seq<integer_sequence, int, 0>;
}

//--- b.cppm
export module b;
import a;

export template<typename T>
void b() {
n::make_integer_sequence<T>();
}

//--- test.cpp
// expected-no-diagnostics
import b;
void test() {
b<int>();
}

0 comments on commit 4915fdd

Please sign in to comment.