Commit 56e0346d by Jason Merrill Committed by Jason Merrill

PR c++/92268 - hard error satisfying return-type-requirement

Previously we would put the template arguments for the concept-check in a
TEMPLATE_ID and then also pass them to constraints_satisfied_p, which meant
that we would try to normalize the concept-check with the fully instantiated
arguments, leading to sadness.  Simply not passing the args to
constraints_satisfied_p fixes the problem.

I also noticed that we weren't detecting substitution failure in the
constraints, but were silently treating it as success.

	* constraint.cc (type_deducible_p): Check for substitution failure.
	(diagnose_compound_requirement): Adjust diagnostic.
	* pt.c (do_auto_deduction): Don't pass cargs to
	constraints_satisfied_p.

From-SVN: r277654
parent d11368e6
2019-10-30 Jason Merrill <jason@redhat.com>
PR c++/92268 - hard error satisfying return-type-requirement
* constraint.cc (type_deducible_p): Check for substitution failure.
(diagnose_compound_requirement): Adjust diagnostic.
* pt.c (do_auto_deduction): Don't pass cargs to
constraints_satisfied_p.
2019-10-30 Jakub Jelinek <jakub@redhat.com> 2019-10-30 Jakub Jelinek <jakub@redhat.com>
PR c++/91369 - Implement P0784R7: constexpr new PR c++/91369 - Implement P0784R7: constexpr new
......
...@@ -1822,10 +1822,7 @@ tsubst_type_requirement (tree t, tree args, subst_info info) ...@@ -1822,10 +1822,7 @@ tsubst_type_requirement (tree t, tree args, subst_info info)
return finish_type_requirement (EXPR_LOCATION (t), type); return finish_type_requirement (EXPR_LOCATION (t), type);
} }
/* True if TYPE can be deduced from EXPR. /* True if TYPE can be deduced from EXPR. */
FIXME: C++20 compound requirement constraints should be normalized and then
satisfied rather than substituted. */
static bool static bool
type_deducible_p (tree expr, tree type, tree placeholder, tree args, type_deducible_p (tree expr, tree type, tree placeholder, tree args,
...@@ -1839,12 +1836,17 @@ type_deducible_p (tree expr, tree type, tree placeholder, tree args, ...@@ -1839,12 +1836,17 @@ type_deducible_p (tree expr, tree type, tree placeholder, tree args,
substitutes args into any template parameters in the trailing substitutes args into any template parameters in the trailing
result type. */ result type. */
tree saved_constr = PLACEHOLDER_TYPE_CONSTRAINTS (placeholder); tree saved_constr = PLACEHOLDER_TYPE_CONSTRAINTS (placeholder);
PLACEHOLDER_TYPE_CONSTRAINTS (placeholder) tree subst_constr
= tsubst_constraint (saved_constr, = tsubst_constraint (saved_constr,
args, args,
info.complain | tf_partial, info.complain | tf_partial,
info.in_decl); info.in_decl);
if (subst_constr == error_mark_node)
return false;
PLACEHOLDER_TYPE_CONSTRAINTS (placeholder) = subst_constr;
/* Temporarily unlink the canonical type. */ /* Temporarily unlink the canonical type. */
tree saved_type = TYPE_CANONICAL (placeholder); tree saved_type = TYPE_CANONICAL (placeholder);
TYPE_CANONICAL (placeholder) = NULL_TREE; TYPE_CANONICAL (placeholder) = NULL_TREE;
...@@ -3139,7 +3141,8 @@ diagnose_compound_requirement (tree req, tree args, tree in_decl) ...@@ -3139,7 +3141,8 @@ diagnose_compound_requirement (tree req, tree args, tree in_decl)
if (!type_deducible_p (expr, type, placeholder, args, quiet)) if (!type_deducible_p (expr, type, placeholder, args, quiet))
{ {
tree orig_expr = TREE_OPERAND (req, 0); tree orig_expr = TREE_OPERAND (req, 0);
inform (loc, "type deduction from %qE failed", orig_expr); inform (loc, "%qE does not satisfy return-type-requirement",
orig_expr);
/* Further explain the reason for the error. */ /* Further explain the reason for the error. */
type_deducible_p (expr, type, placeholder, args, noisy); type_deducible_p (expr, type, placeholder, args, noisy);
......
...@@ -28138,7 +28138,7 @@ do_auto_deduction (tree type, tree init, tree auto_node, ...@@ -28138,7 +28138,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
/* Rebuild the check using the deduced arguments. */ /* Rebuild the check using the deduced arguments. */
check = build_concept_check (cdecl, cargs, tf_none); check = build_concept_check (cdecl, cargs, tf_none);
if (!constraints_satisfied_p (check, cargs)) if (!constraints_satisfied_p (check))
{ {
if (complain & tf_warning_or_error) if (complain & tf_warning_or_error)
{ {
......
...@@ -8,12 +8,12 @@ concept bool SameAs = __is_same_as(T, U); ...@@ -8,12 +8,12 @@ concept bool SameAs = __is_same_as(T, U);
template <class T> template <class T>
concept bool R1 = requires (T& t) { // { dg-message "in requirements" } concept bool R1 = requires (T& t) { // { dg-message "in requirements" }
{ t.begin() } -> T; // { dg-error "no match" } { t.begin() } -> T; // { dg-error "no match" }
{ t.end() } -> SameAs<T*>; // { dg-error "does not satisfy" } { t.end() } -> SameAs<T*>; // { dg-message "does not satisfy" }
}; };
template <class T> template <class T>
concept bool R2 = requires (T& t) { // { dg-message "in requirements" } concept bool R2 = requires (T& t) { // { dg-message "in requirements" }
{ t.end() } -> SameAs<T*>; // { dg-error "does not satisfy" } { t.end() } -> SameAs<T*>; // { dg-message "does not satisfy" }
}; };
struct foo { struct foo {
......
...@@ -8,7 +8,7 @@ concept bool Same = __is_same_as(T, U); ...@@ -8,7 +8,7 @@ concept bool Same = __is_same_as(T, U);
template <class T> template <class T>
concept bool C = concept bool C =
requires { // { dg-message "in requirements" } requires { // { dg-message "in requirements" }
{ 0 } -> Same<T>; // { dg-error "does not satisfy" } { 0 } -> Same<T>; // { dg-message "does not satisfy" }
}; };
template <C c> template <C c>
......
...@@ -8,7 +8,7 @@ concept bool Same = __is_same_as(T, U); ...@@ -8,7 +8,7 @@ concept bool Same = __is_same_as(T, U);
template <class T> template <class T>
concept bool C = concept bool C =
requires { // { dg-message "in requirements" } requires { // { dg-message "in requirements" }
{ 0 } -> Same<T>; // { dg-error "does not satisfy" } { 0 } -> Same<T>; // { dg-message "does not satisfy" }
}; };
template <class T> template <class T>
......
...@@ -12,7 +12,7 @@ concept C0 = requires (auto x) { // { dg-error "placeholder type" } ...@@ -12,7 +12,7 @@ concept C0 = requires (auto x) { // { dg-error "placeholder type" }
template<typename T> template<typename T>
concept C1 = requires (C1 auto x) { // { dg-error "not been declared|placeholder|two or more|in requirements" } concept C1 = requires (C1 auto x) { // { dg-error "not been declared|placeholder|two or more|in requirements" }
x; // { dg-error "not declared" } x; // { dg-error "not declared" }
{ x } -> c; // { dg-error "not declared|does not satisfy" } { x } -> c; // { dg-message "not declared|does not satisfy" }
}; };
template<typename T> template<typename T>
......
...@@ -10,7 +10,7 @@ concept SameAs = __is_same_as(T, U); ...@@ -10,7 +10,7 @@ concept SameAs = __is_same_as(T, U);
template <typename T> template <typename T>
concept C1 = requires(T t) { // { dg-message "in requirements" } concept C1 = requires(T t) { // { dg-message "in requirements" }
{ t } -> SameAs<T>; // NOTE: t deduced as decltype((t)) { t } -> SameAs<T>; // NOTE: t deduced as decltype((t))
// { dg-error "does not satisfy placeholder constraints" "" { target *-*-* } .-1 } // { dg-message "does not satisfy" "" { target *-*-* } .-1 }
}; };
template <typename T> template <typename T>
......
// PR c++/92268
// { dg-do compile { target c++2a } }
template <class T> concept Two = true;
template <class T> concept One = Two<typename T::type>;
template <class T> concept Zero = requires
{
{ T() } -> One;
};
template <class T>
void f() requires Zero<T>;
template <class T>
int f(...);
int main()
{
f<int>();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment