aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/constraint.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/constraint.cc')
-rw-r--r--gcc/cp/constraint.cc270
1 files changed, 169 insertions, 101 deletions
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 8d7aec3..d4a83e4 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2490,10 +2490,11 @@ satisfy_atom (tree t, tree args, sat_info info)
result = force_rvalue (result, info.complain);
if (result == error_mark_node)
return cache.save (inst_cache.save (error_mark_node));
+ tree substituted = result;
if (!same_type_p (TREE_TYPE (result), boolean_type_node))
{
if (info.noisy ())
- diagnose_atomic_constraint (t, args, result, info);
+ diagnose_atomic_constraint (t, args, substituted, info);
return cache.save (inst_cache.save (error_mark_node));
}
@@ -2511,7 +2512,7 @@ satisfy_atom (tree t, tree args, sat_info info)
}
result = satisfaction_value (result);
if (result == boolean_false_node && info.diagnose_unsatisfaction_p ())
- diagnose_atomic_constraint (t, args, result, info);
+ diagnose_atomic_constraint (t, args, substituted, info);
return cache.save (inst_cache.save (result));
}
@@ -3063,11 +3064,9 @@ get_constraint_error_location (tree t)
/* Emit a diagnostic for a failed trait. */
-static void
-diagnose_trait_expr (tree expr, tree args)
+void
+diagnose_trait_expr (location_t loc, tree expr, tree args)
{
- location_t loc = cp_expr_location (expr);
-
/* Build a "fake" version of the instantiated trait, so we can
get the instantiated types from result. */
++processing_template_decl;
@@ -3076,218 +3075,246 @@ diagnose_trait_expr (tree expr, tree args)
tree t1 = TRAIT_EXPR_TYPE1 (expr);
tree t2 = TRAIT_EXPR_TYPE2 (expr);
- if (t2 && TREE_CODE (t2) == TREE_VEC)
- {
- /* Convert the TREE_VEC of arguments into a TREE_LIST, since we can't
- directly print a TREE_VEC but we can a TREE_LIST via the E format
- specifier. */
- tree list = NULL_TREE;
- for (tree t : tree_vec_range (t2))
- list = tree_cons (NULL_TREE, t, list);
- t2 = nreverse (list);
- }
+
+ /* For traits intrinsically about the properties of user-defined types,
+ decl_loc will point to the declaration of that type. */
+ location_t decl_loc = location_of (t1);
+ if (decl_loc == input_location)
+ decl_loc = loc;
+
switch (TRAIT_EXPR_KIND (expr))
{
case CPTK_HAS_NOTHROW_ASSIGN:
- inform (loc, " %qT is not nothrow copy assignable", t1);
+ inform (decl_loc, "%qT is not nothrow copy assignable", t1);
break;
case CPTK_HAS_NOTHROW_CONSTRUCTOR:
- inform (loc, " %qT is not nothrow default constructible", t1);
+ inform (decl_loc, "%qT is not nothrow default constructible", t1);
break;
case CPTK_HAS_NOTHROW_COPY:
- inform (loc, " %qT is not nothrow copy constructible", t1);
+ inform (decl_loc, "%qT is not nothrow copy constructible", t1);
break;
case CPTK_HAS_TRIVIAL_ASSIGN:
- inform (loc, " %qT is not trivially copy assignable", t1);
+ inform (decl_loc, "%qT is not trivially copy assignable", t1);
break;
case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
- inform (loc, " %qT is not trivially default constructible", t1);
+ inform (decl_loc, "%qT is not trivially default constructible", t1);
break;
case CPTK_HAS_TRIVIAL_COPY:
- inform (loc, " %qT is not trivially copy constructible", t1);
+ inform (decl_loc, "%qT is not trivially copy constructible", t1);
break;
case CPTK_HAS_TRIVIAL_DESTRUCTOR:
- inform (loc, " %qT is not trivially destructible", t1);
+ inform (decl_loc, "%qT is not trivially destructible", t1);
break;
case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
- inform (loc, " %qT does not have unique object representations", t1);
+ inform (decl_loc, "%qT does not have unique object representations", t1);
break;
case CPTK_HAS_VIRTUAL_DESTRUCTOR:
- inform (loc, " %qT does not have a virtual destructor", t1);
+ {
+ location_t dtor_loc = decl_loc;
+ if (NON_UNION_CLASS_TYPE_P (t1))
+ if (tree dtor = CLASSTYPE_DESTRUCTOR (t1))
+ dtor_loc = DECL_SOURCE_LOCATION (dtor);
+ inform (dtor_loc, "%qT does not have a virtual destructor", t1);
+ }
break;
case CPTK_IS_ABSTRACT:
- inform (loc, " %qT is not an abstract class", t1);
+ inform (decl_loc, "%qT is not an abstract class", t1);
break;
case CPTK_IS_AGGREGATE:
- inform (loc, " %qT is not an aggregate", t1);
+ inform (decl_loc, "%qT is not an aggregate", t1);
break;
case CPTK_IS_ARRAY:
- inform (loc, " %qT is not an array", t1);
+ inform (loc, "%qT is not an array", t1);
break;
case CPTK_IS_ASSIGNABLE:
- inform (loc, " %qT is not assignable from %qT", t1, t2);
+ inform (loc, "%qT is not assignable from %qT, because", t1, t2);
+ is_xible (MODIFY_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_BASE_OF:
- inform (loc, " %qT is not a base of %qT", t1, t2);
+ inform (decl_loc, "%qT is not a base of %qT", t1, t2);
break;
case CPTK_IS_BOUNDED_ARRAY:
- inform (loc, " %qT is not a bounded array", t1);
+ inform (loc, "%qT is not a bounded array", t1);
break;
case CPTK_IS_CLASS:
- inform (loc, " %qT is not a class", t1);
+ inform (decl_loc, "%qT is not a class", t1);
break;
case CPTK_IS_CONST:
- inform (loc, " %qT is not a const type", t1);
+ inform (loc, "%qT is not a const type", t1);
break;
case CPTK_IS_CONSTRUCTIBLE:
- if (!t2)
- inform (loc, " %qT is not default constructible", t1);
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not default constructible, because", t1);
else
- inform (loc, " %qT is not constructible from %qE", t1, t2);
+ inform (loc, "%qT is not constructible from %qT, because", t1, t2);
+ is_xible (INIT_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_CONVERTIBLE:
- inform (loc, " %qT is not convertible from %qE", t2, t1);
+ /* The errors produced here all seem to mention "convertible" in the
+ diagnostic, so an extra inform here appears redundant. */
+ is_convertible (t1, t2, /*explain=*/true);
break;
case CPTK_IS_DESTRUCTIBLE:
- inform (loc, " %qT is not destructible", t1);
+ inform (loc, "%qT is not destructible, because", t1);
+ is_xible (BIT_NOT_EXPR, t1, NULL_TREE, /*explain=*/true);
break;
case CPTK_IS_EMPTY:
- inform (loc, " %qT is not an empty class", t1);
+ inform (decl_loc, "%qT is not an empty class", t1);
break;
case CPTK_IS_ENUM:
- inform (loc, " %qT is not an enum", t1);
+ inform (decl_loc, "%qT is not an enum", t1);
break;
case CPTK_IS_FINAL:
- inform (loc, " %qT is not a final class", t1);
+ inform (decl_loc, "%qT is not a final class", t1);
break;
case CPTK_IS_FUNCTION:
- inform (loc, " %qT is not a function", t1);
+ inform (loc, "%qT is not a function", t1);
break;
case CPTK_IS_INVOCABLE:
- if (!t2)
- inform (loc, " %qT is not invocable", t1);
- else
- inform (loc, " %qT is not invocable by %qE", t1, t2);
+ {
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not invocable, because", t1);
+ else
+ inform (loc, "%qT is not invocable by %qT, because", t1, t2);
+ tree call = build_invoke (t1, t2, tf_error);
+ gcc_assert (call == error_mark_node);
+ }
break;
case CPTK_IS_LAYOUT_COMPATIBLE:
- inform (loc, " %qT is not layout compatible with %qT", t1, t2);
+ inform (loc, "%qT is not layout compatible with %qT", t1, t2);
break;
case CPTK_IS_LITERAL_TYPE:
- inform (loc, " %qT is not a literal type", t1);
+ inform (decl_loc, "%qT is not a literal type", t1);
break;
case CPTK_IS_MEMBER_FUNCTION_POINTER:
- inform (loc, " %qT is not a member function pointer", t1);
+ inform (loc, "%qT is not a member function pointer", t1);
break;
case CPTK_IS_MEMBER_OBJECT_POINTER:
- inform (loc, " %qT is not a member object pointer", t1);
+ inform (loc, "%qT is not a member object pointer", t1);
break;
case CPTK_IS_MEMBER_POINTER:
- inform (loc, " %qT is not a member pointer", t1);
+ inform (loc, "%qT is not a member pointer", t1);
break;
case CPTK_IS_NOTHROW_ASSIGNABLE:
- inform (loc, " %qT is not nothrow assignable from %qT", t1, t2);
+ inform (loc, "%qT is not nothrow assignable from %qT, because", t1, t2);
+ is_nothrow_xible (MODIFY_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
- if (!t2)
- inform (loc, " %qT is not nothrow default constructible", t1);
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not nothrow default constructible, because", t1);
else
- inform (loc, " %qT is not nothrow constructible from %qE", t1, t2);
+ inform (loc, "%qT is not nothrow constructible from %qT, because",
+ t1, t2);
+ is_nothrow_xible (INIT_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_NOTHROW_CONVERTIBLE:
- inform (loc, " %qT is not nothrow convertible from %qE", t2, t1);
+ inform (loc, "%qT is not nothrow convertible from %qT, because", t1, t2);
+ is_nothrow_convertible (t1, t2, /*explain=*/true);
break;
case CPTK_IS_NOTHROW_DESTRUCTIBLE:
- inform (loc, " %qT is not nothrow destructible", t1);
+ inform (loc, "%qT is not nothrow destructible, because", t1);
+ is_nothrow_xible (BIT_NOT_EXPR, t1, NULL_TREE, /*explain=*/true);
break;
case CPTK_IS_NOTHROW_INVOCABLE:
- if (!t2)
- inform (loc, " %qT is not nothrow invocable", t1);
- else
- inform (loc, " %qT is not nothrow invocable by %qE", t1, t2);
+ {
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not nothrow invocable, because", t1);
+ else
+ inform (loc, "%qT is not nothrow invocable by %qT, because", t1, t2);
+ tree call = build_invoke (t1, t2, tf_error);
+ if (call != error_mark_node)
+ explain_not_noexcept (call);
+ }
break;
case CPTK_IS_NOTHROW_RELOCATABLE:
- inform (loc, " %qT is not nothrow relocatable", t1);
+ inform (loc, "%qT is not nothrow relocatable", t1);
break;
case CPTK_IS_OBJECT:
- inform (loc, " %qT is not an object type", t1);
+ inform (loc, "%qT is not an object type", t1);
break;
case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
- inform (loc, " %qT is not pointer-interconvertible base of %qT",
+ inform (decl_loc, "%qT is not a pointer-interconvertible base of %qT",
t1, t2);
break;
case CPTK_IS_POD:
- inform (loc, " %qT is not a POD type", t1);
+ inform (loc, "%qT is not a POD type", t1);
break;
case CPTK_IS_POINTER:
- inform (loc, " %qT is not a pointer", t1);
+ inform (loc, "%qT is not a pointer", t1);
break;
case CPTK_IS_POLYMORPHIC:
- inform (loc, " %qT is not a polymorphic type", t1);
+ inform (decl_loc, "%qT is not a polymorphic type", t1);
break;
case CPTK_IS_REFERENCE:
- inform (loc, " %qT is not a reference", t1);
+ inform (loc, "%qT is not a reference", t1);
break;
case CPTK_IS_REPLACEABLE:
- inform (loc, " %qT is not replaceable", t1);
+ inform (loc, "%qT is not replaceable", t1);
break;
case CPTK_IS_SAME:
- inform (loc, " %qT is not the same as %qT", t1, t2);
+ inform (loc, "%q#T is not the same as %q#T", t1, t2);
break;
case CPTK_IS_SCOPED_ENUM:
- inform (loc, " %qT is not a scoped enum", t1);
+ inform (decl_loc, "%qT is not a scoped enum", t1);
break;
case CPTK_IS_STD_LAYOUT:
- inform (loc, " %qT is not an standard layout type", t1);
+ inform (decl_loc, "%qT is not a standard layout type", t1);
break;
case CPTK_IS_TRIVIAL:
- inform (loc, " %qT is not a trivial type", t1);
+ inform (decl_loc, "%qT is not a trivial type", t1);
break;
case CPTK_IS_TRIVIALLY_ASSIGNABLE:
- inform (loc, " %qT is not trivially assignable from %qT", t1, t2);
+ inform (loc, "%qT is not trivially assignable from %qT, because", t1, t2);
+ is_trivially_xible (MODIFY_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
- if (!t2)
- inform (loc, " %qT is not trivially default constructible", t1);
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not trivially default constructible, because", t1);
else
- inform (loc, " %qT is not trivially constructible from %qE", t1, t2);
+ inform (loc, "%qT is not trivially constructible from %qT, because",
+ t1, t2);
+ is_trivially_xible (INIT_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_TRIVIALLY_COPYABLE:
- inform (loc, " %qT is not trivially copyable", t1);
+ inform (decl_loc, "%qT is not trivially copyable", t1);
break;
case CPTK_IS_TRIVIALLY_DESTRUCTIBLE:
- inform (loc, " %qT is not trivially destructible", t1);
+ inform (loc, "%qT is not trivially destructible, because", t1);
+ is_trivially_xible (BIT_NOT_EXPR, t1, NULL_TREE, /*explain=*/true);
break;
case CPTK_IS_TRIVIALLY_RELOCATABLE:
- inform (loc, " %qT is not trivially relocatable", t1);
+ inform (loc, "%qT is not trivially relocatable", t1);
break;
case CPTK_IS_UNBOUNDED_ARRAY:
- inform (loc, " %qT is not an unbounded array", t1);
+ inform (loc, "%qT is not an unbounded array", t1);
break;
case CPTK_IS_UNION:
- inform (loc, " %qT is not a union", t1);
+ inform (decl_loc, "%qT is not a union", t1);
break;
case CPTK_IS_VIRTUAL_BASE_OF:
- inform (loc, " %qT is not a virtual base of %qT", t1, t2);
+ inform (decl_loc, "%qT is not a virtual base of %qT", t1, t2);
+ if (CLASS_TYPE_P (t2))
+ inform (location_of (t2), "%qT declared here", t2);
break;
case CPTK_IS_VOLATILE:
- inform (loc, " %qT is not a volatile type", t1);
+ inform (loc, "%qT is not a volatile type", t1);
break;
case CPTK_RANK:
- inform (loc, " %qT cannot yield a rank", t1);
+ inform (loc, "%qT cannot yield a rank", t1);
break;
case CPTK_TYPE_ORDER:
- inform (loc, " %qT and %qT cannot be ordered", t1, t2);
+ inform (loc, "%qT and %qT cannot be ordered", t1, t2);
break;
case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
- inform (loc, " %qT is not a reference that binds to a temporary "
+ inform (loc, "%qT is not a reference that binds to a temporary "
"object of type %qT (direct-initialization)", t1, t2);
break;
case CPTK_REF_CONVERTS_FROM_TEMPORARY:
- inform (loc, " %qT is not a reference that binds to a temporary "
+ inform (loc, "%qT is not a reference that binds to a temporary "
"object of type %qT (copy-initialization)", t1, t2);
break;
case CPTK_IS_DEDUCIBLE:
- inform (loc, " %qD is not deducible from %qT", t1, t2);
+ inform (loc, "%qD is not deducible from %qT", t1, t2);
break;
#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
case CPTK_##CODE:
@@ -3300,10 +3327,50 @@ diagnose_trait_expr (tree expr, tree args)
}
}
+/* Attempt to detect if this is a standard type trait, defined in terms
+ of a compiler builtin (above). If so, this will allow us to provide
+ more helpful diagnostics. */
+
+bool
+maybe_diagnose_standard_trait (location_t loc, tree expr)
+{
+ gcc_assert (TREE_CODE (expr) != TRAIT_EXPR);
+ expr = tree_strip_nop_conversions (expr);
+
+ /* TODO: in some cases it would be possible to provide more helpful
+ diagnostics for negations of traits, e.g. '!is_same_v<T1, T2>'. */
+
+ tree args = NULL_TREE;
+ if (VAR_P (expr) && DECL_LANG_SPECIFIC (expr) && DECL_USE_TEMPLATE (expr))
+ {
+ tree tinfo = DECL_TEMPLATE_INFO (expr);
+ if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo)) && TI_PARTIAL_INFO (tinfo))
+ tinfo = TI_PARTIAL_INFO (tinfo);
+ else if (DECL_TEMPLATE_SPECIALIZATION (expr))
+ /* In an explicit specialisation we no longer know what the original
+ initializer looked like. */
+ tinfo = NULL_TREE;
+
+ if (tinfo)
+ {
+ expr = DECL_INITIAL (DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo)));
+ args = TI_ARGS (tinfo);
+ }
+ }
+
+ if (TREE_CODE (expr) == TRAIT_EXPR)
+ {
+ diagnose_trait_expr (loc, expr, args);
+ return true;
+ }
+
+ return false;
+}
+
/* Diagnose a substitution failure in the atomic constraint T using ARGS. */
static void
-diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info)
+diagnose_atomic_constraint (tree t, tree args, tree substituted, sat_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. */
@@ -3324,25 +3391,26 @@ diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info)
/* Generate better diagnostics for certain kinds of expressions. */
tree expr = ATOMIC_CONSTR_EXPR (t);
STRIP_ANY_LOCATION_WRAPPER (expr);
- switch (TREE_CODE (expr))
+
+ if (TREE_CODE (expr) == REQUIRES_EXPR)
{
- case TRAIT_EXPR:
- diagnose_trait_expr (expr, args);
- break;
- case REQUIRES_EXPR:
gcc_checking_assert (info.diagnose_unsatisfaction_p ());
/* Clear in_decl before replaying the substitution to avoid emitting
seemingly unhelpful "in declaration ..." notes that follow some
substitution failure error messages. */
info.in_decl = NULL_TREE;
tsubst_requires_expr (expr, args, info);
- break;
- default:
- if (!same_type_p (TREE_TYPE (result), boolean_type_node))
- error_at (loc, "constraint %qE has type %qT, not %<bool%>",
- t, TREE_TYPE (result));
+ }
+ else if (!same_type_p (TREE_TYPE (substituted), boolean_type_node))
+ error_at (loc, "constraint %qE has type %qT, not %<bool%>",
+ t, TREE_TYPE (substituted));
+ else
+ {
+ inform (loc, "the expression %qE evaluated to %<false%>", t);
+ if (TREE_CODE (expr) == TRAIT_EXPR)
+ diagnose_trait_expr (loc, expr, args);
else
- inform (loc, "the expression %qE evaluated to %<false%>", t);
+ maybe_diagnose_standard_trait (loc, substituted);
}
}