+2020-02-26 Patrick Palka <ppalka@redhat.com>
+
+ * constraint.cc (finish_constraint_binary_op): Set expr's location range
+ to the range of its operands.
+ (satisfy_atom): Pass MAP instead of ARGS to diagnose_atomic_constraint.
+ (diagnose_trait_expr): Take the instantiated parameter mapping MAP
+ instead of the corresponding template arguments ARGS and adjust body
+ accordingly.
+ (diagnose_requires_expr): Likewise.
+ (diagnose_atomic_constraint): Likewise. When printing an atomic
+ constraint expression, print the instantiated parameter mapping
+ alongside it.
+ * cxx-pretty-print.cc (cxx_pretty_printer::expression)
+ [NONTYPE_ARGUMENT_PACK]: Print braces around a NONTYPE_ARGUMENT_PACK.
+ (cxx_pretty_printer::type_id): Handle TYPE_ARGUMENT_PACK.
+
2020-02-26 Marek Polacek <polacek@redhat.com>
PR c++/93676 - value-init crash in template.
if (!check_constraint_operands (loc, lhs, rhs))
return error_mark_node;
tree overload;
- tree expr = build_x_binary_op (loc, code,
- lhs, TREE_CODE (lhs),
- rhs, TREE_CODE (rhs),
- &overload, tf_none);
+ cp_expr expr = build_x_binary_op (loc, code,
+ lhs, TREE_CODE (lhs),
+ rhs, TREE_CODE (rhs),
+ &overload, tf_none);
/* When either operand is dependent, the overload set may be non-empty. */
if (expr == error_mark_node)
return error_mark_node;
- SET_EXPR_LOCATION (expr, loc);
+ expr.set_range (lhs.get_start (), rhs.get_finish ());
return expr;
}
/* Compute the value of the constraint. */
result = satisfaction_value (cxx_constant_value (result));
if (result == boolean_false_node && info.noisy ())
- diagnose_atomic_constraint (t, args, info);
+ diagnose_atomic_constraint (t, map, info);
return cache.save (result);
}
/* Emit a diagnostic for a failed trait. */
void
-diagnose_trait_expr (tree expr, tree args)
+diagnose_trait_expr (tree expr, tree map)
{
location_t loc = cp_expr_location (expr);
+ tree args = get_mapped_args (map);
/* Build a "fake" version of the instantiated trait, so we can
get the instantiated types from result. */
}
static void
-diagnose_requires_expr (tree expr, tree args, tree in_decl)
+diagnose_requires_expr (tree expr, tree map, tree in_decl)
{
local_specialization_stack stack (lss_copy);
tree parms = TREE_OPERAND (expr, 0);
tree body = TREE_OPERAND (expr, 1);
+ tree args = get_mapped_args (map);
cp_unevaluated u;
subst_info info (tf_warning_or_error, NULL_TREE);
}
}
-/* Diagnose a substitution failure in the atomic constraint T. Note that
- ARGS have been previously instantiated through the parameter map. */
+/* Diagnose a substitution failure in the atomic constraint T when applied
+ with the instantiated parameter mapping MAP. */
static void
-diagnose_atomic_constraint (tree t, tree args, subst_info info)
+diagnose_atomic_constraint (tree t, tree map, subst_info info)
{
/* If the constraint is already ill-formed, we've previously diagnosed
the reason. We should still say why the constraints aren't satisfied. */
switch (TREE_CODE (expr))
{
case TRAIT_EXPR:
- diagnose_trait_expr (expr, args);
+ diagnose_trait_expr (expr, map);
break;
case REQUIRES_EXPR:
- diagnose_requires_expr (expr, args, info.in_decl);
+ diagnose_requires_expr (expr, map, info.in_decl);
break;
case INTEGER_CST:
/* This must be either 0 or false. */
inform (loc, "%qE is never satisfied", expr);
break;
default:
- inform (loc, "the expression %qE evaluated to %<false%>", expr);
+ tree a = copy_node (t);
+ ATOMIC_CONSTR_MAP (a) = map;
+ inform (loc, "the expression %qE evaluated to %<false%>", a);
+ ggc_free (a);
}
}
{
tree args = ARGUMENT_PACK_ARGS (t);
int i, len = TREE_VEC_LENGTH (args);
+ pp_cxx_left_brace (this);
for (i = 0; i < len; ++i)
{
if (i > 0)
pp_cxx_separate_with (this, ',');
expression (TREE_VEC_ELT (args, i));
}
+ pp_cxx_right_brace (this);
}
break;
pp_cxx_ws_string (this, "...");
break;
+ case TYPE_ARGUMENT_PACK:
+ {
+ tree args = ARGUMENT_PACK_ARGS (t);
+ int len = TREE_VEC_LENGTH (args);
+ pp_cxx_left_brace (this);
+ for (int i = 0; i < len; ++i)
+ {
+ if (i > 0)
+ pp_cxx_separate_with (this, ',');
+ type_id (TREE_VEC_ELT (args, i));
+ }
+ pp_cxx_right_brace (this);
+ }
+ break;
+
default:
c_pretty_printer::type_id (t);
break;
--- /dev/null
+// { dg-do compile { target c++2a } }
+// { dg-options "-fdiagnostics-show-caret" }
+
+template<typename T>
+ inline constexpr bool foo_v = false;
+
+template<typename T>
+ concept foo = foo_v<T> || foo_v<T&>; // { dg-message "neither operand" }
+/* { dg-begin-multiline-output "" }
+ concept foo = foo_v<T> || foo_v<T&>;
+ ~~~~~~~~~^~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+
+template<typename T>
+ requires foo<T>
+ void bar();
+/* { dg-begin-multiline-output "" }
+ void bar();
+ { dg-end-multiline-output "" } */
+/* { dg-prune-output "~" } */
+
+void
+baz()
+{
+ bar<int>(); // { dg-error "unsatisfied constraints" }
+/* { dg-begin-multiline-output "" }
+ bar<int>();
+ ^
+ { dg-end-multiline-output "" } */
+}
--- /dev/null
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+ inline constexpr bool foo_v = false;
+
+template<typename T>
+ concept foo = (bool)(foo_v<T> | foo_v<T&>);
+
+template<typename... Ts>
+requires (foo<Ts> && ...)
+void
+bar() // { dg-message "with Ts = .int, char... evaluated to .false." }
+{ }
+
+template<int>
+struct S { };
+
+template<int... Is>
+requires (foo<S<Is>> && ...)
+void
+baz() // { dg-message "with Is = .2, 3, 4... evaluated to .false." }
+{ }
+
+void
+baz()
+{
+ bar<int, char>(); // { dg-error "unsatisfied constraints" }
+ baz<2,3,4>(); // { dg-error "unsatisfied constraints" }
+}