ChuanqiXu updated this revision to Diff 412657.
ChuanqiXu added a comment.

Rebase and update tests.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D113545/new/

https://reviews.llvm.org/D113545

Files:
  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.lookup/basic.lookup.argdep/Inputs/Friend-in-reachable-class.cppm
  
clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4-friend-in-reachable-class.cpp
  clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp
  clang/test/CXX/module/module.interface/Inputs/p7.cppm
  clang/test/CXX/module/module.interface/p2.cpp
  clang/test/CXX/module/module.interface/p7.cpp
  clang/test/CXX/module/module.reach/Inputs/p4/bar.cppm
  clang/test/CXX/module/module.reach/Inputs/p4/foo.cppm
  clang/test/CXX/module/module.reach/Inputs/p5-A.cppm
  clang/test/CXX/module/module.reach/p4/TransitiveImport.cpp
  clang/test/CXX/module/module.reach/p5.cpp
  clang/test/CXX/module/module.unit/p7/t6.cpp
  clang/test/Modules/Inputs/Reachability-Private/Private.cppm
  clang/test/Modules/Inputs/Reachability-func-default-arg/func_default_arg.cppm
  clang/test/Modules/Inputs/Reachability-func-ret/func_ret.cppm
  
clang/test/Modules/Inputs/Reachability-template-default-arg/template_default_arg.cppm
  clang/test/Modules/Inputs/Reachability-template-instantiation/Templ.cppm
  clang/test/Modules/Inputs/Reachability-template-instantiation/Templ.h
  clang/test/Modules/Inputs/Reachability-template-instantiation/Use.cppm
  clang/test/Modules/Inputs/Reachability-using-templates/mod-templates.cppm
  clang/test/Modules/Inputs/Reachability-using/mod.cppm
  clang/test/Modules/Inputs/derived_class/bar.h
  clang/test/Modules/Inputs/derived_class/foo.cppm
  clang/test/Modules/Inputs/explicitly-specialized-template/X.cppm
  clang/test/Modules/Inputs/explicitly-specialized-template/foo.h
  clang/test/Modules/Inputs/template-function-specialization/foo.cppm
  clang/test/Modules/Inputs/template_default_argument/B.cppm
  clang/test/Modules/Inputs/template_default_argument/templ.h
  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/cxx20-10-1-ex2.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

Index: clang/test/Modules/template_default_argument.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/template_default_argument.cpp
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: %clang -std=c++20 %S/Inputs/template_default_argument/B.cppm --precompile -o %t/B.pcm
+// RUN: %clang -std=c++20 -fprebuilt-module-path=%t %s -c -o -
+// expected-no-diagnostics
+import B;
+auto foo() {
+  return bar<int>();
+}
Index: clang/test/Modules/template-function-specialization.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/template-function-specialization.cpp
@@ -0,0 +1,18 @@
+// RUN: rm -fr %t
+// RUN: mkdir %t
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %S/Inputs/template-function-specialization/foo.cppm -o %t/foo.pcm
+// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %s -verify -fsyntax-only
+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>();
+}
Index: clang/test/Modules/explicitly-specialized-template.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/explicitly-specialized-template.cpp
@@ -0,0 +1,12 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: %clang -std=c++20 %S/Inputs/explicitly-specialized-template/X.cppm --precompile -o %t/X.pcm
+// RUN: %clang -std=c++20 -fprebuilt-module-path=%t %s -fsyntax-only -Xclang -verify -o -
+
+import X;
+foo<int> f; // expected-error {{'foo' must be declared before it is used}}
+            // expected-note@Inputs/explicitly-specialized-template/foo.h:10 {{declaration here is not visible}}
+int bar() {
+  X<int> x;
+  return x.print();
+}
Index: clang/test/Modules/derived_class.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/derived_class.cpp
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: %clang -std=c++20 %S/Inputs/derived_class/foo.cppm --precompile -o %t/foo.pcm
+// RUN: %clang -std=c++20 -fprebuilt-module-path=%t %s -c
+// expected-no-diagnostics
+import foo;
+void test() {
+  foo<int>();
+}
Index: clang/test/Modules/cxx20-10-1-ex2.cpp
===================================================================
--- clang/test/Modules/cxx20-10-1-ex2.cpp
+++ clang/test/Modules/cxx20-10-1-ex2.cpp
@@ -53,10 +53,12 @@
 //--- std10-1-ex2-tu6.cpp
 import B;
 // error, n is module-local and this is not a module.
-int &c = n; // expected-error {{use of undeclared identifier}}
+int &c = n; // expected-error {{declaration of 'n' must be imported}}
+            // expected-note@* {{declaration here is not visible}}
 
 //--- std10-1-ex2-tu7.cpp
 module B:X3; // does not implicitly import B
 import :X2;  // X2 is an implementation so exports nothing.
              // error: n not visible here.
-int &c = n;  // expected-error {{use of undeclared identifier }}
+int &c = n;  // expected-error {{declaration of 'n' must be imported}}
+             // expected-note@* {{declaration here is not visible}}
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{};
+}
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<int> v{};
+}
Index: clang/test/Modules/Reachability-template-instantiation.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/Reachability-template-instantiation.cpp
@@ -0,0 +1,16 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: %clang -std=c++20 %S/Inputs/Reachability-template-instantiation/Templ.cppm --precompile -o %t/Templ.pcm
+// RUN: %clang -std=c++20 %S/Inputs/Reachability-template-instantiation/Use.cppm -fprebuilt-module-path=%t --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 User;
+
+export template <class T>
+class User {
+public:
+  Wrapper<T> value;
+};
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<t> 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-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-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-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.<private>' before it is required}}
+       // expected-error@-1 {{definition of 'X' must be imported from module 'Private.<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/Inputs/template_default_argument/templ.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/template_default_argument/templ.h
@@ -0,0 +1,4 @@
+template <typename T, typename U = T>
+class templ {};
+template <typename T, typename U = void>
+void templ_func() {}
Index: clang/test/Modules/Inputs/template_default_argument/B.cppm
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/template_default_argument/B.cppm
@@ -0,0 +1,8 @@
+module;
+#include "templ.h"
+export module B;
+export template <typename G>
+templ<G> bar() {
+  templ_func<G>();
+  return {};
+}
Index: clang/test/Modules/Inputs/template-function-specialization/foo.cppm
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/template-function-specialization/foo.cppm
@@ -0,0 +1,36 @@
+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>() {
+}
Index: clang/test/Modules/Inputs/explicitly-specialized-template/foo.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/explicitly-specialized-template/foo.h
@@ -0,0 +1,16 @@
+#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
Index: clang/test/Modules/Inputs/explicitly-specialized-template/X.cppm
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/explicitly-specialized-template/X.cppm
@@ -0,0 +1,12 @@
+module;
+#include "foo.h"
+export module X;
+export template <class T>
+class X {
+  foo<int> x;
+
+public:
+  int print() {
+    return x.getInt();
+  }
+};
Index: clang/test/Modules/Inputs/derived_class/foo.cppm
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/derived_class/foo.cppm
@@ -0,0 +1,12 @@
+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;
+}
Index: clang/test/Modules/Inputs/derived_class/bar.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/derived_class/bar.h
@@ -0,0 +1,16 @@
+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 {
+};
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/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 <class> struct t {};
+export template <class T> using u = t<T>;
Index: clang/test/Modules/Inputs/Reachability-template-instantiation/Use.cppm
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/Reachability-template-instantiation/Use.cppm
@@ -0,0 +1,14 @@
+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;
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 T>
+class Wrapper {
+public:
+  T value;
+};
+#endif
Index: clang/test/Modules/Inputs/Reachability-template-instantiation/Templ.cppm
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/Reachability-template-instantiation/Templ.cppm
@@ -0,0 +1,6 @@
+export module Templ;
+export template <class T>
+class Wrapper2 {
+public:
+  T value;
+};
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,7 @@
+export module template_default_arg;
+struct t {};
+
+export template <typename T = t>
+struct A {
+  T a;
+};
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-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-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/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
@@ -2,14 +2,11 @@
 // 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(); // 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();
 }
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.reach/p4/TransitiveImport.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/module/module.reach/p4/TransitiveImport.cpp
@@ -0,0 +1,15 @@
+// RUN: rm -fr %t
+// RUN: mkdir %t
+// RUN: %clang_cc1 -std=c++20 %S/../Inputs/p4/foo.cppm -emit-module-interface -o %t/foo.pcm
+// RUN: %clang_cc1 -std=c++20 %S/../Inputs/p4/bar.cppm -emit-module-interface -fprebuilt-module-path=%t -o %t/bar.pcm
+// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t -verify %s
+// 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.
+}
\ No newline at end of file
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/Inputs/p4/foo.cppm
===================================================================
--- /dev/null
+++ clang/test/CXX/module/module.reach/Inputs/p4/foo.cppm
@@ -0,0 +1,3 @@
+export module foo;
+export class foo {
+};
Index: clang/test/CXX/module/module.reach/Inputs/p4/bar.cppm
===================================================================
--- /dev/null
+++ clang/test/CXX/module/module.reach/Inputs/p4/bar.cppm
@@ -0,0 +1,5 @@
+export module bar;
+import foo;
+export auto bar() {
+  return foo{};
+}
\ No newline at end of file
Index: clang/test/CXX/module/module.interface/p7.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/module/module.interface/p7.cpp
@@ -0,0 +1,19 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: %clang -std=c++20 %S/Inputs/p7.cppm --precompile -o %t/p7.pcm
+// RUN: %clang -std=c++20 -fprebuilt-module-path=%t %s -c
+// expected-no-diagnostics
+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();
+}
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.interface/Inputs/p7.cppm
===================================================================
--- /dev/null
+++ clang/test/CXX/module/module.interface/Inputs/p7.cppm
@@ -0,0 +1,25 @@
+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{};
+}
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-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 {{not visible}}
+                // expected-n...@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-n...@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-n...@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-n...@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-n...@p2.cpp:18 {{declared here}}
+  // 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}}
 #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-n...@p2.cpp:20 {{declaration here is not visible}}
 #endif
 
   not_exported_private = 1;
Index: clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4-friend-in-reachable-class.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4-friend-in-reachable-class.cpp
@@ -0,0 +1,14 @@
+// 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: %clang_cc1 -std=c++20 -emit-module-interface %S/Inputs/Friend-in-reachable-class.cppm -o %t/X.pcm
+// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %s -verify -fsyntax-only
+// expected-no-diagnostics
+import X;
+int use() {
+  A a, b;
+  return a + b;
+}
Index: clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/Inputs/Friend-in-reachable-class.cppm
===================================================================
--- /dev/null
+++ clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/Inputs/Friend-in-reachable-class.cppm
@@ -0,0 +1,10 @@
+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;
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/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/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -8600,6 +8600,78 @@
   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;
+
+  // We need to filter the use other than C++20 modules. Note the check abvoe is
+  // not sufficient. Considering the case we are using clang module + -std=c++20
+  // combination.
+  Module *M = D->getOwningModule();
+  if (M && M->isModuleMapModule())
+    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 isn't in global module fragment and it isn't module private,
+  // we could infer that D is reachable from [module.reach]p3.1.
+  if (M && !M->isGlobalModule())
+    return true;
+
+  if (D->isDiscardedInGlobalModuleFragment())
+    return false;
+
+  // [module.reach]/p1-3
+  //   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]). 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.
+  //
+  //   A declaration is reachable if it is reachable from any point in the
+  //   instantiation context ([module.context]). 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.
+  //
+  // Since the standard leaves space for compilers to decide whether the
+  // additional translation unit is reachable, we treat all translation unit as
+  // reachable here to ease the implementation. This strategy would surprise
+  // user less and save compilation time.
+  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();
@@ -8669,20 +8741,19 @@
   // 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))
-    checkSpecializationVisibility(Loc, Def);
+    checkSpecializationReachability(Loc, Def);
 
   // 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/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<NamedDecl*>(PatternDef), &SuggestedDef,
-                              /*OnlyNeedComplete*/false)) {
+    if (!hasReachableDefinition(const_cast<NamedDecl *>(PatternDef),
+                                &SuggestedDef,
+                                /*OnlyNeedComplete*/ false)) {
       // If we're allowed to diagnose this and recover, do so.
       bool Recover = Complain && !isSFINAEContext();
       if (Complain)
@@ -5237,7 +5238,7 @@
   HasDefaultArg = false;
 
   if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) {
-    if (!hasVisibleDefaultArgument(TypeParm))
+    if (!hasReachableDefaultArgument(TypeParm))
       return TemplateArgumentLoc();
 
     HasDefaultArg = true;
@@ -5254,7 +5255,7 @@
 
   if (NonTypeTemplateParmDecl *NonTypeParm
         = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
-    if (!hasVisibleDefaultArgument(NonTypeParm))
+    if (!hasReachableDefaultArgument(NonTypeParm))
       return TemplateArgumentLoc();
 
     HasDefaultArg = true;
@@ -5272,7 +5273,7 @@
 
   TemplateTemplateParmDecl *TempTempParm
     = cast<TemplateTemplateParmDecl>(Param);
-  if (!hasVisibleDefaultArgument(TempTempParm))
+  if (!hasReachableDefaultArgument(TempTempParm))
     return TemplateArgumentLoc();
 
   HasDefaultArg = true;
@@ -5610,10 +5611,10 @@
                                  ->getTemplateParameters()
                                  ->getParam(D->getIndex()));
 
-  // If there's a default argument that's not visible, diagnose that we're
+  // If there's a default argument that's not reachable, diagnose that we're
   // missing a module import.
   llvm::SmallVector<Module*, 8> Modules;
-  if (D->hasDefaultArgument() && !S.hasVisibleDefaultArgument(D, &Modules)) {
+  if (D->hasDefaultArgument() && !S.hasReachableDefaultArgument(D, &Modules)) {
     S.diagnoseMissingImport(Loc, cast<NamedDecl>(TD),
                             D->getDefaultArgumentLoc(), Modules,
                             Sema::MissingImportKind::DefaultArgument,
@@ -5796,7 +5797,7 @@
     // (when the template parameter was part of a nested template) into
     // the default argument.
     if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
-      if (!hasVisibleDefaultArgument(TTP))
+      if (!hasReachableDefaultArgument(TTP))
         return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP,
                                        NewArgs);
 
@@ -5813,7 +5814,7 @@
                                 ArgType);
     } else if (NonTypeTemplateParmDecl *NTTP
                  = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
-      if (!hasVisibleDefaultArgument(NTTP))
+      if (!hasReachableDefaultArgument(NTTP))
         return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP,
                                        NewArgs);
 
@@ -5831,7 +5832,7 @@
       TemplateTemplateParmDecl *TempParm
         = cast<TemplateTemplateParmDecl>(*Param);
 
-      if (!hasVisibleDefaultArgument(TempParm))
+      if (!hasReachableDefaultArgument(TempParm))
         return diagnoseMissingArgument(*this, TemplateLoc, Template, TempParm,
                                        NewArgs);
 
@@ -10986,10 +10987,12 @@
   Sema &S;
   SourceLocation Loc;
   llvm::SmallVector<Module *, 8> Modules;
+  bool CheckReachability = false;
 
 public:
-  ExplicitSpecializationVisibilityChecker(Sema &S, SourceLocation Loc)
-      : S(S), Loc(Loc) {}
+  ExplicitSpecializationVisibilityChecker(Sema &S, SourceLocation Loc,
+                                          bool Reachability)
+      : S(S), Loc(Loc), CheckReachability(Reachability) {}
 
   void check(NamedDecl *ND) {
     if (auto *FD = dyn_cast<FunctionDecl>(ND))
@@ -11017,6 +11020,24 @@
       S.diagnoseMissingImport(Loc, D, D->getLocation(), Modules, Kind, Recover);
   }
 
+  bool CheckMemberSpecialization(const NamedDecl *D) {
+    if (CheckReachability)
+      return S.hasReachableMemberSpecialization(D);
+    return S.hasVisibleMemberSpecialization(D);
+  }
+
+  bool CheckExplicitSpecialization(const NamedDecl *D) {
+    if (CheckReachability)
+      return S.hasReachableExplicitSpecialization(D);
+    return S.hasVisibleExplicitSpecialization(D);
+  }
+
+  bool CheckDeclaration(const NamedDecl *D) {
+    if (CheckReachability)
+      return S.hasReachableDeclaration(D);
+    return S.hasVisibleDeclaration(D);
+  }
+
   // Check a specific declaration. There are three problematic cases:
   //
   //  1) The declaration is an explicit specialization of a template
@@ -11033,10 +11054,9 @@
   void checkImpl(SpecDecl *Spec) {
     bool IsHiddenExplicitSpecialization = false;
     if (Spec->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
-      IsHiddenExplicitSpecialization =
-          Spec->getMemberSpecializationInfo()
-              ? !S.hasVisibleMemberSpecialization(Spec, &Modules)
-              : !S.hasVisibleExplicitSpecialization(Spec, &Modules);
+      IsHiddenExplicitSpecialization = Spec->getMemberSpecializationInfo()
+                                           ? !CheckMemberSpecialization(Spec)
+                                           : !CheckExplicitSpecialization(Spec);
     } else {
       checkInstantiated(Spec);
     }
@@ -11060,7 +11080,7 @@
       checkTemplate(TD);
     else if (auto *TD =
                  From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
-      if (!S.hasVisibleDeclaration(TD))
+      if (!CheckDeclaration(TD))
         diagnose(TD, true);
       checkTemplate(TD);
     }
@@ -11076,7 +11096,7 @@
       checkTemplate(TD);
     else if (auto *TD =
                  From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
-      if (!S.hasVisibleDeclaration(TD))
+      if (!CheckDeclaration(TD))
         diagnose(TD, true);
       checkTemplate(TD);
     }
@@ -11087,7 +11107,7 @@
   template<typename TemplDecl>
   void checkTemplate(TemplDecl *TD) {
     if (TD->isMemberSpecialization()) {
-      if (!S.hasVisibleMemberSpecialization(TD, &Modules))
+      if (!CheckMemberSpecialization(TD))
         diagnose(TD->getMostRecentDecl(), false);
     }
   }
@@ -11098,5 +11118,15 @@
   if (!getLangOpts().Modules)
     return;
 
-  ExplicitSpecializationVisibilityChecker(*this, Loc).check(Spec);
+  ExplicitSpecializationVisibilityChecker(*this, Loc, /*Reachability*/ false)
+      .check(Spec);
+}
+
+void Sema::checkSpecializationReachability(SourceLocation Loc,
+                                           NamedDecl *Spec) {
+  if (!getLangOpts().CPlusPlusModules)
+    return checkSpecializationVisibility(Loc, Spec);
+
+  ExplicitSpecializationVisibilityChecker(*this, Loc, /*Reachability*/ true)
+      .check(Spec);
 }
Index: clang/lib/Sema/SemaModule.cpp
===================================================================
--- clang/lib/Sema/SemaModule.cpp
+++ clang/lib/Sema/SemaModule.cpp
@@ -90,7 +90,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.
@@ -284,10 +291,16 @@
   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
+    TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
   TU->setLocalOwningModule(Mod);
 
   // We are in the module purview, but before any other (non import)
Index: clang/lib/Sema/SemaLookup.cpp
===================================================================
--- clang/lib/Sema/SemaLookup.cpp
+++ clang/lib/Sema/SemaLookup.cpp
@@ -1583,17 +1583,21 @@
   return false;
 }
 
-template<typename ParmDecl>
-static bool
-hasVisibleDefaultArgument(Sema &S, const ParmDecl *D,
-                          llvm::SmallVectorImpl<Module *> *Modules) {
+template <typename ParmDecl>
+static bool hasVisibleDefaultArgument(Sema &S, const ParmDecl *D,
+                                      llvm::SmallVectorImpl<Module *> *Modules,
+                                      bool RequireReachable = false) {
   if (!D->hasDefaultArgument())
     return false;
 
   while (D) {
     auto &DefaultArg = D->getDefaultArgStorage();
-    if (!DefaultArg.isInherited() && S.isVisible(D))
-      return true;
+    if (!DefaultArg.isInherited()) {
+      if (S.isVisible(D))
+        return true;
+      if (RequireReachable && S.hasReachableDeclaration(D))
+        return true;
+    }
 
     if (!DefaultArg.isInherited() && Modules) {
       auto *NonConstD = const_cast<ParmDecl*>(D);
@@ -1616,10 +1620,26 @@
                                      Modules);
 }
 
-template<typename Filter>
+bool Sema::hasReachableDefaultArgument(
+    const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {
+  // It is meaningless to talk about reachable if we are not in C++20 modules.
+  if (!getLangOpts().CPlusPlusModules)
+    return hasVisibleDefaultArgument(D, Modules);
+
+  if (auto *P = dyn_cast<TemplateTypeParmDecl>(D))
+    return ::hasVisibleDefaultArgument(*this, P, Modules,
+                                       /*RequireReachable*/ true);
+  if (auto *P = dyn_cast<NonTypeTemplateParmDecl>(D))
+    return ::hasVisibleDefaultArgument(*this, P, Modules,
+                                       /*RequireReachable*/ true);
+  return ::hasVisibleDefaultArgument(*this, cast<TemplateTemplateParmDecl>(D),
+                                     Modules, /*RequireReachable*/ true);
+}
+
+template <typename Filter>
 static bool hasVisibleDeclarationImpl(Sema &S, const NamedDecl *D,
                                       llvm::SmallVectorImpl<Module *> *Modules,
-                                      Filter F) {
+                                      Filter F, bool RequireReachable = false) {
   bool HasFilteredRedecls = false;
 
   for (auto *Redecl : D->redecls()) {
@@ -1630,6 +1650,9 @@
     if (S.isVisible(R))
       return true;
 
+    if (RequireReachable && S.hasReachableDeclaration(R))
+      return true;
+
     HasFilteredRedecls = true;
 
     if (Modules)
@@ -1672,6 +1695,45 @@
   });
 }
 
+bool Sema::hasReachableExplicitSpecialization(
+    const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {
+  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");
+      },
+      /*RequireReachable=*/true);
+}
+
+bool Sema::hasReachableMemberSpecialization(
+    const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {
+  assert(isa<CXXRecordDecl>(D->getDeclContext()) &&
+         "not a member specialization");
+  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();
+      },
+      /*RequireReachable=*/true);
+}
+
 /// Determine whether a declaration is visible to name lookup.
 ///
 /// This routine determines whether the declaration D is visible in the current
@@ -1687,8 +1749,9 @@
   Module *DeclModule = SemaRef.getOwningModule(D);
   assert(DeclModule && "hidden decl has no owning module");
 
-  if (SemaRef.isModuleVisible(DeclModule, D->isModulePrivate()))
-    // If the owning module is visible, the decl is visible.
+  // If the owning module is visible, the decl is visible.
+  if (SemaRef.isModuleVisible(DeclModule,
+                              D->isInvisibleOutsideTheOwningModule()))
     return true;
 
   // Determine whether a decl context is a file context for the purpose of
@@ -1756,6 +1819,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.
@@ -1881,6 +1956,17 @@
                                    [](const NamedDecl *) { return true; });
 }
 
+bool Sema::hasReachableDeclaration(const NamedDecl *D,
+                                   llvm::SmallVectorImpl<Module *> *Modules) {
+  if (!getLangOpts().CPlusPlusModules)
+    return hasVisibleDeclaration(D, Modules);
+  if (D->isReachable() || isVisibleSlow(D))
+    return true;
+  return hasVisibleDeclarationImpl(
+      *this, D, Modules, [](const NamedDecl *) { return true; },
+      /*RequireReachable*/ true);
+}
+
 NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
   if (auto *ND = dyn_cast<NamespaceDecl>(D)) {
     // Namespaces are a bit of a special case: we expect there to be a lot of
@@ -1903,6 +1989,32 @@
   return findAcceptableDecl(getSema(), D, IDNS);
 }
 
+bool LookupResult::isReachableAndAcceptable(NamedDecl *ND) const {
+  if (!getSema().getLangOpts().CPlusPlusModules)
+    return false;
+
+  // We should check the visibility at the callsite already.
+  assert(!isVisible(getSema(), ND));
+
+  // [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.
+  if (auto *ECD = dyn_cast<EnumConstantDecl>(ND))
+    return getSema().hasReachableDeclaration(
+        cast<NamedDecl>(ECD->getDeclContext()));
+
+  // If ND is not visible and it is at namespace scope, it shouldn't be found
+  // by name lookup.
+  if (!ND->getDeclContext()->isRecord())
+    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.
+  return getSema().hasReachableDeclaration(
+      cast<RecordDecl>(ND->getDeclContext()));
+}
+
 /// Perform unqualified name lookup starting from a given
 /// scope.
 ///
@@ -3633,7 +3745,13 @@
           }
         } else if (D->getFriendObjectKind()) {
           auto *RD = cast<CXXRecordDecl>(D->getLexicalDeclContext());
-          if (AssociatedClasses.count(RD) && isVisible(D)) {
+          // [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,
+          if (AssociatedClasses.count(RD) && hasReachableDeclaration(D)) {
             Visible = true;
             break;
           }
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17303,7 +17303,7 @@
   if (NeedDefinition &&
       (Func->getTemplateSpecializationKind() != TSK_Undeclared ||
        Func->getMemberSpecializationInfo()))
-    checkSpecializationVisibility(Loc, Func);
+    checkSpecializationReachability(Loc, Func);
 
   if (getLangOpts().CUDA)
     CheckCUDACall(Loc, Func);
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -16244,7 +16244,12 @@
   if (getLangOpts().CPlusPlusModules && isCurrentModulePurview()) {
     Module *GlobalModule =
         PushGlobalModuleFragment(ExternLoc, /*IsImplicit=*/true);
-    D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
+    /// 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->setLocalOwningModule(GlobalModule);
   }
 
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/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/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -2276,8 +2276,12 @@
                         llvm::SmallVectorImpl<Module *> *Modules = nullptr) {
     return isVisible(D) || hasVisibleDeclarationSlow(D, Modules);
   }
+
   bool hasVisibleDeclarationSlow(const NamedDecl *D,
                                  llvm::SmallVectorImpl<Module *> *Modules);
+  bool
+  hasReachableDeclaration(const NamedDecl *D,
+                          llvm::SmallVectorImpl<Module *> *Modules = nullptr);
 
   bool hasVisibleMergedDefinition(NamedDecl *Def);
   bool hasMergedDefinitionInCurrentModule(NamedDecl *Def);
@@ -2295,21 +2299,42 @@
     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);
+  }
+
   /// 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 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 different modules, and thus an ambiguity error can be downgraded to
@@ -3048,8 +3073,9 @@
 
   /// 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, and diagnose if not.
+  /// and partial specializations are visible/reachable, 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 {
Index: clang/include/clang/Sema/Lookup.h
===================================================================
--- clang/include/clang/Sema/Lookup.h
+++ clang/include/clang/Sema/Lookup.h
@@ -362,7 +362,8 @@
     if (!D->isInIdentifierNamespace(IDNS))
       return nullptr;
 
-    if (isVisible(getSema(), D) || isHiddenDeclarationVisible(D))
+    if (isVisible(getSema(), D) || isHiddenDeclarationVisible(D) ||
+        isReachableAndAcceptable(D))
       return D;
 
     return getAcceptableDeclSlow(D);
@@ -371,6 +372,29 @@
 private:
   static bool isVisibleSlow(Sema &SemaRef, NamedDecl *D);
   NamedDecl *getAcceptableDeclSlow(NamedDecl *D) const;
+  /// Determine whether this lookup is permitted to see reachable
+  /// declarations. Note that the reachable but not visible declaration
+  /// inhabit at 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 isReachableAndAcceptable would return false when we looks
+  ///   'reachable' here.
+  ///   // return reachable(43).v;
+  ///   // Valid. The field name 'v' is allowed during name lookup.
+  ///   // So isReachableAndAcceptable would return true when we looks 'v' here.
+  ///   return func().v;
+  /// }
+  /// ```
+  bool isReachableAndAcceptable(NamedDecl *ND) const;
 
 public:
   /// Returns the identifier namespace mask for this lookup.
Index: clang/include/clang/Basic/Module.h
===================================================================
--- clang/include/clang/Basic/Module.h
+++ clang/include/clang/Basic/Module.h
@@ -165,6 +165,8 @@
   /// some C++ module.
   bool isGlobalModule() const { return Kind == GlobalModuleFragment; }
 
+  bool isModuleMapModule() const { return Kind == ModuleMapModule; }
+
 private:
   /// The submodules of this module, indexed by name.
   std::vector<Module *> SubModules;
Index: clang/include/clang/AST/DeclBase.h
===================================================================
--- clang/include/clang/AST/DeclBase.h
+++ clang/include/clang/AST/DeclBase.h
@@ -225,8 +225,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
   };
 
@@ -235,8 +242,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<Decl *, 2, ModuleOwnershipKind> NextInContextAndBits;
+  /// The extra three bits are used for the ModuleOwnershipKind.
+  llvm::PointerIntPair<Decl *, 3, ModuleOwnershipKind> NextInContextAndBits;
 
 private:
   friend class DeclContext;
@@ -621,6 +628,14 @@
   ///   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;
@@ -798,6 +813,11 @@
     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() {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to