Index: clang/include/clang/AST/DeclBase.h =================================================================== --- clang/include/clang/AST/DeclBase.h +++ clang/include/clang/AST/DeclBase.h @@ -18,6 +18,7 @@ #include "clang/AST/DeclarationName.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" +#include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "llvm/ADT/ArrayRef.h" @@ -231,8 +232,15 @@ /// module is imported. VisibleWhenImported, + /// This declaration has an owninig module, and is visible to lookups + /// that occurs within that module. And it is reachable to other module + /// when the owninig module is 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 }; @@ -241,8 +249,8 @@ /// DeclContext. These pointers form the linked list that is /// traversed via DeclContext's decls_begin()/decls_end(). /// - /// The extra two bits are used for the ModuleOwnershipKind. - llvm::PointerIntPair NextInContextAndBits; + /// The extra three bits are used for the ModuleOwnershipKind. + llvm::PointerIntPair NextInContextAndBits; private: friend class DeclContext; @@ -613,6 +621,19 @@ return getModuleOwnershipKind() == ModuleOwnershipKind::ModulePrivate; } + bool isInvisibleOutsideTheOwningModule() const { + return getModuleOwnershipKind() > ModuleOwnershipKind::VisibleWhenImported; + } + + bool isInGlobalModuleFragment() const { + Module *M = getOwningModule(); + return M ? M->isGlobalModule() : false; + } + + /// 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; Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -2283,6 +2283,13 @@ return hasVisibleDefinition(const_cast(D), &Hidden); } + bool hasReachableDefinition(NamedDecl *D, NamedDecl **Suggested, + bool OnlyNeedComplete = false); + bool hasReachableDefinition(NamedDecl *D) { + NamedDecl *Hidden; + return hasVisibleDefinition(D, &Hidden); + } + /// Determine if the template parameter \p D has a visible default argument. bool hasVisibleDefaultArgument(const NamedDecl *D, Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -579,6 +579,7 @@ // FIXME: Handle isModulePrivate. switch (D->getModuleOwnershipKind()) { case Decl::ModuleOwnershipKind::Unowned: + case Decl::ModuleOwnershipKind::ReachableWhenImported: case Decl::ModuleOwnershipKind::ModulePrivate: return false; case Decl::ModuleOwnershipKind::Visible: Index: clang/lib/Sema/SemaCXXScopeSpec.cpp =================================================================== --- clang/lib/Sema/SemaCXXScopeSpec.cpp +++ clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -121,7 +121,7 @@ // entering the context, and that can't happen in a SFINAE context. assert(!isSFINAEContext() && "partial specialization scope specifier in SFINAE context?"); - if (!hasVisibleDeclaration(PartialSpec)) + if (!hasReachableDefinition(PartialSpec)) diagnoseMissingImport(SS.getLastQualifierNameLoc(), PartialSpec, MissingImportKind::PartialSpecialization, /*Recover*/true); @@ -243,8 +243,8 @@ if (EnumD->isCompleteDefinition()) { // If we know about the definition but it is not visible, complain. NamedDecl *SuggestedDef = nullptr; - if (!hasVisibleDefinition(EnumD, &SuggestedDef, - /*OnlyNeedComplete*/false)) { + if (!hasReachableDefinition(EnumD, &SuggestedDef, + /*OnlyNeedComplete*/ false)) { // If the user is going to see an error here, recover by making the // definition visible. bool TreatAsComplete = !isSFINAEContext(); Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -16159,7 +16159,7 @@ if (getLangOpts().CPlusPlusModules && isCurrentModulePurview()) { Module *GlobalModule = PushGlobalModuleFragment(ExternLoc, /*IsImplicit=*/true); - D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); + D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ReachableWhenImported); D->setLocalOwningModule(GlobalModule); } Index: clang/lib/Sema/SemaLookup.cpp =================================================================== --- clang/lib/Sema/SemaLookup.cpp +++ clang/lib/Sema/SemaLookup.cpp @@ -1684,7 +1684,8 @@ assert(DeclModule && "hidden decl has no owning module"); // If the owning module is visible, the decl is visible. - if (SemaRef.isModuleVisible(DeclModule, D->isModulePrivate())) + if (SemaRef.isModuleVisible(DeclModule, + D->isInvisibleOutsideTheOwningModule())) return true; // Determine whether a decl context is a file context for the purpose of @@ -1752,6 +1753,18 @@ } 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. In this + // case, the global module fragment shouldn't own an AST File. + if (M->isGlobalModule() && M->getASTFile()) + return false; + // The module might be ordinarily visible. For a module-private query, that // means it is part of the current module. For any other query, that means it // is in our visible module set. Index: clang/lib/Sema/SemaModule.cpp =================================================================== --- clang/lib/Sema/SemaModule.cpp +++ clang/lib/Sema/SemaModule.cpp @@ -73,7 +73,14 @@ // All declarations created from now on are owned by the global module. auto *TU = Context.getTranslationUnitDecl(); - TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible); + // [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->setLocalOwningModule(GlobalModule); // FIXME: Consider creating an explicit representation of this declaration. @@ -225,10 +232,17 @@ VisibleModules.setVisible(Mod, ModuleLoc); // From now on, we have an owning module for all declarations we see. - // However, those declarations are module-private unless explicitly + // In C++20 modules, those declaration would be reachable when imported + // unless explicitily exported. + // Otherwise, those declarations are module-private unless explicitly // exported. auto *TU = Context.getTranslationUnitDecl(); - TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); + if (getLangOpts().CPlusPlusModules) + TU->setModuleOwnershipKind( + Decl::ModuleOwnershipKind::ReachableWhenImported); + else + // We want to leave the semantics of ModuleTS untouched. + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); TU->setLocalOwningModule(Mod); // FIXME: Create a ModuleDecl. Index: clang/lib/Sema/SemaTemplate.cpp =================================================================== --- clang/lib/Sema/SemaTemplate.cpp +++ clang/lib/Sema/SemaTemplate.cpp @@ -795,8 +795,9 @@ if (PatternDef && !IsEntityBeingDefined) { NamedDecl *SuggestedDef = nullptr; - if (!hasVisibleDefinition(const_cast(PatternDef), &SuggestedDef, - /*OnlyNeedComplete*/false)) { + if (!hasReachableDefinition(const_cast(PatternDef), + &SuggestedDef, + /*OnlyNeedComplete*/ false)) { // If we're allowed to diagnose this and recover, do so. bool Recover = Complain && !isSFINAEContext(); if (Complain) Index: clang/lib/Sema/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -8584,6 +8584,57 @@ return false; } +// [module.reach]p3.1: +// A declaration D is reachable from a point P if +// - D appears prior to P in the same translation unit, or +// - 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 is reachable if it is reachable from +// any point in the instantiation context ([module.context]). +// +// [module.reach]p2: +// All translation units that are necessarily reachable are reachable. +// 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. +bool Sema::hasReachableDefinition(NamedDecl *D, NamedDecl **Suggested, + bool OnlyNeedComplete) { + bool IsVisible = hasVisibleDefinition(D, Suggested, OnlyNeedComplete); + + // If it didn't introduce C++ Modules, it is meaningless to talk about + // reachable definition. + if (!getLangOpts().CPlusPlusModules) + return IsVisible; + + // Any visible declaration is reachable. + if (IsVisible) + return true; + + // If D owns a module and the corresponding top level module is not visible. + // It implies that the module is not imported. So we should return false + // directly. This is possible in case of `#pragma clang module`. See + // clang/test/SemaCXX/compare-modules-cxx2a.cpp for example. + if (D->getOwningModule() && + !VisibleModules.isVisible(D->getOwningModule()->getTopLevelModule())) + return false; + + // If D isn't from AST file, it implies that D appears in the same TU. + // So it should be reachable. + if (!D->isFromASTFile()) + return true; + + if (D->isModulePrivate()) + return false; + + if (!D->isInGlobalModuleFragment()) + return true; + + if (D->isDiscardedInGlobalModuleFragment()) + return false; + + return true; +} + /// Locks in the inheritance model for the given class and all of its bases. static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { RD = RD->getMostRecentNonInjectedDecl(); @@ -8657,16 +8708,15 @@ // If we have a complete type, we're done. if (!Incomplete) { - // If we know about the definition but it is not visible, complain. - NamedDecl *SuggestedDef = nullptr; + NamedDecl *Suggested = nullptr; if (Def && - !hasVisibleDefinition(Def, &SuggestedDef, /*OnlyNeedComplete*/true)) { + !hasReachableDefinition(Def, &Suggested, /*OnlyNeedComplete=*/true)) { // If the user is going to see an error here, recover by making the // definition visible. bool TreatAsComplete = Diagnoser && !isSFINAEContext(); - if (Diagnoser && SuggestedDef) - diagnoseMissingImport(Loc, SuggestedDef, MissingImportKind::Definition, - /*Recover*/TreatAsComplete); + if (Diagnoser && Suggested) + diagnoseMissingImport(Loc, Suggested, MissingImportKind::Definition, + /*Recover*/ TreatAsComplete); return !TreatAsComplete; } else if (Def && !TemplateInstCallbacks.empty()) { CodeSynthesisContext TempInst; Index: clang/lib/Serialization/ASTReaderDecl.cpp =================================================================== --- clang/lib/Serialization/ASTReaderDecl.cpp +++ clang/lib/Serialization/ASTReaderDecl.cpp @@ -603,15 +603,22 @@ D->setTopLevelDeclInObjCContainer(Record.readInt()); D->setAccess((AccessSpecifier)Record.readInt()); D->FromASTFile = true; - bool ModulePrivate = Record.readInt(); + auto ModuleOwnership = (Decl::ModuleOwnershipKind)Record.readInt(); + bool ModulePrivate = + (ModuleOwnership == Decl::ModuleOwnershipKind::ModulePrivate); // Determine whether this declaration is part of a (sub)module. If so, it // may not yet be visible. if (unsigned SubmoduleID = readSubmoduleID()) { + if (ModuleOwnership == Decl::ModuleOwnershipKind::Visible) + ModuleOwnership = Decl::ModuleOwnershipKind::VisibleWhenImported; + + if ((int)ModuleOwnership > 4) + llvm::report_fatal_error( + "The size of sizeModuleOwnership is larger than 4.\n"); + + 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) { Index: clang/lib/Serialization/ASTWriterDecl.cpp =================================================================== --- clang/lib/Serialization/ASTWriterDecl.cpp +++ clang/lib/Serialization/ASTWriterDecl.cpp @@ -310,7 +310,7 @@ Record.push_back(D->isReferenced()); Record.push_back(D->isTopLevelDeclInObjCContainer()); Record.push_back(D->getAccess()); - Record.push_back(D->isModulePrivate()); + Record.push_back((uint64_t)D->getModuleOwnershipKind()); Record.push_back(Writer.getSubmoduleID(D->getOwningModule())); // If this declaration injected a name into a context different from its @@ -1921,7 +1921,7 @@ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -1954,7 +1954,7 @@ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -1992,7 +1992,7 @@ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2042,7 +2042,7 @@ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2104,7 +2104,7 @@ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2152,7 +2152,7 @@ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2181,7 +2181,7 @@ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2233,7 +2233,7 @@ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Referenced Abv->Add(BitCodeAbbrevOp(0)); // InObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Access - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(DeclarationName::Identifier)); // NameKind Index: clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp =================================================================== --- clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp +++ clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp @@ -30,17 +30,20 @@ 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-note@p2.cpp:16 {{not visible}} + // expected-note@p2.cpp:16 {{not visible}} exported = 1; // expected-error {{must be imported from module 'A'}} - // expected-note@p2.cpp:18 {{not visible}} + // expected-note@p2.cpp:18 {{declaration here is not visible}} - not_exported = 1; // expected-error {{undeclared identifier}} + not_exported = 1; // expected-error {{declaration of 'not_exported' must be imported from module 'A' before it is required}} + // expected-note@p2.cpp:19 {{declaration here is not visible}} - internal = 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-note@p2.cpp:20 {{declaration here is not visible}} not_exported_private = 1; // expected-error {{undeclared identifier}} @@ -55,7 +58,7 @@ 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-note@p2.cpp:16 {{not visible}} @@ -64,14 +67,14 @@ not_exported = 1; #ifndef IMPLEMENTATION - // expected-error@-2 {{undeclared identifier 'not_exported'; did you mean 'exported'}} - // expected-note@p2.cpp:18 {{declared here}} + // expected-error@-2 {{declaration of 'not_exported' must be imported from module 'A' before it is required}} + // expected-note@p2.cpp:19 {{declaration here is not visible}} #endif internal = 1; #ifndef IMPLEMENTATION - // FIXME: should not be visible here - // expected-error@-3 {{undeclared identifier}} + // expected-error@-2 {{declaration of 'internal' must be imported from module 'A' before it is required}} + // expected-note@p2.cpp:20 {{declaration here is not visible}} #endif not_exported_private = 1; Index: clang/test/CXX/module/module.interface/p2.cpp =================================================================== --- clang/test/CXX/module/module.interface/p2.cpp +++ clang/test/CXX/module/module.interface/p2.cpp @@ -69,22 +69,29 @@ void use() { // namespace A is implicitly exported by the export of A::g. - A::f(); // expected-error {{no member named 'f' in namespace 'A'}} + 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::g(); - A::h(); // expected-error {{no member named 'h' in namespace 'A'}} - using namespace A::inner; // expected-error {{expected namespace name}} + 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}} // namespace B and B::inner are explicitly exported using namespace B; using namespace B::inner; - B::f(); // expected-error {{no member named 'f' in namespace 'B'}} - f(); // expected-error {{undeclared identifier 'f'}} + 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}} // namespace C is not exported - using namespace C; // expected-error {{expected namespace name}} + 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}} // namespace D is exported, but D::f is not - D::f(); // expected-error {{no member named 'f' in namespace 'D'}} + D::f(); // expected-error {{declaration of 'f' must be imported from module 'p2' before it is required}} + // expected-note@* {{declaration here is not visible}} } int use_header() { return foo + bar::baz(); } Index: clang/test/CXX/module/module.reach/Inputs/p5-A.cppm =================================================================== --- /dev/null +++ clang/test/CXX/module/module.reach/Inputs/p5-A.cppm @@ -0,0 +1,3 @@ +export module A; +struct X {}; +export using Y = X; Index: clang/test/CXX/module/module.reach/p5.cpp =================================================================== --- /dev/null +++ clang/test/CXX/module/module.reach/p5.cpp @@ -0,0 +1,10 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: %clang -std=c++20 %S/Inputs/p5-A.cppm --precompile -o %t/A.pcm +// RUN: %clang -std=c++20 -fprebuilt-module-path=%t %s -c -Xclang -verify + +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@Inputs/p5-A.cppm:2 {{declaration here is not visible}} Index: clang/test/CXX/module/module.unit/p7/t6.cpp =================================================================== --- clang/test/CXX/module/module.unit/p7/t6.cpp +++ clang/test/CXX/module/module.unit/p7/t6.cpp @@ -7,9 +7,5 @@ export module use; import X; void printX(CPP *cpp) { - 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}} + cpp->print(); // expected-error {{no member named 'print' in 'CPP'}} } Index: clang/test/Modules/Inputs/Reachability-Private/Private.cppm =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/Reachability-Private/Private.cppm @@ -0,0 +1,18 @@ +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() {} Index: clang/test/Modules/Inputs/Reachability-func-default-arg/func_default_arg.cppm =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/Reachability-func-default-arg/func_default_arg.cppm @@ -0,0 +1,5 @@ +export module func_default_arg; +struct t { }; +export t foo(t t1= t()) { + return t1; +} Index: clang/test/Modules/Inputs/Reachability-func-ret/func_ret.cppm =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/Reachability-func-ret/func_ret.cppm @@ -0,0 +1,5 @@ +export module func_ret; +struct t { }; +export t foo() { + return t{}; +} Index: clang/test/Modules/Inputs/Reachability-template-default-arg/template_default_arg.cppm =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/Reachability-template-default-arg/template_default_arg.cppm @@ -0,0 +1,8 @@ +export module template_default_arg; +struct t { }; + +export +template +struct A { + T a; +}; Index: clang/test/Modules/Inputs/Reachability-template-instantiation/Templ.h =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/Reachability-template-instantiation/Templ.h @@ -0,0 +1,8 @@ +#ifndef TEMPL_H +#define TEMPL_H +template +class Wrapper { +public: + T value; +}; +#endif Index: clang/test/Modules/Inputs/Reachability-template-instantiation/Use.cppm =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/Reachability-template-instantiation/Use.cppm @@ -0,0 +1,8 @@ +module; +#include "Templ.h" +export module Use; +export template +class Use { +public: + Wrapper value; +}; Index: clang/test/Modules/Inputs/Reachability-using-templates/mod-templates.cppm =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/Reachability-using-templates/mod-templates.cppm @@ -0,0 +1,3 @@ +export module mod.templates; +template struct t { }; +export template using u = t; Index: clang/test/Modules/Inputs/Reachability-using/mod.cppm =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/Reachability-using/mod.cppm @@ -0,0 +1,3 @@ +export module mod; +struct t { }; +export using u = t; Index: clang/test/Modules/Reachability-Private.cpp =================================================================== --- /dev/null +++ clang/test/Modules/Reachability-Private.cpp @@ -0,0 +1,19 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: %clang -std=c++20 %S/Inputs/Reachability-Private/Private.cppm --precompile -o %t/Private.pcm +// RUN: %clang -std=c++20 -fprebuilt-module-path=%t %s -c -Xclang -verify + +import Private; +void foo() { + X x; // expected-error {{definition of 'X' must be imported from module 'Private.' before it is required}} + // expected-error@-1 {{definition of 'X' must be imported from module 'Private.' before it is required}} + // expected-note@Inputs/Reachability-Private/Private.cppm:13 {{definition here is not reachable}} + // expected-note@Inputs/Reachability-Private/Private.cppm:13 {{definition here is not reachable}} + auto _ = factory(); + auto *__ = factory(); + X *___ = factory(); + + g(__); + g(___); + g(factory()); +} Index: clang/test/Modules/Reachability-func-default-arg.cpp =================================================================== --- /dev/null +++ clang/test/Modules/Reachability-func-default-arg.cpp @@ -0,0 +1,9 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: %clang -std=c++20 %S/Inputs/Reachability-func-default-arg/func_default_arg.cppm --precompile -o %t/func_default_arg.pcm +// RUN: %clang -std=c++20 -fprebuilt-module-path=%t %s -c +// expected-no-diagnostics +import func_default_arg; +void bar() { + auto ret = foo(); +} Index: clang/test/Modules/Reachability-func-ret.cpp =================================================================== --- /dev/null +++ clang/test/Modules/Reachability-func-ret.cpp @@ -0,0 +1,9 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: %clang -std=c++20 %S/Inputs/Reachability-func-ret/func_ret.cppm --precompile -o %t/func_ret.pcm +// RUN: %clang -std=c++20 -fprebuilt-module-path=%t %s -c +// expected-no-diagnostics +import func_ret; +void bar() { + auto ret = foo(); +} Index: clang/test/Modules/Reachability-template-default-arg.cpp =================================================================== --- /dev/null +++ clang/test/Modules/Reachability-template-default-arg.cpp @@ -0,0 +1,11 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: %clang -std=c++20 %S/Inputs/Reachability-template-default-arg/template_default_arg.cppm --precompile -o %t/template_default_arg.pcm +// RUN: %clang -std=c++20 -fprebuilt-module-path=%t %s -c -Xclang -verify + +import template_default_arg; +void bar() { + A<> a0; + A a1; // expected-error {{declaration of 't' must be imported from module 'template_default_arg' before it is required}} + // expected-note@Inputs/Reachability-template-default-arg/template_default_arg.cppm:2 {{declaration here is not visible}} +} Index: clang/test/Modules/Reachability-template-instantiation.cpp =================================================================== --- /dev/null +++ clang/test/Modules/Reachability-template-instantiation.cpp @@ -0,0 +1,13 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: %clang -std=c++20 %S/Inputs/Reachability-template-instantiation/Use.cppm --precompile -o %t/Use.pcm +// RUN: %clang -std=c++20 -fprebuilt-module-path=%t -I%S/Inputs/Reachability-template-instantiation %s -c -Xclang -verify +// expected-no-diagnostics +module; +#include "Templ.h" +export module Use; +export template +class Use { +public: + Wrapper value; +}; Index: clang/test/Modules/Reachability-using-templates.cpp =================================================================== --- /dev/null +++ clang/test/Modules/Reachability-using-templates.cpp @@ -0,0 +1,9 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: %clang -std=c++20 %S/Inputs/Reachability-using-templates/mod-templates.cppm --precompile -o %t/mod.templates.pcm +// RUN: %clang -std=c++20 -fprebuilt-module-path=%t %s -c +// expected-no-diagnostics +import mod.templates; +void foo() { + u v{}; +} Index: clang/test/Modules/Reachability-using.cpp =================================================================== --- /dev/null +++ clang/test/Modules/Reachability-using.cpp @@ -0,0 +1,9 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: %clang -std=c++20 %S/Inputs/Reachability-using/mod.cppm --precompile -o %t/mod.pcm +// RUN: %clang -std=c++20 -fprebuilt-module-path=%t %s -c +// expected-no-diagnostics +import mod; +void foo() { + u v{}; +}