forked from OSchip/llvm-project
[C++20] [Modules] Handle linkage properly for specializations when overloading
Currently, the semantics of linkage in clang is slightly different from the semantics in C++ spec. In C++ spec, only names have linkage. So that all entities of the same should share one linkage. But in clang, different entities of the same could have different linkage. It would break a use case where the template have external linkage and its specialization have internal linkage due to its type argument is internal linkage. The root cause is that the semantics of internal linkage in clang is a mixed form of internal linkage and TU-local in C++ spec. It is hard to solve the root problem and I tried to add a workaround inplace.
This commit is contained in:
parent
93f8657c74
commit
15ddc09ef9
|
@ -6403,11 +6403,21 @@ void Sema::AddOverloadCandidate(
|
|||
// Functions with internal linkage are only viable in the same module unit.
|
||||
if (auto *MF = Function->getOwningModule()) {
|
||||
if (getLangOpts().CPlusPlusModules && !MF->isModuleMapModule() &&
|
||||
Function->getFormalLinkage() <= Linkage::InternalLinkage &&
|
||||
!isModuleUnitOfCurrentTU(MF)) {
|
||||
Candidate.Viable = false;
|
||||
Candidate.FailureKind = ovl_fail_module_mismatched;
|
||||
return;
|
||||
/// FIXME: Currently, the semantics of linkage in clang is slightly
|
||||
/// different from the semantics in C++ spec. In C++ spec, only names
|
||||
/// have linkage. So that all entities of the same should share one
|
||||
/// linkage. But in clang, different entities of the same could have
|
||||
/// different linkage.
|
||||
NamedDecl *ND = Function;
|
||||
if (auto *SpecInfo = Function->getTemplateSpecializationInfo())
|
||||
ND = SpecInfo->getTemplate();
|
||||
|
||||
if (ND->getFormalLinkage() <= Linkage::InternalLinkage) {
|
||||
Candidate.Viable = false;
|
||||
Candidate.FailureKind = ovl_fail_module_mismatched;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: split-file %s %t
|
||||
// RUN: cd %t
|
||||
//
|
||||
// RUN: %clang_cc1 -std=c++20 %t/A.cppm -I%t -emit-module-interface -o %t/A.pcm
|
||||
// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t %t/Use.cpp -verify -fsyntax-only
|
||||
//
|
||||
//--- foo.h
|
||||
|
||||
namespace ns {
|
||||
struct A {};
|
||||
|
||||
template<typename Func>
|
||||
constexpr bool __call_is_nt(A)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
ns::A make();
|
||||
|
||||
template <typename T>
|
||||
bool foo(T t) {
|
||||
auto func = [](){};
|
||||
return __call_is_nt<decltype(func)>(t);
|
||||
}
|
||||
}
|
||||
|
||||
//--- A.cppm
|
||||
module;
|
||||
#include "foo.h"
|
||||
export module A;
|
||||
export namespace ns {
|
||||
using ns::foo;
|
||||
using ns::make;
|
||||
}
|
||||
|
||||
//--- Use.cpp
|
||||
// expected-no-diagnostics
|
||||
import A;
|
||||
void test() {
|
||||
auto a = ns::make();
|
||||
ns::foo(a);
|
||||
}
|
Loading…
Reference in New Issue