Bug 115746 - [C++26] P2963R3 - Ordering of constraints involving fold expressions
Summary: [C++26] P2963R3 - Ordering of constraints involving fold expressions
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 15.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks: c++26-core 116106
  Show dependency treegraph
 
Reported: 2024-07-02 08:45 UTC by Jakub Jelinek
Modified: 2024-12-19 15:37 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2024-07-02 00:00:00


Attachments
gcc15-pr115746-wip.patch (9.15 KB, patch)
2024-07-25 17:54 UTC, Jakub Jelinek
Details | Diff
gcc15-pr115746-wip.patch (6.85 KB, patch)
2024-07-26 07:45 UTC, Jakub Jelinek
Details | Diff
gcc15-pr115746-wip.patch (8.90 KB, patch)
2024-08-01 16:54 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jakub Jelinek 2024-07-02 08:45:36 UTC
See <https://wg21.link/P2963R3>.
Comment 1 Jakub Jelinek 2024-07-25 17:54:14 UTC
Created attachment 58759 [details]
gcc15-pr115746-wip.patch

Untested WIP patch.
Comment 2 Jakub Jelinek 2024-07-25 18:16:02 UTC
I'm afraid I'd appreciate some guidance, mainly with how to implement the satisfaction checking of fold expanded constraints.
The way I've implemented it is that when testing its satisfaction, another argument with TREE_LIST of the packs and corresponding current index (which pack element is currently being tested for satisfaction) is passed, in sat_hasher::hash
and sat_hasher::equal this is looked up and in tsubst_parameter_mapping too and if it sees a pack, it replaces it with the pack element.
Now, this works fine for the easy testcases (concepts/variadic{2,4}.C, cpp26/fold-constr{1,2,4}.C), where in the atomic constraint mapping the template argument is used directly, but it doesn't work and causes ICE on the concepts/diagnostic3.C and cpp26/fold-constr3.C testcases; e.g. in diagnostic3.C, the fold expanded constraint notes it is a pack expansion of the Is pack, but in the mapping it uses S<Is> as the parameter.
I also think cpp26/fold-constr5.C fails because of that (though, in there there is a mismatch between my expectations where I expect
static_assert (bar <int> ());
to fail because
C<typename U::type> && ... && C<typename T::type>
should be normalized to
(C<typename U::type> && ...) && C<typename T::type>
where U is an empty pack, so (C<typename U::type> && ...) should be satisfied, but
C<typename T::type> shouldn't be because int::type is invalid, and for conjunction I think that should then be unsatisfied, but clang++ trunk doesn't diagnose that one).
In fold-constr6.C static_assert (U<int>::bar<int> ()); is rejected by clang++ trunk and I think in that case it shouldn't subsume but with my patch apparently it is accepted.
Comment 3 Jakub Jelinek 2024-07-25 18:21:49 UTC
BTW, with a modified version of fold-constr5.C which doesn't involve any fold expanded constraints:
struct A {
  using type = int;
};
struct B {
  using type = long;
};

template <class T> concept C = true;

template <class T, class U> requires (C<typename U::type> && C<typename T::type>)	// { dg-error "is not a class, struct, or union type" }
constexpr bool bar () { return true; };

static_assert (bar <A, B> ());
static_assert (bar <int, int> ());	// { dg-error "no matching function for call" }
static_assert (bar <B, long> ());	// { dg-error "no matching function for call" }
static_assert (bar <unsigned, A> ());	// { dg-error "no matching function for call" }

template <class T, class U> requires (C<typename T::type> && C<typename U::type>)	// { dg-error "is not a class, struct, or union type" }
constexpr bool baz () { return true; };

static_assert (baz <B, A> ());
static_assert (baz <int, long> ());	// { dg-error "no matching function for call" }
static_assert (baz <B, long> ());	// { dg-error "no matching function for call" }
static_assert (baz <unsigned, A> ());	// { dg-error "no matching function for call" }

template <class T, class U> requires (C<typename U::type> || C<typename T::type>)	// { dg-error "is not a class, struct, or union type" }
constexpr bool corge () { return true; };

static_assert (corge <B, A> ());
static_assert (corge <int, int> ());	// { dg-error "no matching function for call" }
static_assert (corge <B, long> ());
static_assert (corge <unsigned, A> ());

template <class T, class U> requires (C<typename T::type> || C<typename U::type>)	// { dg-error "is not a class, struct, or union type" }
constexpr bool garply () { return true; };

static_assert (garply <B, A> ());
static_assert (garply <int, int> ());	// { dg-error "no matching function for call" }
static_assert (garply <B, long> ());
static_assert (garply <unsigned, A> ());

g++ accepts all of this without any errors (tried 10.1, 11.1, 12.1, 13.1, 14.1 and trunk), while clang++ rejects it at the dg-error lines;
and my (sure, limited) understanding suggests that it should not be satisfied.
Comment 4 Jakub Jelinek 2024-07-26 07:45:02 UTC
Created attachment 58763 [details]
gcc15-pr115746-wip.patch

Updated patch which handles satisfy_atom by modifying (a copy of) args instead of the old way, plus removes the pack tree from in between FOLD_CONSTR and the actual constraint.
Sadly, this fixed only diagnostic3.C, but not the rest:
FAIL: g++.dg/cpp26/fold-constr3.C  -std=c++26 (internal compiler error: in dependent_type_p, at cp/pt.cc:28060)
FAIL: g++.dg/cpp26/fold-constr3.C  -std=c++26  (test for errors, line 10)
FAIL: g++.dg/cpp26/fold-constr3.C  -std=c++26  (test for errors, line 14)
FAIL: g++.dg/cpp26/fold-constr3.C  -std=c++26 (test for excess errors)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 13)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 19)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 20)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 21)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 23)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 28)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 29)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 30)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 32)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 37)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 38)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 39)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 41)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 47)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 51)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 56)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 60)
FAIL: g++.dg/cpp26/fold-constr5.C  -std=c++26  (test for errors, line 65)
FAIL: g++.dg/cpp26/fold-constr6.C  -std=c++26  (test for errors, line 20)
Comment 5 Jakub Jelinek 2024-07-26 11:03:36 UTC
(In reply to Jakub Jelinek from comment #3)
> BTW, with a modified version of fold-constr5.C which doesn't involve any
> fold expanded constraints:

I've filed PR116106 for that case as well as fold-constr5.C in the patch, which suffers from the same issue.
Comment 6 Jakub Jelinek 2024-08-01 16:54:20 UTC
Created attachment 58793 [details]
gcc15-pr115746-wip.patch

Attaching latest version of the patch.  I'm afraid I don't know enough about the parameter mapping/substitutions to finish this patch, so unassigning myself, hope somebody will find at least some parts of the patch useful.