From aaaa0b61427c26fec9adc47951a39d0367ce65e1 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 18 May 2017 02:29:20 +0000 Subject: [PATCH] [modules] Switch from inferring owning modules based on source location to inferring based on the current module at the point of creation. This should result in no functional change except when building a preprocessed module (or more generally when using #pragma clang module begin/end to switch module in the middle of a file), in which case it allows us to correctly track the owning module for declarations. We can't map from FileID to module in the preprocessed module case, since all modules would have the same FileID. There are still a couple of remaining places that try to infer a module from a source location; I'll clean those up in follow-up changes. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@303322 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 2 +- include/clang/AST/DeclBase.h | 19 +++-- include/clang/Basic/LangOptions.h | 2 +- include/clang/Sema/Sema.h | 8 +- include/clang/Serialization/ASTWriter.h | 4 - lib/CodeGen/CGDebugInfo.cpp | 2 +- lib/Sema/SemaDecl.cpp | 65 +++++++-------- lib/Sema/SemaLookup.cpp | 104 ++++++++++++++---------- lib/Sema/SemaTemplate.cpp | 4 +- lib/Serialization/ASTWriter.cpp | 19 ----- lib/Serialization/ASTWriterDecl.cpp | 2 +- test/Modules/preprocess-module.cpp | 14 ++-- test/SemaCXX/modules-ts.cppm | 3 +- 13 files changed, 123 insertions(+), 125 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 474cf2c0e3..2221d6f9fc 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -935,7 +935,7 @@ public: /// \brief Get the additional modules in which the definition \p Def has /// been merged. - ArrayRef getModulesWithMergedDefinition(NamedDecl *Def) { + ArrayRef getModulesWithMergedDefinition(const NamedDecl *Def) { auto MergedIt = MergedDefModules.find(Def); if (MergedIt == MergedDefModules.end()) return None; diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 08879b36cc..29889fde96 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -332,15 +332,15 @@ private: bool AccessDeclContextSanity() const; protected: - Decl(Kind DK, DeclContext *DC, SourceLocation L) - : NextInContextAndBits(), DeclCtx(DC), - Loc(L), DeclKind(DK), InvalidDecl(0), - HasAttrs(false), Implicit(false), Used(false), Referenced(false), - Access(AS_none), FromASTFile(0), Hidden(DC && cast(DC)->Hidden), - IdentifierNamespace(getIdentifierNamespaceForKind(DK)), - CacheValidAndLinkage(0) - { + : NextInContextAndBits(), DeclCtx(DC), Loc(L), DeclKind(DK), + InvalidDecl(0), HasAttrs(false), Implicit(false), Used(false), + Referenced(false), Access(AS_none), FromASTFile(0), + Hidden(DC && cast(DC)->Hidden && + (!cast(DC)->isFromASTFile() || + hasLocalOwningModuleStorage())), + IdentifierNamespace(getIdentifierNamespaceForKind(DK)), + CacheValidAndLinkage(0) { if (StatisticsEnabled) add(DK); } @@ -698,6 +698,9 @@ public: Module *getLocalOwningModule() const { if (isFromASTFile() || !Hidden) return nullptr; + + assert(hasLocalOwningModuleStorage() && + "hidden local decl but no local module storage"); return reinterpret_cast(this)[-1]; } void setLocalOwningModule(Module *M) { diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index ceaedf5857..2513de70e7 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -168,7 +168,7 @@ public: /// Do we need to track the owning module for a local declaration? bool trackLocalOwningModule() const { - return ModulesLocalVisibility; + return isCompilingModule() || ModulesLocalVisibility || ModulesTS; } bool isSignedOverflowDefined() const { diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ba2da92c5b..36ae6501a8 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1507,6 +1507,12 @@ public: hasVisibleDefaultArgument(const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr); + /// Determine if there is a visible declaration of \p D that is an explicit + /// specialization declaration for a specialization of a template. (For a + /// member specialization, use hasVisibleMemberSpecialization.) + bool hasVisibleExplicitSpecialization( + const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr); + /// Determine if there is a visible declaration of \p D that is a member /// specialization declaration (as opposed to an instantiated declaration). bool hasVisibleMemberSpecialization( @@ -2360,7 +2366,7 @@ public: void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld); void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old); bool checkVarDeclRedefinition(VarDecl *OldDefn, VarDecl *NewDefn); - void notePreviousDefinition(SourceLocation Old, SourceLocation New); + void notePreviousDefinition(const NamedDecl *Old, SourceLocation New); bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S); // AssignmentAction - This is used by all the assignment diagnostic functions diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 17cf726e4d..f14dfc73ba 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -627,10 +627,6 @@ public: /// \brief Add a version tuple to the given record void AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record); - /// \brief Infer the submodule ID that contains an entity at the given - /// source location. - serialization::SubmoduleID inferSubmoduleIDFromLocation(SourceLocation Loc); - /// \brief Retrieve or create a submodule ID for this module, or return 0 if /// the submodule is neither local (a submodle of the currently-written module) /// nor from an imported module. diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index bf178dd7fd..0a1dc09211 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -2613,7 +2613,7 @@ llvm::DIModule *CGDebugInfo::getParentModuleOrNull(const Decl *D) { // best to make this behavior a command line or debugger tuning // option. FullSourceLoc Loc(D->getLocation(), CGM.getContext().getSourceManager()); - if (Module *M = ClangModuleMap->inferModuleFromLocation(Loc)) { + if (Module *M = D->getOwningModule()) { // This is a (sub-)module. auto Info = ExternalASTSource::ASTSourceDescriptor(*M); return getOrCreateModuleRef(Info, /*SkeletonCU=*/false); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index dca51b0e8c..4928f3f35a 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2021,7 +2021,7 @@ bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) { Diag(New->getLocation(), diag::err_redefinition_variably_modified_typedef) << Kind << NewType; if (Old->getLocation().isValid()) - notePreviousDefinition(Old->getLocation(), New->getLocation()); + notePreviousDefinition(Old, New->getLocation()); New->setInvalidDecl(); return true; } @@ -2034,7 +2034,7 @@ bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) { Diag(New->getLocation(), diag::err_redefinition_different_typedef) << Kind << NewType << OldType; if (Old->getLocation().isValid()) - notePreviousDefinition(Old->getLocation(), New->getLocation()); + notePreviousDefinition(Old, New->getLocation()); New->setInvalidDecl(); return true; } @@ -2101,7 +2101,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, NamedDecl *OldD = OldDecls.getRepresentativeDecl(); if (OldD->getLocation().isValid()) - notePreviousDefinition(OldD->getLocation(), New->getLocation()); + notePreviousDefinition(OldD, New->getLocation()); return New->setInvalidDecl(); } @@ -2193,7 +2193,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); - notePreviousDefinition(Old->getLocation(), New->getLocation()); + notePreviousDefinition(Old, New->getLocation()); return New->setInvalidDecl(); } @@ -2214,7 +2214,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, Diag(New->getLocation(), diag::ext_redefinition_of_typedef) << New->getDeclName(); - notePreviousDefinition(Old->getLocation(), New->getLocation()); + notePreviousDefinition(Old, New->getLocation()); } /// DeclhasAttr - returns true if decl Declaration already has the target @@ -2448,7 +2448,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, return false; } -static const Decl *getDefinition(const Decl *D) { +static const NamedDecl *getDefinition(const Decl *D) { if (const TagDecl *TD = dyn_cast(D)) return TD->getDefinition(); if (const VarDecl *VD = dyn_cast(D)) { @@ -2475,7 +2475,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { if (!New->hasAttrs()) return; - const Decl *Def = getDefinition(Old); + const NamedDecl *Def = getDefinition(Old); if (!Def || Def == New) return; @@ -2502,7 +2502,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { : diag::err_redefinition; S.Diag(VD->getLocation(), Diag) << VD->getDeclName(); if (Diag == diag::err_redefinition) - S.notePreviousDefinition(Def->getLocation(), VD->getLocation()); + S.notePreviousDefinition(Def, VD->getLocation()); else S.Diag(Def->getLocation(), diag::note_previous_definition); VD->setInvalidDecl(); @@ -2891,7 +2891,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, } else { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); - notePreviousDefinition(OldD->getLocation(), New->getLocation()); + notePreviousDefinition(OldD, New->getLocation()); return true; } } @@ -2928,7 +2928,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, !Old->hasAttr()) { Diag(New->getLocation(), diag::err_internal_linkage_redeclaration) << New->getDeclName(); - notePreviousDefinition(Old->getLocation(), New->getLocation()); + notePreviousDefinition(Old, New->getLocation()); New->dropAttr(); } @@ -3657,7 +3657,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { if (!Old) { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); - notePreviousDefinition(Previous.getRepresentativeDecl()->getLocation(), + notePreviousDefinition(Previous.getRepresentativeDecl(), New->getLocation()); return New->setInvalidDecl(); } @@ -3687,7 +3687,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { Old->getStorageClass() == SC_None && !Old->hasAttr()) { Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName(); - notePreviousDefinition(Old->getLocation(), New->getLocation()); + notePreviousDefinition(Old, New->getLocation()); // Remove weak_import attribute on new declaration. New->dropAttr(); } @@ -3696,7 +3696,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { !Old->hasAttr()) { Diag(New->getLocation(), diag::err_internal_linkage_redeclaration) << New->getDeclName(); - notePreviousDefinition(Old->getLocation(), New->getLocation()); + notePreviousDefinition(Old, New->getLocation()); New->dropAttr(); } @@ -3853,29 +3853,22 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { New->setImplicitlyInline(); } -void Sema::notePreviousDefinition(SourceLocation Old, SourceLocation New) { +void Sema::notePreviousDefinition(const NamedDecl *Old, SourceLocation New) { SourceManager &SrcMgr = getSourceManager(); auto FNewDecLoc = SrcMgr.getDecomposedLoc(New); - auto FOldDecLoc = SrcMgr.getDecomposedLoc(Old); + auto FOldDecLoc = SrcMgr.getDecomposedLoc(Old->getLocation()); auto *FNew = SrcMgr.getFileEntryForID(FNewDecLoc.first); auto *FOld = SrcMgr.getFileEntryForID(FOldDecLoc.first); auto &HSI = PP.getHeaderSearchInfo(); - StringRef HdrFilename = SrcMgr.getFilename(SrcMgr.getSpellingLoc(Old)); + StringRef HdrFilename = + SrcMgr.getFilename(SrcMgr.getSpellingLoc(Old->getLocation())); - auto noteFromModuleOrInclude = [&](SourceLocation &Loc, - SourceLocation &IncLoc) -> bool { - Module *Mod = nullptr; + auto noteFromModuleOrInclude = [&](Module *Mod, + SourceLocation IncLoc) -> bool { // Redefinition errors with modules are common with non modular mapped // headers, example: a non-modular header H in module A that also gets // included directly in a TU. Pointing twice to the same header/definition // is confusing, try to get better diagnostics when modules is on. - if (getLangOpts().Modules) { - auto ModLoc = SrcMgr.getModuleImportLoc(Old); - if (!ModLoc.first.isInvalid()) - Mod = HSI.getModuleMap().inferModuleFromLocation( - FullSourceLoc(Loc, SrcMgr)); - } - if (IncLoc.isValid()) { if (Mod) { Diag(IncLoc, diag::note_redefinition_modules_same_file) @@ -3899,19 +3892,19 @@ void Sema::notePreviousDefinition(SourceLocation Old, SourceLocation New) { if (FNew == FOld && FNewDecLoc.second == FOldDecLoc.second) { SourceLocation OldIncLoc = SrcMgr.getIncludeLoc(FOldDecLoc.first); SourceLocation NewIncLoc = SrcMgr.getIncludeLoc(FNewDecLoc.first); - EmittedDiag = noteFromModuleOrInclude(Old, OldIncLoc); - EmittedDiag |= noteFromModuleOrInclude(New, NewIncLoc); + EmittedDiag = noteFromModuleOrInclude(Old->getOwningModule(), OldIncLoc); + EmittedDiag |= noteFromModuleOrInclude(getCurrentModule(), NewIncLoc); // If the header has no guards, emit a note suggesting one. if (FOld && !HSI.isFileMultipleIncludeGuarded(FOld)) - Diag(Old, diag::note_use_ifdef_guards); + Diag(Old->getLocation(), diag::note_use_ifdef_guards); if (EmittedDiag) return; } // Redefinition coming from different files or couldn't do better above. - Diag(Old, diag::note_previous_definition); + Diag(Old->getLocation(), diag::note_previous_definition); } /// We've just determined that \p Old and \p New both appear to be definitions @@ -3934,7 +3927,7 @@ bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) { return false; } else { Diag(New->getLocation(), diag::err_redefinition) << New; - notePreviousDefinition(Old->getLocation(), New->getLocation()); + notePreviousDefinition(Old, New->getLocation()); New->setInvalidDecl(); return true; } @@ -13503,9 +13496,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } else if (TUK == TUK_Reference && (PrevTagDecl->getFriendObjectKind() == Decl::FOK_Undeclared || - PP.getModuleContainingLocation( - PrevDecl->getLocation()) != - PP.getModuleContainingLocation(KWLoc)) && + PrevDecl->getOwningModule() != getCurrentModule()) && SS.isEmpty()) { // This declaration is a reference to an existing entity, but // has different visibility from that entity: it either makes @@ -13561,7 +13552,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, Diag(NameLoc, diag::warn_redefinition_in_param_list) << Name; else Diag(NameLoc, diag::err_redefinition) << Name; - notePreviousDefinition(Def->getLocation(), + notePreviousDefinition(Def, NameLoc.isValid() ? NameLoc : KWLoc); // If this is a redefinition, recover by making this // struct be anonymous, which will make any later @@ -13652,7 +13643,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // The tag name clashes with something else in the target scope, // issue an error and recover by making this tag be anonymous. Diag(NameLoc, diag::err_redefinition_different_kind) << Name; - notePreviousDefinition(PrevDecl->getLocation(), NameLoc); + notePreviousDefinition(PrevDecl, NameLoc); Name = nullptr; Invalid = true; } @@ -15356,7 +15347,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id; else Diag(IdLoc, diag::err_redefinition) << Id; - notePreviousDefinition(PrevDecl->getLocation(), IdLoc); + notePreviousDefinition(PrevDecl, IdLoc); return nullptr; } } diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 04350831c6..66c10093d9 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1420,11 +1420,46 @@ bool Sema::hasVisibleDefaultArgument(const NamedDecl *D, Modules); } +template +static bool hasVisibleDeclarationImpl(Sema &S, const NamedDecl *D, + llvm::SmallVectorImpl *Modules, + Filter F) { + for (auto *Redecl : D->redecls()) { + auto *R = cast(Redecl); + if (!F(R)) + continue; + + if (S.isVisible(R)) + return true; + + if (Modules) { + Modules->push_back(R->getOwningModule()); + const auto &Merged = S.Context.getModulesWithMergedDefinition(R); + Modules->insert(Modules->end(), Merged.begin(), Merged.end()); + } + } + + return false; +} + +bool Sema::hasVisibleExplicitSpecialization( + const NamedDecl *D, llvm::SmallVectorImpl *Modules) { + return hasVisibleDeclarationImpl(*this, D, Modules, [](const NamedDecl *D) { + if (auto *RD = dyn_cast(D)) + return RD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization; + if (auto *FD = dyn_cast(D)) + return FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization; + if (auto *VD = dyn_cast(D)) + return VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization; + llvm_unreachable("unknown explicit specialization kind"); + }); +} + bool Sema::hasVisibleMemberSpecialization( const NamedDecl *D, llvm::SmallVectorImpl *Modules) { assert(isa(D->getDeclContext()) && "not a member specialization"); - for (auto *Redecl : D->redecls()) { + return hasVisibleDeclarationImpl(*this, D, Modules, [](const NamedDecl *D) { // If the specialization is declared at namespace scope, then it's a member // specialization declaration. If it's lexically inside the class // definition then it was instantiated. @@ -1432,19 +1467,8 @@ bool Sema::hasVisibleMemberSpecialization( // FIXME: This is a hack. There should be a better way to determine this. // FIXME: What about MS-style explicit specializations declared within a // class definition? - if (Redecl->getLexicalDeclContext()->isFileContext()) { - auto *NonConstR = const_cast(cast(Redecl)); - - if (isVisible(NonConstR)) - return true; - - if (Modules) { - Modules->push_back(getOwningModule(NonConstR)); - const auto &Merged = Context.getModulesWithMergedDefinition(NonConstR); - Modules->insert(Modules->end(), Merged.begin(), Merged.end()); - } - } - } + return D->getLexicalDeclContext()->isFileContext(); + }); return false; } @@ -1459,23 +1483,19 @@ bool Sema::hasVisibleMemberSpecialization( /// your module can see, including those later on in your module). bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { assert(D->isHidden() && "should not call this: not in slow case"); - Module *DeclModule = nullptr; - - if (SemaRef.getLangOpts().ModulesLocalVisibility) { - DeclModule = SemaRef.getOwningModule(D); - if (!DeclModule) { - assert(!D->isHidden() && "hidden decl not from a module"); - return true; - } - // If the owning module is visible, and the decl is not module private, - // then the decl is visible too. (Module private is ignored within the same - // top-level module.) - if ((!D->isFromASTFile() || !D->isModulePrivate()) && - (SemaRef.isModuleVisible(DeclModule) || - SemaRef.hasVisibleMergedDefinition(D))) - return true; - } + Module *DeclModule = SemaRef.getOwningModule(D); + assert(DeclModule && "hidden decl not from a module"); + + // If the owning module is visible, and the decl is not module private, + // then the decl is visible too. (Module private is ignored within the same + // top-level module.) + // FIXME: Check the owning module for module-private declarations rather than + // assuming "same AST file" is the same thing as "same module". + if ((!D->isFromASTFile() || !D->isModulePrivate()) && + (SemaRef.isModuleVisible(DeclModule) || + SemaRef.hasVisibleMergedDefinition(D))) + return true; // If this declaration is not at namespace scope nor module-private, // then it is visible if its lexical parent has a visible definition. @@ -1571,20 +1591,8 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) { bool Sema::hasVisibleDeclarationSlow(const NamedDecl *D, llvm::SmallVectorImpl *Modules) { assert(!isVisible(D) && "not in slow case"); - - for (auto *Redecl : D->redecls()) { - auto *NonConstR = const_cast(cast(Redecl)); - if (isVisible(NonConstR)) - return true; - - if (Modules) { - Modules->push_back(getOwningModule(NonConstR)); - const auto &Merged = Context.getModulesWithMergedDefinition(NonConstR); - Modules->insert(Modules->end(), Merged.begin(), Merged.end()); - } - } - - return false; + return hasVisibleDeclarationImpl(*this, D, Modules, + [](const NamedDecl *) { return true; }); } NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const { @@ -4957,6 +4965,14 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, MissingImportKind MIK, bool Recover) { assert(!Modules.empty()); + // Weed out duplicates from module list. + llvm::SmallVector UniqueModules; + llvm::SmallDenseSet UniqueModuleSet; + for (auto *M : Modules) + if (UniqueModuleSet.insert(M).second) + UniqueModules.push_back(M); + Modules = UniqueModules; + if (Modules.size() > 1) { std::string ModuleList; unsigned N = 0; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index a479d10275..8cd7efbb1d 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -7901,6 +7901,7 @@ bool Sema::CheckFunctionTemplateSpecialization( TemplateSpecializationKind TSK = SpecInfo->getTemplateSpecializationKind(); if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation) { Specialization->setLocation(FD->getLocation()); + Specialization->setLexicalDeclContext(FD->getLexicalDeclContext()); // C++11 [dcl.constexpr]p1: An explicit specialization of a constexpr // function can differ from the template declaration with respect to // the constexpr specifier. @@ -7961,6 +7962,7 @@ bool Sema::CheckFunctionTemplateSpecialization( // FIXME: We need an update record for this AST mutation. Specialization->setDeletedAsWritten(false); } + // FIXME: We need an update record for this AST mutation. SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization); MarkUnusedFileScopedDecl(Specialization); } @@ -9745,7 +9747,7 @@ private: IsHiddenExplicitSpecialization = Spec->getMemberSpecializationInfo() ? !S.hasVisibleMemberSpecialization(Spec, &Modules) - : !S.hasVisibleDeclaration(Spec); + : !S.hasVisibleExplicitSpecialization(Spec, &Modules); } else { checkInstantiated(Spec); } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index b6c0cb2815..b3556371c9 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -2841,25 +2841,6 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { "non-imported submodule?"); } -serialization::SubmoduleID -ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) { - if (Loc.isInvalid() || !WritingModule) - return 0; // No submodule - - // Find the module that owns this location. - ModuleMap &ModMap = PP->getHeaderSearchInfo().getModuleMap(); - Module *OwningMod - = ModMap.inferModuleFromLocation(FullSourceLoc(Loc,PP->getSourceManager())); - if (!OwningMod) - return 0; - - // Check whether this submodule is part of our own module. - if (WritingModule != OwningMod && !OwningMod->isSubModuleOf(WritingModule)) - return 0; - - return getSubmoduleID(OwningMod); -} - void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, bool isModule) { llvm::SmallDenseMap diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 812cd9e916..8fa64aa1b9 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -299,7 +299,7 @@ void ASTDeclWriter::VisitDecl(Decl *D) { Record.push_back(D->isTopLevelDeclInObjCContainer()); Record.push_back(D->getAccess()); Record.push_back(D->isModulePrivate()); - Record.push_back(Writer.inferSubmoduleIDFromLocation(D->getLocation())); + Record.push_back(Writer.getSubmoduleID(D->getOwningModule())); // If this declaration injected a name into a context different from its // lexical context, and that context is an imported namespace, we need to diff --git a/test/Modules/preprocess-module.cpp b/test/Modules/preprocess-module.cpp index 64af00c471..eaab313693 100644 --- a/test/Modules/preprocess-module.cpp +++ b/test/Modules/preprocess-module.cpp @@ -25,8 +25,8 @@ // RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm -fmodule-map-file=%S/Inputs/preprocess/module.modulemap -x c++-module-map-cpp-output %t/rewrite.ii -emit-module -o /dev/null // Check the module we built works. -// RUN: %clang_cc1 -fmodules -fmodule-file=%t/no-rewrite.pcm %s -verify -// RUN: %clang_cc1 -fmodules -fmodule-file=%t/rewrite.pcm %s -verify +// RUN: %clang_cc1 -fmodules -fmodule-file=%t/no-rewrite.pcm %s -I%t -verify -fno-modules-error-recovery +// RUN: %clang_cc1 -fmodules -fmodule-file=%t/rewrite.pcm %s -I%t -verify -fno-modules-error-recovery -DREWRITE // == module map @@ -95,10 +95,12 @@ // NO-REWRITE: #pragma clang module end -// expected-no-diagnostics - -// FIXME: This should be rejected: we have not imported the submodule defining it yet. -__FILE *a; +__FILE *a; // expected-error {{declaration of '__FILE' must be imported}} +#ifdef REWRITE +// expected-note@rewrite.ii:1 {{here}} +#else +// expected-note@no-rewrite.ii:1 {{here}} +#endif #pragma clang module import file diff --git a/test/SemaCXX/modules-ts.cppm b/test/SemaCXX/modules-ts.cppm index d1d7aaa96e..29122ec7da 100644 --- a/test/SemaCXX/modules-ts.cppm +++ b/test/SemaCXX/modules-ts.cppm @@ -18,7 +18,8 @@ int n; #if TEST >= 2 // expected-error@-2 {{redefinition of '}} // expected-note@-3 {{unguarded header; consider using #ifdef guards or #pragma once}} -// expected-note-re@modules-ts.cppm:1 {{'{{.*}}modules-ts.cppm' included multiple times, additional include site here}} +// FIXME: We should drop the "header from" in this diagnostic. +// expected-note-re@modules-ts.cppm:1 {{'{{.*}}modules-ts.cppm' included multiple times, additional include site in header from module 'foo'}} #endif #if TEST == 0 -- 2.50.1