diff options
Diffstat (limited to 'gcc/cp/constraint.cc')
| -rw-r--r-- | gcc/cp/constraint.cc | 341 |
1 files changed, 241 insertions, 100 deletions
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 2f1678c..6abd096 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -1836,7 +1836,7 @@ tsubst_parameter_mapping (tree map, tree args, tsubst_flags_t complain, tree in_ static bool satisfying_constraint; /* A vector of incomplete types (and of declarations with undeduced return type), - appended to by note_failed_type_completion_for_satisfaction. The + appended to by note_failed_type_completion. The satisfaction caches use this in order to keep track of "potentially unstable" satisfaction results. @@ -1845,19 +1845,67 @@ static bool satisfying_constraint; static GTY((deletable)) vec<tree, va_gc> *failed_type_completions; +/* A map of where types were found to be incomplete in SFINAE context, for + warning if they are later completed. */ + +static GTY((cache)) hash_map<tree, location_t, decl_location_traits> *failed_completions_map; + /* Called whenever a type completion (or return type deduction) failure occurs that definitely affects the meaning of the program, by e.g. inducing substitution failure. */ void -note_failed_type_completion_for_satisfaction (tree t) +note_failed_type_completion (tree t, tsubst_flags_t complain) { + if (dependent_template_arg_p (t)) + return; + + gcc_checking_assert ((TYPE_P (t) && !COMPLETE_TYPE_P (t)) + || (DECL_P (t) && undeduced_auto_decl (t))); + if (satisfying_constraint) + vec_safe_push (failed_type_completions, t); + + if (TYPE_P (t)) + { + if (!CLASS_TYPE_P (t)) + return; + t = TYPE_MAIN_DECL (t); + } + if (!(complain & tf_error) + && warning_enabled_at (DECL_SOURCE_LOCATION (t), + OPT_Wsfinae_incomplete_)) + { + if (warn_sfinae_incomplete > 1) + { + if (TREE_CODE (t) == TYPE_DECL) + warning (OPT_Wsfinae_incomplete_, + "failed to complete %qT in SFINAE context", TREE_TYPE (t)); + else + warning (OPT_Wsfinae_incomplete_, + "failed to deduce %qD in SFINAE context", t); + } + if (!failed_completions_map) + failed_completions_map + = hash_map<tree, location_t, decl_location_traits>::create_ggc (); + failed_completions_map->put (t, input_location); + } +} + +/* If T was previously found to be incomplete in SFINAE context, return the + location where that happened, otherwise UNKNOWN_LOCATION. */ + +location_t +failed_completion_location (tree t) +{ + if (failed_completions_map) { - gcc_checking_assert ((TYPE_P (t) && !COMPLETE_TYPE_P (t)) - || (DECL_P (t) && undeduced_auto_decl (t))); - vec_safe_push (failed_type_completions, t); + if (TYPE_P (t)) + t = TYPE_MAIN_DECL (t); + if (location_t *p = failed_completions_map->get (t)) + return *p; } + return UNKNOWN_LOCATION; } /* Returns true if the range [BEGIN, END) of elements within the @@ -2442,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)); } @@ -2463,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)); } @@ -2704,6 +2753,8 @@ satisfy_declaration_constraints (tree t, sat_info info) static tree satisfy_declaration_constraints (tree t, tree args, sat_info info) { + tree orig_args = args; + /* Update the declaration for diagnostics. */ info.in_decl = t; @@ -2732,7 +2783,7 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info) tree result = boolean_true_node; if (tree norm = get_normalized_constraints_from_decl (t, info.noisy ())) { - if (!push_tinst_level (t, args)) + if (!push_tinst_level (t, orig_args)) return result; tree pattern = DECL_TEMPLATE_RESULT (t); push_to_top_level (); @@ -3013,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; @@ -3026,197 +3075,248 @@ 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); - } + gcc_checking_assert (t1 != error_mark_node && t2 != error_mark_node); + + iloc_sentinel ils (loc); + + /* 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, because", t1); + type_has_unique_obj_representations (t1, /*explain=*/true); 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 (location_of (t2), "%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, 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_IMPLICIT_LIFETIME: + inform (decl_loc, "%qT is not an implicit-lifetime type", 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); + build_invoke (t1, t2, tf_error); + } 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, because", t1, t2); + layout_compatible_type_p (t1, t2, /*explain=*/true); 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, 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_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 (location_of (t2), + "%qT is not a pointer-interconvertible base of %qT, because", t1, t2); + pointer_interconvertible_base_of_p (t1, t2, /*explain=*/true); 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_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, because", t1); + is_trivially_xible (BIT_NOT_EXPR, t1, NULL_TREE, /*explain=*/true); 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 (location_of (t2), "%qT is not a virtual base of %qT", t1, 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); + break; + case CPTK_STRUCTURED_BINDING_SIZE: + inform (loc, "%qT is not destructurable", t1); 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: @@ -3229,10 +3329,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 (expr && 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. */ @@ -3253,25 +3393,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); } } |
