Bug 66834 - [concepts] variadic concepts and DR 1430 and DR 2686
Summary: [concepts] variadic concepts and DR 1430 and DR 2686
Status: SUSPENDED
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:
: 66841 79686 (view as bug list)
Depends on: 66092
Blocks: concepts c++-core-issues
  Show dependency treegraph
 
Reported: 2015-07-10 17:56 UTC by Eric Niebler
Modified: 2023-03-27 15:28 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2015-08-04 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Eric Niebler 2015-07-10 17:56:52 UTC
Before rev 225651 (the fix for #66758), the following worked. It no longer does. Not sure if it's legit.

template <class From, class To>
concept bool ExplicitlyConvertible =
  requires (From&& f) {
    static_cast<To>((From&&)f);
  };

template <class T, class... Args>
concept bool Constructible =
  ExplicitlyConvertible<Args..., T> ||
  requires (Args&&... args) {
    T{((Args&&)(args))...};
  };

template <class T, class...Args>
constexpr bool constructible() { return false; }

Constructible{T, ...Args}
constexpr bool constructible() { return false; }

int main() {}


Yields:

/cygdrive/c/Users/eric/Code/cmcstl2/test/iterator.cpp: In function ‘constexpr bool Constructible()’:
/cygdrive/c/Users/eric/Code/cmcstl2/test/iterator.cpp:9:5: error: pack expansion argument for non-pack parameter ‘From’ of concept ‘template
<class From, class To> constexpr const bool ExplicitlyConvertible<From, To>’
     ExplicitlyConvertible<Args..., T> ||
     ^
/cygdrive/c/Users/eric/Code/cmcstl2/test/iterator.cpp:1:11: note: declared here
 template< class From, class To >
           ^
Comment 1 Jason Merrill 2015-07-11 02:48:50 UTC
This was introduced by my patch for bug 66092, applying the tentative resolution of core issue 1430 to concepts as well as alias templates.  This makes sense to me since they have the same issue of needing to substitute dependent arguments into the template, in this case during normalization.

So I think your example is invalid, but it could use some discussion in core.
Comment 2 Andrew Sutton 2015-07-11 15:32:07 UTC
I think that this is invalid too. There's an expansion from an
uninstantiated template argument pack into a pair of template
parameters.

I think the program must be ill-formed in this case. It's not possible
to substitute a single pack through the two parameters declared for
ExplicitlyConvertible in order to normalize the constraint.

The TS is silent on this, but the resolution should be the same as that of 1430.

Andrew Sutton


On Fri, Jul 10, 2015 at 10:48 PM, jason at gcc dot gnu.org
<gcc-bugzilla@gcc.gnu.org> wrote:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66834
>
> --- Comment #1 from Jason Merrill <jason at gcc dot gnu.org> ---
> This was introduced by my patch for bug 66092, applying the tentative
> resolution of core issue 1430 to concepts as well as alias templates.  This
> makes sense to me since they have the same issue of needing to substitute
> dependent arguments into the template, in this case during normalization.
>
> So I think your example is invalid, but it could use some discussion in core.
>
> --
> You are receiving this mail because:
> You are on the CC list for the bug.
Comment 3 Eric Niebler 2015-07-11 17:29:09 UTC
I was thinking that overloading the Constructible concept would be a conforming way to express this, but it doesn't seems to work. Any clue why?


template <class T, class U>
concept bool Same = __is_same_as(T, U);

template <class T, class U>
concept bool ExplicitlyConvertible() { return
  Same<T, U> ||
  requires(T&& t) {
    static_cast<U>((T&&)(t));
  };
}

template <class T, class... Args>
concept bool Constructible() { return
  ExplicitlyConvertible<Args..., T>() ||
  requires (Args&&... args) {
    T{ (Args&&)(args)... };
  };
}

template <class T, class U>
concept bool Constructible() { return
  ExplicitlyConvertible<U, T>() ||
  requires (U&& u) {
    T{ (U&&)(u) };
  };
}

template <class T, class U>
  requires Constructible<T, U>()
constexpr bool f() { return false; }

template <class T, ExplicitlyConvertible<T> >
constexpr bool f() { return true; }

static_assert(f<int,int>(), "");
static_assert(f<int,long>(), "");

struct A {
  A(int);
};
struct B {
  explicit B(int);
};
static_assert(f<A, int>(), "");
static_assert(!f<B, int>(), "");


Yields:

/cygdrive/c/Users/eric/Code/cmcstl2/test/core_concepts.cpp:32:25: error: invalid reference to function concept ‘template<class T, class U> constexpr bool Constructible()’
   requires Constructible<T, U>()
                         ^
/cygdrive/c/Users/eric/Code/cmcstl2/test/core_concepts.cpp:48:1: error: static assertion failed
 static_assert(!f<B, int>(), "");
 ^

I can't make sense of the error. Is this just a bug?
Comment 4 Casey Carter 2015-07-11 17:38:53 UTC
I conjecture that Constructible<T, U>() is ambiguous, since both templates will specialize for it. I was thinking:

template <class T>
concept bool Constructible() {
  return requires {
    T{};
  };
}

template <class T, class U>
concept bool Constructible() {
  return ExplicitlyConvertible<U, T>() ||
  requires (U&& u) {
    T{ (U&&)(u) };
  };
}

template <class T, class First, class Second, class... Rest>
concept bool Constructible() {
  return requires (First&& first, Second&& second, Rest&&... rest) {
    T{ (First&&)first, (Second&&)second, (Rest&&)(rest)... };
  };
}

which has no such ambiguities of specialization. (This is getting a little off-topic for this bug report - we should takes this offline.)
Comment 5 Eric Niebler 2015-07-11 17:53:18 UTC
I would expect a partial ordering to prefer the two-parameter overload in that case. But yeah, it's a separate issue.
Comment 6 Eric Niebler 2015-07-11 19:09:29 UTC
Exhaustively overloading Constructible to avoid the kind mismatch and the ambiguity runs into a different problem:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66841

I haven't filed an issue for the ambiguity/partial order problem. Should I, or is that by design?

Either the kind mismatch problem needs to be fixed, or issue #66841. Right now I don't seem to have a way to express what I'm trying to express.
Comment 7 Andrew Sutton 2015-07-12 20:33:33 UTC
> I would expect a partial ordering to prefer the two-parameter overload in that
> case. But yeah, it's a separate issue.

The problem is that partial ordering doesn't apply to template
parameters whose arguments can only be given explicitly. I got caught
by this last year, and sent an email to core, and then (I think) Ville
submitted a core issue or NB comment (I don't remember the details).

Andrew
Comment 8 Jason Merrill 2015-07-13 20:16:02 UTC
I think we should reconsider the rule against partial specialization of a variable concept, as that seems like the right way to handle this situation.
Comment 9 Jason Merrill 2015-07-13 20:31:55 UTC
(In reply to Jason Merrill from comment #8)
> I think we should reconsider the rule against partial specialization of a
> variable concept, as that seems like the right way to handle this situation.

Except that would still run into the DR 1430 issue: a requires-clause that uses a pack expansion would normalize using the primary template defined with a parameter pack, even if a later instantiation of that requires-clause would work better with a different partial specialization.
Comment 10 Jason Merrill 2015-07-14 04:10:04 UTC
(In reply to Jason Merrill from comment #9)

So it seems that applying the DR 1430 tentative resolution to concepts severely limits the usability of variadic concepts, and we should reconsider that, so that instead we delay normalization of template-ids with variadic arguments until instantiation time.

The restriction on expansion arguments to non-expansion parameters initially applied to all variadic templates until N2555, which Eric was also involved with...

I guess I'll revert my change for the moment.
Comment 11 Jason Merrill 2015-07-14 04:11:43 UTC
Author: jason
Date: Tue Jul 14 04:11:11 2015
New Revision: 225758

URL: https://gcc.gnu.org/viewcvs?rev=225758&root=gcc&view=rev
Log:
	PR c++/66092
	PR c++/66834
	* gcc/cp/pt.c (coerce_template_parms): Revert earlier change.

Removed:
    branches/c++-concepts/gcc/testsuite/g++.dg/concepts/dr1430.C
Modified:
    branches/c++-concepts/ChangeLog.concepts
    branches/c++-concepts/gcc/cp/pt.c
Comment 12 Andrew Sutton 2015-07-14 13:33:31 UTC
> So it seems that applying the DR 1430 tentative resolution to concepts severely
> limits the usability of variadic concepts, and we should reconsider that, so
> that instead we delay normalization of template-ids with variadic arguments
> until instantiation time.
>
> The restriction on expansion arguments to non-expansion parameters initially
> applied to all variadic templates until N2555, which Eric was also involved
> with...

I don't think that's a good idea. It means the template-id would be
characterized as an atomic constraint for purposes of partial
ordering. You lose the ability to order on constraints within the
concept, which means you're no better off than using a type trait for
the definition.

I would make the following observations:

1. Variadics require meteaprogramming and pattern matching
2. The constraint are not intended to be turing complete, so we can't
reason about metaprograms
3. There may be useful logical extensions to the constraint language
for working with variadics in principled ways
4. Some variadic constraints might be useful as core language
constraints (intrinsics).

Plus, I have a feeling that I'm going to to have to re-think the
entire concept definition and requires-expression bit when we propose
concepts for C++. There were too many NB comments to ignore.

Andrew
Comment 13 Jason Merrill 2015-07-14 14:47:25 UTC
(In reply to Andrew Sutton from comment #12)
> I don't think that's a good idea. It means the template-id would be
> characterized as an atomic constraint for purposes of partial
> ordering. You lose the ability to order on constraints within the
> concept, which means you're no better off than using a type trait for
> the definition.

True, I guess it's a trade-off between power and ease of use.  Should I re-apply the change to coerce_template_parms?
Comment 14 Jason Merrill 2015-07-17 17:43:40 UTC
Author: jason
Date: Fri Jul 17 17:43:09 2015
New Revision: 225959

URL: https://gcc.gnu.org/viewcvs?rev=225959&root=gcc&view=rev
Log:
	PR c++/66092
	PR c++/66834
	* gcc/cp/pt.c (coerce_template_parms): Re-apply earlier change.

Added:
    branches/c++-concepts/gcc/testsuite/g++.dg/concepts/dr1430.C
Modified:
    branches/c++-concepts/ChangeLog.concepts
    branches/c++-concepts/gcc/cp/pt.c
Comment 15 Jason Merrill 2015-08-04 13:37:48 UTC
*** Bug 66841 has been marked as a duplicate of this bug. ***
Comment 16 Jason Merrill 2015-08-04 13:41:45 UTC
Suspending.
Comment 17 Patrick Palka 2020-10-15 18:54:18 UTC
*** Bug 79686 has been marked as a duplicate of this bug. ***