[PATCH] D154324: [C++20] [Modules] [ODRHash] Use CanonicalType for base classes
Alexander Kornienko via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 21 07:31:34 PDT 2023
alexfh added a comment.
In D154324#4522541 <https://reviews.llvm.org/D154324#4522541>, @alexfh wrote:
> In D154324#4520096 <https://reviews.llvm.org/D154324#4520096>, @alexfh wrote:
>
>> In D154324#4516964 <https://reviews.llvm.org/D154324#4516964>, @alexfh wrote:
>>
>>> In D154324#4516917 <https://reviews.llvm.org/D154324#4516917>, @ChuanqiXu wrote:
>>>
>>>> Maybe we got something wrong with this. I'd like to revert this patch in case it breaks something. But would you like to reduce your reproducer further to a state without external includes to STL or protobuf? Then we can add the reduced reproducer to the tests to avoid further regressions.
>>>
>>> That turned out to be quite time-consuming, but I can try nevertheless. I also asked @rsmith if he could figure out what the problem is. Hopefully, he can help with the test case, if gets to the bottom of the problem.
>>
>> I have a reduced reproducer, but I still depends on the internal build setup. I need a bit more time to make the reproducer standalone.
>
> Okay, here's the repro:
> F28380583: modules-repro.tar.gz <https://reviews.llvm.org/F28380583>
>
> And my observations with it:
>
> $ cat a.cppmap
> module "a" {
> export *
> module "a.h" {
> export *
> header "a.h"
> }
> use "c"
> }
> $ cat b.cppmap
> module "b" {
> export *
> module "b.h" {
> export *
> header "b.h"
> }
> use "c"
> }
> $ cat c.cppmap
> module "c" {
> export *
> module "c1.h" {
> export *
> textual header "c1.h"
> }
> module "c2.h" {
> export *
> textual header "c2.h"
> }
> module "c3.h" {
> export *
> textual header "c3.h"
> }
> }
> $ cat test.cppmap
> module "test" {
> export *
> use "a"
> use "b"
> }
> $ cat a.h
> #ifndef A_H_
> #define A_H_
>
> #include "c1.h"
>
> namespace q {
> template <typename T,
> typename std::enable_if<::p::P<T>::value>::type>
> class X {};
> } // namespace q
>
> #include "c3.h"
>
> #endif // A_H_
> $ cat b.h
> #ifndef B_H_
> #define B_H_
>
> #include "c2.h"
>
> #endif // B_H_
> $ cat c1.h
> #ifndef C1_H_
> #define C1_H_
>
> namespace std {
> template <class _Tp, _Tp __v>
> struct integral_constant {
> static constexpr const _Tp value = __v;
> typedef _Tp value_type;
> typedef integral_constant type;
> constexpr operator value_type() const noexcept { return value; }
> constexpr value_type operator()() const noexcept { return value; }
> };
>
> template <class _Tp, _Tp __v>
> constexpr const _Tp integral_constant<_Tp, __v>::value;
>
> typedef integral_constant<bool, true> true_type;
> typedef integral_constant<bool, false> false_type;
>
> template <bool, class _Tp = void>
> struct enable_if {};
> template <class _Tp>
> struct enable_if<true, _Tp> {
> typedef _Tp type;
> };
> } // namespace std
>
> namespace p {
> template <typename T>
> struct P : ::std::false_type {};
> }
>
> #endif // C1_H_
> $ cat c2.h
> #ifndef C2_H_
> #define C2_H_
>
> #include "c3.h"
>
> enum E {};
> namespace p {
> template <>
> struct P<E> : std::true_type {};
> } // namespace proto2
>
> inline void f(::util::EnumErrorSpace<E>) {}
>
> #endif // C2_H_
> $ cat c3.h
> #ifndef C3_H_
> #define C3_H_
>
> #include "c1.h"
>
> namespace util {
>
> template <typename T>
> class ErrorSpaceImpl;
>
> class ErrorSpace {
> protected:
> template <bool* addr>
> struct OdrUse {
> constexpr OdrUse() : b(*addr) {}
> bool& b;
> };
> template <typename T>
> struct Registerer {
> static bool register_token;
> static constexpr OdrUse<®ister_token> kRegisterTokenUse{};
> };
>
> private:
> template <typename T>
> static const ErrorSpace* GetBase() {
> return 0;
> }
>
> static bool Register(const ErrorSpace* (*space)()) { return true; }
> };
>
> template <typename T>
> bool ErrorSpace::Registerer<T>::register_token =
> Register(&ErrorSpace::GetBase<T>);
>
> template <typename T>
> class ErrorSpaceImpl : public ErrorSpace {
> private:
> static constexpr Registerer<ErrorSpaceImpl> kRegisterer{};
> };
>
> template <typename T, typename = typename std::enable_if<p::P<T>::value>::type>
> class EnumErrorSpace : public ErrorSpaceImpl<EnumErrorSpace<T>> {};
>
> } // namespace util
> #endif // C3_H_
> $ cat test.cc
> #include "a.h"
> #include "b.h"
>
> int main(int, char**) {}
> $ clang -fmodules -fno-implicit-modules -fno-implicit-module-maps -fmodule-name=c -fmodule-map-file=c.cppmap -xc++ -c c.cppmap -Xclang=-emit-module -o c.pcm
> $ clang -fmodules -fno-implicit-modules -fno-implicit-module-maps -fmodule-name=a -fmodule-map-file=a.cppmap -fmodule-map-file=c.cppmap -xc++ -c a.cppmap -Xclang=-emit-module -o a.pcm
> $ clang -fmodules -fno-implicit-modules -fno-implicit-module-maps -fmodule-name=b -fmodule-map-file=b.cppmap -fmodule-map-file=c.cppmap -xc++ -c b.cppmap -Xclang=-emit-module -o b.pcm
> $ clang -fmodules -fno-implicit-modules -fno-implicit-module-maps -fmodule-name=test -fmodule-map-file=test.cppmap -fmodule-map-file=a.cppmap -fmodule-map-file=b.cppmap -Xclang=-fmodule-file=a.pcm -Xclang=-fmodule-file=b.pcm -xc++ -c test.cc -o test.pcm
> In module 'b':
> ./c3.h:44:7: error: 'util::EnumErrorSpace' has different definitions in different modules; definition in module 'b.b.h' is here
> 44 | class EnumErrorSpace : public ErrorSpaceImpl<EnumErrorSpace<T>> {};
> | ^
> ./c3.h:44:7: note: definition in module 'a.a.h' is here
> 44 | class EnumErrorSpace : public ErrorSpaceImpl<EnumErrorSpace<T>> {};
> | ^
> 1 error generated.
BTW, if in a.h I change
typename std::enable_if<::p::P<T>::value>::type>
to
typename std::enable_if<p::P<T>::value>::type>
Compilation succeeds.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D154324/new/
https://reviews.llvm.org/D154324
More information about the cfe-commits
mailing list