https://github.com/hahnjo updated https://github.com/llvm/llvm-project/pull/154158
>From 25ca9b45bfad32d0c273950ce5607fc3172d2145 Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld <jonas.hahnf...@cern.ch> Date: Tue, 19 Aug 2025 14:21:11 +0200 Subject: [PATCH 1/2] [Sema] Compare canonical conversion function 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 https://github.com/llvm/llvm-project/pull/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. --- clang/lib/Sema/SemaOverload.cpp | 9 +- clang/test/Modules/pr133057.cpp | 143 ++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 clang/test/Modules/pr133057.cpp diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 7c4405b414c47..690125d880293 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -4404,14 +4404,19 @@ CompareImplicitConversionSequences(Sema &S, SourceLocation Loc, Result = CompareStandardConversionSequences(S, Loc, ICS1.Standard, ICS2.Standard); else if (ICS1.isUserDefined()) { + auto ConvFunc1 = ICS1.UserDefined.ConversionFunction; + if (ConvFunc1) + ConvFunc1 = ConvFunc1->getCanonicalDecl(); + auto ConvFunc2 = ICS2.UserDefined.ConversionFunction; + if (ConvFunc2) + ConvFunc2 = ConvFunc2->getCanonicalDecl(); // User-defined conversion sequence U1 is a better conversion // sequence than another user-defined conversion sequence U2 if // they contain the same user-defined conversion function or // constructor and if the second standard conversion sequence of // U1 is better than the second standard conversion sequence of // U2 (C++ 13.3.3.2p3). - if (ICS1.UserDefined.ConversionFunction == - ICS2.UserDefined.ConversionFunction) + if (ConvFunc1 == ConvFunc2) Result = CompareStandardConversionSequences(S, Loc, ICS1.UserDefined.After, ICS2.UserDefined.After); diff --git a/clang/test/Modules/pr133057.cpp b/clang/test/Modules/pr133057.cpp new file mode 100644 index 0000000000000..b273fc318058e --- /dev/null +++ b/clang/test/Modules/pr133057.cpp @@ -0,0 +1,143 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// 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 +// 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 +// 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 +// 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 +// 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 + +//--- 2OT.h +#include "LQ1.h" + +namespace ciy { +namespace xqk { +template <typename> +class vum { + public: + using sc = std::C::wmd; + friend bool operator==(vum, vum); +}; +template <typename> +class me { + public: + using vbh = vum<me>; + using sc = std::C::vy<vbh>::sc; + template <typename db> + operator db() { return {}; } +}; +} // namespace xqk +template <typename vus> +xqk::me<vus> uvo(std::C::wmd, vus); +} // namespace ciy + +class ua { + std::C::wmd kij() { + ciy::uvo(kij(), '-'); + return {}; + } +}; + +//--- 9KF.h +#include "LQ1.h" +#include "2OT.h" +namespace { +void al(std::C::wmd lou) { std::C::jv<std::C::wmd> yt = ciy::uvo(lou, '/'); } +} // namespace + +//--- CMO.cppmap +module "hf" { +header "LQ1.h" +} + + +//--- E6H.cppmap +module "g" { +export * +header "2OT.h" +} + + +//--- HMT.cppmap +module "r" { +header "2OT.h" +} + + +//--- JOV.cppmap +module "q" { +header "9KF.h" +} + + +//--- LQ1.h +namespace std { +namespace C { +template <class zd> +struct vy : zd {}; +template <class ub> +struct vy<ub*> { + typedef ub jz; +}; +struct wmd {}; +template <class uo, class zt> +void sk(uo k, zt gf) { + (void)(k != gf); +} +template <class uo> +class fm { + public: + fm(uo); +}; +template <class kj, class kju> +bool operator==(kj, kju); +template <class epn> +void afm(epn) { + using yp = vy<epn>; + if (__is_trivially_copyable(yp)) { + sk(fm(epn()), nullptr); + } +} +template <class ub> +class jv { + public: + constexpr void gq(); + ub *nef; +}; +template <class ub> +constexpr void jv<ub>::gq() { + afm(nef); +} +} // namespace C +} // namespace std +namespace ciy { +} // namespace ciy + +//--- XFD.cc +// expected-no-diagnostics +#include "LQ1.h" +#include "2OT.h" +class wiy { + public: + std::C::wmd eyb(); +}; +template <typename wpa> +void i(wpa fg) { + std::C::jv<std::C::wmd> zs; + zs = ciy::uvo(fg.eyb(), '\n'); +} +namespace ciy { +namespace xqk { +struct sbv; +std::C::jv<sbv> ns() { + std::C::jv<sbv> ubs; + ubs.gq(); + return ubs; +} +} // namespace xqk +} // namespace ciy +void s() { + wiy fg; + i(fg); +} >From fbee42a4173b7de1dea6b3e9e35acc5b7c3a7e48 Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld <jonas.hahnf...@cern.ch> Date: Wed, 20 Aug 2025 08:04:40 +0200 Subject: [PATCH 2/2] Add type to local variables --- clang/lib/Sema/SemaOverload.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 690125d880293..6e02a965e64b4 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -4404,10 +4404,10 @@ CompareImplicitConversionSequences(Sema &S, SourceLocation Loc, Result = CompareStandardConversionSequences(S, Loc, ICS1.Standard, ICS2.Standard); else if (ICS1.isUserDefined()) { - auto ConvFunc1 = ICS1.UserDefined.ConversionFunction; + const FunctionDecl *ConvFunc1 = ICS1.UserDefined.ConversionFunction; if (ConvFunc1) ConvFunc1 = ConvFunc1->getCanonicalDecl(); - auto ConvFunc2 = ICS2.UserDefined.ConversionFunction; + const FunctionDecl *ConvFunc2 = ICS2.UserDefined.ConversionFunction; if (ConvFunc2) ConvFunc2 = ConvFunc2->getCanonicalDecl(); // User-defined conversion sequence U1 is a better conversion _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits