diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 764b9ccffa3..ca5676631ad 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2020-01-24 Jason Merrill + + PR c++/93400 - ICE with constrained friend. + * constraint.cc (maybe_substitute_reqs_for): New. + * decl.c (function_requirements_equivalent_p): Call it. + * pt.c (tsubst_friend_function): Only substitute + TEMPLATE_PARMS_CONSTRAINTS. + (tsubst_template_parms): Copy constraints. + 2020-01-24 Jason Merrill PR c++/93279 - ICE with lambda in member operator. diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 823604afb89..cda644eabe2 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -1189,6 +1189,29 @@ remove_constraints (tree t) decl_constraints->remove (t); } +/* If DECL is a friend, substitute into REQS to produce requirements suitable + for declaration matching. */ + +tree +maybe_substitute_reqs_for (tree reqs, const_tree decl_) +{ + if (reqs == NULL_TREE) + return NULL_TREE; + tree decl = CONST_CAST_TREE (decl_); + tree result = STRIP_TEMPLATE (decl); + if (DECL_FRIEND_P (result)) + { + tree tmpl = decl == result ? DECL_TI_TEMPLATE (result) : decl; + tree gargs = generic_targs_for (tmpl); + processing_template_decl_sentinel s; + if (uses_template_parms (gargs)) + ++processing_template_decl; + reqs = tsubst_constraint (reqs, gargs, + tf_warning_or_error, NULL_TREE); + } + return reqs; +} + /* Returns the template-head requires clause for the template declaration T or NULL_TREE if none. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 77bcf046608..b8035b4360d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7832,6 +7832,7 @@ extern void remove_constraints (tree); extern tree current_template_constraints (void); extern tree associate_classtype_constraints (tree); extern tree build_constraints (tree, tree); +extern tree maybe_substitute_reqs_for (tree, const_tree); extern tree get_template_head_requirements (tree); extern tree get_trailing_function_requirements (tree); extern tree get_shorthand_constraints (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 98ed79f3579..e55de5dd53d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -942,6 +942,8 @@ function_requirements_equivalent_p (tree newfn, tree oldfn) tree reqs2 = get_trailing_function_requirements (oldfn); if ((reqs1 != NULL_TREE) != (reqs2 != NULL_TREE)) return false; + reqs1 = maybe_substitute_reqs_for (reqs1, newfn); + reqs2 = maybe_substitute_reqs_for (reqs2, oldfn); return cp_tree_equal (reqs1, reqs2); } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 209044135cb..45c204e4269 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10834,29 +10834,12 @@ tsubst_friend_function (tree decl, tree args) DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (new_friend)) = DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (decl)); - /* Attach the template requirements to the new declaration - for declaration matching. We need to rebuild the requirements - so that parameter levels match. */ - if (tree ci = get_constraints (decl)) - { - tree parms = DECL_TEMPLATE_PARMS (new_friend); - tree args = generic_targs_for (new_friend); - tree treqs = tsubst_constraint (CI_TEMPLATE_REQS (ci), args, - tf_warning_or_error, NULL_TREE); - tree freqs = tsubst_constraint (CI_DECLARATOR_REQS (ci), args, - tf_warning_or_error, NULL_TREE); - - /* Update the constraints -- these won't really be valid for - checking, but that's not what we need them for. These ensure - that the declared function can find the friend during - declaration matching. */ - tree new_ci = get_constraints (new_friend); - CI_TEMPLATE_REQS (new_ci) = treqs; - CI_DECLARATOR_REQS (new_ci) = freqs; - - /* Also update the template parameter list. */ - TEMPLATE_PARMS_CONSTRAINTS (parms) = treqs; - } + /* Substitute TEMPLATE_PARMS_CONSTRAINTS so that parameter levels will + match in decls_match. */ + tree parms = DECL_TEMPLATE_PARMS (new_friend); + tree treqs = TEMPLATE_PARMS_CONSTRAINTS (parms); + treqs = maybe_substitute_reqs_for (treqs, new_friend); + TEMPLATE_PARMS_CONSTRAINTS (parms) = treqs; } /* The mangled name for the NEW_FRIEND is incorrect. The function @@ -13225,6 +13208,8 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain) tree_cons (size_int (TMPL_PARMS_DEPTH (parms) - TMPL_ARGS_DEPTH (args)), new_vec, NULL_TREE); + TEMPLATE_PARMS_CONSTRAINTS (*new_parms) + = TEMPLATE_PARMS_CONSTRAINTS (parms); } --processing_template_decl; diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-friend3.C index 4f49358ed7d..4278278b9df 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-friend3.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend3.C @@ -4,6 +4,7 @@ template concept True = true; template struct B { int i = ++U::x; }; template void f() { ++U::x; } +template void g() requires True { ++U::x; } template class C { @@ -11,10 +12,12 @@ template class C template friend struct B; template friend void f(); + template friend void g() requires True; }; int main() { f>(); + g>(); B>(); } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend5.C b/gcc/testsuite/g++.dg/cpp2a/concepts-friend5.C new file mode 100644 index 00000000000..394f141bf17 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend5.C @@ -0,0 +1,8 @@ +// PR c++/93400 +// { dg-do compile { target concepts } } + +template bool a = true; +template concept b = a; +template struct f { template friend auto g(c, f); }; +auto d = f<1>{}; +auto e = f<0>{}; diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84140.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84140.C index d901ab20cbf..83a9083cf17 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84140.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84140.C @@ -1,14 +1,13 @@ // { dg-do run { target c++2a } } -// { dg-additional-options "-fconcepts-ts" } template constexpr bool is_same_v = false; template constexpr bool is_same_v = true; template -concept bool Same = is_same_v; +concept Same = is_same_v; template -concept bool Diff = requires(T& t, U& u) { u - t; }; +concept Diff = requires(T& t, U& u) { u - t; }; template int distance(I, S) { return 0; }