[PATCH] D137712: Correctly handle Substitution failure in concept specialization.

Ilya Biryukov via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 16 03:45:23 PST 2022


ilya-biryukov added a comment.

We discussed this with Utkarsh offline, he's OOO for some time, so I wanted to leave the summary here.
This patch attempts to attack the problem by keeping the information about substitution failure in template arguments of `ConceptSpecializationExpr`.
However, it seems that the standard does not give any special treatment to those as compared to other forms of substitution failure and we should rethink our approach. The problem seems to be in how we evaluate SFINAE inside `requires-expression` and/or `nested-requirement`.

E.g. if we replace a concept by a template variable, a failure to substitute template arguments should **not** cause the whole `requires-expression` to evaluate to false:

  template <class T> constexpr bool true_v = true; 
  template <class T> constexpr int foo() requires requires { requires true_v<typename T::type> || true_v<T>; }
      { return 123; }
  
  static_assert(foo<int>() == 123);

GCC and MSVC succeed here, Clang fails: https://gcc.godbolt.org/z/WGdKWYM7e. Clang's behavior seems to be non-standard here.
The proper fix seems to be changing Clang behavior so that the `requires-expression` evaluates to true despite its first branch having a subsitution failure.

Utkarsh has also found an interesting example where GCC (IMO, unexpectedly) evaluates the concept to true despite a substitution failure in its template arguments:

  template <class U> concept true_c = true; 
  template <class T> constexpr int foo() 
      requires requires { requires true_c<typename T::type>; }
      { return 123; }
  
  static_assert(foo<int>() == 123);

Clang and MSVC fail here, GCC succeeds: https://gcc.godbolt.org/z/5qYjcW75q. 
The standard does not seem to be very clear here. It says that an "atomic constraint" that we must evaluate contains both an expression (`true`) and a template parameter mapping (`U -> typename T::type`, where `T` is `int`). The template parameter mapping is clearly not well-formed, the expression still evaluates to `true` and the standard does not seem to mention what to do when template parameter mapping is not well-formed. IMO, to form the template parameter mapping we must substitute `T -> int` into the template argument list (`<typename T::type>`) and at that point we see a substitution failure, hence `requires-expression` should evaluate to `false`. Someone should probably raise this with WG21 to know for sure.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D137712/new/

https://reviews.llvm.org/D137712



More information about the cfe-commits mailing list