Bug 67148 - [concepts] Failed concept check when indirecting through a constrained trait
Summary: [concepts] Failed concept check when indirecting through a constrained trait
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: c++-concepts
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks: concepts
  Show dependency treegraph
 
Reported: 2015-08-07 20:15 UTC by Eric Niebler
Modified: 2019-10-14 17:15 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Eric Niebler 2015-08-07 20:15:15 UTC
I've reduced this as much as I can. Test case below. The two static asserts are testing the same thing, AFAICT. One tests the Function concept directly, the other tests it indirectly through a __function trait that has been constrained with Function. The former succeeds while the latter fails. Somewhat mysterious.

namespace std
{
  typedef unsigned int size_t;
  typedef int ptrdiff_t;
  typedef decltype(nullptr) nullptr_t;
  template<typename _Tp, _Tp... _Idx>
    struct integer_sequence
    {
      typedef _Tp value_type;
      static constexpr size_t size() { return sizeof...(_Idx); }
    };

  template <class T, T Value>
  struct integral_constant {
    using type = integral_constant;
    using value_type = T;
    constexpr operator T() const { return Value; }
    constexpr T operator()() const { return Value; }
    static constexpr T value {Value};
  };
  template <class T, T Value>
  constexpr T integral_constant<T, Value>::value;
  using true_type = integral_constant<bool, true>;
  using false_type = integral_constant<bool, false>;

  template <class T, class U>
  struct is_same : false_type {};
  template <class T>
  struct is_same<T,T> : true_type {};
}
       
namespace meta
{
    inline namespace v1
    {
        template <typename T>
        using _t = typename T::type;
        template <bool... Bools>
        using and_c = std::is_same<std::integer_sequence<bool, Bools...>,
                                   std::integer_sequence<bool, (Bools || true)...>>;
    }
}

namespace stl2 { inline namespace v1 {
using std::declval;
namespace detail {
template <class...>
struct all_same : std::true_type {};
template <class T, class...Rest>
struct all_same<T, Rest...> :
  meta::and_c<__is_same_as(T, Rest)...> {};
}
template <class...Ts>
concept bool Same() {
  return detail::all_same<Ts...>::value;
}
template <class F, class...Args>
using ResultType = decltype(declval<F>()(declval<Args>()...));
template <class>
struct value_type {};
template <class T>
struct value_type<T*> {
  using type = T;
};
template <class T>
using ValueType =
  typename value_type<T>::type;

template <class F, class...Args>
concept bool Function() {
  return requires (F& f, Args&&...args) {
    f((Args&&)args...);
    requires Same<decltype(f((Args&&)args...)), ResultType<F, Args...> >();
  };
}

template <class, class...> struct __function : std::false_type {};
Function{F, ...Args} struct __function<F, Args...> : std::true_type {};

template <class F, class I1, class I2>
concept bool IndirectCallable() {
  return Function<F, ValueType<I1>, ValueType<I2>>();
}

template <class F, class I1, class I2>
concept bool IndirectCallable2() {
  return __function<F, ValueType<I1>, ValueType<I2>>::value;
}

namespace ext { namespace models {
template <class, class, class>
constexpr bool indirect_callable() { return false; }
IndirectCallable{F, I1, I2}
constexpr bool indirect_callable() { return true; }

template <class, class, class>
constexpr bool indirect_callable2() { return false; }
IndirectCallable2{F, I1, I2}
constexpr bool indirect_callable2() { return true; }
}}
}}

namespace models = stl2::ext::models;

template <class T = void>
struct plus {
  T operator()(T, T) const;
};

static_assert((models::indirect_callable<::plus<int>, int*, int*>()), "Concept check failed: " "models::indirect_callable<::plus<int>, int*, int*>()");
static_assert((models::indirect_callable2<::plus<int>, int*, int*>()), "Concept check failed: " "models::indirect_callable2<::plus<int>, int*, int*>()");
Comment 1 Eric Niebler 2015-08-07 20:25:06 UTC
If I replace the variadic Same concept with the binary one below, the problem goes away.

template<class T, class U>
concept bool Same() {
  return __is_same_as(T,U);
}
Comment 2 Casey Carter 2015-08-09 02:03:34 UTC
Here's a somewhat minimized test case that illustrates that overload resolution works correctly, but matching partial specializations of a class template or variable template does not:

template <bool Value>
struct bool_ {
  static constexpr bool value {Value};
};
using true_type = bool_<true>;
using false_type = bool_<false>;

template <class...> struct all_same : true_type {};
template <class T, class...Rest>
struct all_same<T, T, Rest...> : all_same<T, Rest...> {};
template <class T, class U, class...Rest>
struct all_same<T, U, Rest...> : false_type {};

template <class...Ts>
concept bool Same() {
  return all_same<Ts...>::value;
}

template <class F, class...Args>
concept bool Function() {
  return requires (F& f, Args&&...args) {
    requires Same<int, decltype(f((Args&&)args...))>();
  };
}

template <class, class...>
constexpr bool function() { return false; }
Function{F, ...Args}
constexpr bool function() { return true; }

template <class, class...>
constexpr bool func_v = false;
Function{F, ...Args}
constexpr bool func_v<F, Args...> = true;

template <class, class...>
struct is_function : false_type {};
Function{F, ...Args}
struct is_function<F, Args...> : true_type {};

struct plus { int operator()(int) const; };

static_assert(function<::plus, int>());         // Fine
static_assert(func_v<::plus, int>);             // Error
static_assert(is_function<::plus, int>::value); // Error
Comment 3 Andrew Sutton 2019-09-04 15:01:30 UTC
This seems to have been fixed at some point. All examples compile in the concepts-cxx2a branch, which also has a test for this PR.
Comment 4 Jonathan Wakely 2019-10-14 17:15:16 UTC
This be closed now that concepts-cxx2a has been merged to trunk.