From: Richard Smith Date: Thu, 12 Feb 2015 23:21:45 +0000 (+0000) Subject: [modules] When collecting declarations to complete a redeclaration chain for an X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d25dc45a79c019fd32a0db2b69d4dbc655b3b8ea;p=clang [modules] When collecting declarations to complete a redeclaration chain for an entity, put the originally-canonical decl IDs in the right places in the redecl chain rather than reordering them all to the start. If we don't ensure that the redecl chain order is consistent with the topological module order, we can fail to make a declaration visible if later declarations are in more IDNSs than earlier ones (for instance, because the earlier decls are invisible friends). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@228978 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 5fc99b5312..8c16dfde87 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -3264,47 +3264,53 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) { } namespace { - /// \brief Module visitor class that finds all of the redeclarations of a - /// + /// \brief Module visitor class that finds all of the redeclarations of a + /// redeclarable declaration. class RedeclChainVisitor { ASTReader &Reader; SmallVectorImpl &SearchDecls; llvm::SmallPtrSetImpl &Deserialized; GlobalDeclID CanonID; SmallVector Chain; - + public: RedeclChainVisitor(ASTReader &Reader, SmallVectorImpl &SearchDecls, llvm::SmallPtrSetImpl &Deserialized, GlobalDeclID CanonID) : Reader(Reader), SearchDecls(SearchDecls), Deserialized(Deserialized), - CanonID(CanonID) { - for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I) - addToChain(Reader.GetDecl(SearchDecls[I])); + CanonID(CanonID) { + // Ensure that the canonical ID goes at the start of the chain. + addToChain(Reader.GetDecl(CanonID)); } - + static bool visit(ModuleFile &M, bool Preorder, void *UserData) { if (Preorder) return false; - + return static_cast(UserData)->visit(M); } - + void addToChain(Decl *D) { if (!D) return; - + if (Deserialized.erase(D)) Chain.push_back(D); } - + void searchForID(ModuleFile &M, GlobalDeclID GlobalID) { // Map global ID of the first declaration down to the local ID // used in this module file. DeclID ID = Reader.mapGlobalIDToModuleFileGlobalID(M, GlobalID); if (!ID) return; - + + // If the search decl was from this module, add it to the chain before any + // of its redeclarations in this module or users of it, and after any from + // imported modules. + if (CanonID != GlobalID && Reader.isDeclIDFromModule(GlobalID, M)) + addToChain(Reader.GetDecl(GlobalID)); + // Perform a binary search to find the local redeclarations for this // declaration (if any). const LocalRedeclarationsInfo Compare = { ID, 0 }; diff --git a/test/Modules/Inputs/merge-decl-order/a.h b/test/Modules/Inputs/merge-decl-order/a.h new file mode 100644 index 0000000000..f505a424c7 --- /dev/null +++ b/test/Modules/Inputs/merge-decl-order/a.h @@ -0,0 +1,2 @@ +namespace N { struct SA { friend struct foo; }; } +namespace N { struct foo; } diff --git a/test/Modules/Inputs/merge-decl-order/b.h b/test/Modules/Inputs/merge-decl-order/b.h new file mode 100644 index 0000000000..49b06cafd0 --- /dev/null +++ b/test/Modules/Inputs/merge-decl-order/b.h @@ -0,0 +1,2 @@ +namespace N { struct SB { friend struct foo; }; } +#include "a.h" diff --git a/test/Modules/Inputs/merge-decl-order/module.modulemap b/test/Modules/Inputs/merge-decl-order/module.modulemap new file mode 100644 index 0000000000..61578a1865 --- /dev/null +++ b/test/Modules/Inputs/merge-decl-order/module.modulemap @@ -0,0 +1,2 @@ +module a { header "a.h" export * } +module b { header "b.h" export * } diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp index cbe2b65bdd..46c2f33ef1 100644 --- a/test/Modules/cxx-templates.cpp +++ b/test/Modules/cxx-templates.cpp @@ -189,11 +189,11 @@ namespace Std { // CHECK-NAMESPACE-N-NEXT: `-FunctionTemplate {{.*}} 'f' // CHECK-DUMP: ClassTemplateDecl {{.*}} <{{.*[/\\]}}cxx-templates-common.h:1:1, {{.*}}> col:{{.*}} in cxx_templates_common SomeTemplate -// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev [[CHAR2:[^ ]*]] {{.*}} SomeTemplate +// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate // CHECK-DUMP-NEXT: TemplateArgument type 'char [2]' -// CHECK-DUMP: ClassTemplateSpecializationDecl [[CHAR2]] {{.*}} SomeTemplate definition +// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition // CHECK-DUMP-NEXT: TemplateArgument type 'char [2]' -// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev [[CHAR1:[^ ]*]] {{.*}} SomeTemplate +// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate // CHECK-DUMP-NEXT: TemplateArgument type 'char [1]' -// CHECK-DUMP: ClassTemplateSpecializationDecl [[CHAR1]] {{.*}} SomeTemplate definition +// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition // CHECK-DUMP-NEXT: TemplateArgument type 'char [1]' diff --git a/test/Modules/merge-decl-order.cpp b/test/Modules/merge-decl-order.cpp new file mode 100644 index 0000000000..d3b21fdf8a --- /dev/null +++ b/test/Modules/merge-decl-order.cpp @@ -0,0 +1,9 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I%S/Inputs/merge-decl-order -verify %s +// expected-no-diagnostics + +// Check that we include all decls from 'a' before the decls from 'b' in foo's +// redecl chain. If we don't, then name lookup only finds invisible friend +// declarations and the lookup below will fail. +#include "b.h" +N::foo *use;