Index: include/clang/Serialization/ASTReader.h =================================================================== --- include/clang/Serialization/ASTReader.h +++ include/clang/Serialization/ASTReader.h @@ -971,13 +971,24 @@ /// the last time we loaded information about this identifier. llvm::DenseMap IdentifierGeneration; - /// \brief Contains declarations and definitions that will be + class InterestingDecl { + Decl *D; + bool DeclHasPendingBody; + public: + InterestingDecl(Decl *D, bool HasBody) + : D(D), DeclHasPendingBody(HasBody) {} + Decl *getDecl() { return D; } + /// Whether the declaration has a pending body. + bool HasPendingBody() { return DeclHasPendingBody; } + }; + + /// \brief Contains declarations and definitions that could be /// "interesting" to the ASTConsumer, when we get that AST consumer. /// /// "Interesting" declarations are those that have data that may /// need to be emitted, such as inline function definitions or /// Objective-C protocols. - std::deque InterestingDecls; + std::deque PotentiallyInterestingDecls; /// \brief The list of redeclaration chains that still need to be /// reconstructed, and the local offset to the corresponding list Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -7006,31 +7006,6 @@ Consumer->HandleInterestingDecl(DeclGroupRef(ImplD)); } -void ASTReader::PassInterestingDeclsToConsumer() { - assert(Consumer); - - if (PassingDeclsToConsumer) - return; - - // Guard variable to avoid recursively redoing the process of passing - // decls to consumer. - SaveAndRestore GuardPassingDeclsToConsumer(PassingDeclsToConsumer, - true); - - // Ensure that we've loaded all potentially-interesting declarations - // that need to be eagerly loaded. - for (auto ID : EagerlyDeserializedDecls) - GetDecl(ID); - EagerlyDeserializedDecls.clear(); - - while (!InterestingDecls.empty()) { - Decl *D = InterestingDecls.front(); - InterestingDecls.pop_front(); - - PassInterestingDeclToConsumer(D); - } -} - void ASTReader::PassInterestingDeclToConsumer(Decl *D) { if (ObjCImplDecl *ImplD = dyn_cast(D)) PassObjCImplDeclToConsumer(ImplD, Consumer); Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -3605,12 +3605,36 @@ // AST consumer might need to know about, queue it. // We don't pass it to the consumer immediately because we may be in recursive // loading, and some declarations may still be initializing. - if (isConsumerInterestedIn(Context, D, Reader.hasPendingBody())) - InterestingDecls.push_back(D); + PotentiallyInterestingDecls.push_back(InterestingDecl(D, Reader.hasPendingBody())); return D; } +void ASTReader::PassInterestingDeclsToConsumer() { + assert(Consumer); + + if (PassingDeclsToConsumer) + return; + + // Guard variable to avoid recursively redoing the process of passing + // decls to consumer. + SaveAndRestore GuardPassingDeclsToConsumer(PassingDeclsToConsumer, + true); + + // Ensure that we've loaded all potentially-interesting declarations + // that need to be eagerly loaded. + for (auto ID : EagerlyDeserializedDecls) + GetDecl(ID); + EagerlyDeserializedDecls.clear(); + + while (!PotentiallyInterestingDecls.empty()) { + InterestingDecl D = PotentiallyInterestingDecls.front(); + PotentiallyInterestingDecls.pop_front(); + if (isConsumerInterestedIn(Context, D.getDecl(), D.HasPendingBody())) + PassInterestingDeclToConsumer(D.getDecl()); + } +} + void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) { // The declaration may have been modified by files later in the chain. // If this is the case, read the record containing the updates from each file @@ -3642,7 +3666,7 @@ // we need to hand it off to the consumer. if (!WasInteresting && isConsumerInterestedIn(Context, D, Reader.hasPendingBody())) { - InterestingDecls.push_back(D); + PotentiallyInterestingDecls.push_back(InterestingDecl(D, Reader.hasPendingBody())); WasInteresting = true; } } Index: test/Modules/Inputs/delay-emit-check/Module.h =================================================================== --- /dev/null +++ test/Modules/Inputs/delay-emit-check/Module.h @@ -0,0 +1,4 @@ +namespace a { namespace b { + int foo(); + const int x = foo(); +}} Index: test/Modules/Inputs/delay-emit-check/module.modulemap =================================================================== --- /dev/null +++ test/Modules/Inputs/delay-emit-check/module.modulemap @@ -0,0 +1 @@ +module "a" { header "Module.h" } Index: test/Modules/delay-emit-check.cpp =================================================================== --- /dev/null +++ test/Modules/delay-emit-check.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -fmodules-cache-path=%t/cache -fmodules -fimplicit-module-maps -emit-obj -I%S/Inputs/delay-emit-check/ %s -o %t.o + +namespace a { namespace b { + int foo(); +}} +#include "Module.h" Index: test/PCH/Inputs/empty-def-fwd-struct.modulemap =================================================================== --- /dev/null +++ test/PCH/Inputs/empty-def-fwd-struct.modulemap @@ -0,0 +1,2 @@ +module M { header "../empty-def-fwd-struct.h" } + Index: test/PCH/delay-PCH-emit-check.cpp =================================================================== --- /dev/null +++ test/PCH/delay-PCH-emit-check.cpp @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -x c++ -std=c++14 -fmodules -emit-module -fmodule-name=M %S/Inputs/empty-def-fwd-struct.modulemap -o %t.pcm +// RUN: %clang_cc1 -x c++ -std=c++14 -fmodules -emit-llvm -fmodule-file=%t.pcm %s -o %t.o + +#include "empty-def-fwd-struct.h"