hahnjo wrote: Thanks, the reproducer is indeed useful. The first "bad" commit is the second `Complete only needed partial specializations`.
I was manually able to further reduce the example (throwing out empty files & modules, inline through typedefs, etc) <details><summary>Smaller reproducer</summary> ``` //--- 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 //--- Makefile .ALWAYS: FZV.o: .ALWAYS WI9.pcm 4BK.pcm LUM.pcm 9VX.pcm $(CLANG) -fmodule-name=p -Xclang=-fno-cxx-modules -fmodules -fno-implicit-modules -fno-implicit-module-maps -Xclang=-fmodule-file=9VX.pcm -fmodule-map-file=CMO.cppmap -std=gnu++20 -c XFD.cc -o FZV.o WI9.pcm: .ALWAYS $(CLANG) -fmodule-name=hf -fmodule-map-file=CMO.cppmap -Xclang=-fno-cxx-modules -xc++ -Xclang=-emit-module -fmodules -fno-implicit-modules -fno-implicit-module-maps -std=gnu++20 -c CMO.cppmap -o WI9.pcm 4BK.pcm: .ALWAYS WI9.pcm $(CLANG) -fmodule-name=g -fmodule-map-file=E6H.cppmap -Xclang=-fno-cxx-modules -xc++ -Xclang=-emit-module -fmodules -fno-implicit-modules -fno-implicit-module-maps -Xclang=-fmodule-file=WI9.pcm -fmodule-map-file=CMO.cppmap -std=gnu++20 -c E6H.cppmap -o 4BK.pcm LUM.pcm: .ALWAYS WI9.pcm $(CLANG) -fmodule-name=r -fmodule-map-file=HMT.cppmap -Xclang=-fno-cxx-modules -xc++ -Xclang=-emit-module -fmodules -fno-implicit-modules -fno-implicit-module-maps -Xclang=-fmodule-file=WI9.pcm -fmodule-map-file=CMO.cppmap -std=gnu++20 -c HMT.cppmap -o LUM.pcm 9VX.pcm: .ALWAYS WI9.pcm 4BK.pcm LUM.pcm $(CLANG) -fmodule-name=q -fmodule-map-file=JOV.cppmap -Xclang=-fno-cxx-modules -xc++ -Xclang=-emit-module -fmodules -fno-implicit-modules -fno-implicit-module-maps -Xclang=-fmodule-file=LUM.pcm -Xclang=-fmodule-file=4BK.pcm -fmodule-map-file=CMO.cppmap -std=gnu++20 -c JOV.cppmap -o 9VX.pcm .PHONY: clean clean: find . \( -name '*.pcm' -o -name '*.o' \) -delete //--- XFD.cc #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); } ``` </details> The failure with modules and this PR is: ``` XFD.cc:10:6: error: use of overloaded operator '=' is ambiguous (with operand types 'std::C::jv<std::C::wmd>' and 'xqk::me<char>') 10 | zs = ciy::uvo(fg.eyb(), '\n'); | ~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~ XFD.cc:24:3: note: in instantiation of function template specialization 'i<wiy>' requested here 24 | i(fg); | ^ ./LQ1.h:29:7: note: candidate function (the implicit copy assignment operator) 29 | class jv { | ^ ./LQ1.h:29:7: note: candidate function (the implicit move assignment operator) ``` Two observations: 1. There is a diamond module structure: Both `4BK.pcm` and `LUM.pcm` depend on `WI9.pcm` and contain `2OT.h` with different module names (I removed transitive empty includes). I'm not sure if this is valid... @emaxx-google is it possible to share the modulemap for Abseil? We should check if all private headers that are potentially used by multiple "public" modules are correctly taken care of. 2. The problem is the conversion operator `xqk::me` that is declared as `template`. I *think* the problem is that an object can be implicitly converted into multiple temporaries that can either be copy- or move-constructed. https://github.com/llvm/llvm-project/pull/133057 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits