Skip to content

Commit a9dafc9

Browse files
authored
[Sema] Compare canonical conversion function (#154158)
With lazy template loading, it is possible to find non-canonical FunctionDecls, depending on when redecl chains are completed. This is a problem for templated conversion operators that would allow to call either the copy assignment or the move assignment operator. This ambiguity is resolved by isBetterReferenceBindingKind (called from CompareStandardConversionSequences) ranking rvalue refs over lvalue refs. Unfortunately, this fix is hard to test in isolation without the changes in #133057 that make lazy template loading more likely to complete redecl chains at "inconvenient" times. The added reproducer passes before and after this commit, but would have failed with the proposed changes of the linked PR. Kudos to Maksim Ivanov for providing an initial version of the reproducer that I further simplified.
1 parent 38896d6 commit a9dafc9

File tree

2 files changed

+154
-2
lines changed

2 files changed

+154
-2
lines changed

clang/lib/Sema/SemaOverload.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4413,14 +4413,23 @@ CompareImplicitConversionSequences(Sema &S, SourceLocation Loc,
44134413
Result = CompareStandardConversionSequences(S, Loc,
44144414
ICS1.Standard, ICS2.Standard);
44154415
else if (ICS1.isUserDefined()) {
4416+
// With lazy template loading, it is possible to find non-canonical
4417+
// FunctionDecls, depending on when redecl chains are completed. Make sure
4418+
// to compare the canonical decls of conversion functions. This avoids
4419+
// ambiguity problems for templated conversion operators.
4420+
const FunctionDecl *ConvFunc1 = ICS1.UserDefined.ConversionFunction;
4421+
if (ConvFunc1)
4422+
ConvFunc1 = ConvFunc1->getCanonicalDecl();
4423+
const FunctionDecl *ConvFunc2 = ICS2.UserDefined.ConversionFunction;
4424+
if (ConvFunc2)
4425+
ConvFunc2 = ConvFunc2->getCanonicalDecl();
44164426
// User-defined conversion sequence U1 is a better conversion
44174427
// sequence than another user-defined conversion sequence U2 if
44184428
// they contain the same user-defined conversion function or
44194429
// constructor and if the second standard conversion sequence of
44204430
// U1 is better than the second standard conversion sequence of
44214431
// U2 (C++ 13.3.3.2p3).
4422-
if (ICS1.UserDefined.ConversionFunction ==
4423-
ICS2.UserDefined.ConversionFunction)
4432+
if (ConvFunc1 == ConvFunc2)
44244433
Result = CompareStandardConversionSequences(S, Loc,
44254434
ICS1.UserDefined.After,
44264435
ICS2.UserDefined.After);

clang/test/Modules/pr133057.cpp

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: split-file %s %t
4+
//
5+
// RUN: %clang_cc1 -xc++ -std=c++20 -emit-module -fmodule-name=hf -fno-cxx-modules -fmodules -fno-implicit-modules %t/CMO.cppmap -o %t/WI9.pcm
6+
// RUN: %clang_cc1 -xc++ -std=c++20 -emit-module -fmodule-name=g -fno-cxx-modules -fmodules -fno-implicit-modules -fmodule-file=%t/WI9.pcm %t/E6H.cppmap -o %t/4BK.pcm
7+
// RUN: %clang_cc1 -xc++ -std=c++20 -emit-module -fmodule-name=r -fno-cxx-modules -fmodules -fno-implicit-modules -fmodule-file=%t/WI9.pcm %t/HMT.cppmap -o %t/LUM.pcm
8+
// RUN: %clang_cc1 -xc++ -std=c++20 -emit-module -fmodule-name=q -fno-cxx-modules -fmodules -fno-implicit-modules -fmodule-file=%t/LUM.pcm -fmodule-file=%t/4BK.pcm %t/JOV.cppmap -o %t/9VX.pcm
9+
// RUN: %clang_cc1 -xc++ -std=c++20 -verify -fsyntax-only -fno-cxx-modules -fmodules -fno-implicit-modules -fmodule-file=%t/9VX.pcm %t/XFD.cc
10+
11+
//--- 2OT.h
12+
#include "LQ1.h"
13+
14+
namespace ciy {
15+
namespace xqk {
16+
template <typename>
17+
class vum {
18+
public:
19+
using sc = std::C::wmd;
20+
friend bool operator==(vum, vum);
21+
};
22+
template <typename>
23+
class me {
24+
public:
25+
using vbh = vum<me>;
26+
using sc = std::C::vy<vbh>::sc;
27+
template <typename db>
28+
operator db() { return {}; }
29+
};
30+
} // namespace xqk
31+
template <typename vus>
32+
xqk::me<vus> uvo(std::C::wmd, vus);
33+
} // namespace ciy
34+
35+
class ua {
36+
std::C::wmd kij() {
37+
ciy::uvo(kij(), '-');
38+
return {};
39+
}
40+
};
41+
42+
//--- 9KF.h
43+
#include "LQ1.h"
44+
#include "2OT.h"
45+
namespace {
46+
void al(std::C::wmd lou) { std::C::jv<std::C::wmd> yt = ciy::uvo(lou, '/'); }
47+
} // namespace
48+
49+
//--- CMO.cppmap
50+
module "hf" {
51+
header "LQ1.h"
52+
}
53+
54+
55+
//--- E6H.cppmap
56+
module "g" {
57+
export *
58+
header "2OT.h"
59+
}
60+
61+
62+
//--- HMT.cppmap
63+
module "r" {
64+
header "2OT.h"
65+
}
66+
67+
68+
//--- JOV.cppmap
69+
module "q" {
70+
header "9KF.h"
71+
}
72+
73+
74+
//--- LQ1.h
75+
namespace std {
76+
namespace C {
77+
template <class zd>
78+
struct vy : zd {};
79+
template <class ub>
80+
struct vy<ub*> {
81+
typedef ub jz;
82+
};
83+
struct wmd {};
84+
template <class uo, class zt>
85+
void sk(uo k, zt gf) {
86+
(void)(k != gf);
87+
}
88+
template <class uo>
89+
class fm {
90+
public:
91+
fm(uo);
92+
};
93+
template <class kj, class kju>
94+
bool operator==(kj, kju);
95+
template <class epn>
96+
void afm(epn) {
97+
using yp = vy<epn>;
98+
if (__is_trivially_copyable(yp)) {
99+
sk(fm(epn()), nullptr);
100+
}
101+
}
102+
template <class ub>
103+
class jv {
104+
public:
105+
constexpr void gq();
106+
ub *nef;
107+
};
108+
template <class ub>
109+
constexpr void jv<ub>::gq() {
110+
afm(nef);
111+
}
112+
} // namespace C
113+
} // namespace std
114+
namespace ciy {
115+
} // namespace ciy
116+
117+
//--- XFD.cc
118+
// expected-no-diagnostics
119+
#include "LQ1.h"
120+
#include "2OT.h"
121+
class wiy {
122+
public:
123+
std::C::wmd eyb();
124+
};
125+
template <typename wpa>
126+
void i(wpa fg) {
127+
std::C::jv<std::C::wmd> zs;
128+
zs = ciy::uvo(fg.eyb(), '\n');
129+
}
130+
namespace ciy {
131+
namespace xqk {
132+
struct sbv;
133+
std::C::jv<sbv> ns() {
134+
std::C::jv<sbv> ubs;
135+
ubs.gq();
136+
return ubs;
137+
}
138+
} // namespace xqk
139+
} // namespace ciy
140+
void s() {
141+
wiy fg;
142+
i(fg);
143+
}

0 commit comments

Comments
 (0)