llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.17k stars 12.04k forks source link

Weird failure/interaction in substitution/specialization matching #38328

Open CaseyCarter opened 6 years ago

CaseyCarter commented 6 years ago
Bugzilla Link 38980
Version trunk
OS Windows NT
CC @cjdb,@DougGregor,@zygoloid,@sw6ueyz

Extended Description

Compiling this correct program with -std=c++1z:

  template<class, class> constexpr bool is_same_v = false;
  template<class T> constexpr bool is_same_v<T, T> = true;

  template<class...> using void_t = void;

  template<class T> struct id { using type = T; };

  template<class T> T val() noexcept;

  template<class X, class Y> using cond_res = 
      decltype(false ? val<const X&>() : val<const Y&>());

  template<class, class, class = void>
  struct CT { using type = void; };

  template<class D1, class D2>
  #ifndef WORKAROUND
  struct CT<D1, D2, void_t<cond_res<D1, D2>>> : id<cond_res<D1, D2>> {};
  #else
  struct CT<D1, D2, void_t<cond_res<D1, D2>>> {
      using type = cond_res<D1, D2>;
  };
  #endif

  struct S1 {};
  struct S2 : private S1 {};
  struct S3 : protected S1 {};

  static_assert(is_same_v<void, CT<S1, S2>::type>); // Fine
  static_assert(is_same_v<void, CT<S1, S3>::type>); // Error

produces diagnostices (https://godbolt.org/z/WGvIFN):

  <source>:11:40: error: cannot cast 'const S3' to its protected base class 
  'const S1'
    decltype(false ? val<const X&>() : val<const Y&>());
                                       ^
  <source>:18:50: note: in instantiation of template type alias 'cond_res' 
  requested here
  struct CT<D1, D2, void_t<cond_res<D1, D2>>> : id<cond_res<D1, D2>> {};
                                                 ^
  <source>:30:31: note: in instantiation of template class 'CT<S1, S3, 
  void>' requested here
  static_assert(is_same_v<void, CT<S1, S3>::type>); // Error
                              ^
  <source>:27:13: note: declared protected here
  struct S3 : protected S1 {};
              ^~~~~~~~~~~~
  1 error generated.

Private base class? Fine. Protected base class? EXPLODES

ec04fc15-fa35-46f2-80e1-5d271f2ef708 commented 2 years ago

mentioned in issue llvm/llvm-bugzilla-archive#40321

ec04fc15-fa35-46f2-80e1-5d271f2ef708 commented 3 years ago

See also the example from llvm/llvm-bugzilla-archive#40321 , which is another partial specialization selection / void_t / access mishap, but not involving an alias template.

ec04fc15-fa35-46f2-80e1-5d271f2ef708 commented 3 years ago

Bug llvm/llvm-bugzilla-archive#40321 has been marked as a duplicate of this bug.

ec04fc15-fa35-46f2-80e1-5d271f2ef708 commented 3 years ago

Interesting. void_t has historically been broken in Clang; I'm about to land a fix for that, but it doesn't actually help in this case. I have some guesses as to what might be happening here:

... but in any case, in both cases we should hit a SFINAE failure during substitution into the partial specialization's template-id, so we should select the primary template.