/* Call-backs for C++ error reporting. This code is non-reentrant. Copyright (C) 1993-2019 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" /* For use with name_hint. */ #define INCLUDE_UNIQUE_PTR #include "system.h" #include "coretypes.h" #include "cp-tree.h" #include "stringpool.h" #include "tree-diagnostic.h" #include "langhooks-def.h" #include "intl.h" #include "cxx-pretty-print.h" #include "tree-pretty-print.h" #include "gimple-pretty-print.h" #include "c-family/c-objc.h" #include "ubsan.h" #include "internal-fn.h" #include "gcc-rich-location.h" #include "cp-name-hint.h" #define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',') #define pp_separate_with_semicolon(PP) pp_cxx_separate_with (PP, ';') /* cxx_pp is a C++ front-end-specific pretty printer: this is where we dump C++ ASTs as strings. It is mostly used only by the various tree -> string functions that are occasionally called from the debugger or by the front-end for things like __PRETTY_FUNCTION__. */ static cxx_pretty_printer actual_pretty_printer; static cxx_pretty_printer * const cxx_pp = &actual_pretty_printer; /* Translate if being used for diagnostics, but not for dump files or __PRETTY_FUNCTION. */ #define M_(msgid) (pp_translate_identifiers (cxx_pp) ? _(msgid) : (msgid)) # define NEXT_CODE(T) (TREE_CODE (TREE_TYPE (T))) static const char *args_to_string (tree, int); static const char *code_to_string (enum tree_code); static const char *cv_to_string (tree, int); static const char *decl_to_string (tree, int); static const char *fndecl_to_string (tree, int); static const char *op_to_string (bool, enum tree_code); static const char *parm_to_string (int); static const char *type_to_string (tree, int, bool, bool *, bool); static void dump_alias_template_specialization (cxx_pretty_printer *, tree, int); static void dump_type (cxx_pretty_printer *, tree, int); static void dump_typename (cxx_pretty_printer *, tree, int); static void dump_simple_decl (cxx_pretty_printer *, tree, tree, int); static void dump_decl (cxx_pretty_printer *, tree, int); static void dump_template_decl (cxx_pretty_printer *, tree, int); static void dump_function_decl (cxx_pretty_printer *, tree, int); static void dump_expr (cxx_pretty_printer *, tree, int); static void dump_unary_op (cxx_pretty_printer *, const char *, tree, int); static void dump_binary_op (cxx_pretty_printer *, const char *, tree, int); static void dump_aggr_type (cxx_pretty_printer *, tree, int); static void dump_type_prefix (cxx_pretty_printer *, tree, int); static void dump_type_suffix (cxx_pretty_printer *, tree, int); static void dump_function_name (cxx_pretty_printer *, tree, int); static void dump_call_expr_args (cxx_pretty_printer *, tree, int, bool); static void dump_aggr_init_expr_args (cxx_pretty_printer *, tree, int, bool); static void dump_expr_list (cxx_pretty_printer *, tree, int); static void dump_global_iord (cxx_pretty_printer *, tree); static void dump_parameters (cxx_pretty_printer *, tree, int); static void dump_ref_qualifier (cxx_pretty_printer *, tree, int); static void dump_exception_spec (cxx_pretty_printer *, tree, int); static void dump_template_argument (cxx_pretty_printer *, tree, int); static void dump_template_argument_list (cxx_pretty_printer *, tree, int); static void dump_template_parameter (cxx_pretty_printer *, tree, int); static void dump_template_bindings (cxx_pretty_printer *, tree, tree, vec *); 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_context *); static void maybe_print_instantiation_context (diagnostic_context *); static void print_instantiation_full_context (diagnostic_context *); static void print_instantiation_partial_context (diagnostic_context *, struct tinst_level *, location_t); static void maybe_print_constraint_context (diagnostic_context *); static void cp_diagnostic_starter (diagnostic_context *, diagnostic_info *); static void cp_print_error_function (diagnostic_context *, diagnostic_info *); static bool cp_printer (pretty_printer *, text_info *, const char *, int, bool, bool, bool, bool *, const char **); /* Struct for handling %H or %I, which require delaying printing the type until a postprocessing stage. */ class deferred_printed_type { public: deferred_printed_type () : m_tree (NULL_TREE), m_buffer_ptr (NULL), m_verbose (false), m_quote (false) {} deferred_printed_type (tree type, const char **buffer_ptr, bool verbose, bool quote) : m_tree (type), m_buffer_ptr (buffer_ptr), m_verbose (verbose), m_quote (quote) { gcc_assert (type); gcc_assert (buffer_ptr); } /* The tree is not GTY-marked: they are only non-NULL within a call to pp_format. */ tree m_tree; const char **m_buffer_ptr; bool m_verbose; bool m_quote; }; /* Subclass of format_postprocessor for the C++ frontend. This handles the %H and %I formatting codes, printing them in a postprocessing phase (since they affect each other). */ class cxx_format_postprocessor : public format_postprocessor { public: cxx_format_postprocessor () : m_type_a (), m_type_b () {} void handle (pretty_printer *pp) FINAL OVERRIDE; deferred_printed_type m_type_a; deferred_printed_type m_type_b; }; /* CONTEXT->printer is a basic pretty printer that was constructed presumably by diagnostic_initialize(), called early in the compiler's initialization process (in general_init) Before the FE is initialized. This (C++) FE-specific diagnostic initializer is thus replacing the basic pretty printer with one that has C++-aware capacities. */ void cxx_initialize_diagnostics (diagnostic_context *context) { pretty_printer *base = context->printer; cxx_pretty_printer *pp = XNEW (cxx_pretty_printer); context->printer = new (pp) cxx_pretty_printer (); /* It is safe to free this object because it was previously XNEW()'d. */ base->~pretty_printer (); XDELETE (base); c_common_diagnostics_set_defaults (context); diagnostic_starter (context) = cp_diagnostic_starter; /* diagnostic_finalizer is already c_diagnostic_finalizer. */ diagnostic_format_decoder (context) = cp_printer; pp->m_format_postprocessor = new cxx_format_postprocessor (); } /* Dump a scope, if deemed necessary. */ static void dump_scope (cxx_pretty_printer *pp, tree scope, int flags) { int f = flags & (TFF_SCOPE | TFF_CHASE_TYPEDEF); if (scope == NULL_TREE) return; /* Enum values within an unscoped enum will be CONST_DECL with an ENUMERAL_TYPE as their "scope". Use CP_TYPE_CONTEXT of the ENUMERAL_TYPE, so as to print any enclosing namespace. */ if (UNSCOPED_ENUM_P (scope)) scope = CP_TYPE_CONTEXT (scope); if (TREE_CODE (scope) == NAMESPACE_DECL) { if (scope != global_namespace) { dump_decl (pp, scope, f); pp_cxx_colon_colon (pp); } } else if (AGGREGATE_TYPE_P (scope) || SCOPED_ENUM_P (scope)) { dump_type (pp, scope, f); pp_cxx_colon_colon (pp); } else if ((flags & TFF_SCOPE) && TREE_CODE (scope) == FUNCTION_DECL) { dump_function_decl (pp, scope, f); pp_cxx_colon_colon (pp); } } /* Dump the template ARGument under control of FLAGS. */ static void dump_template_argument (cxx_pretty_printer *pp, tree arg, int flags) { if (ARGUMENT_PACK_P (arg)) dump_template_argument_list (pp, ARGUMENT_PACK_ARGS (arg), /* No default args in argument packs. */ flags|TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS); else if (TYPE_P (arg) || TREE_CODE (arg) == TEMPLATE_DECL) dump_type (pp, arg, flags & ~TFF_CLASS_KEY_OR_ENUM); else { if (TREE_CODE (arg) == TREE_LIST) arg = TREE_VALUE (arg); /* Strip implicit conversions. */ while (CONVERT_EXPR_P (arg)) arg = TREE_OPERAND (arg, 0); dump_expr (pp, arg, (flags | TFF_EXPR_IN_PARENS) & ~TFF_CLASS_KEY_OR_ENUM); } } /* Count the number of template arguments ARGS whose value does not match the (optional) default template parameter in PARAMS */ static int get_non_default_template_args_count (tree args, int flags) { int n = TREE_VEC_LENGTH (INNERMOST_TEMPLATE_ARGS (args)); if (/* We use this flag when generating debug information. We don't want to expand templates at this point, for this may generate new decls, which gets decl counts out of sync, which may in turn cause codegen differences between compilations with and without -g. */ (flags & TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS) != 0 || !flag_pretty_templates) return n; return GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (INNERMOST_TEMPLATE_ARGS (args)); } /* Dump a template-argument-list ARGS (always a TREE_VEC) under control of FLAGS. */ static void dump_template_argument_list (cxx_pretty_printer *pp, tree args, int flags) { int n = get_non_default_template_args_count (args, flags); int need_comma = 0; int i; for (i = 0; i < n; ++i) { tree arg = TREE_VEC_ELT (args, i); /* Only print a comma if we know there is an argument coming. In the case of an empty template argument pack, no actual argument will be printed. */ if (need_comma && (!ARGUMENT_PACK_P (arg) || TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg)) > 0)) pp_separate_with_comma (pp); dump_template_argument (pp, arg, flags); need_comma = 1; } } /* Dump a template parameter PARM (a TREE_LIST) under control of FLAGS. */ static void dump_template_parameter (cxx_pretty_printer *pp, tree parm, int flags) { tree p; tree a; if (parm == error_mark_node) return; p = TREE_VALUE (parm); a = TREE_PURPOSE (parm); if (TREE_CODE (p) == TYPE_DECL) { if (flags & TFF_DECL_SPECIFIERS) { pp_cxx_ws_string (pp, "class"); if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (p))) pp_cxx_ws_string (pp, "..."); if (DECL_NAME (p)) pp_cxx_tree_identifier (pp, DECL_NAME (p)); } else if (DECL_NAME (p)) pp_cxx_tree_identifier (pp, DECL_NAME (p)); else pp_cxx_canonical_template_parameter (pp, TREE_TYPE (p)); } else dump_decl (pp, p, flags | TFF_DECL_SPECIFIERS); if ((flags & TFF_FUNCTION_DEFAULT_ARGUMENTS) && a != NULL_TREE) { pp_cxx_whitespace (pp); pp_equal (pp); pp_cxx_whitespace (pp); if (TREE_CODE (p) == TYPE_DECL || TREE_CODE (p) == TEMPLATE_DECL) dump_type (pp, a, flags & ~TFF_CHASE_TYPEDEF); else dump_expr (pp, a, flags | TFF_EXPR_IN_PARENS); } } /* Dump, under control of FLAGS, a template-parameter-list binding. PARMS is a TREE_LIST of TREE_VEC of TREE_LIST and ARGS is a TREE_VEC. */ static void dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args, vec *typenames) { bool need_semicolon = false; int i; tree t; while (parms) { tree p = TREE_VALUE (parms); int lvl = TMPL_PARMS_DEPTH (parms); int arg_idx = 0; int i; tree lvl_args = NULL_TREE; /* Don't crash if we had an invalid argument list. */ if (TMPL_ARGS_DEPTH (args) >= lvl) lvl_args = TMPL_ARGS_LEVEL (args, lvl); for (i = 0; i < TREE_VEC_LENGTH (p); ++i) { tree arg = NULL_TREE; /* Don't crash if we had an invalid argument list. */ if (lvl_args && NUM_TMPL_ARGS (lvl_args) > arg_idx) arg = TREE_VEC_ELT (lvl_args, arg_idx); if (need_semicolon) pp_separate_with_semicolon (pp); dump_template_parameter (pp, TREE_VEC_ELT (p, i), TFF_PLAIN_IDENTIFIER); pp_cxx_whitespace (pp); pp_equal (pp); pp_cxx_whitespace (pp); if (arg) { if (ARGUMENT_PACK_P (arg)) pp_cxx_left_brace (pp); dump_template_argument (pp, arg, TFF_PLAIN_IDENTIFIER); if (ARGUMENT_PACK_P (arg)) pp_cxx_right_brace (pp); } else pp_string (pp, M_("")); ++arg_idx; need_semicolon = true; } parms = TREE_CHAIN (parms); } /* Don't bother with typenames for a partial instantiation. */ if (vec_safe_is_empty (typenames) || uses_template_parms (args)) return; /* Don't try to print typenames when we're processing a clone. */ if (current_function_decl && !DECL_LANG_SPECIFIC (current_function_decl)) return; /* Don't try to do this once cgraph starts throwing away front-end information. */ if (at_eof >= 2) return; FOR_EACH_VEC_SAFE_ELT (typenames, i, t) { if (need_semicolon) pp_separate_with_semicolon (pp); dump_type (pp, t, TFF_PLAIN_IDENTIFIER); pp_cxx_whitespace (pp); pp_equal (pp); pp_cxx_whitespace (pp); push_deferring_access_checks (dk_no_check); t = tsubst (t, args, tf_none, NULL_TREE); pop_deferring_access_checks (); /* Strip typedefs. We can't just use TFF_CHASE_TYPEDEF because pp_simple_type_specifier doesn't know about it. */ t = strip_typedefs (t, NULL, STF_USER_VISIBLE); dump_type (pp, t, TFF_PLAIN_IDENTIFIER); } } /* Dump a human-readable equivalent of the alias template specialization of T. */ static void dump_alias_template_specialization (cxx_pretty_printer *pp, tree t, int flags) { gcc_assert (alias_template_specialization_p (t)); tree decl = TYPE_NAME (t); if (!(flags & TFF_UNQUALIFIED_NAME)) dump_scope (pp, CP_DECL_CONTEXT (decl), flags); pp_cxx_tree_identifier (pp, DECL_NAME (decl)); dump_template_parms (pp, DECL_TEMPLATE_INFO (decl), /*primary=*/false, flags & ~TFF_TEMPLATE_HEADER); } /* Dump a human-readable equivalent of TYPE. FLAGS controls the format. */ static void dump_type (cxx_pretty_printer *pp, tree t, int flags) { if (t == NULL_TREE) return; /* Don't print e.g. "struct mytypedef". */ if (TYPE_P (t) && typedef_variant_p (t)) { tree decl = TYPE_NAME (t); if ((flags & TFF_CHASE_TYPEDEF) || DECL_SELF_REFERENCE_P (decl) || (!flag_pretty_templates && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))) { unsigned int stf_flags = (!(pp->flags & pp_c_flag_gnu_v3) ? STF_USER_VISIBLE : 0); t = strip_typedefs (t, NULL, stf_flags); } else if (alias_template_specialization_p (t)) { dump_alias_template_specialization (pp, t, flags); return; } else if (same_type_p (t, TREE_TYPE (decl))) t = decl; else { pp_cxx_cv_qualifier_seq (pp, t); pp_cxx_tree_identifier (pp, TYPE_IDENTIFIER (t)); return; } } if (TYPE_PTRMEMFUNC_P (t)) goto offset_type; switch (TREE_CODE (t)) { case LANG_TYPE: if (t == init_list_type_node) pp_string (pp, M_("")); else if (t == unknown_type_node) pp_string (pp, M_("")); else { pp_cxx_cv_qualifier_seq (pp, t); pp_cxx_tree_identifier (pp, TYPE_IDENTIFIER (t)); } break; case TREE_LIST: /* A list of function parms. */ dump_parameters (pp, t, flags); break; case IDENTIFIER_NODE: pp_cxx_tree_identifier (pp, t); break; case TREE_BINFO: dump_type (pp, BINFO_TYPE (t), flags); break; case RECORD_TYPE: case UNION_TYPE: case ENUMERAL_TYPE: dump_aggr_type (pp, t, flags); break; case TYPE_DECL: if (flags & TFF_CHASE_TYPEDEF) { dump_type (pp, DECL_ORIGINAL_TYPE (t) ? DECL_ORIGINAL_TYPE (t) : TREE_TYPE (t), flags); break; } /* Fall through. */ case TEMPLATE_DECL: case NAMESPACE_DECL: dump_decl (pp, t, flags & ~TFF_DECL_SPECIFIERS); break; case INTEGER_TYPE: case REAL_TYPE: case VOID_TYPE: case BOOLEAN_TYPE: case COMPLEX_TYPE: case VECTOR_TYPE: case FIXED_POINT_TYPE: pp_type_specifier_seq (pp, t); break; case TEMPLATE_TEMPLATE_PARM: /* For parameters inside template signature. */ if (TYPE_IDENTIFIER (t)) pp_cxx_tree_identifier (pp, TYPE_IDENTIFIER (t)); else pp_cxx_canonical_template_parameter (pp, t); break; case BOUND_TEMPLATE_TEMPLATE_PARM: { tree args = TYPE_TI_ARGS (t); pp_cxx_cv_qualifier_seq (pp, t); pp_cxx_tree_identifier (pp, TYPE_IDENTIFIER (t)); pp_cxx_begin_template_argument_list (pp); dump_template_argument_list (pp, args, flags); pp_cxx_end_template_argument_list (pp); } break; case TEMPLATE_TYPE_PARM: pp_cxx_cv_qualifier_seq (pp, t); if (template_placeholder_p (t)) { t = TREE_TYPE (CLASS_PLACEHOLDER_TEMPLATE (t)); pp_cxx_tree_identifier (pp, TYPE_IDENTIFIER (t)); pp_string (pp, "<...auto...>"); } else if (TYPE_IDENTIFIER (t)) pp_cxx_tree_identifier (pp, TYPE_IDENTIFIER (t)); else pp_cxx_canonical_template_parameter (pp, TEMPLATE_TYPE_PARM_INDEX (t)); /* If this is a constrained placeholder, add the requirements. */ if (tree c = PLACEHOLDER_TYPE_CONSTRAINTS (t)) pp_cxx_constrained_type_spec (pp, c); break; /* This is not always necessary for pointers and such, but doing this reduces code size. */ case ARRAY_TYPE: case POINTER_TYPE: case REFERENCE_TYPE: case OFFSET_TYPE: offset_type: case FUNCTION_TYPE: case METHOD_TYPE: { dump_type_prefix (pp, t, flags); dump_type_suffix (pp, t, flags); break; } case TYPENAME_TYPE: if (! (flags & TFF_CHASE_TYPEDEF) && DECL_ORIGINAL_TYPE (TYPE_NAME (t))) { dump_decl (pp, TYPE_NAME (t), TFF_PLAIN_IDENTIFIER); break; } pp_cxx_cv_qualifier_seq (pp, t); pp_cxx_ws_string (pp, TYPENAME_IS_ENUM_P (t) ? "enum" : TYPENAME_IS_CLASS_P (t) ? "class" : "typename"); dump_typename (pp, t, flags); break; case UNBOUND_CLASS_TEMPLATE: if (! (flags & TFF_UNQUALIFIED_NAME)) { dump_type (pp, TYPE_CONTEXT (t), flags); pp_cxx_colon_colon (pp); } pp_cxx_ws_string (pp, "template"); dump_type (pp, TYPE_IDENTIFIER (t), flags); break; case TYPEOF_TYPE: pp_cxx_ws_string (pp, "__typeof__"); pp_cxx_whitespace (pp); pp_cxx_left_paren (pp); dump_expr (pp, TYPEOF_TYPE_EXPR (t), flags & ~TFF_EXPR_IN_PARENS); pp_cxx_right_paren (pp); break; case UNDERLYING_TYPE: pp_cxx_ws_string (pp, "__underlying_type"); pp_cxx_whitespace (pp); pp_cxx_left_paren (pp); dump_expr (pp, UNDERLYING_TYPE_TYPE (t), flags & ~TFF_EXPR_IN_PARENS); pp_cxx_right_paren (pp); break; case TYPE_PACK_EXPANSION: dump_type (pp, PACK_EXPANSION_PATTERN (t), flags); pp_cxx_ws_string (pp, "..."); break; case TYPE_ARGUMENT_PACK: dump_template_argument (pp, t, flags); break; case DECLTYPE_TYPE: pp_cxx_ws_string (pp, "decltype"); pp_cxx_whitespace (pp); pp_cxx_left_paren (pp); dump_expr (pp, DECLTYPE_TYPE_EXPR (t), flags & ~TFF_EXPR_IN_PARENS); pp_cxx_right_paren (pp); break; case NULLPTR_TYPE: pp_string (pp, "std::nullptr_t"); break; default: pp_unsupported_tree (pp, t); /* Fall through. */ case ERROR_MARK: pp_string (pp, M_("")); break; } } /* Dump a TYPENAME_TYPE. We need to notice when the context is itself a TYPENAME_TYPE. */ static void dump_typename (cxx_pretty_printer *pp, tree t, int flags) { tree ctx = TYPE_CONTEXT (t); if (TREE_CODE (ctx) == TYPENAME_TYPE) dump_typename (pp, ctx, flags); else dump_type (pp, ctx, flags & ~TFF_CLASS_KEY_OR_ENUM); pp_cxx_colon_colon (pp); dump_decl (pp, TYPENAME_TYPE_FULLNAME (t), flags); } /* Return the name of the supplied aggregate, or enumeral type. */ const char * class_key_or_enum_as_string (tree t) { if (TREE_CODE (t) == ENUMERAL_TYPE) { if (SCOPED_ENUM_P (t)) return "enum class"; else return "enum"; } else if (TREE_CODE (t) == UNION_TYPE) return "union"; else if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t)) return "class"; else return "struct"; } /* Print out a class declaration T under the control of FLAGS, in the form `class foo'. */ static void dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags) { tree name; const char *variety = class_key_or_enum_as_string (t); int typdef = 0; int tmplate = 0; pp_cxx_cv_qualifier_seq (pp, t); if (flags & TFF_CLASS_KEY_OR_ENUM) pp_cxx_ws_string (pp, variety); name = TYPE_NAME (t); if (name) { typdef = (!DECL_ARTIFICIAL (name) /* An alias specialization is not considered to be a typedef. */ && !alias_template_specialization_p (t)); if ((typdef && ((flags & TFF_CHASE_TYPEDEF) || (!flag_pretty_templates && DECL_LANG_SPECIFIC (name) && DECL_TEMPLATE_INFO (name)))) || DECL_SELF_REFERENCE_P (name)) { t = TYPE_MAIN_VARIANT (t); name = TYPE_NAME (t); typdef = 0; } tmplate = !typdef && TREE_CODE (t) != ENUMERAL_TYPE && TYPE_LANG_SPECIFIC (t) && CLASSTYPE_TEMPLATE_INFO (t) && (TREE_CODE (CLASSTYPE_TI_TEMPLATE (t)) != TEMPLATE_DECL || PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t))); if (! (flags & TFF_UNQUALIFIED_NAME)) dump_scope (pp, CP_DECL_CONTEXT (name), flags | TFF_SCOPE); flags &= ~TFF_UNQUALIFIED_NAME; if (tmplate) { /* Because the template names are mangled, we have to locate the most general template, and use that name. */ tree tpl = TYPE_TI_TEMPLATE (t); while (DECL_TEMPLATE_INFO (tpl)) tpl = DECL_TI_TEMPLATE (tpl); name = tpl; } name = DECL_NAME (name); } if (LAMBDA_TYPE_P (t)) { /* A lambda's "type" is essentially its signature. */ pp_string (pp, M_("")); else pp_printf (pp, M_(""), variety); } else pp_cxx_tree_identifier (pp, name); if (tmplate) dump_template_parms (pp, TYPE_TEMPLATE_INFO (t), !CLASSTYPE_USE_TEMPLATE (t), flags & ~TFF_TEMPLATE_HEADER); } /* Dump into the obstack the initial part of the output for a given type. This is necessary when dealing with things like functions returning functions. Examples: return type of `int (* fee ())()': pointer -> function -> int. Both pointer (and reference and offset) and function (and member) types must deal with prefix and suffix. Arrays must also do this for DECL nodes, like int a[], and for things like int *[]&. */ static void dump_type_prefix (cxx_pretty_printer *pp, tree t, int flags) { if (TYPE_PTRMEMFUNC_P (t)) { t = TYPE_PTRMEMFUNC_FN_TYPE (t); goto offset_type; } switch (TREE_CODE (t)) { case POINTER_TYPE: case REFERENCE_TYPE: { tree sub = TREE_TYPE (t); dump_type_prefix (pp, sub, flags); if (TREE_CODE (sub) == ARRAY_TYPE || TREE_CODE (sub) == FUNCTION_TYPE) { pp_cxx_whitespace (pp); pp_cxx_left_paren (pp); pp_c_attributes_display (pp, TYPE_ATTRIBUTES (sub)); } if (TYPE_PTR_P (t)) pp_star (pp); else if (TYPE_REF_P (t)) { if (TYPE_REF_IS_RVALUE (t)) pp_ampersand_ampersand (pp); else pp_ampersand (pp); } pp->padding = pp_before; pp_cxx_cv_qualifier_seq (pp, t); } break; case OFFSET_TYPE: offset_type: dump_type_prefix (pp, TREE_TYPE (t), flags); if (TREE_CODE (t) == OFFSET_TYPE) /* pmfs deal with this in d_t_p */ { pp_maybe_space (pp); if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) pp_cxx_left_paren (pp); dump_type (pp, TYPE_OFFSET_BASETYPE (t), flags); pp_cxx_colon_colon (pp); } pp_cxx_star (pp); pp_cxx_cv_qualifier_seq (pp, t); pp->padding = pp_before; break; /* This can be reached without a pointer when dealing with templates, e.g. std::is_function. */ case FUNCTION_TYPE: dump_type_prefix (pp, TREE_TYPE (t), flags); break; case METHOD_TYPE: dump_type_prefix (pp, TREE_TYPE (t), flags); pp_maybe_space (pp); pp_cxx_left_paren (pp); dump_aggr_type (pp, TYPE_METHOD_BASETYPE (t), flags); pp_cxx_colon_colon (pp); break; case ARRAY_TYPE: dump_type_prefix (pp, TREE_TYPE (t), flags); break; case ENUMERAL_TYPE: case IDENTIFIER_NODE: case INTEGER_TYPE: case BOOLEAN_TYPE: case REAL_TYPE: case RECORD_TYPE: case TEMPLATE_TYPE_PARM: case TEMPLATE_TEMPLATE_PARM: case BOUND_TEMPLATE_TEMPLATE_PARM: case TREE_LIST: case TYPE_DECL: case TREE_VEC: case UNION_TYPE: case LANG_TYPE: case VOID_TYPE: case TYPENAME_TYPE: case COMPLEX_TYPE: case VECTOR_TYPE: case TYPEOF_TYPE: case UNDERLYING_TYPE: case DECLTYPE_TYPE: case TYPE_PACK_EXPANSION: case FIXED_POINT_TYPE: case NULLPTR_TYPE: dump_type (pp, t, flags); pp->padding = pp_before; break; default: pp_unsupported_tree (pp, t); /* fall through. */ case ERROR_MARK: pp_string (pp, M_("")); break; } } /* Dump the suffix of type T, under control of FLAGS. This is the part which appears after the identifier (or function parms). */ static void dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags) { if (TYPE_PTRMEMFUNC_P (t)) t = TYPE_PTRMEMFUNC_FN_TYPE (t); switch (TREE_CODE (t)) { case POINTER_TYPE: case REFERENCE_TYPE: case OFFSET_TYPE: if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE) pp_cxx_right_paren (pp); if (TREE_CODE (t) == POINTER_TYPE) flags |= TFF_POINTER; dump_type_suffix (pp, TREE_TYPE (t), flags); break; case FUNCTION_TYPE: case METHOD_TYPE: { tree arg; if (TREE_CODE (t) == METHOD_TYPE) /* Can only be reached through a pointer. */ pp_cxx_right_paren (pp); arg = TYPE_ARG_TYPES (t); if (TREE_CODE (t) == METHOD_TYPE) arg = TREE_CHAIN (arg); /* Function pointers don't have default args. Not in standard C++, anyway; they may in g++, but we'll just pretend otherwise. */ dump_parameters (pp, arg, flags & ~TFF_FUNCTION_DEFAULT_ARGUMENTS); pp->padding = pp_before; pp_cxx_cv_qualifiers (pp, type_memfn_quals (t), TREE_CODE (t) == FUNCTION_TYPE && (flags & TFF_POINTER)); dump_ref_qualifier (pp, t, flags); if (tx_safe_fn_type_p (t)) pp_cxx_ws_string (pp, "transaction_safe"); dump_exception_spec (pp, TYPE_RAISES_EXCEPTIONS (t), flags); dump_type_suffix (pp, TREE_TYPE (t), flags); break; } case ARRAY_TYPE: pp_maybe_space (pp); pp_cxx_left_bracket (pp); if (tree dtype = TYPE_DOMAIN (t)) { tree max = TYPE_MAX_VALUE (dtype); /* Zero-length arrays have an upper bound of SIZE_MAX. */ if (integer_all_onesp (max)) pp_character (pp, '0'); else if (tree_fits_shwi_p (max)) pp_wide_integer (pp, tree_to_shwi (max) + 1); else { STRIP_NOPS (max); if (TREE_CODE (max) == SAVE_EXPR) max = TREE_OPERAND (max, 0); if (TREE_CODE (max) == MINUS_EXPR || TREE_CODE (max) == PLUS_EXPR) { max = TREE_OPERAND (max, 0); while (CONVERT_EXPR_P (max)) max = TREE_OPERAND (max, 0); } else max = fold_build2_loc (input_location, PLUS_EXPR, dtype, max, build_int_cst (dtype, 1)); dump_expr (pp, max, flags & ~TFF_EXPR_IN_PARENS); } } pp_cxx_right_bracket (pp); dump_type_suffix (pp, TREE_TYPE (t), flags); break; case ENUMERAL_TYPE: case IDENTIFIER_NODE: case INTEGER_TYPE: case BOOLEAN_TYPE: case REAL_TYPE: case RECORD_TYPE: case TEMPLATE_TYPE_PARM: case TEMPLATE_TEMPLATE_PARM: case BOUND_TEMPLATE_TEMPLATE_PARM: case TREE_LIST: case TYPE_DECL: case TREE_VEC: case UNION_TYPE: case LANG_TYPE: case VOID_TYPE: case TYPENAME_TYPE: case COMPLEX_TYPE: case VECTOR_TYPE: case TYPEOF_TYPE: case UNDERLYING_TYPE: case DECLTYPE_TYPE: case TYPE_PACK_EXPANSION: case FIXED_POINT_TYPE: case NULLPTR_TYPE: break; default: pp_unsupported_tree (pp, t); case ERROR_MARK: /* Don't mark it here, we should have already done in dump_type_prefix. */ break; } } static void dump_global_iord (cxx_pretty_printer *pp, tree t) { const char *p = NULL; if (DECL_GLOBAL_CTOR_P (t)) p = M_("(static initializers for %s)"); else if (DECL_GLOBAL_DTOR_P (t)) p = M_("(static destructors for %s)"); else gcc_unreachable (); pp_printf (pp, p, DECL_SOURCE_FILE (t)); } static void dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags) { if (template_parm_object_p (t)) return dump_expr (pp, DECL_INITIAL (t), flags); if (flags & TFF_DECL_SPECIFIERS) { if (VAR_P (t) && DECL_DECLARED_CONSTEXPR_P (t)) { if (DECL_LANG_SPECIFIC (t) && DECL_DECLARED_CONCEPT_P (t)) pp_cxx_ws_string (pp, "concept"); else pp_cxx_ws_string (pp, "constexpr"); } dump_type_prefix (pp, type, flags & ~TFF_UNQUALIFIED_NAME); pp_maybe_space (pp); } if (! (flags & TFF_UNQUALIFIED_NAME) && TREE_CODE (t) != PARM_DECL && (!DECL_INITIAL (t) || TREE_CODE (DECL_INITIAL (t)) != TEMPLATE_PARM_INDEX)) dump_scope (pp, CP_DECL_CONTEXT (t), flags); flags &= ~TFF_UNQUALIFIED_NAME; if ((flags & TFF_DECL_SPECIFIERS) && DECL_TEMPLATE_PARM_P (t) && TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (t))) pp_string (pp, "..."); if (DECL_NAME (t)) { if (TREE_CODE (t) == FIELD_DECL && DECL_NORMAL_CAPTURE_P (t)) { pp_less (pp); pp_string (pp, IDENTIFIER_POINTER (DECL_NAME (t)) + 2); pp_string (pp, " capture>"); } else dump_decl (pp, DECL_NAME (t), flags); } else if (DECL_DECOMPOSITION_P (t)) pp_string (pp, M_("")); else pp_string (pp, M_("")); if (flags & TFF_DECL_SPECIFIERS) dump_type_suffix (pp, type, flags); } /* Print an IDENTIFIER_NODE that is the name of a declaration. */ static void dump_decl_name (cxx_pretty_printer *pp, tree t, int flags) { /* These special cases are duplicated here so that other functions can feed identifiers to error and get them demangled properly. */ if (IDENTIFIER_CONV_OP_P (t)) { pp_cxx_ws_string (pp, "operator"); /* Not exactly IDENTIFIER_TYPE_VALUE. */ dump_type (pp, TREE_TYPE (t), flags); return; } if (dguide_name_p (t)) { dump_decl (pp, CLASSTYPE_TI_TEMPLATE (TREE_TYPE (t)), TFF_UNQUALIFIED_NAME); return; } const char *str = IDENTIFIER_POINTER (t); if (!strncmp (str, "_ZGR", 3)) { pp_cxx_ws_string (pp, ""); return; } pp_cxx_tree_identifier (pp, t); } /* Dump a human readable string for the decl T under control of FLAGS. */ static void dump_decl (cxx_pretty_printer *pp, tree t, int flags) { if (t == NULL_TREE) return; /* If doing Objective-C++, give Objective-C a chance to demangle Objective-C method names. */ if (c_dialect_objc ()) { const char *demangled = objc_maybe_printable_name (t, flags); if (demangled) { pp_string (pp, demangled); return; } } switch (TREE_CODE (t)) { case TYPE_DECL: /* Don't say 'typedef class A' */ if (DECL_ARTIFICIAL (t) && !DECL_SELF_REFERENCE_P (t)) { if ((flags & TFF_DECL_SPECIFIERS) && TREE_CODE (TREE_TYPE (t)) == TEMPLATE_TYPE_PARM) { /* Say `class T' not just `T'. */ pp_cxx_ws_string (pp, "class"); /* Emit the `...' for a parameter pack. */ if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (t))) pp_cxx_ws_string (pp, "..."); } dump_type (pp, TREE_TYPE (t), flags); break; } if (TYPE_DECL_ALIAS_P (t) && (flags & TFF_DECL_SPECIFIERS || flags & TFF_CLASS_KEY_OR_ENUM)) { pp_cxx_ws_string (pp, "using"); dump_decl (pp, DECL_NAME (t), flags); pp_cxx_whitespace (pp); pp_cxx_ws_string (pp, "="); pp_cxx_whitespace (pp); dump_type (pp, (DECL_ORIGINAL_TYPE (t) ? DECL_ORIGINAL_TYPE (t) : TREE_TYPE (t)), flags); break; } if ((flags & TFF_DECL_SPECIFIERS) && !DECL_SELF_REFERENCE_P (t)) pp_cxx_ws_string (pp, "typedef"); dump_simple_decl (pp, t, DECL_ORIGINAL_TYPE (t) ? DECL_ORIGINAL_TYPE (t) : TREE_TYPE (t), flags); break; case VAR_DECL: if (DECL_NAME (t) && VTABLE_NAME_P (DECL_NAME (t))) { pp_string (pp, M_("vtable for ")); gcc_assert (TYPE_P (DECL_CONTEXT (t))); dump_type (pp, DECL_CONTEXT (t), flags); break; } /* Fall through. */ case FIELD_DECL: case PARM_DECL: dump_simple_decl (pp, t, TREE_TYPE (t), flags); /* Handle variable template specializations. */ if (VAR_P (t) && DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t) && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t))) { pp_cxx_begin_template_argument_list (pp); tree args = INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (t)); dump_template_argument_list (pp, args, flags); pp_cxx_end_template_argument_list (pp); } break; case RESULT_DECL: pp_string (pp, M_(" ")); dump_simple_decl (pp, t, TREE_TYPE (t), flags); break; case NAMESPACE_DECL: if (flags & TFF_DECL_SPECIFIERS) pp->declaration (t); else { if (! (flags & TFF_UNQUALIFIED_NAME)) dump_scope (pp, CP_DECL_CONTEXT (t), flags); flags &= ~TFF_UNQUALIFIED_NAME; if (DECL_NAME (t) == NULL_TREE) { if (!(pp->flags & pp_c_flag_gnu_v3)) pp_cxx_ws_string (pp, M_("{anonymous}")); else pp_cxx_ws_string (pp, M_("(anonymous namespace)")); } else pp_cxx_tree_identifier (pp, DECL_NAME (t)); } break; case SCOPE_REF: dump_type (pp, TREE_OPERAND (t, 0), flags); pp_cxx_colon_colon (pp); dump_decl (pp, TREE_OPERAND (t, 1), TFF_UNQUALIFIED_NAME); break; case ARRAY_REF: dump_decl (pp, TREE_OPERAND (t, 0), flags); pp_cxx_left_bracket (pp); dump_decl (pp, TREE_OPERAND (t, 1), flags); pp_cxx_right_bracket (pp); break; /* So that we can do dump_decl on an aggr type. */ case RECORD_TYPE: case UNION_TYPE: case ENUMERAL_TYPE: dump_type (pp, t, flags); break; case BIT_NOT_EXPR: /* This is a pseudo destructor call which has not been folded into a PSEUDO_DTOR_EXPR yet. */ pp_cxx_complement (pp); dump_type (pp, TREE_OPERAND (t, 0), flags); break; case TYPE_EXPR: gcc_unreachable (); break; case IDENTIFIER_NODE: dump_decl_name (pp, t, flags); break; case OVERLOAD: if (!OVL_SINGLE_P (t)) { tree ctx = ovl_scope (t); if (ctx != global_namespace) { if (TYPE_P (ctx)) dump_type (pp, ctx, flags); else dump_decl (pp, ctx, flags); pp_cxx_colon_colon (pp); } dump_decl (pp, OVL_NAME (t), flags); break; } /* If there's only one function, just treat it like an ordinary FUNCTION_DECL. */ t = OVL_FIRST (t); /* Fall through. */ case FUNCTION_DECL: if (! DECL_LANG_SPECIFIC (t)) { if (DECL_ABSTRACT_ORIGIN (t) && DECL_ABSTRACT_ORIGIN (t) != t) dump_decl (pp, DECL_ABSTRACT_ORIGIN (t), flags); else dump_function_name (pp, t, flags); } else if (DECL_GLOBAL_CTOR_P (t) || DECL_GLOBAL_DTOR_P (t)) dump_global_iord (pp, t); else dump_function_decl (pp, t, flags); break; case TEMPLATE_DECL: dump_template_decl (pp, t, flags); break; case CONCEPT_DECL: pp_cxx_ws_string (pp, "concept"); dump_decl_name (pp, DECL_NAME (t), flags); break; case WILDCARD_DECL: pp_string (pp, ""); break; case TEMPLATE_ID_EXPR: { tree name = TREE_OPERAND (t, 0); tree args = TREE_OPERAND (t, 1); if (!identifier_p (name)) name = OVL_NAME (name); dump_decl (pp, name, flags); pp_cxx_begin_template_argument_list (pp); if (args == error_mark_node) pp_string (pp, M_("