diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -795,6 +795,10 @@ /// This candidate was not viable because its associated constraints were /// not satisfied. ovl_fail_constraints_not_satisfied, + + /// This candidate was not viable because it has internal linkage and is + /// from a different module unit than the use. + ovl_fail_module_mismatched, }; /// A list of implicit conversion sequences for the arguments of an diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6400,6 +6400,17 @@ return; } + // Functions with internal linkage are only viable in the same module unit. + if (auto *MF = Function->getOwningModule()) { + if (Function->getFormalLinkage() <= Linkage::InternalLinkage && + getLangOpts().CPlusPlusModules && + MF->getTopLevelModule() != getCurrentModule()->getTopLevelModule()) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_module_mismatched; + return; + } + } + if (Function->isMultiVersion() && Function->hasAttr() && !Function->getAttr()->isDefaultVersion()) { Candidate.Viable = false; diff --git a/clang/test/CXX/basic/basic.link/p10-ex2.cpp b/clang/test/CXX/basic/basic.link/p10-ex2.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CXX/basic/basic.link/p10-ex2.cpp @@ -0,0 +1,35 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// RUN: cd %t +// +// RUN: %clang_cc1 -std=c++20 M.cpp -fsyntax-only -DTEST_INTERFACE -verify +// RUN: %clang_cc1 -std=c++20 M.cpp -emit-module-interface -o M.pcm +// RUN: %clang_cc1 -std=c++20 useM.cpp -fsyntax-only -fmodule-file=M.pcm -verify + +//--- decls.h +int f(); // #1, attached to the global module +int g(); // #2, attached to the global module + +//--- M.cpp +module; +#include "decls.h" +export module M; +export using ::f; // OK, does not declare an entity, exports #1 +#if TEST_INTERFACE +// error: matches #2, but attached to M +int g(); // expected-error {{declaration of 'g' in module M follows declaration in the global module}} +// expected-note@decls.h:2 {{previous declaration is here}} +#endif +export int h(); // #3 +export int k(); // #4 + +//--- useM.cpp +import M; +// error: matches #3 +static int h(); // expected-error {{static declaration of 'h' follows non-static declaration}} +// expected-note@M.cpp:10 {{previous declaration is here}} + +// error: matches #4 +int k(); // expected-error {{declaration of 'k' in the global module follows declaration in module M}} +// expected-note@M.cpp:11 {{previous declaration is here}} diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p5-ex2.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p5-ex2.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p5-ex2.cpp @@ -0,0 +1,68 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// RUN: cd %t +// +// RUN: %clang_cc1 -std=c++20 M.cpp -emit-module-interface -o M.pcm +// RUN: %clang_cc1 -std=c++20 N.cpp -emit-module-interface -o N.pcm \ +// RUN: -fmodule-file=M.pcm +// RUN: %clang_cc1 -std=c++20 Q.cpp -emit-module-interface -o Q.pcm +// RUN: %clang_cc1 -std=c++20 Q-impl.cpp -fsyntax-only -fmodule-file=Q.pcm \ +// RUN: -fmodule-file=N.pcm -verify + +//--- M.cpp +export module M; +namespace R { +export struct X {}; +export void f(X); +} // namespace R +namespace S { +export void f(R::X, R::X); +} + +//--- N.cpp +export module N; +import M; +export R::X make(); +namespace R { +static int g(X); +} +export template +void apply(T t, U u) { + f(t, u); + g(t); +} + +//--- Q.cpp +export module Q; + +//--- Q-impl.cpp +module Q; +import N; + +namespace S { +struct Z { + template operator T(); +}; +} // namespace S +void test() { + // OK, decltype(x) is R::X in module M + auto x = make(); + + // error: R and R::f are not visible here + R::f(x); // expected-error {{declaration of 'R' must be imported from module 'N' before it is required}} + // expected-note@N.cpp:4 {{declaration here is not visible}} + // expected-error@-2 {{no type named 'f' in namespace 'R'}} + + // Not OK, R::f from interface of M is reachable, but not visible to lookup. + f(x); // expected-error {{use of undeclared identifier 'f'}} + + // error: S::f in module M not considered even though S is an associated + // namespace + f(x, S::Z()); // expected-error {{use of undeclared identifier 'f'}} + + // error: S::f is visible in instantiation context, but R::g has internal + // linkage and cannot be used outside N.cpp + apply(x, S::Z()); // expected-error@N.cpp:10 {{no matching function for call to 'g'}} + // expected-note@-1 {{in instantiation of function template specialization 'apply' requested here}} +}