Author: Chuanqi Xu Date: 2022-06-29T12:43:26+08:00 New Revision: 7a541406b5a23a811a4f37432292a6de3307b0f1
URL: https://github.com/llvm/llvm-project/commit/7a541406b5a23a811a4f37432292a6de3307b0f1 DIFF: https://github.com/llvm/llvm-project/commit/7a541406b5a23a811a4f37432292a6de3307b0f1.diff LOG: Revert "[C++20] [Modules] Implement Reachable initiallly" This reverts commit a223ba0a697c1598b434cf2495c9cd9ec5640fc7. The previous commit don't contain additional information, which is bad. Added: Modified: clang/include/clang/AST/DeclBase.h clang/include/clang/Basic/Module.h clang/include/clang/Sema/Lookup.h clang/include/clang/Sema/Sema.h clang/lib/AST/Decl.cpp clang/lib/Sema/SemaCXXScopeSpec.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaLookup.cpp clang/lib/Sema/SemaModule.cpp clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/SemaType.cpp clang/lib/Serialization/ASTReaderDecl.cpp clang/lib/Serialization/ASTWriterDecl.cpp clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp clang/test/CXX/module/module.import/p2.cpp clang/test/CXX/module/module.interface/p2.cpp clang/test/CXX/module/module.unit/p7/t6.cpp clang/test/CXX/modules-ts/basic/basic.link/p2/other.cpp clang/test/Modules/cxx20-10-1-ex2.cpp clang/test/Modules/module-private.cpp Removed: clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4-friend-in-reachable-class.cpp clang/test/CXX/module/module.context/p7.cpp clang/test/CXX/module/module.interface/p7.cpp clang/test/CXX/module/module.reach/ex1.cpp clang/test/CXX/module/module.reach/p2.cpp clang/test/CXX/module/module.reach/p4/TransitiveImport.cpp clang/test/CXX/module/module.reach/p5.cpp clang/test/Modules/Reachability-Private.cpp clang/test/Modules/Reachability-func-default-arg.cpp clang/test/Modules/Reachability-func-ret.cpp clang/test/Modules/Reachability-template-default-arg.cpp clang/test/Modules/Reachability-template-instantiation.cpp clang/test/Modules/Reachability-using-templates.cpp clang/test/Modules/Reachability-using.cpp clang/test/Modules/derived_class.cpp clang/test/Modules/explicitly-specialized-template.cpp clang/test/Modules/template-function-specialization.cpp clang/test/Modules/template_default_argument.cpp ################################################################################ diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 52fe8dd6b1e57..0611cf5ccb000 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -225,15 +225,8 @@ class alignas(8) Decl { /// module is imported. VisibleWhenImported, - /// This declaration has an owning module, and is visible to lookups - /// that occurs within that module. And it is reachable in other module - /// when the owning module is transitively imported. - ReachableWhenImported, - /// This declaration has an owning module, but is only visible to /// lookups that occur within that module. - /// The discarded declarations in global module fragment belongs - /// to this group too. ModulePrivate }; @@ -242,8 +235,8 @@ class alignas(8) Decl { /// DeclContext. These pointers form the linked list that is /// traversed via DeclContext's decls_begin()/decls_end(). /// - /// The extra three bits are used for the ModuleOwnershipKind. - llvm::PointerIntPair<Decl *, 3, ModuleOwnershipKind> NextInContextAndBits; + /// The extra two bits are used for the ModuleOwnershipKind. + llvm::PointerIntPair<Decl *, 2, ModuleOwnershipKind> NextInContextAndBits; private: friend class DeclContext; @@ -629,14 +622,6 @@ class alignas(8) Decl { /// export void B::f2(); // isInExportDeclContext() == true bool isInExportDeclContext() const; - bool isInvisibleOutsideTheOwningModule() const { - return getModuleOwnershipKind() > ModuleOwnershipKind::VisibleWhenImported; - } - - /// FIXME: Implement discarding declarations actually in global module - /// fragment. See [module.global.frag]p3,4 for details. - bool isDiscardedInGlobalModuleFragment() const { return false; } - /// Return true if this declaration has an attribute which acts as /// definition of the entity, such as 'alias' or 'ifunc'. bool hasDefiningAttr() const; @@ -814,11 +799,6 @@ class alignas(8) Decl { return (int)getModuleOwnershipKind() <= (int)ModuleOwnershipKind::Visible; } - bool isReachable() const { - return (int)getModuleOwnershipKind() <= - (int)ModuleOwnershipKind::ReachableWhenImported; - } - /// Set that this declaration is globally visible, even if it came from a /// module that is not visible. void setVisibleDespiteOwningModule() { diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h index a1778baa04530..5ce5fea45c670 100644 --- a/clang/include/clang/Basic/Module.h +++ b/clang/include/clang/Basic/Module.h @@ -170,8 +170,6 @@ class Module { bool isPrivateModule() const { return Kind == PrivateModuleFragment; } - bool isModuleMapModule() const { return Kind == ModuleMapModule; } - private: /// The submodules of this module, indexed by name. std::vector<Module *> SubModules; @@ -538,10 +536,6 @@ class Module { return Kind == ModuleInterfaceUnit || isModulePartition(); } - bool isModuleInterfaceUnit() const { - return Kind == ModuleInterfaceUnit || Kind == ModulePartitionInterface; - } - /// Get the primary module interface name from a partition. StringRef getPrimaryModuleInterfaceName() const { // Technically, global module fragment belongs to global module. And global diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h index 8b11273416c55..1f43ff0b5aaf6 100644 --- a/clang/include/clang/Sema/Lookup.h +++ b/clang/include/clang/Sema/Lookup.h @@ -346,56 +346,30 @@ class LookupResult { /// Determine whether the given declaration is visible to the /// program. - static bool isVisible(Sema &SemaRef, NamedDecl *D); + static bool isVisible(Sema &SemaRef, NamedDecl *D) { + // If this declaration is not hidden, it's visible. + if (D->isUnconditionallyVisible()) + return true; - static bool isReachable(Sema &SemaRef, NamedDecl *D); - - static bool isAcceptable(Sema &SemaRef, NamedDecl *D, - Sema::AcceptableKind Kind) { - return Kind == Sema::AcceptableKind::Visible ? isVisible(SemaRef, D) - : isReachable(SemaRef, D); + // During template instantiation, we can refer to hidden declarations, if + // they were visible in any module along the path of instantiation. + return isVisibleSlow(SemaRef, D); } - /// Determine whether this lookup is permitted to see the declaration. - /// Note that a reachable but not visible declaration inhabiting a namespace - /// is not allowed to be seen during name lookup. - /// - /// For example: - /// ``` - /// // m.cppm - /// export module m; - /// struct reachable { int v; } - /// export auto func() { return reachable{43}; } - /// // Use.cpp - /// import m; - /// auto Use() { - /// // Not valid. We couldn't see reachable here. - /// // So isAvailableForLookup would return false when we look - /// up 'reachable' here. - /// // return reachable(43).v; - /// // Valid. The field name 'v' is allowed during name lookup. - /// // So isAvailableForLookup would return true when we look up 'v' here. - /// return func().v; - /// } - /// ``` - static bool isAvailableForLookup(Sema &SemaRef, NamedDecl *ND); - /// Retrieve the accepted (re)declaration of the given declaration, /// if there is one. NamedDecl *getAcceptableDecl(NamedDecl *D) const { if (!D->isInIdentifierNamespace(IDNS)) return nullptr; - if (isAvailableForLookup(getSema(), D) || isHiddenDeclarationVisible(D)) + if (isVisible(getSema(), D) || isHiddenDeclarationVisible(D)) return D; return getAcceptableDeclSlow(D); } private: - static bool isAcceptableSlow(Sema &SemaRef, NamedDecl *D, - Sema::AcceptableKind Kind); - static bool isReachableSlow(Sema &SemaRef, NamedDecl *D); + static bool isVisibleSlow(Sema &SemaRef, NamedDecl *D); NamedDecl *getAcceptableDeclSlow(NamedDecl *D) const; public: diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 07f3d2c654c1b..f3b134953d400 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -363,6 +363,8 @@ class Sema final { static bool mightHaveNonExternalLinkage(const DeclaratorDecl *FD); + bool isVisibleSlow(const NamedDecl *D); + /// Determine whether two declarations should be linked together, given that /// the old declaration might not be visible and the new declaration might /// not have external linkage. @@ -2216,8 +2218,6 @@ class Sema final { Default = AcceptSizeless }; - enum class AcceptableKind { Visible, Reachable }; - private: /// Methods for marking which expressions involve dereferencing a pointer /// marked with the 'noderef' attribute. Expressions are checked bottom up as @@ -2252,6 +2252,11 @@ class Sema final { /// Namespace definitions that we will export when they finish. llvm::SmallPtrSet<const NamespaceDecl*, 8> DeferredExportedNamespaces; + /// Get the module unit whose scope we are currently within. + Module *getCurrentModule() const { + return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module; + } + /// Helper function to judge if we are in module purview. /// Return false if we are not in a module. bool isCurrentModulePurview() const { @@ -2270,14 +2275,7 @@ class Sema final { bool isUsableModule(const Module *M); - bool isAcceptableSlow(const NamedDecl *D, AcceptableKind Kind); - public: - /// Get the module unit whose scope we are currently within. - Module *getCurrentModule() const { - return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module; - } - /// Get the module owning an entity. Module *getOwningModule(const Decl *Entity) { return Entity->getOwningModule(); @@ -2301,20 +2299,7 @@ class Sema final { /// Determine whether a declaration is visible to name lookup. bool isVisible(const NamedDecl *D) { - return D->isUnconditionallyVisible() || - isAcceptableSlow(D, AcceptableKind::Visible); - } - - /// Determine whether a declaration is reachable. - bool isReachable(const NamedDecl *D) { - // All visible declarations are reachable. - return D->isUnconditionallyVisible() || - isAcceptableSlow(D, AcceptableKind::Reachable); - } - - /// Determine whether a declaration is acceptable (visible/reachable). - bool isAcceptable(const NamedDecl *D, AcceptableKind Kind) { - return Kind == AcceptableKind::Visible ? isVisible(D) : isReachable(D); + return D->isUnconditionallyVisible() || isVisibleSlow(D); } /// Determine whether any declaration of an entity is visible. @@ -2323,17 +2308,8 @@ class Sema final { llvm::SmallVectorImpl<Module *> *Modules = nullptr) { return isVisible(D) || hasVisibleDeclarationSlow(D, Modules); } - bool hasVisibleDeclarationSlow(const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules); - /// Determine whether any declaration of an entity is reachable. - bool - hasReachableDeclaration(const NamedDecl *D, - llvm::SmallVectorImpl<Module *> *Modules = nullptr) { - return isReachable(D) || hasReachableDeclarationSlow(D, Modules); - } - bool hasReachableDeclarationSlow( - const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr); bool hasVisibleMergedDefinition(NamedDecl *Def); bool hasMergedDefinitionInCurrentModule(NamedDecl *Def); @@ -2351,54 +2327,21 @@ class Sema final { return hasVisibleDefinition(const_cast<NamedDecl*>(D), &Hidden); } - /// Determine if \p D has a reachable definition. If not, suggest a - /// declaration that should be made reachable to expose the definition. - bool hasReachableDefinition(NamedDecl *D, NamedDecl **Suggested, - bool OnlyNeedComplete = false); - bool hasReachableDefinition(NamedDecl *D) { - NamedDecl *Hidden; - return hasReachableDefinition(D, &Hidden); - } - - bool hasAcceptableDefinition(NamedDecl *D, NamedDecl **Suggested, - AcceptableKind Kind, - bool OnlyNeedComplete = false); - bool hasAcceptableDefinition(NamedDecl *D, AcceptableKind Kind) { - NamedDecl *Hidden; - return hasAcceptableDefinition(D, &Hidden, Kind); - } - /// Determine if the template parameter \p D has a visible default argument. bool hasVisibleDefaultArgument(const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr); - /// Determine if the template parameter \p D has a reachable default argument. - bool hasReachableDefaultArgument( - const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr); - /// Determine if the template parameter \p D has a reachable default argument. - bool hasAcceptableDefaultArgument(const NamedDecl *D, - llvm::SmallVectorImpl<Module *> *Modules, - Sema::AcceptableKind Kind); /// 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<Module *> *Modules = nullptr); - /// Determine if there is a reachable declaration of \p D that is an explicit - /// specialization declaration for a specialization of a template. (For a - /// member specialization, use hasReachableMemberSpecialization.) - bool hasReachableExplicitSpecialization( - const NamedDecl *D, llvm::SmallVectorImpl<Module *> *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( const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr); - /// Determine if there is a reachable declaration of \p D that is a member - /// specialization declaration (as opposed to an instantiated declaration). - bool hasReachableMemberSpecialization( - const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr); /// Determine if \p A and \p B are equivalent internal linkage declarations /// from diff erent modules, and thus an ambiguity error can be downgraded to @@ -3157,9 +3100,8 @@ class Sema final { /// We've found a use of a templated declaration that would trigger an /// implicit instantiation. Check that any relevant explicit specializations - /// and partial specializations are visible/reachable, and diagnose if not. + /// and partial specializations are visible, and diagnose if not. void checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec); - void checkSpecializationReachability(SourceLocation Loc, NamedDecl *Spec); /// Retrieve a suitable printing policy for diagnostics. PrintingPolicy getPrintingPolicy() const { diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 5e5101203e6cf..94f5d5cb89a24 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -588,7 +588,6 @@ static bool isExportedFromModuleInterfaceUnit(const NamedDecl *D) { // FIXME: Handle isModulePrivate. switch (D->getModuleOwnershipKind()) { case Decl::ModuleOwnershipKind::Unowned: - case Decl::ModuleOwnershipKind::ReachableWhenImported: case Decl::ModuleOwnershipKind::ModulePrivate: return false; case Decl::ModuleOwnershipKind::Visible: diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 3f8fedda7174e..97783ebd6b530 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -121,7 +121,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, // entering the context, and that can't happen in a SFINAE context. assert(!isSFINAEContext() && "partial specialization scope specifier in SFINAE context?"); - if (!hasReachableDefinition(PartialSpec)) + if (!hasVisibleDeclaration(PartialSpec)) diagnoseMissingImport(SS.getLastQualifierNameLoc(), PartialSpec, MissingImportKind::PartialSpecialization, /*Recover*/true); @@ -243,8 +243,8 @@ bool Sema::RequireCompleteEnumDecl(EnumDecl *EnumD, SourceLocation L, if (EnumD->isCompleteDefinition()) { // If we know about the definition but it is not visible, complain. NamedDecl *SuggestedDef = nullptr; - if (!hasReachableDefinition(EnumD, &SuggestedDef, - /*OnlyNeedComplete*/ false)) { + if (!hasVisibleDefinition(EnumD, &SuggestedDef, + /*OnlyNeedComplete*/false)) { // If the user is going to see an error here, recover by making the // definition visible. bool TreatAsComplete = !isSFINAEContext(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 7ed338d49a869..99dfebd603ffc 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -16310,12 +16310,7 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, if (getLangOpts().CPlusPlusModules && isCurrentModulePurview()) { Module *GlobalModule = PushGlobalModuleFragment(ExternLoc, /*IsImplicit=*/true); - /// According to [module.reach]p3.2, - /// The declaration in global module fragment is reachable if it is not - /// discarded. And the discarded declaration should be deleted. So it - /// doesn't matter mark the declaration in global module fragment as - /// reachable here. - D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ReachableWhenImported); + D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); D->setLocalOwningModule(GlobalModule); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 40fb60c729bc6..ce7706ab96cac 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -17943,7 +17943,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (NeedDefinition && (Func->getTemplateSpecializationKind() != TSK_Undeclared || Func->getMemberSpecializationInfo())) - checkSpecializationReachability(Loc, Func); + checkSpecializationVisibility(Loc, Func); if (getLangOpts().CUDA) CheckCUDACall(Loc, Func); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 47c7a61f8072f..9f2e1eac41be6 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1607,17 +1607,16 @@ bool Sema::hasMergedDefinitionInCurrentModule(NamedDecl *Def) { return false; } -template <typename ParmDecl> +template<typename ParmDecl> static bool -hasAcceptableDefaultArgument(Sema &S, const ParmDecl *D, - llvm::SmallVectorImpl<Module *> *Modules, - Sema::AcceptableKind Kind) { +hasVisibleDefaultArgument(Sema &S, const ParmDecl *D, + llvm::SmallVectorImpl<Module *> *Modules) { if (!D->hasDefaultArgument()) return false; while (D) { auto &DefaultArg = D->getDefaultArgStorage(); - if (!DefaultArg.isInherited() && S.isAcceptable(D, Kind)) + if (!DefaultArg.isInherited() && S.isVisible(D)) return true; if (!DefaultArg.isInherited() && Modules) { @@ -1631,36 +1630,20 @@ hasAcceptableDefaultArgument(Sema &S, const ParmDecl *D, return false; } -bool Sema::hasAcceptableDefaultArgument( - const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules, - Sema::AcceptableKind Kind) { - if (auto *P = dyn_cast<TemplateTypeParmDecl>(D)) - return ::hasAcceptableDefaultArgument(*this, P, Modules, Kind); - - if (auto *P = dyn_cast<NonTypeTemplateParmDecl>(D)) - return ::hasAcceptableDefaultArgument(*this, P, Modules, Kind); - - return ::hasAcceptableDefaultArgument( - *this, cast<TemplateTemplateParmDecl>(D), Modules, Kind); -} - bool Sema::hasVisibleDefaultArgument(const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) { - return hasAcceptableDefaultArgument(D, Modules, - Sema::AcceptableKind::Visible); -} - -bool Sema::hasReachableDefaultArgument( - const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) { - return hasAcceptableDefaultArgument(D, Modules, - Sema::AcceptableKind::Reachable); + if (auto *P = dyn_cast<TemplateTypeParmDecl>(D)) + return ::hasVisibleDefaultArgument(*this, P, Modules); + if (auto *P = dyn_cast<NonTypeTemplateParmDecl>(D)) + return ::hasVisibleDefaultArgument(*this, P, Modules); + return ::hasVisibleDefaultArgument(*this, cast<TemplateTemplateParmDecl>(D), + Modules); } -template <typename Filter> -static bool -hasAcceptableDeclarationImpl(Sema &S, const NamedDecl *D, - llvm::SmallVectorImpl<Module *> *Modules, Filter F, - Sema::AcceptableKind Kind) { +template<typename Filter> +static bool hasVisibleDeclarationImpl(Sema &S, const NamedDecl *D, + llvm::SmallVectorImpl<Module *> *Modules, + Filter F) { bool HasFilteredRedecls = false; for (auto *Redecl : D->redecls()) { @@ -1668,7 +1651,7 @@ hasAcceptableDeclarationImpl(Sema &S, const NamedDecl *D, if (!F(R)) continue; - if (S.isAcceptable(R, Kind)) + if (S.isVisible(R)) return true; HasFilteredRedecls = true; @@ -1684,115 +1667,74 @@ hasAcceptableDeclarationImpl(Sema &S, const NamedDecl *D, return true; } -static bool -hasAcceptableExplicitSpecialization(Sema &S, const NamedDecl *D, - llvm::SmallVectorImpl<Module *> *Modules, - Sema::AcceptableKind Kind) { - return hasAcceptableDeclarationImpl( - S, D, Modules, - [](const NamedDecl *D) { - if (auto *RD = dyn_cast<CXXRecordDecl>(D)) - return RD->getTemplateSpecializationKind() == - TSK_ExplicitSpecialization; - if (auto *FD = dyn_cast<FunctionDecl>(D)) - return FD->getTemplateSpecializationKind() == - TSK_ExplicitSpecialization; - if (auto *VD = dyn_cast<VarDecl>(D)) - return VD->getTemplateSpecializationKind() == - TSK_ExplicitSpecialization; - llvm_unreachable("unknown explicit specialization kind"); - }, - Kind); -} - bool Sema::hasVisibleExplicitSpecialization( const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) { - return ::hasAcceptableExplicitSpecialization(*this, D, Modules, - Sema::AcceptableKind::Visible); + return hasVisibleDeclarationImpl(*this, D, Modules, [](const NamedDecl *D) { + if (auto *RD = dyn_cast<CXXRecordDecl>(D)) + return RD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization; + if (auto *FD = dyn_cast<FunctionDecl>(D)) + return FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization; + if (auto *VD = dyn_cast<VarDecl>(D)) + return VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization; + llvm_unreachable("unknown explicit specialization kind"); + }); } -bool Sema::hasReachableExplicitSpecialization( +bool Sema::hasVisibleMemberSpecialization( const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) { - return ::hasAcceptableExplicitSpecialization(*this, D, Modules, - Sema::AcceptableKind::Reachable); -} - -static bool -hasAcceptableMemberSpecialization(Sema &S, const NamedDecl *D, - llvm::SmallVectorImpl<Module *> *Modules, - Sema::AcceptableKind Kind) { assert(isa<CXXRecordDecl>(D->getDeclContext()) && "not a member specialization"); - return hasAcceptableDeclarationImpl( - S, 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. - // - // 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? - return D->getLexicalDeclContext()->isFileContext(); - }, - Kind); -} - -bool Sema::hasVisibleMemberSpecialization( - const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) { - return hasAcceptableMemberSpecialization(*this, D, Modules, - Sema::AcceptableKind::Visible); -} - -bool Sema::hasReachableMemberSpecialization( - const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) { - return hasAcceptableMemberSpecialization(*this, D, Modules, - Sema::AcceptableKind::Reachable); + 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. + // + // 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? + return D->getLexicalDeclContext()->isFileContext(); + }); } -/// Determine whether a declaration is acceptable to name lookup. +/// Determine whether a declaration is visible to name lookup. /// -/// This routine determines whether the declaration D is acceptable in the -/// current lookup context, taking into account the current template -/// instantiation stack. During template instantiation, a declaration is -/// acceptable if it is acceptable from a module containing any entity on the -/// template instantiation path (by instantiating a template, you allow it to -/// see the declarations that your module can see, including those later on in -/// your module). -bool LookupResult::isAcceptableSlow(Sema &SemaRef, NamedDecl *D, - Sema::AcceptableKind Kind) { +/// This routine determines whether the declaration D is visible in the current +/// lookup context, taking into account the current template instantiation +/// stack. During template instantiation, a declaration is visible if it is +/// visible from a module containing any entity on the template instantiation +/// path (by instantiating a template, you allow it to see the declarations that +/// your module can see, including those later on in your module). +bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { assert(!D->isUnconditionallyVisible() && "should not call this: not in slow case"); Module *DeclModule = SemaRef.getOwningModule(D); assert(DeclModule && "hidden decl has no owning module"); - // If the owning module is visible, the decl is acceptable. - if (SemaRef.isModuleVisible(DeclModule, - D->isInvisibleOutsideTheOwningModule())) + if (SemaRef.isModuleVisible(DeclModule, D->isModulePrivate())) + // If the owning module is visible, the decl is visible. return true; // Determine whether a decl context is a file context for the purpose of - // visibility/reachability. This looks through some (export and linkage spec) - // transparent contexts, but not others (enums). + // visibility. This looks through some (export and linkage spec) transparent + // contexts, but not others (enums). auto IsEffectivelyFileContext = [](const DeclContext *DC) { return DC->isFileContext() || isa<LinkageSpecDecl>(DC) || isa<ExportDecl>(DC); }; // If this declaration is not at namespace scope - // then it is acceptable if its lexical parent has a acceptable definition. + // then it is visible if its lexical parent has a visible definition. DeclContext *DC = D->getLexicalDeclContext(); if (DC && !IsEffectivelyFileContext(DC)) { // For a parameter, check whether our current template declaration's - // lexical context is acceptable, not whether there's some other acceptable + // lexical context is visible, not whether there's some other visible // definition of it, because parameters aren't "within" the definition. // - // In C++ we need to check for a acceptable definition due to ODR merging, + // In C++ we need to check for a visible definition due to ODR merging, // and in C we must not because each declaration of a function gets its own // set of declarations for tags in prototype scope. - bool AcceptableWithinParent; + bool VisibleWithinParent; if (D->isTemplateParameter()) { bool SearchDefinitions = true; if (const auto *DCD = dyn_cast<Decl>(DC)) { @@ -1803,63 +1745,41 @@ bool LookupResult::isAcceptableSlow(Sema &SemaRef, NamedDecl *D, } } if (SearchDefinitions) - AcceptableWithinParent = - SemaRef.hasAcceptableDefinition(cast<NamedDecl>(DC), Kind); + VisibleWithinParent = SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC)); else - AcceptableWithinParent = - isAcceptable(SemaRef, cast<NamedDecl>(DC), Kind); + VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC)); } else if (isa<ParmVarDecl>(D) || (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus)) - AcceptableWithinParent = isAcceptable(SemaRef, cast<NamedDecl>(DC), Kind); + VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC)); else if (D->isModulePrivate()) { - // A module-private declaration is only acceptable if an enclosing lexical + // A module-private declaration is only visible if an enclosing lexical // parent was merged with another definition in the current module. - AcceptableWithinParent = false; + VisibleWithinParent = false; do { if (SemaRef.hasMergedDefinitionInCurrentModule(cast<NamedDecl>(DC))) { - AcceptableWithinParent = true; + VisibleWithinParent = true; break; } DC = DC->getLexicalParent(); } while (!IsEffectivelyFileContext(DC)); } else { - AcceptableWithinParent = - SemaRef.hasAcceptableDefinition(cast<NamedDecl>(DC), Kind); + VisibleWithinParent = SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC)); } - if (AcceptableWithinParent && SemaRef.CodeSynthesisContexts.empty() && - Kind == Sema::AcceptableKind::Visible && + if (VisibleWithinParent && SemaRef.CodeSynthesisContexts.empty() && // FIXME: Do something better in this case. !SemaRef.getLangOpts().ModulesLocalVisibility) { // Cache the fact that this declaration is implicitly visible because // its parent has a visible definition. D->setVisibleDespiteOwningModule(); } - return AcceptableWithinParent; + return VisibleWithinParent; } - if (Kind == Sema::AcceptableKind::Visible) - return false; - - assert(Kind == Sema::AcceptableKind::Reachable && - "Additional Sema::AcceptableKind?"); - return isReachableSlow(SemaRef, D); + return false; } bool Sema::isModuleVisible(const Module *M, bool ModulePrivate) { - // [module.global.frag]p2: - // A global-module-fragment specifies the contents of the global module - // fragment for a module unit. The global module fragment can be used to - // provide declarations that are attached to the global module and usable - // within the module unit. - // - // Global module fragment is special. Global Module fragment is only usable - // within the module unit it got defined [module.global.frag]p2. So here we - // check if the Module is the global module fragment in current translation - // unit. - if (M->isGlobalModule() && M != this->GlobalModuleFragment) - return false; - // The module might be ordinarily visible. For a module-private query, that // means it is part of the current module. if (ModulePrivate && isUsableModule(M)) @@ -1892,74 +1812,8 @@ bool Sema::isModuleVisible(const Module *M, bool ModulePrivate) { }); } -// FIXME: Return false directly if we don't have an interface dependency on the -// translation unit containing D. -bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) { - assert(!isVisible(SemaRef, D) && "Shouldn't call the slow case.\n"); - - Module *DeclModule = SemaRef.getOwningModule(D); - assert(DeclModule && "hidden decl has no owning module"); - - // Entities in module map modules are reachable only if they're visible. - if (DeclModule->isModuleMapModule()) - return false; - - // If D comes from a module and SemaRef doesn't own a module, it implies D - // comes from another TU. In case SemaRef owns a module, we could judge if D - // comes from another TU by comparing the module unit. - // - // FIXME: It would look better if we have direct method to judge whether D is - // in another TU. - if (SemaRef.getCurrentModule() && - SemaRef.getCurrentModule()->getTopLevelModule() == - DeclModule->getTopLevelModule()) - return true; - - // [module.reach]/p3: - // A declaration D is reachable from a point P if: - // ... - // - D is not discarded ([module.global.frag]), appears in a translation unit - // that is reachable from P, and does not appear within a private module - // fragment. - // - // A declaration that's discarded in the GMF should be module-private. - if (D->isModulePrivate()) - return false; - - // [module.reach]/p1 - // A translation unit U is necessarily reachable from a point P if U is a - // module interface unit on which the translation unit containing P has an - // interface dependency, or the translation unit containing P imports U, in - // either case prior to P ([module.import]). - // - // [module.import]/p10 - // A translation unit has an interface dependency on a translation unit U if - // it contains a declaration (possibly a module-declaration) that imports U - // or if it has an interface dependency on a translation unit that has an - // interface dependency on U. - // - // So we could conclude the module unit U is necessarily reachable if: - // (1) The module unit U is module interface unit. - // (2) The current unit has an interface dependency on the module unit U. - // - // Here we only check for the first condition. Since we couldn't see - // DeclModule if it isn't (transitively) imported. - if (DeclModule->getTopLevelModule()->isModuleInterfaceUnit()) - return true; - - // [module.reach]/p2 - // Additional translation units on - // which the point within the program has an interface dependency may be - // considered reachable, but it is unspecified which are and under what - // circumstances. - // - // The decision here is to treat all additional tranditional units as - // unreachable. - return false; -} - -bool Sema::isAcceptableSlow(const NamedDecl *D, Sema::AcceptableKind Kind) { - return LookupResult::isAcceptable(*this, const_cast<NamedDecl *>(D), Kind); +bool Sema::isVisibleSlow(const NamedDecl *D) { + return LookupResult::isVisible(*this, const_cast<NamedDecl*>(D)); } bool Sema::shouldLinkPossiblyHiddenDecl(LookupResult &R, const NamedDecl *New) { @@ -2008,7 +1862,7 @@ bool Sema::shouldLinkPossiblyHiddenDecl(LookupResult &R, const NamedDecl *New) { /// and visible. If no declaration of D is visible, returns null. static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D, unsigned IDNS) { - assert(!LookupResult::isAvailableForLookup(SemaRef, D) && "not in slow case"); + assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case"); for (auto RD : D->redecls()) { // Don't bother with extra checks if we already know this one isn't visible. @@ -2020,7 +1874,7 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D, // visible in the same scope as D. This needs to be done much more // carefully. if (ND->isInIdentifierNamespace(IDNS) && - LookupResult::isAvailableForLookup(SemaRef, ND)) + LookupResult::isVisible(SemaRef, ND)) return ND; } @@ -2030,17 +1884,8 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D, bool Sema::hasVisibleDeclarationSlow(const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) { assert(!isVisible(D) && "not in slow case"); - return hasAcceptableDeclarationImpl( - *this, D, Modules, [](const NamedDecl *) { return true; }, - Sema::AcceptableKind::Visible); -} - -bool Sema::hasReachableDeclarationSlow( - const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) { - assert(!isReachable(D) && "not in slow case"); - return hasAcceptableDeclarationImpl( - *this, D, Modules, [](const NamedDecl *) { return true; }, - Sema::AcceptableKind::Reachable); + return hasVisibleDeclarationImpl(*this, D, Modules, + [](const NamedDecl *) { return true; }); } NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const { @@ -2065,60 +1910,6 @@ NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const { return findAcceptableDecl(getSema(), D, IDNS); } -bool LookupResult::isVisible(Sema &SemaRef, NamedDecl *D) { - // If this declaration is already visible, return it directly. - if (D->isUnconditionallyVisible()) - return true; - - // During template instantiation, we can refer to hidden declarations, if - // they were visible in any module along the path of instantiation. - return isAcceptableSlow(SemaRef, D, Sema::AcceptableKind::Visible); -} - -bool LookupResult::isReachable(Sema &SemaRef, NamedDecl *D) { - if (D->isUnconditionallyVisible()) - return true; - - return isAcceptableSlow(SemaRef, D, Sema::AcceptableKind::Reachable); -} - -bool LookupResult::isAvailableForLookup(Sema &SemaRef, NamedDecl *ND) { - // We should check the visibility at the callsite already. - if (isVisible(SemaRef, ND)) - return true; - - auto *DC = ND->getDeclContext(); - // If ND is not visible and it is at namespace scope, it shouldn't be found - // by name lookup. - if (DC->isFileContext()) - return false; - - // [module.interface]p7 - // Class and enumeration member names can be found by name lookup in any - // context in which a definition of the type is reachable. - // - // FIXME: The current implementation didn't consider about scope. For example, - // ``` - // // m.cppm - // export module m; - // enum E1 { e1 }; - // // Use.cpp - // import m; - // void test() { - // auto a = E1::e1; // Error as expected. - // auto b = e1; // Should be error. namespace-scope name e1 is not visible - // } - // ``` - // For the above example, the current implementation would emit error for `a` - // correctly. However, the implementation wouldn't diagnose about `b` now. - // Since we only check the reachability for the parent only. - // See clang/test/CXX/module/module.interface/p7.cpp for example. - if (auto *TD = dyn_cast<TagDecl>(DC)) - return SemaRef.hasReachableDefinition(TD); - - return false; -} - /// Perform unqualified name lookup starting from a given /// scope. /// @@ -3850,16 +3641,7 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, } } else if (D->getFriendObjectKind()) { auto *RD = cast<CXXRecordDecl>(D->getLexicalDeclContext()); - // [basic.lookup.argdep]p4: - // Argument-dependent lookup finds all declarations of functions and - // function templates that - // - ... - // - are declared as a friend ([class.friend]) of any class with a - // reachable definition in the set of associated entities, - // - // FIXME: If there's a merged definition of D that is reachable, then - // the friend declaration should be considered. - if (AssociatedClasses.count(RD) && isReachable(D)) { + if (AssociatedClasses.count(RD) && isVisible(D)) { Visible = true; break; } diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index 3aa124d457b03..b0e7d30526a3c 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -90,14 +90,7 @@ Sema::ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc) { // All declarations created from now on are owned by the global module. auto *TU = Context.getTranslationUnitDecl(); - // [module.global.frag]p2 - // A global-module-fragment specifies the contents of the global module - // fragment for a module unit. The global module fragment can be used to - // provide declarations that are attached to the global module and usable - // within the module unit. - // - // So the declations in the global module shouldn't be visible by default. - TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ReachableWhenImported); + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible); TU->setLocalOwningModule(GlobalModule); // FIXME: Consider creating an explicit representation of this declaration. @@ -332,12 +325,10 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, VisibleModules.setVisible(Mod, ModuleLoc); // From now on, we have an owning module for all declarations we see. - // In C++20 modules, those declaration would be reachable when imported - // unless explicitily exported. - // Otherwise, those declarations are module-private unless explicitly + // However, those declarations are module-private unless explicitly // exported. auto *TU = Context.getTranslationUnitDecl(); - TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ReachableWhenImported); + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); TU->setLocalOwningModule(Mod); // We are in the module purview, but before any other (non import) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index dbfe6164bda2c..250dbcd4aba63 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -799,9 +799,8 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation, if (PatternDef && !IsEntityBeingDefined) { NamedDecl *SuggestedDef = nullptr; - if (!hasReachableDefinition(const_cast<NamedDecl *>(PatternDef), - &SuggestedDef, - /*OnlyNeedComplete*/ false)) { + if (!hasVisibleDefinition(const_cast<NamedDecl*>(PatternDef), &SuggestedDef, + /*OnlyNeedComplete*/false)) { // If we're allowed to diagnose this and recover, do so. bool Recover = Complain && !isSFINAEContext(); if (Complain) @@ -5256,7 +5255,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, HasDefaultArg = false; if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) { - if (!hasReachableDefaultArgument(TypeParm)) + if (!hasVisibleDefaultArgument(TypeParm)) return TemplateArgumentLoc(); HasDefaultArg = true; @@ -5273,7 +5272,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, if (NonTypeTemplateParmDecl *NonTypeParm = dyn_cast<NonTypeTemplateParmDecl>(Param)) { - if (!hasReachableDefaultArgument(NonTypeParm)) + if (!hasVisibleDefaultArgument(NonTypeParm)) return TemplateArgumentLoc(); HasDefaultArg = true; @@ -5291,7 +5290,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, TemplateTemplateParmDecl *TempTempParm = cast<TemplateTemplateParmDecl>(Param); - if (!hasReachableDefaultArgument(TempTempParm)) + if (!hasVisibleDefaultArgument(TempTempParm)) return TemplateArgumentLoc(); HasDefaultArg = true; @@ -5629,10 +5628,10 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc, ->getTemplateParameters() ->getParam(D->getIndex())); - // If there's a default argument that's not reachable, diagnose that we're + // If there's a default argument that's not visible, diagnose that we're // missing a module import. llvm::SmallVector<Module*, 8> Modules; - if (D->hasDefaultArgument() && !S.hasReachableDefaultArgument(D, &Modules)) { + if (D->hasDefaultArgument() && !S.hasVisibleDefaultArgument(D, &Modules)) { S.diagnoseMissingImport(Loc, cast<NamedDecl>(TD), D->getDefaultArgumentLoc(), Modules, Sema::MissingImportKind::DefaultArgument, @@ -5815,7 +5814,7 @@ bool Sema::CheckTemplateArgumentList( // (when the template parameter was part of a nested template) into // the default argument. if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { - if (!hasReachableDefaultArgument(TTP)) + if (!hasVisibleDefaultArgument(TTP)) return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP, NewArgs); @@ -5832,7 +5831,7 @@ bool Sema::CheckTemplateArgumentList( ArgType); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { - if (!hasReachableDefaultArgument(NTTP)) + if (!hasVisibleDefaultArgument(NTTP)) return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP, NewArgs); @@ -5850,7 +5849,7 @@ bool Sema::CheckTemplateArgumentList( TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(*Param); - if (!hasReachableDefaultArgument(TempParm)) + if (!hasVisibleDefaultArgument(TempParm)) return diagnoseMissingArgument(*this, TemplateLoc, Template, TempParm, NewArgs); @@ -11007,12 +11006,10 @@ class ExplicitSpecializationVisibilityChecker { Sema &S; SourceLocation Loc; llvm::SmallVector<Module *, 8> Modules; - Sema::AcceptableKind Kind; public: - ExplicitSpecializationVisibilityChecker(Sema &S, SourceLocation Loc, - Sema::AcceptableKind Kind) - : S(S), Loc(Loc), Kind(Kind) {} + ExplicitSpecializationVisibilityChecker(Sema &S, SourceLocation Loc) + : S(S), Loc(Loc) {} void check(NamedDecl *ND) { if (auto *FD = dyn_cast<FunctionDecl>(ND)) @@ -11040,23 +11037,6 @@ class ExplicitSpecializationVisibilityChecker { S.diagnoseMissingImport(Loc, D, D->getLocation(), Modules, Kind, Recover); } - bool CheckMemberSpecialization(const NamedDecl *D) { - return Kind == Sema::AcceptableKind::Visible - ? S.hasVisibleMemberSpecialization(D) - : S.hasReachableMemberSpecialization(D); - } - - bool CheckExplicitSpecialization(const NamedDecl *D) { - return Kind == Sema::AcceptableKind::Visible - ? S.hasVisibleExplicitSpecialization(D) - : S.hasReachableExplicitSpecialization(D); - } - - bool CheckDeclaration(const NamedDecl *D) { - return Kind == Sema::AcceptableKind::Visible ? S.hasVisibleDeclaration(D) - : S.hasReachableDeclaration(D); - } - // Check a specific declaration. There are three problematic cases: // // 1) The declaration is an explicit specialization of a template @@ -11073,9 +11053,10 @@ class ExplicitSpecializationVisibilityChecker { void checkImpl(SpecDecl *Spec) { bool IsHiddenExplicitSpecialization = false; if (Spec->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { - IsHiddenExplicitSpecialization = Spec->getMemberSpecializationInfo() - ? !CheckMemberSpecialization(Spec) - : !CheckExplicitSpecialization(Spec); + IsHiddenExplicitSpecialization = + Spec->getMemberSpecializationInfo() + ? !S.hasVisibleMemberSpecialization(Spec, &Modules) + : !S.hasVisibleExplicitSpecialization(Spec, &Modules); } else { checkInstantiated(Spec); } @@ -11099,7 +11080,7 @@ class ExplicitSpecializationVisibilityChecker { checkTemplate(TD); else if (auto *TD = From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) { - if (!CheckDeclaration(TD)) + if (!S.hasVisibleDeclaration(TD)) diagnose(TD, true); checkTemplate(TD); } @@ -11115,7 +11096,7 @@ class ExplicitSpecializationVisibilityChecker { checkTemplate(TD); else if (auto *TD = From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) { - if (!CheckDeclaration(TD)) + if (!S.hasVisibleDeclaration(TD)) diagnose(TD, true); checkTemplate(TD); } @@ -11126,7 +11107,7 @@ class ExplicitSpecializationVisibilityChecker { template<typename TemplDecl> void checkTemplate(TemplDecl *TD) { if (TD->isMemberSpecialization()) { - if (!CheckMemberSpecialization(TD)) + if (!S.hasVisibleMemberSpecialization(TD, &Modules)) diagnose(TD->getMostRecentDecl(), false); } } @@ -11137,17 +11118,5 @@ void Sema::checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec) { if (!getLangOpts().Modules) return; - ExplicitSpecializationVisibilityChecker(*this, Loc, - Sema::AcceptableKind::Visible) - .check(Spec); -} - -void Sema::checkSpecializationReachability(SourceLocation Loc, - NamedDecl *Spec) { - if (!getLangOpts().CPlusPlusModules) - return checkSpecializationVisibility(Loc, Spec); - - ExplicitSpecializationVisibilityChecker(*this, Loc, - Sema::AcceptableKind::Reachable) - .check(Spec); + ExplicitSpecializationVisibilityChecker(*this, Loc).check(Spec); } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 3edce941c3817..0015d6a870b98 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8642,8 +8642,17 @@ bool Sema::hasStructuralCompatLayout(Decl *D, Decl *Suggested) { return Ctx.IsEquivalent(D, Suggested); } -bool Sema::hasAcceptableDefinition(NamedDecl *D, NamedDecl **Suggested, - AcceptableKind Kind, bool OnlyNeedComplete) { +/// Determine whether there is any declaration of \p D that was ever a +/// definition (perhaps before module merging) and is currently visible. +/// \param D The definition of the entity. +/// \param Suggested Filled in with the declaration that should be made visible +/// in order to provide a definition of this entity. +/// \param OnlyNeedComplete If \c true, we only need the type to be complete, +/// not defined. This only matters for enums with a fixed underlying +/// type, since in all other cases, a type is complete if and only if it +/// is defined. +bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, + bool OnlyNeedComplete) { // Easy case: if we don't have modules, all declarations are visible. if (!getLangOpts().Modules && !getLangOpts().ModulesLocalVisibility) return true; @@ -8687,14 +8696,13 @@ bool Sema::hasAcceptableDefinition(NamedDecl *D, NamedDecl **Suggested, VD = Pattern; D = VD->getDefinition(); } - assert(D && "missing definition for pattern of instantiated definition"); *Suggested = D; - auto DefinitionIsAcceptable = [&] { + auto DefinitionIsVisible = [&] { // The (primary) definition might be in a visible module. - if (isAcceptable(D, Kind)) + if (isVisible(D)) return true; // A visible module might have a merged definition instead. @@ -8712,51 +8720,19 @@ bool Sema::hasAcceptableDefinition(NamedDecl *D, NamedDecl **Suggested, return false; }; - if (DefinitionIsAcceptable()) + if (DefinitionIsVisible()) return true; // The external source may have additional definitions of this entity that are // visible, so complete the redeclaration chain now and ask again. if (auto *Source = Context.getExternalSource()) { Source->CompleteRedeclChain(D); - return DefinitionIsAcceptable(); + return DefinitionIsVisible(); } return false; } -/// Determine whether there is any declaration of \p D that was ever a -/// definition (perhaps before module merging) and is currently visible. -/// \param D The definition of the entity. -/// \param Suggested Filled in with the declaration that should be made visible -/// in order to provide a definition of this entity. -/// \param OnlyNeedComplete If \c true, we only need the type to be complete, -/// not defined. This only matters for enums with a fixed underlying -/// type, since in all other cases, a type is complete if and only if it -/// is defined. -bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, - bool OnlyNeedComplete) { - return hasAcceptableDefinition(D, Suggested, Sema::AcceptableKind::Visible, - OnlyNeedComplete); -} - -/// Determine whether there is any declaration of \p D that was ever a -/// definition (perhaps before module merging) and is currently -/// reachable. -/// \param D The definition of the entity. -/// \param Suggested Filled in with the declaration that should be made -/// reachable -/// in order to provide a definition of this entity. -/// \param OnlyNeedComplete If \c true, we only need the type to be complete, -/// not defined. This only matters for enums with a fixed underlying -/// type, since in all other cases, a type is complete if and only if it -/// is defined. -bool Sema::hasReachableDefinition(NamedDecl *D, NamedDecl **Suggested, - bool OnlyNeedComplete) { - return hasAcceptableDefinition(D, Suggested, Sema::AcceptableKind::Reachable, - OnlyNeedComplete); -} - /// Locks in the inheritance model for the given class and all of its bases. static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { RD = RD->getMostRecentNonInjectedDecl(); @@ -8826,19 +8802,20 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // Check that any necessary explicit specializations are visible. For an // enum, we just need the declaration, so don't check this. if (Def && !isa<EnumDecl>(Def)) - checkSpecializationReachability(Loc, Def); + checkSpecializationVisibility(Loc, Def); // If we have a complete type, we're done. if (!Incomplete) { - NamedDecl *Suggested = nullptr; + // If we know about the definition but it is not visible, complain. + NamedDecl *SuggestedDef = nullptr; if (Def && - !hasReachableDefinition(Def, &Suggested, /*OnlyNeedComplete=*/true)) { + !hasVisibleDefinition(Def, &SuggestedDef, /*OnlyNeedComplete*/true)) { // If the user is going to see an error here, recover by making the // definition visible. bool TreatAsComplete = Diagnoser && !isSFINAEContext(); - if (Diagnoser && Suggested) - diagnoseMissingImport(Loc, Suggested, MissingImportKind::Definition, - /*Recover*/ TreatAsComplete); + if (Diagnoser && SuggestedDef) + diagnoseMissingImport(Loc, SuggestedDef, MissingImportKind::Definition, + /*Recover*/TreatAsComplete); return !TreatAsComplete; } else if (Def && !TemplateInstCallbacks.empty()) { CodeSynthesisContext TempInst; diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index b4506da2bb2ba..ae298557ee49c 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -605,27 +605,15 @@ void ASTDeclReader::VisitDecl(Decl *D) { D->setTopLevelDeclInObjCContainer(Record.readInt()); D->setAccess((AccessSpecifier)Record.readInt()); D->FromASTFile = true; - auto ModuleOwnership = (Decl::ModuleOwnershipKind)Record.readInt(); - bool ModulePrivate = - (ModuleOwnership == Decl::ModuleOwnershipKind::ModulePrivate); + bool ModulePrivate = Record.readInt(); // Determine whether this declaration is part of a (sub)module. If so, it // may not yet be visible. if (unsigned SubmoduleID = readSubmoduleID()) { - - switch (ModuleOwnership) { - case Decl::ModuleOwnershipKind::Visible: - ModuleOwnership = Decl::ModuleOwnershipKind::VisibleWhenImported; - break; - case Decl::ModuleOwnershipKind::Unowned: - case Decl::ModuleOwnershipKind::VisibleWhenImported: - case Decl::ModuleOwnershipKind::ReachableWhenImported: - case Decl::ModuleOwnershipKind::ModulePrivate: - break; - } - - D->setModuleOwnershipKind(ModuleOwnership); // Store the owning submodule ID in the declaration. + D->setModuleOwnershipKind( + ModulePrivate ? Decl::ModuleOwnershipKind::ModulePrivate + : Decl::ModuleOwnershipKind::VisibleWhenImported); D->setOwningModuleID(SubmoduleID); if (ModulePrivate) { diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 01f692c9611b7..3666d5a6daab8 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -311,7 +311,7 @@ void ASTDeclWriter::VisitDecl(Decl *D) { Record.push_back(D->isReferenced()); Record.push_back(D->isTopLevelDeclInObjCContainer()); Record.push_back(D->getAccess()); - Record.push_back((uint64_t)D->getModuleOwnershipKind()); + Record.push_back(D->isModulePrivate()); Record.push_back(Writer.getSubmoduleID(D->getOwningModule())); // If this declaration injected a name into a context diff erent from its @@ -1928,7 +1928,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModuleOwnershipKind + Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -1961,7 +1961,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModuleOwnershipKind + Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -1999,7 +1999,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModuleOwnershipKind + Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2049,7 +2049,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModuleOwnershipKind + Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2111,7 +2111,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModuleOwnershipKind + Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2159,7 +2159,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModuleOwnershipKind + Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2188,7 +2188,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModuleOwnershipKind + Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2240,7 +2240,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Referenced Abv->Add(BitCodeAbbrevOp(0)); // InObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Access - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModuleOwnershipKind + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(DeclarationName::Identifier)); // NameKind diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4-friend-in-reachable-class.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4-friend-in-reachable-class.cpp deleted file mode 100644 index 638057cbd681f..0000000000000 --- a/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4-friend-in-reachable-class.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// This tests for [basic.lookup.argdep]/p4.2: -// Argument-dependent lookup finds all declarations of functions and function templates that -// - ... -// - are declared as a friend ([class.friend]) of any class with a reachable definition in the set of associated entities, -// -// RUN: rm -fr %t -// RUN: mkdir %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/Friend-in-reachable-class.cppm -o %t/X.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/Use.cpp -verify -fsyntax-only -// -//--- Friend-in-reachable-class.cppm -module; -# 3 __FILE__ 1 -struct A { - friend int operator+(const A &lhs, const A &rhs) { - return 0; - } -}; -# 6 "" 2 -export module X; -export using ::A; - -//--- Use.cpp -// expected-no-diagnostics -import X; -int use() { - A a, b; - return a + b; -} diff --git a/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp b/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp index d4b425b22fd6a..79529c6c0fc0a 100644 --- a/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp +++ b/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp @@ -30,20 +30,17 @@ module; void test_early() { in_header = 1; // expected-error {{missing '#include "foo.h"'; 'in_header' must be declared before it is used}} - // expected-note@* {{not visible}} + // expected-note@*{{not visible}} global_module_fragment = 1; // expected-error {{missing '#include'; 'global_module_fragment' must be declared before it is used}} - // expected-n...@p2.cpp:16 {{not visible}} + // expected-n...@p2.cpp:16 {{not visible}} exported = 1; // expected-error {{must be imported from module 'A'}} - // expected-n...@p2.cpp:18 {{declaration here is not visible}} + // expected-n...@p2.cpp:18 {{not visible}} - not_exported = 1; // expected-error {{declaration of 'not_exported' must be imported from module 'A' before it is required}} - // expected-n...@p2.cpp:19 {{declaration here is not visible}} + not_exported = 1; // expected-error {{undeclared identifier}} - // FIXME: We need better diagnostic message for static variable. - internal = 1; // expected-error {{declaration of 'internal' must be imported from module 'A' before it is required}} - // expected-n...@p2.cpp:20 {{declaration here is not visible}} + internal = 1; // expected-error {{undeclared identifier}} not_exported_private = 1; // expected-error {{undeclared identifier}} @@ -58,7 +55,7 @@ import A; void test_late() { in_header = 1; // expected-error {{missing '#include "foo.h"'; 'in_header' must be declared before it is used}} - // expected-note@* {{not visible}} + // expected-note@*{{not visible}} global_module_fragment = 1; // expected-error {{missing '#include'; 'global_module_fragment' must be declared before it is used}} // expected-n...@p2.cpp:16 {{not visible}} @@ -67,14 +64,14 @@ void test_late() { not_exported = 1; #ifndef IMPLEMENTATION - // expected-error@-2 {{declaration of 'not_exported' must be imported from module 'A' before it is required}} - // expected-n...@p2.cpp:19 {{declaration here is not visible}} + // expected-error@-2 {{undeclared identifier 'not_exported'; did you mean 'exported'}} + // expected-n...@p2.cpp:18 {{declared here}} #endif internal = 1; #ifndef IMPLEMENTATION - // expected-error@-2 {{declaration of 'internal' must be imported from module 'A' before it is required}} - // expected-n...@p2.cpp:20 {{declaration here is not visible}} + // FIXME: should not be visible here + // expected-error@-3 {{undeclared identifier}} #endif not_exported_private = 1; diff --git a/clang/test/CXX/module/module.context/p7.cpp b/clang/test/CXX/module/module.context/p7.cpp deleted file mode 100644 index 6a63e3e15aac4..0000000000000 --- a/clang/test/CXX/module/module.context/p7.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// RUN: rm -rf %t -// RUN: split-file %s %t -// RUN: cd %t - -// RUN: %clang_cc1 -std=c++20 -emit-header-unit -xc++-header-unit-header std-10-6-ex1-decl.h \ -// RUN: -o decl.pcm - -// RUN: %clang_cc1 -std=c++20 -emit-header-unit -xc++-header-unit-header std-10-6-ex1-defn.h \ -// RUN: -o defn.pcm - -// RUN: %clang_cc1 -std=c++20 -emit-module-interface std-10-6-ex1-stuff.cpp \ -// RUN: -o stuff.pcm - -// RUN: %clang_cc1 -std=c++20 -emit-module-interface std-10-6-ex1-M1.cpp \ -// RUN: -fmodule-file=stuff.pcm -o M1.pcm -fmodule-file=defn.pcm - -// RUN: %clang_cc1 -std=c++20 -emit-module-interface std-10-6-ex1-M2.cpp \ -// RUN: -fmodule-file=stuff.pcm -o M2.pcm -fmodule-file=decl.pcm - -// RUN: %clang_cc1 -std=c++20 std-10-6-ex1-use.cpp \ -// RUN: -fmodule-file=M1.pcm -fmodule-file=M2.pcm -fsyntax-only -verify - -//--- std-10-6-ex1-decl.h -struct X; - -//--- std-10-6-ex1-defn.h -struct X {}; - -//--- std-10-6-ex1-stuff.cpp -export module stuff; -export template <typename T, typename U> void foo(T, U u) { auto v = u; } -export template <typename T, typename U> void bar(T, U u) { auto v = *u; } - -//--- std-10-6-ex1-M1.cpp -export module M1; -import "std-10-6-ex1-defn.h"; // provides struct X {}; -import stuff; - -export template <typename T> void f(T t) { - X x; - foo(t, x); -} - -//--- std-10-6-ex1-M2.cpp -export module M2; -import "std-10-6-ex1-decl.h"; // provides struct X; (not a definition) - -import stuff; -export template <typename T> void g(T t) { - X *x; - bar(t, x); -} - -//--- std-10-6-ex1-use.cpp -import M1; -import M2; - -void test() { - f(0); - // It is unspecified whether the instantiation of g(0) is valid here. - // We choose to make it invalid here. - g(0); // expected-error@* {{definition of 'X' must be imported from module}} - // expected-note@* {{in instantiation of function template specialization 'bar<int, X *>'}} - // expected-note@* {{in instantiation of function template specialization}} - // expected-note@* {{definition here is not reachable}} -} diff --git a/clang/test/CXX/module/module.import/p2.cpp b/clang/test/CXX/module/module.import/p2.cpp index 0c02d253f3a89..7aa54e38f8c3f 100644 --- a/clang/test/CXX/module/module.import/p2.cpp +++ b/clang/test/CXX/module/module.import/p2.cpp @@ -23,10 +23,7 @@ export A f(); //--- Use.cpp import M; void test() { - A a; // expected-error {{declaration of 'A' must be imported from module 'M:impl'}} - // expected-error@-1 {{definition of 'A' must be imported from module 'M:impl'}} expected-error@-1 {{}} - // expected-n...@impl.cppm:2 {{declaration here is not visible}} - // expected-n...@impl.cppm:2 {{definition here is not reachable}} expected-n...@impl.cppm:2 {{}} + A a; // expected-error {{unknown type name 'A'}} } //--- UseInPartA.cppm @@ -41,10 +38,7 @@ void test() { export module B; import M; void test() { - A a; // expected-error {{declaration of 'A' must be imported from module 'M:impl'}} - // expected-error@-1 {{definition of 'A' must be imported from module 'M:impl'}} expected-error@-1 {{}} - // expected-n...@impl.cppm:2 {{declaration here is not visible}} - // expected-n...@impl.cppm:2 {{definition here is not reachable}} expected-n...@impl.cppm:2 {{}} + A a; // expected-error {{unknown type name 'A'}} } //--- Private.cppm diff --git a/clang/test/CXX/module/module.interface/p2.cpp b/clang/test/CXX/module/module.interface/p2.cpp index 804b0363ffa31..0a6f8c2aad567 100644 --- a/clang/test/CXX/module/module.interface/p2.cpp +++ b/clang/test/CXX/module/module.interface/p2.cpp @@ -69,29 +69,22 @@ import "header.h"; void use() { // namespace A is implicitly exported by the export of A::g. - A::f(); // expected-error {{declaration of 'f' must be imported from module 'p2' before it is required}} - // expected-note@* {{declaration here is not visible}} + A::f(); // expected-error {{no member named 'f' in namespace 'A'}} A::g(); - A::h(); // expected-error {{declaration of 'h' must be imported from module 'p2' before it is required}} - // expected-note@* {{declaration here is not visible}} - using namespace A::inner; // expected-error {{declaration of 'inner' must be imported from module 'p2' before it is required}} - // expected-note@* {{declaration here is not visible}} + A::h(); // expected-error {{no member named 'h' in namespace 'A'}} + using namespace A::inner; // expected-error {{expected namespace name}} // namespace B and B::inner are explicitly exported using namespace B; using namespace B::inner; - B::f(); // expected-error {{declaration of 'f' must be imported from module 'p2' before it is required}} - // expected-note@* {{declaration here is not visible}} - f(); // expected-error {{declaration of 'f' must be imported from module 'p2' before it is required}} - // expected-note@* {{declaration here is not visible}} + B::f(); // expected-error {{no member named 'f' in namespace 'B'}} + f(); // expected-error {{undeclared identifier 'f'}} // namespace C is not exported - using namespace C; // expected-error {{declaration of 'C' must be imported from module 'p2' before it is required}} - // expected-note@* {{declaration here is not visible}} + using namespace C; // expected-error {{expected namespace name}} // namespace D is exported, but D::f is not - D::f(); // expected-error {{declaration of 'f' must be imported from module 'p2' before it is required}} - // expected-note@* {{declaration here is not visible}} + D::f(); // expected-error {{no member named 'f' in namespace 'D'}} } int use_header() { return foo + bar::baz(); } diff --git a/clang/test/CXX/module/module.interface/p7.cpp b/clang/test/CXX/module/module.interface/p7.cpp deleted file mode 100644 index 1572390f0d289..0000000000000 --- a/clang/test/CXX/module/module.interface/p7.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 %t/p7.cppm -emit-module-interface -o %t/p7.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/Use.cpp -verify - -//--- p7.cppm -export module p7; -struct reachable { - constexpr static int sv = 43; - int value = 44; - - static int getValue() { return 43; } - int get() { return 44; } - - template <typename T> - static bool templ_get(T t) { return false; } - typedef int typedef_type; - using using_type = int; - template <typename T> - using templ_using_type = int; - bool operator()() { - return false; - } - - enum E { a, - b }; -}; - -export auto getReachable() { - return reachable{}; -} - -export enum E1 { e1 }; -enum E2 { e2 }; -export using E2U = E2; -enum E3 { e3 }; -export E3 func(); - -//--- Use.cpp -import p7; -void test() { - auto reachable = getReachable(); - int a = decltype(reachable)::sv; - int b = decltype(reachable)::getValue(); - int c = reachable.value; - int d = reachable.get(); - int e = decltype(reachable)::a; - int f = reachable.templ_get(a); - typename decltype(reachable)::typedef_type g; - typename decltype(reachable)::using_type h; - typename decltype(reachable)::template templ_using_type<int> j; - auto value = reachable(); -} - -void test2() { - auto a = E1::e1; // OK, namespace-scope name E1 is visible and e1 is reachable - auto b = e1; // OK, namespace-scope name e1 is visible - auto c = E2::e2; // expected-error {{declaration of 'E2' must be imported from module}} - // expected-note@* {{declaration here is not visible}} - auto d = e2; // should be error, namespace-scope name e2 is not visible - auto e = E2U::e2; // OK, namespace-scope name E2U is visible and E2::e2 is reachable - auto f = E3::e3; // expected-error {{declaration of 'E3' must be imported from module 'p7' before it is required}} - // expected-note@* {{declaration here is not visible}} - auto g = e3; // should be error, namespace-scope name e3 is not visible - auto h = decltype(func())::e3; // OK, namespace-scope name f is visible and E3::e3 is reachable -} diff --git a/clang/test/CXX/module/module.reach/ex1.cpp b/clang/test/CXX/module/module.reach/ex1.cpp deleted file mode 100644 index 00f87607dc1d8..0000000000000 --- a/clang/test/CXX/module/module.reach/ex1.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// From [module.reach]p4, example 1 -// -// RUN: rm -fr %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/M-A.cppm -o %t/M-A.pcm -// RUN: %clang_cc1 -std=c++20 -emit-module-interface -fprebuilt-module-path=%t %t/M-B-impl.cppm -o %t/M-B.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/M-C.cppm -fsyntax-only -verify -// -// RUN: %clang_cc1 -std=c++20 -emit-module-interface -fprebuilt-module-path=%t %t/M.cppm -o %t/M.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/X.cppm -fsyntax-only -verify -// -//--- M-A.cppm -export module M:A; -export struct B; - -//--- M-B-impl.cppm -module M:B; -struct B { - operator int(); -}; - -//--- M-C.cppm -module M:C; -import :A; -B b1; // expected-error {{variable has incomplete type 'B'}} - // expected-note@* {{forward declaration of 'B'}} - -//--- M.cppm -export module M; -export import :A; -import :B; -B b2; -export void f(B b = B()); - -//--- X.cppm -export module X; -import M; -B b3; // expected-error {{definition of 'B' must be imported from module 'M:B' before it is required}} expected-error {{}} - // expected-note@* {{definition here is not reachable}} expected-note@* {{}} -// FIXME: We should emit an error for unreachable definition of B. -void g() { f(); } diff --git a/clang/test/CXX/module/module.reach/p2.cpp b/clang/test/CXX/module/module.reach/p2.cpp deleted file mode 100644 index 6ccf6ee6d0566..0000000000000 --- a/clang/test/CXX/module/module.reach/p2.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// RUN: %clang_cc1 -std=c++20 %t/impl.cppm -emit-module-interface -o %t/M-impl.pcm -// RUN: %clang_cc1 -std=c++20 %t/M.cppm -emit-module-interface -fprebuilt-module-path=%t -o %t/M.pcm -// RUN: %clang_cc1 -std=c++20 %t/UseStrict.cpp -fprebuilt-module-path=%t -verify -fsyntax-only - -//--- impl.cppm -module M:impl; -class A {}; - -//--- M.cppm -export module M; -import :impl; -export A f(); - -//--- UseStrict.cpp -import M; -void test() { - auto a = f(); // expected-error {{definition of 'A' must be imported from module 'M:impl' before it is required}} expected-error{{}} - // expected-note@* {{definition here is not reachable}} expected-note@* {{}} -} diff --git a/clang/test/CXX/module/module.reach/p4/TransitiveImport.cpp b/clang/test/CXX/module/module.reach/p4/TransitiveImport.cpp deleted file mode 100644 index 96f80a209d266..0000000000000 --- a/clang/test/CXX/module/module.reach/p4/TransitiveImport.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// RUN: rm -fr %t -// RUN: mkdir %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 %t/foo.cppm -emit-module-interface -o %t/foo.pcm -// RUN: %clang_cc1 -std=c++20 %t/bar.cppm -emit-module-interface -fprebuilt-module-path=%t -o %t/bar.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t -verify %t/Use.cpp -fsyntax-only -// -//--- foo.cppm -export module foo; -export class foo { -}; - -//--- bar.cppm -export module bar; -import foo; -export auto bar() { - return foo{}; -} - -//--- Use.cpp -// expected-no-diagnostics -import bar; -auto foo() { - // [module.reach]Note1: - // While module interface units are reachable even when they - // are only transitively imported via a non-exported import declaration, - // namespace-scope names from such module interface units are not found - // by name lookup ([basic.lookup]). - auto b = bar(); // foo should be reachable here. -} diff --git a/clang/test/CXX/module/module.reach/p5.cpp b/clang/test/CXX/module/module.reach/p5.cpp deleted file mode 100644 index 9c498a260530f..0000000000000 --- a/clang/test/CXX/module/module.reach/p5.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// 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 -fprebuilt-module-path=%t %t/B.cppm -fsyntax-only -verify -// -//--- A.cppm -export module A; -struct X {}; -export using Y = X; - -//--- B.cppm -export module B; -import A; -Y y; // OK, definition of X is reachable -X x; // expected-error {{declaration of 'X' must be imported from module 'A' before it is required}} - // expected-note@* {{declaration here is not visible}} diff --git a/clang/test/CXX/module/module.unit/p7/t6.cpp b/clang/test/CXX/module/module.unit/p7/t6.cpp index bcc29d9ba25e0..8bd05c298d95d 100644 --- a/clang/test/CXX/module/module.unit/p7/t6.cpp +++ b/clang/test/CXX/module/module.unit/p7/t6.cpp @@ -2,11 +2,14 @@ // RUN: mkdir %t // RUN: %clang_cc1 -std=c++20 -emit-module-interface %S/Inputs/CPP.cppm -I%S/Inputs -o %t/X.pcm // RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %s -verify -// expected-no-diagnostics module; #include "Inputs/h2.h" export module use; import X; void printX(CPP *cpp) { - cpp->print(); + cpp->print(); // expected-error {{'CPP' must be defined before it is used}} + // expected-error@-1 {{'CPP' must be defined before it is used}} + // expected-error@-2 {{no member named 'print' in 'CPP'}} + // expected-note@Inputs/CPP.cppm:5 {{definition here is not reachable}} + // expected-note@Inputs/CPP.cppm:5 {{definition here is not reachable}} } diff --git a/clang/test/CXX/modules-ts/basic/basic.link/p2/other.cpp b/clang/test/CXX/modules-ts/basic/basic.link/p2/other.cpp index efac3f892ab79..8370777e7ed47 100644 --- a/clang/test/CXX/modules-ts/basic/basic.link/p2/other.cpp +++ b/clang/test/CXX/modules-ts/basic/basic.link/p2/other.cpp @@ -4,13 +4,12 @@ import M; void use_from_module_impl() { external_linkage_fn(); - module_linkage_fn(); // expected-error {{declaration of 'module_linkage_fn' must be imported}} - internal_linkage_fn(); // expected-error {{declaration of 'internal_linkage_fn' must be imported}} + module_linkage_fn(); // expected-error {{undeclared identifier}} + internal_linkage_fn(); // expected-error {{undeclared identifier}} (void)external_linkage_class{}; (void)module_linkage_class{}; // expected-error {{undeclared identifier}} expected-error 0+{{}} (void)internal_linkage_class{}; // expected-error {{undeclared identifier}} expected-error 0+{{}} - // expected-n...@module.cppm:10 {{declaration here is not visible}} - // expected-n...@module.cppm:11 {{declaration here is not visible}} + // expected-n...@module.cppm:9 {{here}} (void)external_linkage_var; (void)module_linkage_var; // expected-error {{undeclared identifier}} (void)internal_linkage_var; // expected-error {{undeclared identifier}} diff --git a/clang/test/Modules/Reachability-Private.cpp b/clang/test/Modules/Reachability-Private.cpp deleted file mode 100644 index fdaf5c349f8ae..0000000000000 --- a/clang/test/Modules/Reachability-Private.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// Tests that the definition in private module fragment is not reachable to its users. -// -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 %t/Private.cppm -emit-module-interface -o %t/Private.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/Use.cpp -verify -fsyntax-only - -//--- Private.cppm -export module Private; -inline void fn_m(); // OK, module-linkage inline function -static void fn_s(); -export struct X; - -export void g(X *x) { - fn_s(); // OK, call to static function in same translation unit - fn_m(); // OK, call to module-linkage inline function -} -export X *factory(); // OK - -module :private; -struct X {}; // definition not reachable from importers of A -X *factory() { - return new X(); -} -void fn_m() {} -void fn_s() {} - -//--- Use.cpp -import Private; -void foo() { - X x; // expected-error {{definition of 'X' must be imported from module 'Private.<private>' before it is required}} - // expected-error@-1 {{definition of 'X' must be imported from module 'Private.<private>' before it is required}} - // expected-note@* {{definition here is not reachable}} - // expected-note@* {{definition here is not reachable}} - auto _ = factory(); - auto *__ = factory(); - X *___ = factory(); - - g(__); - g(___); - g(factory()); -} diff --git a/clang/test/Modules/Reachability-func-default-arg.cpp b/clang/test/Modules/Reachability-func-default-arg.cpp deleted file mode 100644 index 0d6d8655d5329..0000000000000 --- a/clang/test/Modules/Reachability-func-default-arg.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 %t/func_default_arg.cppm -emit-module-interface -o %t/func_default_arg.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/Use.cpp -verify -fsyntax-only -// -//--- func_default_arg.cppm -export module func_default_arg; -struct t {}; -export t foo(t t1 = t()) { - return t1; -} - -//--- Use.cpp -// expected-no-diagnostics -import func_default_arg; -void bar() { - auto ret = foo(); -} diff --git a/clang/test/Modules/Reachability-func-ret.cpp b/clang/test/Modules/Reachability-func-ret.cpp deleted file mode 100644 index ca5bbc68d759f..0000000000000 --- a/clang/test/Modules/Reachability-func-ret.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 %t/func_ret.cppm -emit-module-interface -o %t/func_ret.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/Use.cpp -verify -fsyntax-only -// -//--- func_ret.cppm -export module func_ret; -struct t {}; -export t foo() { - return t{}; -} - -//--- Use.cpp -// expected-no-diagnostics -import func_ret; -void bar() { - auto ret = foo(); -} diff --git a/clang/test/Modules/Reachability-template-default-arg.cpp b/clang/test/Modules/Reachability-template-default-arg.cpp deleted file mode 100644 index 6fb109e41fcf0..0000000000000 --- a/clang/test/Modules/Reachability-template-default-arg.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 %t/template_default_arg.cppm -emit-module-interface -o %t/template_default_arg.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/Use.cpp -fsyntax-only -verify -// -//--- template_default_arg.cppm -export module template_default_arg; -struct t {}; - -export template <typename T = t> -struct A { - T a; -}; - -//--- Use.cpp -import template_default_arg; -void bar() { - A<> a0; - A<t> a1; // expected-error {{declaration of 't' must be imported from module 'template_default_arg' before it is required}} - // expected-note@* {{declaration here is not visible}} -} diff --git a/clang/test/Modules/Reachability-template-instantiation.cpp b/clang/test/Modules/Reachability-template-instantiation.cpp deleted file mode 100644 index 2170c7b92a370..0000000000000 --- a/clang/test/Modules/Reachability-template-instantiation.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 %t/Templ.cppm -emit-module-interface -o %t/Templ.pcm -// RUN: %clang_cc1 -std=c++20 %t/Use.cppm -fprebuilt-module-path=%t -emit-module-interface -o %t/Use.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t -I%t %t/Use.cpp -verify -fsyntax-only -// -//--- Templ.h -#ifndef TEMPL_H -#define TEMPL_H -template <class T> -class Wrapper { -public: - T value; -}; -#endif - -//--- Templ.cppm -export module Templ; -export template <class T> -class Wrapper2 { -public: - T value; -}; - -//--- Use.cppm -module; -#include "Templ.h" -export module Use; -import Templ; - -export template <class T> -class Use { -public: - Wrapper<T> value; - Wrapper2<T> value2; -}; - -export template <class T> -Wrapper<T> wrapper; - -//--- Use.cpp -// expected-no-diagnostics -module; -#include "Templ.h" -export module User; - -export template <class T> -class User { -public: - Wrapper<T> value; -}; diff --git a/clang/test/Modules/Reachability-using-templates.cpp b/clang/test/Modules/Reachability-using-templates.cpp deleted file mode 100644 index f530e15bd4d2b..0000000000000 --- a/clang/test/Modules/Reachability-using-templates.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 %t/mod.templates.cppm -emit-module-interface -o %t/mod.templates.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/Use.cpp -fsyntax-only -verify -// -//--- mod.templates.cppm -export module mod.templates; -template <class> struct t {}; -export template <class T> using u = t<T>; - -//--- Use.cpp -// expected-no-diagnostics -import mod.templates; -void foo() { - u<int> v{}; -} diff --git a/clang/test/Modules/Reachability-using.cpp b/clang/test/Modules/Reachability-using.cpp deleted file mode 100644 index 642b97dd8432c..0000000000000 --- a/clang/test/Modules/Reachability-using.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 %t/mod.cppm -emit-module-interface -o %t/mod.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/Use.cpp -fsyntax-only -verify -// -//--- mod.cppm -export module mod; -struct t {}; -export using u = t; - -//--- Use.cpp -// expected-no-diagnostics -import mod; -void foo() { - u v{}; -} diff --git a/clang/test/Modules/cxx20-10-1-ex2.cpp b/clang/test/Modules/cxx20-10-1-ex2.cpp index 03e2e26339005..88ec945d6a848 100644 --- a/clang/test/Modules/cxx20-10-1-ex2.cpp +++ b/clang/test/Modules/cxx20-10-1-ex2.cpp @@ -53,8 +53,7 @@ int &c = n; // OK //--- std10-1-ex2-tu6.cpp import B; // error, n is module-local and this is not a module. -int &c = n; // expected-error {{declaration of 'n' must be imported}} - // expected-note@* {{declaration here is not visible}} +int &c = n; // expected-error {{use of undeclared identifier}} //--- std10-1-ex2-tu7.cpp // expected-no-diagnostics diff --git a/clang/test/Modules/derived_class.cpp b/clang/test/Modules/derived_class.cpp deleted file mode 100644 index ee9e0ae4637ec..0000000000000 --- a/clang/test/Modules/derived_class.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 %t/foo.cppm -emit-module-interface -o %t/foo.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/Use.cpp -fsyntax-only -verify -// -//--- bar.h -struct bar_base { - enum A { - a, - b, - c, - d - }; - constexpr static bool value = false; - static bool get() { return false; } - bool member_value = false; - bool get_func() { return false; } -}; - -template <typename T> -struct bar : public bar_base { -}; - -//--- foo.cppm -module; -#include "bar.h" -export module foo; -export template <typename T> -int foo() { - bool a = bar<T>::value; - bar<T>::get(); - bar<T> b; - b.member_value = a; - bool c = b.get_func(); - return bar<T>::a; -} - -//--- Use.cpp -// expected-no-diagnostics -import foo; -void test() { - foo<int>(); -} diff --git a/clang/test/Modules/explicitly-specialized-template.cpp b/clang/test/Modules/explicitly-specialized-template.cpp deleted file mode 100644 index 89677254ea739..0000000000000 --- a/clang/test/Modules/explicitly-specialized-template.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 %t/X.cppm -emit-module-interface -o %t/X.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/Use.cpp -fsyntax-only -verify -// -//--- foo.h -#ifndef FOO_H -#define FOO_H -template <typename T> -struct base {}; - -template <typename T> -struct foo; - -template <typename T> -struct foo {}; - -template <> -struct foo<int> : base<int> { - int getInt(); -}; -#endif // FOO_H - -//--- X.cppm -module; -#include "foo.h" -export module X; -export template <class T> -class X { - foo<int> x; - -public: - int print() { - return x.getInt(); - } -}; - -//--- Use.cpp -import X; -foo<int> f; // expected-error {{'foo' must be declared before it is used}} - // expected-note@* {{declaration here is not visible}} -int bar() { - X<int> x; - return x.print(); -} diff --git a/clang/test/Modules/module-private.cpp b/clang/test/Modules/module-private.cpp index 2848226ba067c..a4b3b0fd21d39 100644 --- a/clang/test/Modules/module-private.cpp +++ b/clang/test/Modules/module-private.cpp @@ -21,8 +21,8 @@ int test_broken() { vector<int> vec; // expected-error{{no template named 'vector'}} VisibleStruct vs; - vs.field = 0; - vs.setField(1); + vs.field = 0; // expected-error{{no member named 'field' in 'VisibleStruct'}} + vs.setField(1); // expected-error{{no member named 'setField' in 'VisibleStruct'}} return hidden_var; // expected-error{{use of undeclared identifier 'hidden_var'}} } diff --git a/clang/test/Modules/template-function-specialization.cpp b/clang/test/Modules/template-function-specialization.cpp deleted file mode 100644 index 3eac92e7edb94..0000000000000 --- a/clang/test/Modules/template-function-specialization.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// RUN: rm -fr %t -// RUN: mkdir %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/foo.cppm -o %t/foo.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/Use.cpp -verify -fsyntax-only -// -//--- foo.cppm -module; -# 3 __FILE__ 1 // use the next physical line number here (and below) -template <typename T> -void foo() { -} - -template <> -void foo<int>() { -} - -template <typename T> -void foo2() { -} - -template <> -void foo2<int>() { -} - -template <typename T> -void foo3() { -} - -template <> -void foo3<int>(); - -export module foo; -export using ::foo; -export using ::foo3; - -export template <typename T> -void foo4() { -} - -export template <> -void foo4<int>() { -} - -//--- Use.cpp -import foo; -void use() { - foo<short>(); - foo<int>(); - foo2<short>(); // expected-error {{missing '#include'; 'foo2' must be declared before it is used}} - // expected-note@* {{declaration here is not visible}} - foo2<int>(); // expected-error {{missing '#include'; 'foo2' must be declared before it is used}} - // expected-note@* {{declaration here is not visible}} - foo3<short>(); - foo3<int>(); - - foo4<short>(); - foo4<int>(); -} diff --git a/clang/test/Modules/template_default_argument.cpp b/clang/test/Modules/template_default_argument.cpp deleted file mode 100644 index 5a7d1c04cf181..0000000000000 --- a/clang/test/Modules/template_default_argument.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 %t/B.cppm -emit-module-interface -o %t/B.pcm -// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/Use.cpp -fsyntax-only -verify -// -//--- templ.h -template <typename T, typename U = T> -class templ {}; -template <typename T, typename U = void> -void templ_func() {} - -//--- B.cppm -module; -#include "templ.h" -export module B; -export template <typename G> -templ<G> bar() { - templ_func<G>(); - return {}; -} - -//--- Use.cpp -// expected-no-diagnostics -import B; -auto foo() { - return bar<int>(); -} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits