diff options
Diffstat (limited to 'gcc/cp/constraint.cc')
-rw-r--r-- | gcc/cp/constraint.cc | 270 |
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); } } |