diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 189 | ||||
-rw-r--r-- | gcc/cp/call.cc | 58 | ||||
-rw-r--r-- | gcc/cp/constexpr.cc | 29 | ||||
-rw-r--r-- | gcc/cp/constraint.cc | 270 | ||||
-rw-r--r-- | gcc/cp/coroutines.cc | 39 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 34 | ||||
-rw-r--r-- | gcc/cp/decl.cc | 46 | ||||
-rw-r--r-- | gcc/cp/error.cc | 112 | ||||
-rw-r--r-- | gcc/cp/except.cc | 12 | ||||
-rw-r--r-- | gcc/cp/init.cc | 6 | ||||
-rw-r--r-- | gcc/cp/lambda.cc | 4 | ||||
-rw-r--r-- | gcc/cp/method.cc | 243 | ||||
-rw-r--r-- | gcc/cp/module.cc | 82 | ||||
-rw-r--r-- | gcc/cp/name-lookup.cc | 2 | ||||
-rw-r--r-- | gcc/cp/parser.cc | 38 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 28 | ||||
-rw-r--r-- | gcc/cp/semantics.cc | 17 | ||||
-rw-r--r-- | gcc/cp/tree.cc | 86 | ||||
-rw-r--r-- | gcc/cp/typeck.cc | 29 | ||||
-rw-r--r-- | gcc/cp/typeck2.cc | 20 |
20 files changed, 959 insertions, 385 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a934377..08ec840 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,192 @@ +2025-07-27 Nathaniel Shead <nathanieloshead@gmail.com> + + * cp-tree.h (struct lang_type): Add comment mentioning modules. + * module.cc (trees_out::lang_type_bools): Stream new flags, use + gcc_checking_assert. + (trees_in::lang_type_bools): Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * constexpr.cc: Update usage of "diagnostic_info" to explicitly + refer to "diagnostics::diagnostic_info". + * cp-tree.h: Likewise. + * error.cc: Likewise. + * module.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * call.cc: Update for diagnostic_t becoming + enum class diagnostics::kind. + * constexpr.cc: Likewise. + * cp-tree.h: Likewise. + * decl.cc: Likewise. + * error.cc: Likewise. + * init.cc: Likewise. + * method.cc: Likewise. + * module.cc: Likewise. + * parser.cc: Likewise. + * pt.cc: Likewise. + * semantics.cc: Likewise. + * typeck.cc: Likewise. + * typeck2.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * cp-tree.h: Update for renaming of diagnostic_option_id to + diagnostics::option_id. + * decl.cc: Likewise. + * error.cc: Likewise. + * name-lookup.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * error.cc: Update for move of diagnostic-color.h to + diagnostics/color.h. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * cp-tree.h: Update for diagnostic_context becoming + diagnostics::context. + * error.cc: Likewise. + * module.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * constexpr.cc: Update to add "m_" prefix to fields of + diagnostic_info throughout. + * error.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * cp-tree.h: Update for move of diagnostics output formats into + namespace "diagnostics" as "sinks". + * error.cc: Likewise. + +2025-07-25 Patrick Palka <ppalka@redhat.com> + + * call.cc (build_new_op): If the selected candidate is + rewritten, communicate the LOOKUP_REWRITTEN/REVERSED flags to + the caller via the 'overload' out-parameter, and stop clearing + '*overload' in that case. + * tree.cc (build_min_non_dep_op_overload): Handle rebuilding all + C++20 rewritten comparison operator expressions. + +2025-07-25 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/121219 + * coroutines.cc + (cp_coroutine_transform::build_ramp_function): Reorder the return + expressions for the 'normal' and 'allocation failed' cases so that + NRV constraints are met. + +2025-07-24 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/117294 + PR c++/113854 + * call.cc (implicit_conversion_error): Hide label when printing + a stub object. + (convert_like_internal): Likewise, and nest candidate + diagnostics. + * constexpr.cc (diagnose_failing_condition): Nest diagnostics, + attempt to provide more helpful diagnostics for traits. + * constraint.cc (satisfy_atom): Pass result before constant + evaluation to diagnose_atomic_constraint. + (diagnose_trait_expr): Adjust diagnostics for clarity and + detail. + (maybe_diagnose_standard_trait): New function. + (diagnose_atomic_constraint): Attempt to provide more helpful + diagnostics for more traits. + * cp-tree.h (explain_not_noexcept): Declare new function. + (is_trivially_xible): Add parameter. + (is_nothrow_xible): Likewise. + (is_xible): Likewise. + (is_convertible): Likewise. + (is_nothrow_convertible): Likewise. + (diagnose_trait_expr): Declare new function. + (maybe_diagnose_standard_trait): Declare new function. + * error.cc (dump_type) <case TREE_VEC>: Handle trait types. + * except.cc (explain_not_noexcept): New function. + * method.cc (build_trait_object): Add complain parameter. + (build_invoke): Propagate complain parameter. + (assignable_expr): Add explain parameter to show diagnostics. + (constructible_expr): Likewise. + (destructible_expr): Likewise. + (is_xible_helper): Replace trivial flag with explain flag, + add diagnostics. + (is_trivially_xible): New explain flag. + (is_nothrow_xible): Likewise. + (is_xible): Likewise. + (is_convertible_helper): Add complain flag. + (is_convertible): New explain flag. + (is_nothrow_convertible): Likewise. + * typeck.cc (cp_build_function_call_vec): Add handling for stub + objects. + (convert_arguments): Always return -1 on error. + * typeck2.cc (cxx_readonly_error): Add handling for stub + objects. + +2025-07-24 Jason Merrill <jason@redhat.com> + + * pt.cc (tsubst_lambda_expr): Revert r9-5971 change. + +2025-07-24 Jason Merrill <jason@redhat.com> + + PR c++/114632 + PR c++/101233 + * lambda.cc (maybe_add_lambda_conv_op): Not for xobj lambda. + * pt.cc (tsubst_function_decl): Add cp_evaluated. + (alias_ctad_tweaks): Revert PR101233 fix. + +2025-07-24 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120412 + * module.cc (trees_out::core_vals): Write TU_LOCAL_ENTITY bits. + (trees_in::core_vals): Read it. + (trees_in::tree_node): Handle TU_LOCAL_ENTITY typedefs. + +2025-07-23 Patrick Palka <ppalka@redhat.com> + + PR c++/121179 + * call.cc (build_new_op): Don't clear *overload for a simple + != to == rewrite. + * tree.cc (build_min_non_dep_op_overload): Handle TRUTH_NOT_EXPR + appearing in a rewritten operator expression. + +2025-07-23 Patrick Palka <ppalka@redhat.com> + + PR c++/121055 + * method.cc (build_invoke): Correct reference_wrapper handling. + +2025-07-22 Jason Merrill <jason@redhat.com> + + PR c++/121068 + * constexpr.cc (cxx_eval_store_expression): Allow ARRAY_REFs + when activating an array member of a union. + +2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org> + + * semantics.cc (finish_asm_stmt): Pass null pointer to + parse_{input,output}_constraint(). + +2025-07-16 Kwok Cheung Yeung <kcyeung@baylibre.com> + + * pt.cc (tsubst_omp_clause_decl): Use OMP_ITERATOR_DECL_P. + * semantics.cc (handle_omp_array_sections): Likewise. + (finish_omp_clauses): Likewise. + +2025-07-16 Alfie Richards <alfie.richards@arm.com> + + * class.cc (add_method): Remove argument. + * cp-tree.h (maybe_version_functions): Ditto. + * decl.cc (decls_match): Ditto. + (maybe_version_functions): Ditto. + +2025-07-16 Jeremy Rifkin <jeremy@rifkin.dev> + + PR c/82134 + * call.cc (build_call_a): Add suppress_warning + * cp-gimplify.cc (cp_gimplify_expr): Add suppress_warning + 2025-07-15 Jason Merrill <jason@redhat.com> PR c++/44677 diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 37ad0a9..9283d97 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -220,7 +220,8 @@ static void add_candidates (tree, tree, const vec<tree, va_gc> *, tree, tree, bool, tree, tree, int, struct z_candidate **, tsubst_flags_t); static conversion *merge_conversion_sequences (conversion *, conversion *); -static tree build_temp (tree, tree, int, diagnostic_t *, tsubst_flags_t); +static tree build_temp (tree, tree, int, enum diagnostics::kind *, + tsubst_flags_t); static conversion *build_identity_conv (tree, tree); static inline bool conv_binds_to_array_of_unknown_bound (conversion *); static bool conv_is_prvalue (conversion *); @@ -4927,6 +4928,11 @@ implicit_conversion_error (location_t loc, tree type, tree expr) && !CP_AGGREGATE_TYPE_P (type)) error_at (loc, "designated initializers cannot be used with a " "non-aggregate type %qT", type); + else if (is_stub_object (expr)) + /* The expression is generated by a trait check, we don't have + a useful location to highlight the label. */ + error_at (loc, "could not convert %qH to %qI", + TREE_TYPE (expr), type); else { range_label_for_type_mismatch label (TREE_TYPE (expr), type); @@ -6455,7 +6461,9 @@ build_conditional_expr (const op_location_t &loc, types when the enumeration is still being defined. */; else if (complain & (cxx_dialect >= cxx26 ? tf_warning_or_error : tf_warning)) - emit_diagnostic (cxx_dialect >= cxx26 ? DK_PEDWARN : DK_WARNING, + emit_diagnostic ((cxx_dialect >= cxx26 + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning), loc, OPT_Wenum_compare, "enumerated mismatch " "in conditional expression: %qT vs %qT", arg2_type, arg3_type); @@ -7486,7 +7494,16 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags, else if (TREE_CODE (cand->fn) == FUNCTION_DECL) { if (overload) - *overload = cand->fn; + { + if (cand->rewritten ()) + /* build_min_non_dep_op_overload needs to know whether the + candidate is rewritten/reversed. */ + *overload = build_tree_list (build_int_cst (integer_type_node, + cand->flags), + cand->fn); + else + *overload = cand->fn; + } if (resolve_args (arglist, complain) == NULL) result = error_mark_node; @@ -7535,9 +7552,6 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags, /* If this was a C++20 rewritten comparison, adjust the result. */ if (cand->rewritten ()) { - /* FIXME build_min_non_dep_op_overload can't handle rewrites. */ - if (overload) - *overload = NULL_TREE; switch (code) { case EQ_EXPR: @@ -7636,8 +7650,9 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags, && (complain & tf_warning_or_error) == 0) result = error_mark_node; else if (cxx_dialect >= cxx26 || (complain & tf_warning)) - emit_diagnostic (cxx_dialect >= cxx26 - ? DK_PEDWARN : DK_WARNING, + emit_diagnostic ((cxx_dialect >= cxx26 + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning), loc, OPT_Wenum_compare, "comparison between %q#T and %q#T", arg1_type, arg2_type); @@ -8451,11 +8466,11 @@ complain_about_access (tree decl, tree diag_decl, tree diag_location, static tree build_temp (tree expr, tree type, int flags, - diagnostic_t *diagnostic_kind, tsubst_flags_t complain) + enum diagnostics::kind *diagnostic_kind, tsubst_flags_t complain) { int savew, savee; - *diagnostic_kind = DK_UNSPECIFIED; + *diagnostic_kind = diagnostics::kind::unspecified; /* If the source is a packed field, calling the copy constructor will require binding the field to the reference parameter to the copy constructor, and @@ -8479,9 +8494,9 @@ build_temp (tree expr, tree type, int flags, expr = build_special_member_call (NULL_TREE, complete_ctor_identifier, &args, type, flags, complain); if (warningcount + werrorcount > savew) - *diagnostic_kind = DK_WARNING; + *diagnostic_kind = diagnostics::kind::warning; else if (errorcount > savee) - *diagnostic_kind = DK_ERROR; + *diagnostic_kind = diagnostics::kind::error; return expr; } @@ -8693,9 +8708,10 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, bool nested_p, tsubst_flags_t complain) { tree totype = convs->type; - diagnostic_t diag_kind; + enum diagnostics::kind diag_kind; int flags; location_t loc = cp_expr_loc_or_input_loc (expr); + const bool stub_object_p = is_stub_object (expr); if (convs->bad_p && !(complain & tf_error)) return error_mark_node; @@ -8772,7 +8788,10 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, "from %qH to %qI", TREE_TYPE (expr), totype); if (complained) - print_z_candidate (loc, N_("candidate is:"), t->cand); + { + auto_diagnostic_nesting_level sentinel; + print_z_candidate (loc, N_("candidate is:"), t->cand); + } expr = convert_like (t, expr, fn, argnum, /*issue_conversion_warnings=*/false, /*c_cast_p=*/false, /*nested_p=*/true, @@ -8797,7 +8816,14 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, else if (t->kind == ck_identity) break; } - if (!complained && expr != error_mark_node) + if (!complained && stub_object_p) + { + /* An error diagnosed within a trait, don't give extra labels. */ + error_at (loc, "invalid conversion from %qH to %qI", + TREE_TYPE (expr), totype); + complained = 1; + } + else if (!complained && expr != error_mark_node) { range_label_for_type_mismatch label (TREE_TYPE (expr), totype); gcc_rich_location richloc (loc, &label, highlight_colors::percent_h); @@ -9220,7 +9246,7 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, if (convs->copy_init_p) flags |= LOOKUP_ONLYCONVERTING; expr = build_temp (expr, totype, flags, &diag_kind, complain); - if (diag_kind && complain) + if (diag_kind != diagnostics::kind::unspecified && complain) { auto_diagnostic_group d; maybe_print_user_conv_context (convs); diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index ee06858..f92beb1 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -153,7 +153,7 @@ static bool constexpr_error (location_t location, bool constexpr_fundef_p, const char *gmsgid, ...) { - diagnostic_info diagnostic; + diagnostics::diagnostic_info diagnostic; va_list ap; rich_location richloc (line_table, location); va_start (ap, gmsgid); @@ -161,14 +161,17 @@ constexpr_error (location_t location, bool constexpr_fundef_p, if (!constexpr_fundef_p) { /* Report an error that cannot be suppressed. */ - diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_ERROR); + diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, + diagnostics::kind::error); ret = diagnostic_report_diagnostic (global_dc, &diagnostic); } else if (warn_invalid_constexpr) { diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, - cxx_dialect < cxx23 ? DK_PEDWARN : DK_WARNING); - diagnostic.option_id = OPT_Winvalid_constexpr; + (cxx_dialect < cxx23 + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning)); + diagnostic.m_option_id = OPT_Winvalid_constexpr; ret = diagnostic_report_diagnostic (global_dc, &diagnostic); } else @@ -2883,10 +2886,15 @@ diagnose_failing_condition (tree bad, location_t cloc, bool show_expr_p, if (TREE_CODE (bad) == CLEANUP_POINT_EXPR) bad = TREE_OPERAND (bad, 0); + auto_diagnostic_nesting_level sentinel; + /* Actually explain the failure if this is a concept check or a requires-expression. */ if (concept_check_p (bad) || TREE_CODE (bad) == REQUIRES_EXPR) diagnose_constraints (cloc, bad, NULL_TREE); + /* Similarly if this is a standard trait. */ + else if (maybe_diagnose_standard_trait (cloc, bad)) + ; else if (COMPARISON_CLASS_P (bad) && ARITHMETIC_TYPE_P (TREE_TYPE (TREE_OPERAND (bad, 0)))) { @@ -7736,13 +7744,24 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (*valp), first, NULL_TREE); /* Check for implicit change of active member for a union. */ + + /* LWG3436, CWG2675, c++/121068: The array object model is confused. For + now allow initializing an array element to activate the array. */ + auto only_array_refs = [](const releasing_vec &refs) + { + for (unsigned i = 1; i < refs->length(); i += 3) + if (TREE_CODE ((*refs)[i]) != INTEGER_CST) + return false; + return true; + }; + if (code == UNION_TYPE && (CONSTRUCTOR_NELTS (*valp) == 0 || CONSTRUCTOR_ELT (*valp, 0)->index != index) /* An INIT_EXPR of the last member in an access chain is always OK, but still check implicit change of members earlier on; see cpp2a/constexpr-union6.C. */ - && !(TREE_CODE (t) == INIT_EXPR && refs->is_empty ())) + && !(TREE_CODE (t) == INIT_EXPR && only_array_refs (refs))) { bool has_active_member = CONSTRUCTOR_NELTS (*valp) != 0; tree inner = strip_array_types (reftype); 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); } } diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 52cc186..690e510 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -5050,6 +5050,8 @@ cp_coroutine_transform::build_ramp_function () check the returned pointer and call the func if it's null. Otherwise, no check, and we fail for noexcept/fno-exceptions cases. */ + tree grooaf_if_stmt = NULL_TREE; + tree alloc_ok_scope = NULL_TREE; if (grooaf) { /* [dcl.fct.def.coroutine] / 10 (part 3) @@ -5057,20 +5059,11 @@ cp_coroutine_transform::build_ramp_function () control to the caller of the coroutine and the return value is obtained by a call to T::get_return_object_on_allocation_failure(), where T is the promise type. */ - tree if_stmt = begin_if_stmt (); tree cond = build1 (CONVERT_EXPR, frame_ptr_type, nullptr_node); - cond = build2 (EQ_EXPR, boolean_type_node, coro_fp, cond); - finish_if_stmt_cond (cond, if_stmt); - r = NULL_TREE; - if (void_ramp_p) - /* Execute the get-return-object-on-alloc-fail call... */ - finish_expr_stmt (grooaf); - else - /* Get the fallback return object. */ - r = grooaf; - finish_return_stmt (r); - finish_then_clause (if_stmt); - finish_if_stmt (if_stmt); + cond = build2 (NE_EXPR, boolean_type_node, coro_fp, cond); + grooaf_if_stmt = begin_if_stmt (); + finish_if_stmt_cond (cond, grooaf_if_stmt); + alloc_ok_scope = begin_compound_stmt (BCS_NORMAL); } /* Dereference the frame pointer, to use in member access code. */ @@ -5295,7 +5288,6 @@ cp_coroutine_transform::build_ramp_function () a temp which is then used to intialize the return object, including NVRO. */ - /* Temporary var to hold the g_r_o across the function body. */ coro_gro = coro_build_and_push_artificial_var (loc, "_Coro_gro", gro_type, orig_fn_decl, NULL_TREE); @@ -5328,9 +5320,28 @@ cp_coroutine_transform::build_ramp_function () /* The ramp is done, we just need the return statement, which we build from the return object we constructed before we called the actor. */ + /* This is our 'normal' exit. */ r = void_ramp_p ? NULL_TREE : convert_from_reference (coro_gro); finish_return_stmt (r); + if (grooaf) + { + finish_compound_stmt (alloc_ok_scope); + finish_then_clause (grooaf_if_stmt); + + begin_else_clause (grooaf_if_stmt); + /* We come here if the frame allocation failed. */ + r = NULL_TREE; + if (void_ramp_p) + /* Execute the get-return-object-on-alloc-fail call... */ + finish_expr_stmt (grooaf); + else + /* Get the fallback return object. */ + r = grooaf; + finish_return_stmt (r); + finish_if_stmt (grooaf_if_stmt); + } + finish_compound_stmt (ramp_fnbody); return true; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6810250..0ac3ecb 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2508,7 +2508,9 @@ struct GTY(()) lang_type { /* When adding a flag here, consider whether or not it ought to apply to a template instance if it applies to the template. If - so, make sure to copy it in instantiate_class_template! */ + so, make sure to copy it in instantiate_class_template! + + Also make sure new flags here are streamed in module.cc. */ /* There are some bits left to fill out a 32-bit word. Keep track of this by updating the size of this bitfield whenever you add or @@ -7455,7 +7457,7 @@ extern void maybe_warn_variadic_templates (void); extern void maybe_warn_cpp0x (cpp0x_warn_str str, location_t = input_location); extern bool pedwarn_cxx98 (location_t, - diagnostic_option_id option_id, + diagnostics::option_id option_id, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); extern location_t location_of (tree); extern void qualified_name_lookup_error (tree, tree, tree, @@ -7481,6 +7483,7 @@ extern int nothrow_libfn_p (const_tree); extern void check_handlers (tree); extern tree finish_noexcept_expr (tree, tsubst_flags_t); extern bool expr_noexcept_p (tree, tsubst_flags_t); +extern void explain_not_noexcept (tree); extern void perform_deferred_noexcept_checks (void); extern bool nothrow_spec_p (const_tree); extern bool type_noexcept_p (const_tree); @@ -7602,11 +7605,14 @@ extern void finish_thunk (tree); extern void use_thunk (tree, bool); extern bool trivial_fn_p (tree); extern tree forward_parm (tree); -extern bool is_trivially_xible (enum tree_code, tree, tree); -extern bool is_nothrow_xible (enum tree_code, tree, tree); -extern bool is_xible (enum tree_code, tree, tree); -extern bool is_convertible (tree, tree); -extern bool is_nothrow_convertible (tree, tree); +extern bool is_trivially_xible (enum tree_code, tree, tree, + bool = false); +extern bool is_nothrow_xible (enum tree_code, tree, tree, + bool = false); +extern bool is_xible (enum tree_code, tree, tree, + bool = false); +extern bool is_convertible (tree, tree, bool = false); +extern bool is_nothrow_convertible (tree, tree, bool = false); extern bool ref_xes_from_temporary (tree, tree, bool); extern tree get_defaulted_eh_spec (tree, tsubst_flags_t = tf_warning_or_error); extern bool maybe_explain_implicit_delete (tree); @@ -8459,9 +8465,9 @@ extern void cxx_print_xnode (FILE *, tree, int); extern void cxx_print_decl (FILE *, tree, int); extern void cxx_print_type (FILE *, tree, int); extern void cxx_print_identifier (FILE *, tree, int); -extern void cxx_print_error_function (diagnostic_text_output_format &, +extern void cxx_print_error_function (diagnostics::text_sink &, const char *, - const diagnostic_info *); + const diagnostics::diagnostic_info *); /* in typeck.cc */ /* Says how we should behave when comparing two arrays one of which @@ -8648,7 +8654,7 @@ extern void maybe_warn_pessimizing_move (tree, tree, bool); /* in typeck2.cc */ extern void require_complete_eh_spec_types (tree, tree); extern bool cxx_incomplete_type_diagnostic (location_t, const_tree, - const_tree, diagnostic_t); + const_tree, enum diagnostics::kind); inline location_t loc_or_input_loc (location_t loc) { @@ -8696,7 +8702,7 @@ cp_expr_loc_or_input_loc (const_tree t) inline bool cxx_incomplete_type_diagnostic (const_tree value, const_tree type, - diagnostic_t diag_kind) + enum diagnostics::kind diag_kind) { return cxx_incomplete_type_diagnostic (cp_expr_loc_or_input_loc (value), value, type, diag_kind); @@ -8707,7 +8713,7 @@ extern void cxx_incomplete_type_error (location_t, const_tree, inline void cxx_incomplete_type_error (const_tree value, const_tree type) { - cxx_incomplete_type_diagnostic (value, type, DK_ERROR); + cxx_incomplete_type_diagnostic (value, type, diagnostics::kind::error); } extern void cxx_incomplete_type_inform (const_tree); @@ -8778,7 +8784,7 @@ extern alias_set_type cxx_get_alias_set (tree); extern bool cxx_warn_unused_global_decl (const_tree); extern size_t cp_tree_size (enum tree_code); extern bool cp_var_mod_type_p (tree, tree); -extern void cxx_initialize_diagnostics (diagnostic_context *); +extern void cxx_initialize_diagnostics (diagnostics::context *); extern int cxx_types_compatible_p (tree, tree); extern bool cxx_block_may_fallthru (const_tree); @@ -8923,6 +8929,8 @@ extern bool constraints_equivalent_p (tree, tree); extern bool atomic_constraints_identical_p (tree, tree); extern hashval_t iterative_hash_constraint (tree, hashval_t); extern hashval_t hash_atomic_constraint (tree); +extern void diagnose_trait_expr (location_t, tree, tree); +extern bool maybe_diagnose_standard_trait (location_t, tree); extern void diagnose_constraints (location_t, tree, tree); extern void note_failed_type_completion (tree, tsubst_flags_t); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 0ac92f8..cb3ebff 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -110,7 +110,7 @@ static void initialize_local_var (tree, tree, bool); static void expand_static_init (tree, tree); static location_t smallest_type_location (const cp_decl_specifier_seq*); static bool identify_goto (tree, location_t, const location_t *, - diagnostic_t, bool); + enum diagnostics::kind, bool); /* The following symbols are subsumed in the cp_global_trees array, and listed here individually for documentation purposes. @@ -3737,10 +3737,10 @@ decl_jump_unsafe (tree decl) static bool identify_goto (tree decl, location_t loc, const location_t *locus, - diagnostic_t diag_kind, bool computed) + enum diagnostics::kind diag_kind, bool computed) { if (computed) - diag_kind = DK_WARNING; + diag_kind = diagnostics::kind::warning; bool complained = emit_diagnostic (diag_kind, loc, 0, decl ? G_("jump to label %qD") @@ -3776,7 +3776,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names, if (exited_omp) { - complained = identify_goto (decl, input_location, locus, DK_ERROR, + complained = identify_goto (decl, input_location, locus, + diagnostics::kind::error, computed); if (complained) inform (input_location, " exits OpenMP structured block"); @@ -3798,7 +3799,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names, if (!identified) { - complained = identify_goto (decl, input_location, locus, DK_ERROR, + complained = identify_goto (decl, input_location, locus, + diagnostics::kind::error, computed); identified = 2; } @@ -3866,7 +3868,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names, if (inf) { if (identified < 2) - complained = identify_goto (decl, input_location, locus, DK_ERROR, + complained = identify_goto (decl, input_location, locus, + diagnostics::kind::error, computed); identified = 2; if (complained) @@ -3877,7 +3880,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names, if (!vec_safe_is_empty (computed)) { if (!identified) - complained = identify_goto (decl, input_location, locus, DK_ERROR, + complained = identify_goto (decl, input_location, locus, + diagnostics::kind::error, computed); identified = 2; if (complained) @@ -3949,14 +3953,14 @@ check_goto_1 (named_label_entry *ent, bool computed) || ent->in_omp_scope || ent->in_stmt_expr || !vec_safe_is_empty (ent->bad_decls)) { - diagnostic_t diag_kind = DK_PERMERROR; + enum diagnostics::kind diag_kind = diagnostics::kind::permerror; if (ent->in_try_scope || ent->in_catch_scope || ent->in_constexpr_if || ent->in_consteval_if || ent->in_transaction_scope || ent->in_omp_scope || ent->in_stmt_expr) - diag_kind = DK_ERROR; + diag_kind = diagnostics::kind::error; complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl), &input_location, diag_kind, computed); - identified = 1 + (diag_kind == DK_ERROR); + identified = 1 + (diag_kind == diagnostics::kind::error); } FOR_EACH_VEC_SAFE_ELT (ent->bad_decls, ix, bad) @@ -3969,7 +3973,9 @@ check_goto_1 (named_label_entry *ent, bool computed) if (identified == 1) { complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl), - &input_location, DK_ERROR, computed); + &input_location, + diagnostics::kind::error, + computed); identified = 2; } if (complained) @@ -4013,7 +4019,8 @@ check_goto_1 (named_label_entry *ent, bool computed) { complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl), - &input_location, DK_ERROR, + &input_location, + diagnostics::kind::error, computed); identified = 2; } @@ -4037,7 +4044,8 @@ check_goto_1 (named_label_entry *ent, bool computed) { complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl), - &input_location, DK_ERROR, computed); + &input_location, diagnostics::kind::error, + computed); identified = 2; } if (complained) @@ -4053,7 +4061,8 @@ check_goto_1 (named_label_entry *ent, bool computed) { complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl), - &input_location, DK_ERROR, computed); + &input_location, diagnostics::kind::error, + computed); identified = 2; } if (complained) @@ -11275,12 +11284,12 @@ grokfndecl (tree ctype, t && t != void_list_node; t = TREE_CHAIN (t)) if (TREE_PURPOSE (t)) { - diagnostic_t diag_kind = DK_PERMERROR; + enum diagnostics::kind diag_kind = diagnostics::kind::permerror; /* For templates, mark the default argument as erroneous and give a hard error. */ if (processing_template_decl) { - diag_kind = DK_ERROR; + diag_kind = diagnostics::kind::error; TREE_PURPOSE (t) = error_mark_node; } if (!has_errored) @@ -11288,7 +11297,7 @@ grokfndecl (tree ctype, has_errored = true; emit_diagnostic (diag_kind, DECL_SOURCE_LOCATION (decl), - /*diagnostic_option_id=*/0, + /*diagnostics::option_id=*/0, "friend declaration of %qD specifies default " "arguments and isn%'t a definition", decl); } @@ -17397,7 +17406,8 @@ xref_basetypes (tree ref, tree base_list) compatibility. */ if (processing_template_decl && CLASS_TYPE_P (basetype) && TYPE_BEING_DEFINED (basetype)) - cxx_incomplete_type_diagnostic (NULL_TREE, basetype, DK_PEDWARN); + cxx_incomplete_type_diagnostic (NULL_TREE, basetype, + diagnostics::kind::pedwarn); if (!dependent_type_p (basetype) && !complete_type_or_else (basetype, NULL)) /* An incomplete type. Remove it from the list. */ diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index eb2ff33..c427163 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see #include "cp-tree.h" #include "stringpool.h" #include "tree-diagnostic.h" -#include "diagnostic-color.h" +#include "diagnostics/color.h" #include "langhooks-def.h" #include "intl.h" #include "cxx-pretty-print.h" @@ -38,7 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "cp-name-hint.h" #include "attribs.h" #include "pretty-print-format-impl.h" -#include "diagnostic-format-text.h" +#include "diagnostics/text-sink.h" #define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',') #define pp_separate_with_semicolon(PP) pp_cxx_separate_with (PP, ';') @@ -96,17 +96,17 @@ static void dump_scope (cxx_pretty_printer *, tree, int); static void dump_template_parms (cxx_pretty_printer *, tree, int, int); static int get_non_default_template_args_count (tree, int); static const char *function_category (tree); -static void maybe_print_constexpr_context (diagnostic_text_output_format &); -static void maybe_print_instantiation_context (diagnostic_text_output_format &); -static void print_instantiation_full_context (diagnostic_text_output_format &); -static void print_instantiation_partial_context (diagnostic_text_output_format &, +static void maybe_print_constexpr_context (diagnostics::text_sink &); +static void maybe_print_instantiation_context (diagnostics::text_sink &); +static void print_instantiation_full_context (diagnostics::text_sink &); +static void print_instantiation_partial_context (diagnostics::text_sink &, struct tinst_level *, location_t); -static void maybe_print_constraint_context (diagnostic_text_output_format &); -static void cp_diagnostic_text_starter (diagnostic_text_output_format &, - const diagnostic_info *); -static void cp_print_error_function (diagnostic_text_output_format &, - const diagnostic_info *); +static void maybe_print_constraint_context (diagnostics::text_sink &); +static void cp_diagnostic_text_starter (diagnostics::text_sink &, + const diagnostics::diagnostic_info *); +static void cp_print_error_function (diagnostics::text_sink &, + const diagnostics::diagnostic_info *); static bool cp_printer (pretty_printer *, text_info *, const char *, int, bool, bool, bool, bool *, pp_token_list &); @@ -242,7 +242,7 @@ get_current_template () erroneous_templates_t *erroneous_templates; -/* Callback function diagnostic_context::m_adjust_diagnostic_info. +/* Callback function diagnostics::context::m_adjust_diagnostic_info. Errors issued when parsing a template are automatically treated like permerrors associated with the -Wtemplate-body flag and can be @@ -250,16 +250,16 @@ erroneous_templates_t *erroneous_templates; issue an error if we later need to instantiate the template. */ static void -cp_adjust_diagnostic_info (diagnostic_context *context, - diagnostic_info *diagnostic) +cp_adjust_diagnostic_info (diagnostics::context *context, + diagnostics::diagnostic_info *diagnostic) { - if (diagnostic->kind == DK_ERROR) + if (diagnostic->m_kind == diagnostics::kind::error) if (tree tmpl = get_current_template ()) { - diagnostic->option_id = OPT_Wtemplate_body; + diagnostic->m_option_id = OPT_Wtemplate_body; if (context->m_permissive) - diagnostic->kind = DK_WARNING; + diagnostic->m_kind = diagnostics::kind::warning; bool existed; location_t &error_loc @@ -269,7 +269,7 @@ cp_adjust_diagnostic_info (diagnostic_context *context, /* Remember that this template had a parse-time error so that we'll ensure a hard error has been issued upon its instantiation. */ - error_loc = diagnostic->richloc->get_loc (); + error_loc = diagnostic->m_richloc->get_loc (); } } @@ -298,14 +298,14 @@ cp_seen_error () capacities. */ void -cxx_initialize_diagnostics (diagnostic_context *context) +cxx_initialize_diagnostics (diagnostics::context *context) { cxx_pretty_printer *pp = new cxx_pretty_printer (); pp->set_format_postprocessor (std::make_unique<cxx_format_postprocessor> ()); context->set_pretty_printer (std::unique_ptr<pretty_printer> (pp)); c_common_diagnostics_set_defaults (context); - diagnostic_text_starter (context) = cp_diagnostic_text_starter; + diagnostics::text_starter (context) = cp_diagnostic_text_starter; /* diagnostic_finalizer is already c_diagnostic_text_finalizer. */ context->set_format_decoder (cp_printer); context->set_adjust_diagnostic_info_callback (cp_adjust_diagnostic_info); @@ -704,6 +704,20 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags) } break; + case TREE_VEC: + { + /* A list of types used for a trait. */ + bool need_comma = false; + for (tree arg : tree_vec_range (t)) + { + if (need_comma) + pp_separate_with_comma (pp); + dump_type (pp, arg, flags); + need_comma = true; + } + } + break; + case TREE_LIST: /* A list of function parms. */ dump_parameters (pp, t, flags); @@ -3747,9 +3761,9 @@ eh_spec_to_string (tree p, int /*v*/) /* Langhook for print_error_function. */ void -cxx_print_error_function (diagnostic_text_output_format &text_output, +cxx_print_error_function (diagnostics::text_sink &text_output, const char *file, - const diagnostic_info *diagnostic) + const diagnostics::diagnostic_info *diagnostic) { char *prefix; if (file) @@ -3763,8 +3777,8 @@ cxx_print_error_function (diagnostic_text_output_format &text_output, } static void -cp_diagnostic_text_starter (diagnostic_text_output_format &text_output, - const diagnostic_info *diagnostic) +cp_diagnostic_text_starter (diagnostics::text_sink &text_output, + const diagnostics::diagnostic_info *diagnostic) { pp_set_prefix (text_output.get_printer (), text_output.build_indent_prefix (true)); @@ -3780,8 +3794,8 @@ cp_diagnostic_text_starter (diagnostic_text_output_format &text_output, /* Print current function onto BUFFER, in the process of reporting a diagnostic message. Called from cp_diagnostic_starter. */ static void -cp_print_error_function (diagnostic_text_output_format &text_output, - const diagnostic_info *diagnostic) +cp_print_error_function (diagnostics::text_sink &text_output, + const diagnostics::diagnostic_info *diagnostic) { /* If we are in an instantiation context, current_function_decl is likely to be wrong, so just rely on print_instantiation_full_context. */ @@ -3790,7 +3804,7 @@ cp_print_error_function (diagnostic_text_output_format &text_output, /* The above is true for constraint satisfaction also. */ if (current_failed_constraint) return; - diagnostic_context *const context = &text_output.get_context (); + diagnostics::context *const context = &text_output.get_context (); if (diagnostic_last_function_changed (context, diagnostic)) { pretty_printer *const pp = text_output.get_printer (); @@ -3928,7 +3942,7 @@ function_category (tree fn) /* Report the full context of a current template instantiation, onto BUFFER. */ static void -print_instantiation_full_context (diagnostic_text_output_format &text_output) +print_instantiation_full_context (diagnostics::text_sink &text_output) { struct tinst_level *p = current_instantiation (); location_t location = input_location; @@ -3956,7 +3970,7 @@ print_instantiation_full_context (diagnostic_text_output_format &text_output) } static void -print_location (diagnostic_text_output_format &text_output, +print_location (diagnostics::text_sink &text_output, location_t loc) { expanded_location xloc = expand_location (loc); @@ -3970,7 +3984,7 @@ print_location (diagnostic_text_output_format &text_output, } /* A RAII class for use when emitting a line of contextual information - via pp_verbatim to a diagnostic_text_output_format to add before/after + via pp_verbatim to a diagnostics::text_sink to add before/after behaviors to the pp_verbatim calls. If the text output has show_nesting_p (), then the ctor prints @@ -3985,7 +3999,7 @@ print_location (diagnostic_text_output_format &text_output, class auto_context_line { public: - auto_context_line (diagnostic_text_output_format &text_output, + auto_context_line (diagnostics::text_sink &text_output, location_t loc, bool show_locus = false) : m_text_output (text_output), @@ -4016,7 +4030,7 @@ public: diagnostic_show_locus (&m_text_output.get_context (), m_text_output.get_source_printing_options (), &rich_loc, - DK_NOTE, pp); + diagnostics::kind::note, pp); pp_set_prefix (pp, saved_prefix); } } @@ -4028,12 +4042,12 @@ public: diagnostic_show_locus (&m_text_output.get_context (), m_text_output.get_source_printing_options (), &rich_loc, - DK_NOTE, pp); + diagnostics::kind::note, pp); pp_set_prefix (pp, saved_prefix); } } private: - diagnostic_text_output_format &m_text_output; + diagnostics::text_sink &m_text_output; location_t m_loc; bool m_show_locus; }; @@ -4042,7 +4056,7 @@ private: prints a single line of instantiation context. */ static void -print_instantiation_partial_context_line (diagnostic_text_output_format &text_output, +print_instantiation_partial_context_line (diagnostics::text_sink &text_output, struct tinst_level *t, location_t loc, bool recursive_p) { @@ -4080,7 +4094,7 @@ print_instantiation_partial_context_line (diagnostic_text_output_format &text_ou /* Same as print_instantiation_full_context but less verbose. */ static void -print_instantiation_partial_context (diagnostic_text_output_format &text_output, +print_instantiation_partial_context (diagnostics::text_sink &text_output, struct tinst_level *t0, location_t loc) { struct tinst_level *t; @@ -4151,7 +4165,7 @@ print_instantiation_partial_context (diagnostic_text_output_format &text_output, /* Called from cp_thing to print the template context for an error. */ static void -maybe_print_instantiation_context (diagnostic_text_output_format &text_output) +maybe_print_instantiation_context (diagnostics::text_sink &text_output) { if (!problematic_instantiation_changed () || current_instantiation () == 0) return; @@ -4163,7 +4177,7 @@ maybe_print_instantiation_context (diagnostic_text_output_format &text_output) /* Report what constexpr call(s) we're trying to expand, if any. */ void -maybe_print_constexpr_context (diagnostic_text_output_format &text_output) +maybe_print_constexpr_context (diagnostics::text_sink &text_output) { vec<tree> call_stack = cx_error_context (); unsigned ix; @@ -4183,7 +4197,7 @@ maybe_print_constexpr_context (diagnostic_text_output_format &text_output) static void -print_constrained_decl_info (diagnostic_text_output_format &text_output, +print_constrained_decl_info (diagnostics::text_sink &text_output, tree decl) { auto_context_line sentinel (text_output, DECL_SOURCE_LOCATION (decl)); @@ -4192,7 +4206,7 @@ print_constrained_decl_info (diagnostic_text_output_format &text_output, } static void -print_concept_check_info (diagnostic_text_output_format &text_output, +print_concept_check_info (diagnostics::text_sink &text_output, tree expr, tree map, tree args) { gcc_assert (concept_check_p (expr)); @@ -4217,7 +4231,7 @@ print_concept_check_info (diagnostic_text_output_format &text_output, context, if any. */ static tree -print_constraint_context_head (diagnostic_text_output_format &text_output, +print_constraint_context_head (diagnostics::text_sink &text_output, tree cxt, tree args) { tree src = TREE_VALUE (cxt); @@ -4241,7 +4255,7 @@ print_constraint_context_head (diagnostic_text_output_format &text_output, } static void -print_requires_expression_info (diagnostic_text_output_format &text_output, +print_requires_expression_info (diagnostics::text_sink &text_output, tree constr, tree args) { @@ -4271,7 +4285,7 @@ print_requires_expression_info (diagnostic_text_output_format &text_output, } void -maybe_print_single_constraint_context (diagnostic_text_output_format &text_output, +maybe_print_single_constraint_context (diagnostics::text_sink &text_output, tree failed) { if (!failed) @@ -4302,7 +4316,7 @@ maybe_print_single_constraint_context (diagnostic_text_output_format &text_outpu } void -maybe_print_constraint_context (diagnostic_text_output_format &text_output) +maybe_print_constraint_context (diagnostics::text_sink &text_output) { if (!current_failed_constraint) return; @@ -4915,18 +4929,20 @@ maybe_warn_variadic_templates (void) C++0x. */ bool pedwarn_cxx98 (location_t location, - diagnostic_option_id option_id, + diagnostics::option_id option_id, const char *gmsgid, ...) { - diagnostic_info diagnostic; + diagnostics::diagnostic_info diagnostic; va_list ap; bool ret; rich_location richloc (line_table, location); va_start (ap, gmsgid); diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, - (cxx_dialect == cxx98) ? DK_PEDWARN : DK_WARNING); - diagnostic.option_id = option_id; + (cxx_dialect == cxx98 + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning)); + diagnostic.m_option_id = option_id; ret = diagnostic_report_diagnostic (global_dc, &diagnostic); va_end (ap); return ret; diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc index a7f35e4..2c1ef4c 100644 --- a/gcc/cp/except.cc +++ b/gcc/cp/except.cc @@ -1218,6 +1218,18 @@ expr_noexcept_p (tree expr, tsubst_flags_t complain) return true; } +/* Explain why EXPR is not noexcept. */ + +void explain_not_noexcept (tree expr) +{ + tree fn = cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0); + gcc_assert (fn); + if (DECL_P (fn)) + inform (DECL_SOURCE_LOCATION (fn), "%qD is not %<noexcept%>", fn); + else + inform (location_of (fn), "%qT is not %<noexcept%>", TREE_TYPE (fn)); +} + /* Return true iff SPEC is throw() or noexcept(true). */ bool diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index 0a389fb..09fb4f3 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -4181,7 +4181,8 @@ build_vec_delete_1 (location_t loc, tree base, tree maxindex, tree type, "possible problem detected in invocation of " "operator %<delete []%>")) { - cxx_incomplete_type_diagnostic (base, type, DK_WARNING); + cxx_incomplete_type_diagnostic (base, type, + diagnostics::kind::warning); inform (loc, "neither the destructor nor the " "class-specific operator %<delete []%> will be called, " "even if they are declared when the class is defined"); @@ -5286,7 +5287,8 @@ build_delete (location_t loc, tree otype, tree addr, "possible problem detected in invocation of " "%<operator delete%>")) { - cxx_incomplete_type_diagnostic (addr, type, DK_WARNING); + cxx_incomplete_type_diagnostic (addr, type, + diagnostics::kind::warning); inform (loc, "neither the destructor nor the class-specific " "%<operator delete%> will be called, even if " diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index 525e8ef..ecf55eb 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -1143,7 +1143,9 @@ maybe_add_lambda_conv_op (tree type) tree lam = CLASSTYPE_LAMBDA_EXPR (type); if (LAMBDA_EXPR_CAPTURE_LIST (lam) != NULL_TREE - || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) != CPLD_NONE) + || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) != CPLD_NONE + /* CWG2561 ...and no explicit object parameter. */ + || DECL_XOBJ_MEMBER_FUNCTION_P (callop)) return; if (processing_template_decl) diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index a4089c5..62f8d80 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -1187,15 +1187,15 @@ early_check_defaulted_comparison (tree fn) if (!DECL_OVERLOADED_OPERATOR_IS (fn, SPACESHIP_EXPR) && !same_type_p (TREE_TYPE (TREE_TYPE (fn)), boolean_type_node)) { - diagnostic_t kind = DK_UNSPECIFIED; + enum diagnostics::kind kind = diagnostics::kind::unspecified; int opt = 0; if (is_auto (TREE_TYPE (fn))) - kind = DK_PEDWARN; + kind = diagnostics::kind::pedwarn; else - kind = DK_ERROR; + kind = diagnostics::kind::error; emit_diagnostic (kind, loc, opt, "defaulted %qD must return %<bool%>", fn); - if (kind == DK_ERROR) + if (kind == diagnostics::kind::error) ok = false; } @@ -1928,8 +1928,8 @@ is_stub_object (tree expr) /* Build a std::declval<TYPE>() expression and return it. */ -tree -build_trait_object (tree type) +static tree +build_trait_object (tree type, tsubst_flags_t complain) { /* TYPE can't be a function with cv-/ref-qualifiers: std::declval is defined as @@ -1942,7 +1942,11 @@ build_trait_object (tree type) if (FUNC_OR_METHOD_TYPE_P (type) && (type_memfn_quals (type) != TYPE_UNQUALIFIED || type_memfn_rqual (type) != REF_QUAL_NONE)) - return error_mark_node; + { + if (complain & tf_error) + error ("object cannot have qualified function type %qT", type); + return error_mark_node; + } return build_stub_object (type); } @@ -2036,22 +2040,26 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain) const_tree name = DECL_NAME (datum_decl); if (name && (id_equal (name, "reference_wrapper"))) { - /* 1.2 & 1.5: Retrieve T from std::reference_wrapper<T>, + /* 1.2 & 1.5: Retrieve T& from std::reference_wrapper<T>, i.e., decltype(datum.get()). */ datum_type = TREE_VEC_ELT (TYPE_TI_ARGS (non_ref_datum_type), 0); + datum_type = cp_build_reference_type (datum_type, false); datum_is_refwrap = true; } } } - tree datum_expr = build_trait_object (datum_type); + tree datum_expr = build_trait_object (datum_type, complain); if (!ptrmem_is_same_or_base_of_datum && !datum_is_refwrap) /* 1.3 & 1.6: Try to dereference datum_expr. */ datum_expr = build_x_indirect_ref (UNKNOWN_LOCATION, datum_expr, RO_UNARY_STAR, NULL_TREE, complain); - tree fn_expr = build_trait_object (fn_type); + if (error_operand_p (datum_expr)) + return error_mark_node; + + tree fn_expr = build_trait_object (fn_type, complain); ptrmem_expr = build_m_component_ref (datum_expr, fn_expr, complain); if (error_operand_p (ptrmem_expr)) @@ -2068,7 +2076,9 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain) for (int i = is_ptrmemfunc ? 1 : 0; i < TREE_VEC_LENGTH (arg_types); ++i) { tree arg_type = TREE_VEC_ELT (arg_types, i); - tree arg = build_trait_object (arg_type); + tree arg = build_trait_object (arg_type, complain); + if (error_operand_p (arg)) + return error_mark_node; vec_safe_push (args, arg); } @@ -2077,8 +2087,8 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain) invoke_expr = build_offset_ref_call_from_tree (ptrmem_expr, &args, complain); else /* 1.7. */ - invoke_expr = finish_call_expr (build_trait_object (fn_type), &args, false, - false, complain); + invoke_expr = finish_call_expr (build_trait_object (fn_type, complain), + &args, false, false, complain); return invoke_expr; } @@ -2227,12 +2237,20 @@ check_nontriv (tree *tp, int *, void *) /* Return declval<T>() = declval<U>() treated as an unevaluated operand. */ static tree -assignable_expr (tree to, tree from) +assignable_expr (tree to, tree from, bool explain) { cp_unevaluated cp_uneval_guard; - to = build_trait_object (to); - from = build_trait_object (from); - tree r = cp_build_modify_expr (input_location, to, NOP_EXPR, from, tf_none); + tsubst_flags_t complain = explain ? tf_error : tf_none; + + to = build_trait_object (to, complain); + if (to == error_mark_node) + return error_mark_node; + + from = build_trait_object (from, complain); + if (from == error_mark_node) + return error_mark_node; + + tree r = cp_build_modify_expr (input_location, to, NOP_EXPR, from, complain); return r; } @@ -2244,10 +2262,11 @@ assignable_expr (tree to, tree from) Return something equivalent in well-formedness and triviality. */ static tree -constructible_expr (tree to, tree from) +constructible_expr (tree to, tree from, bool explain) { tree expr; cp_unevaluated cp_uneval_guard; + tsubst_flags_t complain = explain ? tf_error : tf_none; const int len = TREE_VEC_LENGTH (from); if (CLASS_TYPE_P (to)) { @@ -2259,14 +2278,14 @@ constructible_expr (tree to, tree from) to = cp_build_reference_type (to, /*rval*/false); tree ob = build_stub_object (to); if (len == 0) - expr = build_value_init (ctype, tf_none); + expr = build_value_init (ctype, complain); else { vec_alloc (args, len); for (tree arg : tree_vec_range (from)) args->quick_push (build_stub_object (arg)); expr = build_special_member_call (ob, complete_ctor_identifier, &args, - ctype, LOOKUP_NORMAL, tf_none); + ctype, LOOKUP_NORMAL, complain); } if (expr == error_mark_node) return error_mark_node; @@ -2276,7 +2295,7 @@ constructible_expr (tree to, tree from) { tree dtor = build_special_member_call (ob, complete_dtor_identifier, NULL, ctype, LOOKUP_NORMAL, - tf_none); + complain); if (dtor == error_mark_node) return error_mark_node; if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (ctype)) @@ -2286,12 +2305,15 @@ constructible_expr (tree to, tree from) else { if (len == 0) - return build_value_init (strip_array_types (to), tf_none); + return build_value_init (strip_array_types (to), complain); if (len > 1) { if (cxx_dialect < cxx20) - /* Too many initializers. */ - return error_mark_node; + { + if (explain) + error ("too many initializers for non-class type %qT", to); + return error_mark_node; + } /* In C++20 this is well-formed: using T = int[2]; @@ -2312,9 +2334,11 @@ constructible_expr (tree to, tree from) } else from = build_stub_object (TREE_VEC_ELT (from, 0)); + + tree orig_from = from; expr = perform_direct_initialization_if_possible (to, from, /*cast*/false, - tf_none); + complain); /* If t(e) didn't work, maybe t{e} will. */ if (expr == NULL_TREE && len == 1 @@ -2326,7 +2350,24 @@ constructible_expr (tree to, tree from) CONSTRUCTOR_IS_PAREN_INIT (from) = true; expr = perform_direct_initialization_if_possible (to, from, /*cast*/false, - tf_none); + complain); + } + + if (expr == NULL_TREE && explain) + { + if (len > 1) + error ("too many initializers for non-class type %qT", to); + else + { + /* Redo the implicit conversion for diagnostics. */ + int count = errorcount + warningcount; + perform_implicit_conversion_flags (to, orig_from, complain, + LOOKUP_NORMAL); + if (count == errorcount + warningcount) + /* The message may have been suppressed due to -w + -fpermissive, + emit a generic response instead. */ + error ("the conversion is invalid"); + } } } return expr; @@ -2340,20 +2381,25 @@ constructible_expr (tree to, tree from) valid or error_mark_node if not. */ static tree -destructible_expr (tree to) +destructible_expr (tree to, bool explain) { cp_unevaluated cp_uneval_guard; + tsubst_flags_t complain = explain ? tf_error : tf_none; int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR; if (TYPE_REF_P (to)) return void_node; if (!COMPLETE_TYPE_P (complete_type (to))) - return error_mark_node; + { + if (explain) + error_at (location_of (to), "%qT is incomplete", to); + return error_mark_node; + } to = strip_array_types (to); if (CLASS_TYPE_P (to)) { - to = build_trait_object (to); + to = build_trait_object (to, complain); return build_delete (input_location, TREE_TYPE (to), to, - sfk_complete_destructor, flags, 0, tf_none); + sfk_complete_destructor, flags, 0, complain); } /* [expr.prim.id.dtor] If the id-expression names a pseudo-destructor, T shall be a scalar type.... */ @@ -2365,70 +2411,109 @@ destructible_expr (tree to) /* Returns a tree iff TO is assignable (if CODE is MODIFY_EXPR) or constructible (otherwise) from FROM, which is a single type for - assignment or a list of types for construction. */ + assignment or a list of types for construction. If EXPLAIN is + set, emit a diagnostic explaining why the operation failed. */ static tree -is_xible_helper (enum tree_code code, tree to, tree from, bool trivial) +is_xible_helper (enum tree_code code, tree to, tree from, bool explain) { to = complete_type (to); deferring_access_check_sentinel acs (dk_no_deferred); - if (VOID_TYPE_P (to) - || (from && FUNC_OR_METHOD_TYPE_P (from) - && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from)))) - return error_mark_node; + + if (VOID_TYPE_P (to)) + { + if (explain) + error_at (location_of (to), "%qT is incomplete", to); + return error_mark_node; + } + if (from + && FUNC_OR_METHOD_TYPE_P (from) + && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from))) + { + if (explain) + error ("%qT is a qualified function type", from); + return error_mark_node; + } + tree expr; if (code == MODIFY_EXPR) - expr = assignable_expr (to, from); + expr = assignable_expr (to, from, explain); else if (code == BIT_NOT_EXPR) - expr = destructible_expr (to); - else if (trivial && TREE_VEC_LENGTH (from) > 1 - && cxx_dialect < cxx20) - return error_mark_node; // only 0- and 1-argument ctors can be trivial - // before C++20 aggregate paren init + expr = destructible_expr (to, explain); else if (TREE_CODE (to) == ARRAY_TYPE && !TYPE_DOMAIN (to)) - return error_mark_node; // can't construct an array of unknown bound + { + if (explain) + error ("cannot construct an array of unknown bound"); + return error_mark_node; + } else - expr = constructible_expr (to, from); + expr = constructible_expr (to, from, explain); return expr; } /* Returns true iff TO is trivially assignable (if CODE is MODIFY_EXPR) or constructible (otherwise) from FROM, which is a single type for - assignment or a list of types for construction. */ + assignment or a list of types for construction. If EXPLAIN, diagnose + why we returned false. */ bool -is_trivially_xible (enum tree_code code, tree to, tree from) +is_trivially_xible (enum tree_code code, tree to, tree from, + bool explain/*=false*/) { - tree expr = is_xible_helper (code, to, from, /*trivial*/true); + /* In some cases, when producing errors is_xible_helper may not return + error_mark_node, so check if it looks like we've already emitted any + diagnostics to ensure we don't do so multiple times. */ + int errs = errorcount + sorrycount; + + tree expr = is_xible_helper (code, to, from, explain); if (expr == NULL_TREE || expr == error_mark_node) return false; + tree nt = cp_walk_tree_without_duplicates (&expr, check_nontriv, NULL); + if (explain && errs == (errorcount + sorrycount)) + { + gcc_assert (nt); + inform (location_of (nt), "%qE is non-trivial", nt); + } return !nt; } /* Returns true iff TO is nothrow assignable (if CODE is MODIFY_EXPR) or constructible (otherwise) from FROM, which is a single type for - assignment or a list of types for construction. */ + assignment or a list of types for construction. If EXPLAIN, diagnose + why we returned false. */ bool -is_nothrow_xible (enum tree_code code, tree to, tree from) +is_nothrow_xible (enum tree_code code, tree to, tree from, + bool explain/*=false*/) { + /* As with is_trivially_xible. */ + int errs = errorcount + sorrycount; + ++cp_noexcept_operand; - tree expr = is_xible_helper (code, to, from, /*trivial*/false); + tree expr = is_xible_helper (code, to, from, explain); --cp_noexcept_operand; if (expr == NULL_TREE || expr == error_mark_node) return false; - return expr_noexcept_p (expr, tf_none); + + bool is_noexcept = expr_noexcept_p (expr, tf_none); + if (explain && errs == (errorcount + sorrycount)) + { + gcc_assert (!is_noexcept); + explain_not_noexcept (expr); + } + return is_noexcept; } /* Returns true iff TO is assignable (if CODE is MODIFY_EXPR) or constructible (otherwise) from FROM, which is a single type for - assignment or a list of types for construction. */ + assignment or a list of types for construction. If EXPLAIN, diagnose + why we returned false. */ bool -is_xible (enum tree_code code, tree to, tree from) +is_xible (enum tree_code code, tree to, tree from, bool explain/*=false*/) { - tree expr = is_xible_helper (code, to, from, /*trivial*/false); + tree expr = is_xible_helper (code, to, from, explain); if (expr == error_mark_node) return false; return !!expr; @@ -2453,7 +2538,7 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p) return false; /* We don't check is_constructible<T, U>: if T isn't constructible from U, we won't be able to create a conversion. */ - tree val = build_trait_object (from); + tree val = build_trait_object (from, tf_none); if (val == error_mark_node) return false; if (!TYPE_REF_P (from) && TREE_CODE (from) != FUNCTION_TYPE) @@ -2462,25 +2547,36 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p) } /* Worker for is_{,nothrow_}convertible. Attempt to perform an implicit - conversion from FROM to TO and return the result. */ + conversion from FROM to TO and return the result. If EXPLAIN, emit a + diagnostic about why the conversion failed. */ static tree -is_convertible_helper (tree from, tree to) +is_convertible_helper (tree from, tree to, bool explain) { if (VOID_TYPE_P (from) && VOID_TYPE_P (to)) return integer_one_node; cp_unevaluated u; - tree expr = build_trait_object (from); + tsubst_flags_t complain = explain ? tf_error : tf_none; + /* std::is_{,nothrow_}convertible test whether the imaginary function definition To test() { return std::declval<From>(); } is well-formed. A function can't return a function. */ - if (FUNC_OR_METHOD_TYPE_P (to) || expr == error_mark_node) + if (FUNC_OR_METHOD_TYPE_P (to)) + { + if (explain) + error ("%qT is a function type", to); + return error_mark_node; + } + + tree expr = build_trait_object (from, complain); + if (expr == error_mark_node) return error_mark_node; + deferring_access_check_sentinel acs (dk_no_deferred); - return perform_implicit_conversion (to, expr, tf_none); + return perform_implicit_conversion (to, expr, complain); } /* Return true if FROM can be converted to TO using implicit conversions, @@ -2489,9 +2585,9 @@ is_convertible_helper (tree from, tree to) to either type" restriction. */ bool -is_convertible (tree from, tree to) +is_convertible (tree from, tree to, bool explain/*=false*/) { - tree expr = is_convertible_helper (from, to); + tree expr = is_convertible_helper (from, to, explain); if (expr == error_mark_node) return false; return !!expr; @@ -2500,12 +2596,18 @@ is_convertible (tree from, tree to) /* Like is_convertible, but the conversion is also noexcept. */ bool -is_nothrow_convertible (tree from, tree to) +is_nothrow_convertible (tree from, tree to, bool explain/*=false*/) { - tree expr = is_convertible_helper (from, to); + tree expr = is_convertible_helper (from, to, explain); if (expr == NULL_TREE || expr == error_mark_node) return false; - return expr_noexcept_p (expr, tf_none); + bool is_noexcept = expr_noexcept_p (expr, tf_none); + if (explain) + { + gcc_assert (!is_noexcept); + explain_not_noexcept (expr); + } + return is_noexcept; } /* Categorize various special_function_kinds. */ @@ -3586,21 +3688,24 @@ maybe_delete_defaulted_fn (tree fn, tree implicit_fn) the program is ill-formed" */ || !TYPE_REF_P (parmtype))); /* Decide if we want to emit a pedwarn, error, or a warning. */ - diagnostic_t diag_kind; + enum diagnostics::kind diag_kind; int opt; if (illformed_p) { - diag_kind = DK_ERROR; + diag_kind = diagnostics::kind::error; opt = 0; } else { - diag_kind = cxx_dialect >= cxx20 ? DK_WARNING : DK_PEDWARN; + diag_kind = (cxx_dialect >= cxx20 + ? diagnostics::kind::warning + : diagnostics::kind::pedwarn); opt = OPT_Wdefaulted_function_deleted; } /* Don't warn for template instantiations. */ - if (DECL_TEMPLATE_INSTANTIATION (fn) && diag_kind == DK_WARNING) + if (DECL_TEMPLATE_INSTANTIATION (fn) + && diag_kind == diagnostics::kind::warning) return; const char *wmsg; diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index e3c1a68..2f6a8ab 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -3883,9 +3883,9 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state { void write_macro_maps (elf_out *to, range_t &, unsigned *crc_ptr); bool read_macro_maps (line_map_uint_t); - void write_diagnostic_classification (elf_out *, diagnostic_context *, + void write_diagnostic_classification (elf_out *, diagnostics::context *, unsigned *); - bool read_diagnostic_classification (diagnostic_context *); + bool read_diagnostic_classification (diagnostics::context *); private: void write_define (bytes_out &, const cpp_macro *); @@ -4822,7 +4822,8 @@ noisy_p () return false; pp_needs_newline (global_dc->get_reference_printer ()) = true; - diagnostic_set_last_function (global_dc, (diagnostic_info *) NULL); + diagnostic_set_last_function (global_dc, + (diagnostics::diagnostic_info *) nullptr); return true; } @@ -6157,7 +6158,7 @@ trees_out::lang_type_bools (tree t, bits_out& bits) WB (lang->declared_class); WB (lang->diamond_shaped); WB (lang->repeated_base); - gcc_assert (!lang->being_defined); + gcc_checking_assert (!lang->being_defined); // lang->debug_requested WB (lang->fields_readonly); WB (lang->ptrmemfunc_flag); @@ -6183,6 +6184,14 @@ trees_out::lang_type_bools (tree t, bits_out& bits) WB (lang->has_constexpr_ctor); WB (lang->unique_obj_representations); WB (lang->unique_obj_representations_set); + gcc_checking_assert (!lang->erroneous); + WB (lang->non_pod_aggregate); + WB (lang->non_aggregate_pod); + WB (lang->trivially_relocatable); + WB (lang->trivially_relocatable_computed); + + WB (lang->replaceable); + WB (lang->replaceable_computed); #undef WB } @@ -6227,8 +6236,8 @@ trees_in::lang_type_bools (tree t, bits_in& bits) RB (lang->declared_class); RB (lang->diamond_shaped); RB (lang->repeated_base); - gcc_assert (!lang->being_defined); - gcc_assert (!lang->debug_requested); + gcc_checking_assert (!lang->being_defined); + gcc_checking_assert (!lang->debug_requested); RB (lang->fields_readonly); RB (lang->ptrmemfunc_flag); @@ -6253,6 +6262,14 @@ trees_in::lang_type_bools (tree t, bits_in& bits) RB (lang->has_constexpr_ctor); RB (lang->unique_obj_representations); RB (lang->unique_obj_representations_set); + gcc_checking_assert (!lang->erroneous); + RB (lang->non_pod_aggregate); + RB (lang->non_aggregate_pod); + RB (lang->trivially_relocatable); + RB (lang->trivially_relocatable_computed); + + RB (lang->replaceable); + RB (lang->replaceable_computed); #undef RB return !get_overrun (); } @@ -6785,6 +6802,13 @@ trees_out::core_vals (tree t) if (streaming_p ()) WU (((lang_tree_node *)t)->trait_expression.kind); break; + + case TU_LOCAL_ENTITY: + WT (((lang_tree_node *)t)->tu_local_entity.name); + if (state) + state->write_location + (*this, ((lang_tree_node *)t)->tu_local_entity.loc); + break; } if (CODE_CONTAINS_STRUCT (code, TS_TYPED)) @@ -7328,6 +7352,11 @@ trees_in::core_vals (tree t) RT (((lang_tree_node *)t)->trait_expression.type2); RUC (cp_trait_kind, ((lang_tree_node *)t)->trait_expression.kind); break; + + case TU_LOCAL_ENTITY: + RT (((lang_tree_node *)t)->tu_local_entity.name); + ((lang_tree_node *)t)->tu_local_entity.loc + = state->read_location (*this); } if (CODE_CONTAINS_STRUCT (code, TS_TYPED)) @@ -10268,7 +10297,8 @@ trees_in::tree_node (bool is_use) && dump ("Read %stypedef %C:%N", DECL_IMPLICIT_TYPEDEF_P (res) ? "implicit " : "", TREE_CODE (res), res); - res = TREE_TYPE (res); + if (TREE_CODE (res) != TU_LOCAL_ENTITY) + res = TREE_TYPE (res); } break; @@ -18325,22 +18355,23 @@ module_state::write_ordinary_maps (elf_out *to, range_t &info, /* Return the prefix to use for dumping a #pragma diagnostic change to DK. */ static const char * -dk_string (diagnostic_t dk) +dk_string (enum diagnostics::kind dk) { - gcc_assert (dk > DK_UNSPECIFIED && dk < DK_LAST_DIAGNOSTIC_KIND); - if (dk == DK_IGNORED) - /* diagnostic.def has an empty string for ignored. */ + gcc_assert (dk > diagnostics::kind::unspecified + && dk < diagnostics::kind::last_diagnostic_kind); + if (dk == diagnostics::kind::ignored) + /* diagnostics/kinds.def has an empty string for ignored. */ return "ignored: "; else - return get_diagnostic_kind_text (dk); + return diagnostics::get_text_for_kind (dk); } /* Dump one #pragma GCC diagnostic entry. */ static bool -dump_dc_change (unsigned index, unsigned opt, diagnostic_t dk) +dump_dc_change (unsigned index, unsigned opt, enum diagnostics::kind dk) { - if (dk == DK_POP) + if (dk == diagnostics::kind::pop) return dump (" Index %u: pop from %d", index, opt); else return dump (" Index %u: %s%s", index, dk_string (dk), @@ -18351,7 +18382,7 @@ dump_dc_change (unsigned index, unsigned opt, diagnostic_t dk) void module_state::write_diagnostic_classification (elf_out *to, - diagnostic_context *dc, + diagnostics::context *dc, unsigned *crc_p) { auto &changes = dc->get_classification_history (); @@ -18367,9 +18398,10 @@ module_state::write_diagnostic_classification (elf_out *to, unsigned len = changes.length (); /* We don't want to write out any entries that came from one of our imports. - But then we need to adjust the total, and change DK_POP targets to match - the index in our actual output. So remember how many lines we had skipped - at each step, where -1 means this line itself is skipped. */ + But then we need to adjust the total, and change diagnostics::kind::pop + targets to match the index in our actual output. So remember how many + lines we had skipped at each step, where -1 means this line itself + is skipped. */ int skips = 0; auto_vec<int> skips_at (len); skips_at.safe_grow (len); @@ -18402,10 +18434,10 @@ module_state::write_diagnostic_classification (elf_out *to, if (sec.streaming_p ()) { unsigned opt = c.option; - if (c.kind == DK_POP) + if (c.kind == diagnostics::kind::pop) opt -= skips_at[opt]; sec.u (opt); - sec.u (c.kind); + sec.u (static_cast<unsigned> (c.kind)); dump () && dump_dc_change (i - skips_at[i], opt, c.kind); } } @@ -18420,7 +18452,7 @@ module_state::write_diagnostic_classification (elf_out *to, /* Read any #pragma GCC diagnostic info from the .dgc section. */ bool -module_state::read_diagnostic_classification (diagnostic_context *dc) +module_state::read_diagnostic_classification (diagnostics::context *dc) { bytes_in sec; @@ -18440,8 +18472,8 @@ module_state::read_diagnostic_classification (diagnostic_context *dc) { location_t loc = read_location (sec); int opt = sec.u (); - diagnostic_t kind = (diagnostic_t) sec.u (); - if (kind == DK_POP) + enum diagnostics::kind kind = (enum diagnostics::kind) sec.u (); + if (kind == diagnostics::kind::pop) /* For a pop, opt is the 'changes' index to return to. */ opt += offset; changes.quick_push ({ loc, opt, kind }); @@ -18456,7 +18488,7 @@ module_state::read_diagnostic_classification (diagnostic_context *dc) gcc_checking_assert (i >= offset); const auto &c = changes[i]; - if (c.kind != DK_POP) + if (c.kind != diagnostics::kind::pop) break; else if (c.option == offset) { @@ -18473,7 +18505,7 @@ module_state::read_diagnostic_classification (diagnostic_context *dc) /* It didn't, so add a pop at its last location to avoid affecting later imports. */ location_t last_loc = ordinary_locs.first + ordinary_locs.second - 1; - changes.quick_push ({ last_loc, offset, DK_POP }); + changes.quick_push ({ last_loc, offset, diagnostics::kind::pop }); dump () && dump (" Adding final pop from index %d", offset); } diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 9aa7c16..f5b36c9 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -7195,7 +7195,7 @@ suggest_alternatives_for_1 (location_t location, tree name, /* Look for exact matches for builtin defines that would have been defined if the user had passed a command-line option (e.g. -fopenmp for "_OPENMP"). */ - diagnostic_option_id option_id + diagnostics::option_id option_id = get_option_for_builtin_define (IDENTIFIER_POINTER (name)); if (option_id.m_idx > 0) return name_hint diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 0d9ed2e..9e9cd9b 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -5266,7 +5266,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) && (id_equal (suffix_id, "i") || id_equal (suffix_id, "if") || id_equal (suffix_id, "il"))); - diagnostic_t kind = DK_ERROR; + enum diagnostics::kind kind = diagnostics::kind::error; int opt = 0; if (i14 && ext) @@ -5276,7 +5276,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) if (cxlit == error_mark_node) { /* No <complex>, so pedwarn and use GNU semantics. */ - kind = DK_PEDWARN; + kind = diagnostics::kind::pedwarn; opt = OPT_Wpedantic; } } @@ -5303,7 +5303,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) "to enable more built-in suffixes"); } - if (kind == DK_ERROR) + if (kind == diagnostics::kind::error) value = error_mark_node; else { @@ -6647,7 +6647,8 @@ cp_parser_primary_expression (cp_parser *parser, member template. */ static void -missing_template_diag (location_t loc, diagnostic_t diag_kind = DK_WARNING) +missing_template_diag (location_t loc, + enum diagnostics::kind diag_kind = diagnostics::kind::warning) { if (warning_suppressed_at (loc, OPT_Wmissing_template_keyword)) return; @@ -8854,8 +8855,10 @@ cp_parser_dot_deref_incomplete (tree *scope, cp_expr *postfix_expression, { /* In a template, be permissive by treating an object expression of incomplete type as dependent (after a pedwarn). */ - diagnostic_t kind = (processing_template_decl - && MAYBE_CLASS_TYPE_P (*scope) ? DK_PEDWARN : DK_ERROR); + enum diagnostics::kind kind = ((processing_template_decl + && MAYBE_CLASS_TYPE_P (*scope)) + ? diagnostics::kind::pedwarn + : diagnostics::kind::error); switch (TREE_CODE (*postfix_expression)) { @@ -8867,27 +8870,27 @@ cp_parser_dot_deref_incomplete (tree *scope, cp_expr *postfix_expression, case IMPLICIT_CONV_EXPR: case VIEW_CONVERT_EXPR: case NON_LVALUE_EXPR: - kind = DK_ERROR; + kind = diagnostics::kind::error; break; case OVERLOAD: /* Don't emit any diagnostic for OVERLOADs. */ - kind = DK_IGNORED; + kind = diagnostics::kind::ignored; break; default: /* Avoid clobbering e.g. DECLs. */ if (!EXPR_P (*postfix_expression)) - kind = DK_ERROR; + kind = diagnostics::kind::error; break; } - if (kind == DK_IGNORED) + if (kind == diagnostics::kind::ignored) return false; location_t exploc = location_of (*postfix_expression); cxx_incomplete_type_diagnostic (exploc, *postfix_expression, *scope, kind); if (!MAYBE_CLASS_TYPE_P (*scope)) return true; - if (kind == DK_ERROR) + if (kind == diagnostics::kind::error) *scope = *postfix_expression = error_mark_node; else if (processing_template_decl) { @@ -9510,7 +9513,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, diagnostic_push_diagnostics (global_dc, input_location); diagnostic_classify_diagnostic (global_dc, OPT_Wconditionally_supported, - DK_IGNORED, input_location); + diagnostics::kind::ignored, input_location); /* Parse the cast-expression. */ expr = cp_parser_simple_cast_expression (parser); /* Restore the PEDANTIC flag. */ @@ -33706,7 +33709,9 @@ cp_parser_constructor_declarator_p (cp_parser *parser, cp_parser_flags flags, && cp_lexer_peek_token (parser->lexer)->type == CPP_TEMPLATE_ID) { auto_diagnostic_group d; - if (emit_diagnostic (cxx_dialect >= cxx20 ? DK_PEDWARN : DK_WARNING, + if (emit_diagnostic ((cxx_dialect >= cxx20 + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning), input_location, OPT_Wtemplate_id_cdtor, "template-id not allowed for constructor in C++20")) inform (input_location, "remove the %qs", "< >"); @@ -53048,11 +53053,14 @@ cp_parser_omp_error (cp_parser *parser, cp_token *pragma_tok, if (msg == NULL) msg = _("<message unknown at compile time>"); } + const enum diagnostics::kind diag_kind = (severity_fatal + ? diagnostics::kind::error + : diagnostics::kind::warning); if (msg) - emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + emit_diagnostic (diag_kind, loc, 0, "%<pragma omp error%> encountered: %s", msg); else - emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + emit_diagnostic (diag_kind, loc, 0, "%<pragma omp error%> encountered"); return false; } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index ca8d61d..71ae764 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -14916,6 +14916,9 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, argvec = NULL_TREE; } + /* Make sure tsubst_decl substitutes all the parameters. */ + cp_evaluated ev; + tree closure = (lambda_fntype ? TYPE_METHOD_BASETYPE (lambda_fntype) : NULL_TREE); tree ctx = closure ? closure : DECL_CONTEXT (t); @@ -17986,9 +17989,7 @@ tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain, return decl; /* Handle OpenMP iterators. */ - if (TREE_CODE (decl) == TREE_LIST - && TREE_PURPOSE (decl) - && TREE_CODE (TREE_PURPOSE (decl)) == TREE_VEC) + if (OMP_ITERATOR_DECL_P (decl)) { tree ret; if (iterator_cache[0] == TREE_PURPOSE (decl)) @@ -20496,11 +20497,6 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) r = error_mark_node; else { - /* The body of a lambda-expression is not a subexpression of the - enclosing expression. Parms are to have DECL_CHAIN tsubsted, - which would be skipped if cp_unevaluated_operand. */ - cp_evaluated ev; - /* Fix the type of 'this'. For static and xobj member functions we use this to transport the lambda's closure type. It appears that in the regular case the @@ -20526,6 +20522,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) /* Let finish_function set this. */ DECL_DECLARED_CONSTEXPR_P (fn) = false; + /* The body of a lambda-expression is not a subexpression of the + enclosing expression. */ + cp_evaluated ev; + bool nested = cfun; if (nested) push_function_context (); @@ -31216,14 +31216,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides) /* Substitute the deduced arguments plus the rewritten template parameters into f to get g. This covers the type, copyness, guideness, and explicit-specifier. */ - tree g; - { - /* Parms are to have DECL_CHAIN tsubsted, which would be skipped - if cp_unevaluated_operand. */ - cp_evaluated ev; - g = tsubst_decl (DECL_TEMPLATE_RESULT (f), targs, complain, + tree g = tsubst_decl (DECL_TEMPLATE_RESULT (f), targs, complain, /*use_spec_table=*/false); - } if (g == error_mark_node) continue; DECL_NAME (g) = name; @@ -31653,7 +31647,9 @@ do_class_deduction (tree ptype, tree tmpl, tree init, tree outer_targs, /* Be permissive with equivalent alias templates. */ tree u = get_underlying_template (tmpl); auto_diagnostic_group d; - diagnostic_t dk = (u == tmpl) ? DK_ERROR : DK_PEDWARN; + const enum diagnostics::kind dk = ((u == tmpl) + ? diagnostics::kind::error + : diagnostics::kind::pedwarn); bool complained = emit_diagnostic (dk, input_location, 0, "alias template deduction only available " diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 640e1ea..52ecac4 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -2338,7 +2338,8 @@ finish_asm_stmt (location_t loc, int volatile_p, tree string, oconstraints[i] = constraint; if (parse_output_constraint (&constraint, i, ninputs, noutputs, - &allows_mem, &allows_reg, &is_inout)) + &allows_mem, &allows_reg, &is_inout, + nullptr)) { /* If the operand is going to end up in memory, mark it addressable. */ @@ -2397,7 +2398,8 @@ finish_asm_stmt (location_t loc, int volatile_p, tree string, constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))); bool constraint_parsed = parse_input_constraint (&constraint, i, ninputs, noutputs, 0, - oconstraints, &allows_mem, &allows_reg); + oconstraints, &allows_mem, &allows_reg, + nullptr); /* If the operand is going to end up in memory, don't call decay_conversion. */ if (constraint_parsed && !allows_reg && allows_mem) @@ -6302,9 +6304,7 @@ handle_omp_array_sections (tree &c, enum c_omp_region_type ort) tree *tp = &OMP_CLAUSE_DECL (c); if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY) - && TREE_CODE (*tp) == TREE_LIST - && TREE_PURPOSE (*tp) - && TREE_CODE (TREE_PURPOSE (*tp)) == TREE_VEC) + && OMP_ITERATOR_DECL_P (*tp)) tp = &TREE_VALUE (*tp); tree first = handle_omp_array_sections_1 (c, *tp, types, maybe_zero_len, first_non_one, @@ -8824,9 +8824,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) /* FALLTHRU */ case OMP_CLAUSE_AFFINITY: t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == TREE_LIST - && TREE_PURPOSE (t) - && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) + if (OMP_ITERATOR_DECL_P (t)) { if (TREE_PURPOSE (t) != last_iterators) last_iterators_remove @@ -13693,7 +13691,8 @@ check_trait_type (tree type, int kind = 1) type = complete_type (strip_array_types (type)); if (!COMPLETE_TYPE_P (type) - && cxx_incomplete_type_diagnostic (NULL_TREE, type, DK_PERMERROR) + && cxx_incomplete_type_diagnostic (NULL_TREE, type, + diagnostics::kind::permerror) && !flag_permissive) return false; return true; diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index a7b8908..d56d73f 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -3696,6 +3696,58 @@ build_min_non_dep_op_overload (enum tree_code op, int nargs, expected_nargs; tree fn, call, obj = NULL_TREE; + releasing_vec args; + va_start (p, overload); + + bool negated = false, rewritten = false, reversed = false; + if (cxx_dialect >= cxx20 && TREE_CODE (overload) == TREE_LIST) + { + /* Handle rebuilding a C++20 rewritten comparison operator expression, + e.g. !(x == y), y <=> x, (x <=> y) @ 0 etc, that resolved to a call + to a user-defined operator<=>/==. */ + gcc_checking_assert (TREE_CODE_CLASS (op) == tcc_comparison + || op == SPACESHIP_EXPR); + int flags = TREE_INT_CST_LOW (TREE_PURPOSE (overload)); + if (TREE_CODE (non_dep) == TRUTH_NOT_EXPR) + { + negated = true; + non_dep = TREE_OPERAND (non_dep, 0); + } + if (flags & LOOKUP_REWRITTEN) + rewritten = true; + if (flags & LOOKUP_REVERSED) + reversed = true; + if (rewritten + && DECL_OVERLOADED_OPERATOR_IS (TREE_VALUE (overload), + SPACESHIP_EXPR)) + { + /* Handle (x <=> y) @ 0 and 0 @ (y <=> x) by recursing to first + rebuild the <=>. Note that both OVERLOAD and the provided arguments + in this case already correspond to the selected operator<=>. */ + + tree spaceship_non_dep = CALL_EXPR_ARG (non_dep, reversed ? 1 : 0); + gcc_checking_assert (TREE_CODE (spaceship_non_dep) == CALL_EXPR); + tree spaceship_op0 = va_arg (p, tree); + tree spaceship_op1 = va_arg (p, tree); + if (reversed) + std::swap (spaceship_op0, spaceship_op1); + + /* Push the correct arguments for the operator OP expression, and + set OVERLOAD appropriately. */ + tree op0 = build_min_non_dep_op_overload (SPACESHIP_EXPR, + spaceship_non_dep, + TREE_VALUE (overload), + spaceship_op0, + spaceship_op1); + tree op1 = CALL_EXPR_ARG (non_dep, reversed ? 0 : 1); + gcc_checking_assert (integer_zerop (op1)); + vec_safe_push (args, op0); + vec_safe_push (args, op1); + overload = CALL_EXPR_FN (non_dep); + } + else + overload = TREE_VALUE (overload); + } non_dep = extract_call_expr (non_dep); nargs = call_expr_nargs (non_dep); @@ -3716,32 +3768,40 @@ build_min_non_dep_op_overload (enum tree_code op, expected_nargs += 1; gcc_assert (nargs == expected_nargs); - releasing_vec args; - va_start (p, overload); - if (!DECL_OBJECT_MEMBER_FUNCTION_P (overload)) { fn = overload; - if (op == ARRAY_REF) - obj = va_arg (p, tree); - for (int i = 0; i < nargs; i++) + if (vec_safe_length (args) != 0) + /* The correct arguments were already pushed above. */ + gcc_checking_assert (rewritten); + else { - tree arg = va_arg (p, tree); - vec_safe_push (args, arg); + if (op == ARRAY_REF) + obj = va_arg (p, tree); + for (int i = 0; i < nargs; i++) + { + tree arg = va_arg (p, tree); + vec_safe_push (args, arg); + } } + if (reversed) + std::swap ((*args)[0], (*args)[1]); } else { + gcc_checking_assert (vec_safe_length (args) == 0); tree object = va_arg (p, tree); - tree binfo = TYPE_BINFO (TREE_TYPE (object)); - tree method = build_baselink (binfo, binfo, overload, NULL_TREE); - fn = build_min (COMPONENT_REF, TREE_TYPE (overload), - object, method, NULL_TREE); for (int i = 0; i < nargs; i++) { tree arg = va_arg (p, tree); vec_safe_push (args, arg); } + if (reversed) + std::swap (object, (*args)[0]); + tree binfo = TYPE_BINFO (TREE_TYPE (object)); + tree method = build_baselink (binfo, binfo, overload, NULL_TREE); + fn = build_min (COMPONENT_REF, TREE_TYPE (overload), + object, method, NULL_TREE); } va_end (p); @@ -3753,6 +3813,8 @@ build_min_non_dep_op_overload (enum tree_code op, CALL_EXPR_ORDERED_ARGS (call_expr) = CALL_EXPR_ORDERED_ARGS (non_dep); CALL_EXPR_REVERSE_ARGS (call_expr) = CALL_EXPR_REVERSE_ARGS (non_dep); + if (negated) + call = build_min (TRUTH_NOT_EXPR, boolean_type_node, call); if (obj) return keep_unused_object_arg (call, obj, overload); return call; diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index a604511..f592894 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -155,7 +155,7 @@ complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain) else if (!COMPLETE_TYPE_P (type)) { if (complain & tf_error) - cxx_incomplete_type_diagnostic (value, type, DK_ERROR); + cxx_incomplete_type_diagnostic (value, type, diagnostics::kind::error); note_failed_type_completion (type, complain); return NULL_TREE; } @@ -618,7 +618,7 @@ type_after_usual_arithmetic_conversions (tree t1, tree t2) static void composite_pointer_error (const op_location_t &location, - diagnostic_t kind, tree t1, tree t2, + enum diagnostics::kind kind, tree t1, tree t2, composite_pointer_operation operation) { switch (operation) @@ -690,7 +690,7 @@ composite_pointer_type_r (const op_location_t &location, else { if (complain & tf_error) - composite_pointer_error (location, DK_PERMERROR, + composite_pointer_error (location, diagnostics::kind::permerror, t1, t2, operation); else return error_mark_node; @@ -716,7 +716,7 @@ composite_pointer_type_r (const op_location_t &location, TYPE_PTRMEM_CLASS_TYPE (t2))) { if (complain & tf_error) - composite_pointer_error (location, DK_PERMERROR, + composite_pointer_error (location, diagnostics::kind::permerror, t1, t2, operation); else return error_mark_node; @@ -851,7 +851,8 @@ composite_pointer_type (const op_location_t &location, else { if (complain & tf_error) - composite_pointer_error (location, DK_ERROR, t1, t2, operation); + composite_pointer_error (location, diagnostics::kind::error, + t1, t2, operation); return error_mark_node; } } @@ -4530,7 +4531,11 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params, { if (complain & tf_error) { - if (!flag_diagnostics_show_caret) + if (is_stub_object (original)) + error_at (input_location, + "%qT cannot be used as a function", + TREE_TYPE (original)); + else if (!flag_diagnostics_show_caret) error_at (input_location, "%qE cannot be used as a function", original); else if (DECL_P (original)) @@ -4672,12 +4677,8 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl, if (type == void_type_node) { if (complain & tf_error) - { - error_args_num (input_location, fndecl, /*too_many_p=*/true); - return i; - } - else - return -1; + error_args_num (input_location, fndecl, /*too_many_p=*/true); + return -1; } /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. @@ -10805,7 +10806,9 @@ maybe_warn_about_returning_address_of_local (tree retval, location_t loc) { if (TYPE_REF_P (valtype)) /* P2748 made this an error in C++26. */ - emit_diagnostic (cxx_dialect >= cxx26 ? DK_PERMERROR : DK_WARNING, + emit_diagnostic ((cxx_dialect >= cxx26 + ? diagnostics::kind::permerror + : diagnostics::kind::warning), loc, OPT_Wreturn_local_addr, "returning reference to temporary"); else if (TYPE_PTR_P (valtype)) diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index 45edd18..faaf1df 100644 --- a/gcc/cp/typeck2.cc +++ b/gcc/cp/typeck2.cc @@ -119,6 +119,11 @@ cxx_readonly_error (location_t loc, tree arg, enum lvalue_use errstring) G_("increment of read-only reference %qD"), G_("decrement of read-only reference %qD"), TREE_OPERAND (arg, 0)); + else if (is_stub_object (arg)) + { + gcc_assert (errstring == lv_assign); + error_at (loc, "assignment to read-only type %qT", TREE_TYPE (arg)); + } else readonly_error (loc, arg, errstring); } @@ -290,11 +295,12 @@ cxx_incomplete_type_inform (const_tree type) /* Print an error message for invalid use of an incomplete type. VALUE is the expression that was used (or 0 if that isn't known) and TYPE is the type that was invalid. DIAG_KIND indicates the - type of diagnostic (see diagnostic.def). */ + type of diagnostic (see diagnostics/kinds.def). */ bool cxx_incomplete_type_diagnostic (location_t loc, const_tree value, - const_tree type, diagnostic_t diag_kind) + const_tree type, + enum diagnostics::kind diag_kind) { bool is_decl = false, complained = false; @@ -440,7 +446,7 @@ cxx_incomplete_type_diagnostic (location_t loc, const_tree value, void cxx_incomplete_type_error (location_t loc, const_tree value, const_tree type) { - cxx_incomplete_type_diagnostic (loc, value, type, DK_ERROR); + cxx_incomplete_type_diagnostic (loc, value, type, diagnostics::kind::error); } @@ -2627,7 +2633,7 @@ add_exception_specifier (tree list, tree spec, tsubst_flags_t complain) bool ok; tree core = spec; bool is_ptr; - diagnostic_t diag_type = DK_UNSPECIFIED; /* none */ + enum diagnostics::kind diag_type = diagnostics::kind::unspecified; /* none */ if (spec == error_mark_node) return list; @@ -2659,7 +2665,7 @@ add_exception_specifier (tree list, tree spec, tsubst_flags_t complain) and calls. So just give a pedwarn at this point; we will give an error later if we hit one of those two cases. */ if (!COMPLETE_TYPE_P (complete_type (core))) - diag_type = DK_PEDWARN; /* pedwarn */ + diag_type = diagnostics::kind::pedwarn; /* pedwarn */ } if (ok) @@ -2673,9 +2679,9 @@ add_exception_specifier (tree list, tree spec, tsubst_flags_t complain) list = tree_cons (NULL_TREE, spec, list); } else - diag_type = DK_ERROR; /* error */ + diag_type = diagnostics::kind::error; /* error */ - if (diag_type != DK_UNSPECIFIED + if (diag_type != diagnostics::kind::unspecified && (complain & tf_warning_or_error)) cxx_incomplete_type_diagnostic (NULL_TREE, core, diag_type); |