iains created this revision. Herald added a project: All. iains added reviewers: urnathan, ChuanqiXu. iains added a subscriber: clang-modules. iains published this revision for review. Herald added a project: clang. Herald added a subscriber: cfe-commits.
This is an implementation of the first part of P1815 <https://reviews.llvm.org/P1815> (and includes the testcase for [basic.def.odr]/ p10). If a function is in a different modular TU, and has internal-linkage, we invalidate its entry in an overload set. In [basic.lookup.argdep] p5 ex 2, we now correctly reject the use of `R::g` in the attempted instantiation of 'apply' in TU #3. Note that clang (and GCC) also rejects `f(x)` in the same TU, where the example currently states it should be OK. A clarification question has been sent to core about this. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D129174 Files: clang/include/clang/Sema/Overload.h clang/lib/Sema/SemaOverload.cpp clang/test/CXX/basic/basic.link/p10-ex2.cpp clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p5-ex2.cpp
Index: clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p5-ex2.cpp =================================================================== --- /dev/null +++ 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 <typename T, typename U> +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 <typename T> 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-n...@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-er...@n.cpp:10 {{no matching function for call to 'g'}} + // expected-note@-1 {{in instantiation of function template specialization 'apply<R::X, S::Z>' requested here}} +} Index: clang/test/CXX/basic/basic.link/p10-ex2.cpp =================================================================== --- /dev/null +++ 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-n...@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-n...@m.cpp:11 {{previous declaration is here}} Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -6400,6 +6400,16 @@ return; } + // Functions with internal linkage are only viable in the same module. + if (auto *MF = Function->getOwningModule()) { + if (Function->getFormalLinkage() <= Linkage::InternalLinkage && + getLangOpts().CPlusPlus20 && MF != getCurrentModule()) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_module_mismatched; + return; + } + } + if (Function->isMultiVersion() && Function->hasAttr<TargetAttr>() && !Function->getAttr<TargetAttr>()->isDefaultVersion()) { Candidate.Viable = false; Index: clang/include/clang/Sema/Overload.h =================================================================== --- clang/include/clang/Sema/Overload.h +++ 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 than the use. + ovl_fail_module_mismatched, }; /// A list of implicit conversion sequences for the arguments of an
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits