[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:28:51 PDT 2023


alexfh added a comment.

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<&register_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.


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