| /* Implementation of subroutines for the GNU C++ pretty-printer. |
| Copyright (C) 2003-2021 Free Software Foundation, Inc. |
| Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net> |
| |
| 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 |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "cp-tree.h" |
| #include "cxx-pretty-print.h" |
| #include "tree-pretty-print.h" |
| |
| static void pp_cxx_unqualified_id (cxx_pretty_printer *, tree); |
| static void pp_cxx_nested_name_specifier (cxx_pretty_printer *, tree); |
| static void pp_cxx_qualified_id (cxx_pretty_printer *, tree); |
| static void pp_cxx_template_argument_list (cxx_pretty_printer *, tree); |
| static void pp_cxx_type_specifier_seq (cxx_pretty_printer *, tree); |
| static void pp_cxx_ptr_operator (cxx_pretty_printer *, tree); |
| static void pp_cxx_parameter_declaration_clause (cxx_pretty_printer *, tree); |
| static void pp_cxx_template_parameter (cxx_pretty_printer *, tree); |
| static void pp_cxx_cast_expression (cxx_pretty_printer *, tree); |
| static void pp_cxx_typeid_expression (cxx_pretty_printer *, tree); |
| static void pp_cxx_unary_left_fold_expression (cxx_pretty_printer *, tree); |
| static void pp_cxx_unary_right_fold_expression (cxx_pretty_printer *, tree); |
| static void pp_cxx_binary_fold_expression (cxx_pretty_printer *, tree); |
| static void pp_cxx_concept_definition (cxx_pretty_printer *, tree); |
| |
| |
| static inline void |
| pp_cxx_nonconsecutive_character (cxx_pretty_printer *pp, int c) |
| { |
| const char *p = pp_last_position_in_text (pp); |
| |
| if (p != NULL && *p == c) |
| pp_cxx_whitespace (pp); |
| pp_character (pp, c); |
| pp->padding = pp_none; |
| } |
| |
| #define pp_cxx_expression_list(PP, T) \ |
| pp_c_expression_list (PP, T) |
| #define pp_cxx_space_for_pointer_operator(PP, T) \ |
| pp_c_space_for_pointer_operator (PP, T) |
| #define pp_cxx_init_declarator(PP, T) \ |
| pp_c_init_declarator (PP, T) |
| #define pp_cxx_call_argument_list(PP, T) \ |
| pp_c_call_argument_list (PP, T) |
| |
| void |
| pp_cxx_colon_colon (cxx_pretty_printer *pp) |
| { |
| pp_colon_colon (pp); |
| pp->padding = pp_none; |
| } |
| |
| void |
| pp_cxx_begin_template_argument_list (cxx_pretty_printer *pp) |
| { |
| pp_cxx_nonconsecutive_character (pp, '<'); |
| } |
| |
| void |
| pp_cxx_end_template_argument_list (cxx_pretty_printer *pp) |
| { |
| pp_cxx_nonconsecutive_character (pp, '>'); |
| } |
| |
| void |
| pp_cxx_separate_with (cxx_pretty_printer *pp, int c) |
| { |
| pp_separate_with (pp, c); |
| pp->padding = pp_none; |
| } |
| |
| /* Expressions. */ |
| |
| /* conversion-function-id: |
| operator conversion-type-id |
| |
| conversion-type-id: |
| type-specifier-seq conversion-declarator(opt) |
| |
| conversion-declarator: |
| ptr-operator conversion-declarator(opt) */ |
| |
| static inline void |
| pp_cxx_conversion_function_id (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_ws_string (pp, "operator"); |
| pp_cxx_type_specifier_seq (pp, TREE_TYPE (t)); |
| } |
| |
| static inline void |
| pp_cxx_template_id (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_unqualified_id (pp, TREE_OPERAND (t, 0)); |
| pp_cxx_begin_template_argument_list (pp); |
| pp_cxx_template_argument_list (pp, TREE_OPERAND (t, 1)); |
| pp_cxx_end_template_argument_list (pp); |
| } |
| |
| /* Prints the unqualified part of the id-expression T. |
| |
| unqualified-id: |
| identifier |
| operator-function-id |
| conversion-function-id |
| ~ class-name |
| template-id */ |
| |
| static void |
| pp_cxx_unqualified_id (cxx_pretty_printer *pp, tree t) |
| { |
| enum tree_code code = TREE_CODE (t); |
| switch (code) |
| { |
| case RESULT_DECL: |
| pp->translate_string ("<return-value>"); |
| break; |
| |
| case OVERLOAD: |
| t = OVL_FIRST (t); |
| /* FALLTHRU */ |
| case VAR_DECL: |
| case PARM_DECL: |
| case CONST_DECL: |
| case TYPE_DECL: |
| case FUNCTION_DECL: |
| case NAMESPACE_DECL: |
| case FIELD_DECL: |
| case LABEL_DECL: |
| case USING_DECL: |
| case TEMPLATE_DECL: |
| t = DECL_NAME (t); |
| /* FALLTHRU */ |
| |
| case IDENTIFIER_NODE: |
| if (t == NULL) |
| pp->translate_string ("<unnamed>"); |
| else if (IDENTIFIER_CONV_OP_P (t)) |
| pp_cxx_conversion_function_id (pp, t); |
| else |
| pp_cxx_tree_identifier (pp, t); |
| break; |
| |
| case TEMPLATE_ID_EXPR: |
| pp_cxx_template_id (pp, t); |
| break; |
| |
| case BASELINK: |
| pp_cxx_unqualified_id (pp, BASELINK_FUNCTIONS (t)); |
| break; |
| |
| case RECORD_TYPE: |
| case UNION_TYPE: |
| case ENUMERAL_TYPE: |
| case TYPENAME_TYPE: |
| case UNBOUND_CLASS_TEMPLATE: |
| pp_cxx_unqualified_id (pp, TYPE_NAME (t)); |
| if (tree ti = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (t)) |
| if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti))) |
| { |
| pp_cxx_begin_template_argument_list (pp); |
| tree args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (ti)); |
| pp_cxx_template_argument_list (pp, args); |
| pp_cxx_end_template_argument_list (pp); |
| } |
| break; |
| |
| case BIT_NOT_EXPR: |
| pp_cxx_complement (pp); |
| pp_cxx_unqualified_id (pp, TREE_OPERAND (t, 0)); |
| break; |
| |
| case TEMPLATE_TYPE_PARM: |
| case TEMPLATE_TEMPLATE_PARM: |
| if (template_placeholder_p (t)) |
| { |
| t = TREE_TYPE (CLASS_PLACEHOLDER_TEMPLATE (t)); |
| pp_cxx_unqualified_id (pp, TYPE_IDENTIFIER (t)); |
| pp_string (pp, "<...auto...>"); |
| } |
| else if (TYPE_IDENTIFIER (t)) |
| pp_cxx_unqualified_id (pp, TYPE_IDENTIFIER (t)); |
| else |
| pp_cxx_canonical_template_parameter (pp, t); |
| break; |
| |
| case TEMPLATE_PARM_INDEX: |
| pp_cxx_unqualified_id (pp, TEMPLATE_PARM_DECL (t)); |
| break; |
| |
| case BOUND_TEMPLATE_TEMPLATE_PARM: |
| pp_cxx_cv_qualifier_seq (pp, t); |
| pp_cxx_unqualified_id (pp, TYPE_IDENTIFIER (t)); |
| pp_cxx_begin_template_argument_list (pp); |
| pp_cxx_template_argument_list (pp, TYPE_TI_ARGS (t)); |
| pp_cxx_end_template_argument_list (pp); |
| break; |
| |
| default: |
| pp_unsupported_tree (pp, t); |
| break; |
| } |
| } |
| |
| /* Pretty-print out the token sequence ":: template" in template codes |
| where it is needed to "inline declare" the (following) member as |
| a template. This situation arises when SCOPE of T is dependent |
| on template parameters. */ |
| |
| static inline void |
| pp_cxx_template_keyword_if_needed (cxx_pretty_printer *pp, tree scope, tree t) |
| { |
| if (TREE_CODE (t) == TEMPLATE_ID_EXPR |
| && TYPE_P (scope) && dependent_type_p (scope)) |
| pp_cxx_ws_string (pp, "template"); |
| } |
| |
| /* nested-name-specifier: |
| class-or-namespace-name :: nested-name-specifier(opt) |
| class-or-namespace-name :: template nested-name-specifier */ |
| |
| static void |
| pp_cxx_nested_name_specifier (cxx_pretty_printer *pp, tree t) |
| { |
| /* FIXME: When diagnosing references to concepts (especially as types?) |
| we end up adding too many '::' to the name. This is partially due |
| to the fact that pp->enclosing_namespace is null. */ |
| if (t == global_namespace) |
| { |
| pp_cxx_colon_colon (pp); |
| } |
| else if (!SCOPE_FILE_SCOPE_P (t) && t != pp->enclosing_scope) |
| { |
| tree scope = get_containing_scope (t); |
| pp_cxx_nested_name_specifier (pp, scope); |
| pp_cxx_template_keyword_if_needed (pp, scope, t); |
| pp_cxx_unqualified_id (pp, t); |
| pp_cxx_colon_colon (pp); |
| } |
| } |
| |
| /* qualified-id: |
| nested-name-specifier template(opt) unqualified-id */ |
| |
| static void |
| pp_cxx_qualified_id (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| /* A pointer-to-member is always qualified. */ |
| case PTRMEM_CST: |
| pp_cxx_nested_name_specifier (pp, PTRMEM_CST_CLASS (t)); |
| pp_cxx_unqualified_id (pp, PTRMEM_CST_MEMBER (t)); |
| break; |
| |
| /* In Standard C++, functions cannot possibly be used as |
| nested-name-specifiers. However, there are situations where |
| is "makes sense" to output the surrounding function name for the |
| purpose of emphasizing on the scope kind. Just printing the |
| function name might not be sufficient as it may be overloaded; so, |
| we decorate the function with its signature too. |
| FIXME: This is probably the wrong pretty-printing for conversion |
| functions and some function templates. */ |
| case OVERLOAD: |
| t = OVL_FIRST (t); |
| /* FALLTHRU */ |
| case FUNCTION_DECL: |
| if (DECL_FUNCTION_MEMBER_P (t)) |
| pp_cxx_nested_name_specifier (pp, DECL_CONTEXT (t)); |
| pp_cxx_unqualified_id |
| (pp, DECL_CONSTRUCTOR_P (t) ? DECL_CONTEXT (t) : t); |
| pp_cxx_parameter_declaration_clause (pp, TREE_TYPE (t)); |
| break; |
| |
| case OFFSET_REF: |
| case SCOPE_REF: |
| pp_cxx_nested_name_specifier (pp, TREE_OPERAND (t, 0)); |
| pp_cxx_unqualified_id (pp, TREE_OPERAND (t, 1)); |
| break; |
| |
| default: |
| { |
| tree scope = get_containing_scope (t); |
| if (scope != pp->enclosing_scope) |
| { |
| pp_cxx_nested_name_specifier (pp, scope); |
| pp_cxx_template_keyword_if_needed (pp, scope, t); |
| } |
| pp_cxx_unqualified_id (pp, t); |
| } |
| break; |
| } |
| } |
| |
| /* Given a value e of ENUMERAL_TYPE: |
| Print out the first ENUMERATOR id with value e, if one is found, |
| (including nested names but excluding the enum name if unscoped) |
| else print out the value as a C-style cast (type-id)value. */ |
| |
| static void |
| pp_cxx_enumeration_constant (cxx_pretty_printer *pp, tree e) |
| { |
| tree type = TREE_TYPE (e); |
| tree value = NULL_TREE; |
| |
| /* Find the name of this constant. */ |
| if ((pp->flags & pp_c_flag_gnu_v3) == 0) |
| for (value = TYPE_VALUES (type); value != NULL_TREE; |
| value = TREE_CHAIN (value)) |
| if (tree_int_cst_equal (DECL_INITIAL (TREE_VALUE (value)), e)) |
| break; |
| |
| if (value != NULL_TREE) |
| { |
| if (!ENUM_IS_SCOPED (type)) |
| type = get_containing_scope (type); |
| pp_cxx_nested_name_specifier (pp, type); |
| pp->id_expression (TREE_PURPOSE (value)); |
| } |
| else |
| { |
| /* Value must have been cast. */ |
| pp_c_type_cast (pp, type); |
| pp_c_integer_constant (pp, e); |
| } |
| } |
| |
| |
| void |
| cxx_pretty_printer::constant (tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case STRING_CST: |
| { |
| const bool in_parens = PAREN_STRING_LITERAL_P (t); |
| if (in_parens) |
| pp_cxx_left_paren (this); |
| c_pretty_printer::constant (t); |
| if (in_parens) |
| pp_cxx_right_paren (this); |
| } |
| break; |
| |
| case INTEGER_CST: |
| if (NULLPTR_TYPE_P (TREE_TYPE (t))) |
| { |
| pp_string (this, "nullptr"); |
| break; |
| } |
| else if (TREE_CODE (TREE_TYPE (t)) == ENUMERAL_TYPE) |
| { |
| pp_cxx_enumeration_constant (this, t); |
| break; |
| } |
| /* fall through. */ |
| |
| default: |
| c_pretty_printer::constant (t); |
| break; |
| } |
| } |
| |
| /* id-expression: |
| unqualified-id |
| qualified-id */ |
| |
| void |
| cxx_pretty_printer::id_expression (tree t) |
| { |
| if (TREE_CODE (t) == OVERLOAD) |
| t = OVL_FIRST (t); |
| if (DECL_P (t) && DECL_CONTEXT (t)) |
| pp_cxx_qualified_id (this, t); |
| else |
| pp_cxx_unqualified_id (this, t); |
| } |
| |
| /* user-defined literal: |
| literal ud-suffix */ |
| |
| void |
| pp_cxx_userdef_literal (cxx_pretty_printer *pp, tree t) |
| { |
| pp->constant (USERDEF_LITERAL_VALUE (t)); |
| pp->id_expression (USERDEF_LITERAL_SUFFIX_ID (t)); |
| } |
| |
| |
| /* primary-expression: |
| literal |
| this |
| :: identifier |
| :: operator-function-id |
| :: qualifier-id |
| ( expression ) |
| id-expression |
| |
| GNU Extensions: |
| __builtin_va_arg ( assignment-expression , type-id ) |
| __builtin_offsetof ( type-id, offsetof-expression ) |
| __builtin_addressof ( expression ) |
| |
| __has_nothrow_assign ( type-id ) |
| __has_nothrow_constructor ( type-id ) |
| __has_nothrow_copy ( type-id ) |
| __has_trivial_assign ( type-id ) |
| __has_trivial_constructor ( type-id ) |
| __has_trivial_copy ( type-id ) |
| __has_unique_object_representations ( type-id ) |
| __has_trivial_destructor ( type-id ) |
| __has_virtual_destructor ( type-id ) |
| __is_abstract ( type-id ) |
| __is_base_of ( type-id , type-id ) |
| __is_class ( type-id ) |
| __is_empty ( type-id ) |
| __is_enum ( type-id ) |
| __is_literal_type ( type-id ) |
| __is_pod ( type-id ) |
| __is_polymorphic ( type-id ) |
| __is_std_layout ( type-id ) |
| __is_trivial ( type-id ) |
| __is_union ( type-id ) */ |
| |
| void |
| cxx_pretty_printer::primary_expression (tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case VOID_CST: |
| case INTEGER_CST: |
| case REAL_CST: |
| case COMPLEX_CST: |
| case STRING_CST: |
| constant (t); |
| break; |
| |
| case USERDEF_LITERAL: |
| pp_cxx_userdef_literal (this, t); |
| break; |
| |
| case BASELINK: |
| t = BASELINK_FUNCTIONS (t); |
| /* FALLTHRU */ |
| case VAR_DECL: |
| case PARM_DECL: |
| case FIELD_DECL: |
| case FUNCTION_DECL: |
| case OVERLOAD: |
| case CONST_DECL: |
| case TEMPLATE_DECL: |
| id_expression (t); |
| break; |
| |
| case RESULT_DECL: |
| case TEMPLATE_TYPE_PARM: |
| case TEMPLATE_TEMPLATE_PARM: |
| case TEMPLATE_PARM_INDEX: |
| pp_cxx_unqualified_id (this, t); |
| break; |
| |
| case STMT_EXPR: |
| pp_cxx_left_paren (this); |
| statement (STMT_EXPR_STMT (t)); |
| pp_cxx_right_paren (this); |
| break; |
| |
| case TRAIT_EXPR: |
| pp_cxx_trait_expression (this, t); |
| break; |
| |
| case VA_ARG_EXPR: |
| pp_cxx_va_arg_expression (this, t); |
| break; |
| |
| case OFFSETOF_EXPR: |
| pp_cxx_offsetof_expression (this, t); |
| break; |
| |
| case ADDRESSOF_EXPR: |
| pp_cxx_addressof_expression (this, t); |
| break; |
| |
| case REQUIRES_EXPR: |
| pp_cxx_requires_expr (this, t); |
| break; |
| |
| default: |
| c_pretty_printer::primary_expression (t); |
| break; |
| } |
| } |
| |
| /* postfix-expression: |
| primary-expression |
| postfix-expression [ expression ] |
| postfix-expression ( expression-list(opt) ) |
| simple-type-specifier ( expression-list(opt) ) |
| typename ::(opt) nested-name-specifier identifier ( expression-list(opt) ) |
| typename ::(opt) nested-name-specifier template(opt) |
| template-id ( expression-list(opt) ) |
| postfix-expression . template(opt) ::(opt) id-expression |
| postfix-expression -> template(opt) ::(opt) id-expression |
| postfix-expression . pseudo-destructor-name |
| postfix-expression -> pseudo-destructor-name |
| postfix-expression ++ |
| postfix-expression -- |
| dynamic_cast < type-id > ( expression ) |
| static_cast < type-id > ( expression ) |
| reinterpret_cast < type-id > ( expression ) |
| const_cast < type-id > ( expression ) |
| typeid ( expression ) |
| typeid ( type-id ) */ |
| |
| void |
| cxx_pretty_printer::postfix_expression (tree t) |
| { |
| enum tree_code code = TREE_CODE (t); |
| |
| switch (code) |
| { |
| case AGGR_INIT_EXPR: |
| case CALL_EXPR: |
| { |
| tree fun = cp_get_callee (t); |
| tree saved_scope = enclosing_scope; |
| bool skipfirst = false; |
| tree arg; |
| |
| if (TREE_CODE (fun) == ADDR_EXPR) |
| fun = TREE_OPERAND (fun, 0); |
| |
| /* In templates, where there is no way to tell whether a given |
| call uses an actual member function. So the parser builds |
| FUN as a COMPONENT_REF or a plain IDENTIFIER_NODE until |
| instantiation time. */ |
| if (TREE_CODE (fun) != FUNCTION_DECL) |
| ; |
| else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)) |
| { |
| tree object = (code == AGGR_INIT_EXPR |
| ? (AGGR_INIT_VIA_CTOR_P (t) |
| ? AGGR_INIT_EXPR_SLOT (t) |
| : AGGR_INIT_EXPR_ARG (t, 0)) |
| : CALL_EXPR_ARG (t, 0)); |
| |
| while (TREE_CODE (object) == NOP_EXPR) |
| object = TREE_OPERAND (object, 0); |
| |
| if (TREE_CODE (object) == ADDR_EXPR) |
| object = TREE_OPERAND (object, 0); |
| |
| if (!TYPE_PTR_P (TREE_TYPE (object))) |
| { |
| postfix_expression (object); |
| pp_cxx_dot (this); |
| } |
| else |
| { |
| postfix_expression (object); |
| pp_cxx_arrow (this); |
| } |
| skipfirst = true; |
| enclosing_scope = strip_pointer_operator (TREE_TYPE (object)); |
| } |
| |
| postfix_expression (fun); |
| enclosing_scope = saved_scope; |
| pp_cxx_left_paren (this); |
| if (code == AGGR_INIT_EXPR) |
| { |
| aggr_init_expr_arg_iterator iter; |
| FOR_EACH_AGGR_INIT_EXPR_ARG (arg, iter, t) |
| { |
| if (skipfirst) |
| skipfirst = false; |
| else |
| { |
| expression (arg); |
| if (more_aggr_init_expr_args_p (&iter)) |
| pp_cxx_separate_with (this, ','); |
| } |
| } |
| } |
| else |
| { |
| call_expr_arg_iterator iter; |
| FOR_EACH_CALL_EXPR_ARG (arg, iter, t) |
| { |
| if (skipfirst) |
| skipfirst = false; |
| else |
| { |
| expression (arg); |
| if (more_call_expr_args_p (&iter)) |
| pp_cxx_separate_with (this, ','); |
| } |
| } |
| } |
| pp_cxx_right_paren (this); |
| } |
| if (code == AGGR_INIT_EXPR && AGGR_INIT_VIA_CTOR_P (t)) |
| { |
| pp_cxx_separate_with (this, ','); |
| postfix_expression (AGGR_INIT_EXPR_SLOT (t)); |
| } |
| break; |
| |
| case BASELINK: |
| case VAR_DECL: |
| case PARM_DECL: |
| case FIELD_DECL: |
| case FUNCTION_DECL: |
| case OVERLOAD: |
| case CONST_DECL: |
| case TEMPLATE_DECL: |
| case RESULT_DECL: |
| primary_expression (t); |
| break; |
| |
| case DYNAMIC_CAST_EXPR: |
| case STATIC_CAST_EXPR: |
| case REINTERPRET_CAST_EXPR: |
| case CONST_CAST_EXPR: |
| if (code == DYNAMIC_CAST_EXPR) |
| pp_cxx_ws_string (this, "dynamic_cast"); |
| else if (code == STATIC_CAST_EXPR) |
| pp_cxx_ws_string (this, "static_cast"); |
| else if (code == REINTERPRET_CAST_EXPR) |
| pp_cxx_ws_string (this, "reinterpret_cast"); |
| else |
| pp_cxx_ws_string (this, "const_cast"); |
| pp_cxx_begin_template_argument_list (this); |
| type_id (TREE_TYPE (t)); |
| pp_cxx_end_template_argument_list (this); |
| pp_left_paren (this); |
| expression (TREE_OPERAND (t, 0)); |
| pp_right_paren (this); |
| break; |
| |
| case BIT_CAST_EXPR: |
| pp_cxx_ws_string (this, "__builtin_bit_cast"); |
| pp_left_paren (this); |
| type_id (TREE_TYPE (t)); |
| pp_comma (this); |
| expression (TREE_OPERAND (t, 0)); |
| pp_right_paren (this); |
| break; |
| |
| case EMPTY_CLASS_EXPR: |
| type_id (TREE_TYPE (t)); |
| pp_left_paren (this); |
| pp_right_paren (this); |
| break; |
| |
| case TYPEID_EXPR: |
| pp_cxx_typeid_expression (this, t); |
| break; |
| |
| case PSEUDO_DTOR_EXPR: |
| postfix_expression (TREE_OPERAND (t, 0)); |
| pp_cxx_dot (this); |
| if (TREE_OPERAND (t, 1)) |
| { |
| pp_cxx_qualified_id (this, TREE_OPERAND (t, 1)); |
| pp_cxx_colon_colon (this); |
| } |
| pp_complement (this); |
| pp_cxx_unqualified_id (this, TREE_OPERAND (t, 2)); |
| break; |
| |
| case ARROW_EXPR: |
| postfix_expression (TREE_OPERAND (t, 0)); |
| pp_cxx_arrow (this); |
| break; |
| |
| default: |
| c_pretty_printer::postfix_expression (t); |
| break; |
| } |
| } |
| |
| /* new-expression: |
| ::(opt) new new-placement(opt) new-type-id new-initializer(opt) |
| ::(opt) new new-placement(opt) ( type-id ) new-initializer(opt) |
| |
| new-placement: |
| ( expression-list ) |
| |
| new-type-id: |
| type-specifier-seq new-declarator(opt) |
| |
| new-declarator: |
| ptr-operator new-declarator(opt) |
| direct-new-declarator |
| |
| direct-new-declarator |
| [ expression ] |
| direct-new-declarator [ constant-expression ] |
| |
| new-initializer: |
| ( expression-list(opt) ) */ |
| |
| static void |
| pp_cxx_new_expression (cxx_pretty_printer *pp, tree t) |
| { |
| enum tree_code code = TREE_CODE (t); |
| tree type = TREE_OPERAND (t, 1); |
| tree init = TREE_OPERAND (t, 2); |
| switch (code) |
| { |
| case NEW_EXPR: |
| case VEC_NEW_EXPR: |
| if (NEW_EXPR_USE_GLOBAL (t)) |
| pp_cxx_colon_colon (pp); |
| pp_cxx_ws_string (pp, "new"); |
| if (TREE_OPERAND (t, 0)) |
| { |
| pp_cxx_call_argument_list (pp, TREE_OPERAND (t, 0)); |
| pp_space (pp); |
| } |
| if (TREE_CODE (type) == ARRAY_REF) |
| type = build_cplus_array_type |
| (TREE_OPERAND (type, 0), |
| build_index_type (fold_build2_loc (input_location, |
| MINUS_EXPR, integer_type_node, |
| TREE_OPERAND (type, 1), |
| integer_one_node))); |
| pp->type_id (type); |
| if (init) |
| { |
| pp_left_paren (pp); |
| if (TREE_CODE (init) == TREE_LIST) |
| pp_c_expression_list (pp, init); |
| else if (init == void_node) |
| ; /* OK, empty initializer list. */ |
| else |
| pp->expression (init); |
| pp_right_paren (pp); |
| } |
| break; |
| |
| default: |
| pp_unsupported_tree (pp, t); |
| } |
| } |
| |
| /* delete-expression: |
| ::(opt) delete cast-expression |
| ::(opt) delete [ ] cast-expression */ |
| |
| static void |
| pp_cxx_delete_expression (cxx_pretty_printer *pp, tree t) |
| { |
| enum tree_code code = TREE_CODE (t); |
| switch (code) |
| { |
| case DELETE_EXPR: |
| case VEC_DELETE_EXPR: |
| if (DELETE_EXPR_USE_GLOBAL (t)) |
| pp_cxx_colon_colon (pp); |
| pp_cxx_ws_string (pp, "delete"); |
| pp_space (pp); |
| if (code == VEC_DELETE_EXPR |
| || DELETE_EXPR_USE_VEC (t)) |
| { |
| pp_left_bracket (pp); |
| pp_right_bracket (pp); |
| pp_space (pp); |
| } |
| pp_c_cast_expression (pp, TREE_OPERAND (t, 0)); |
| break; |
| |
| default: |
| pp_unsupported_tree (pp, t); |
| } |
| } |
| |
| /* unary-expression: |
| postfix-expression |
| ++ cast-expression |
| -- cast-expression |
| unary-operator cast-expression |
| sizeof unary-expression |
| sizeof ( type-id ) |
| sizeof ... ( identifier ) |
| new-expression |
| delete-expression |
| |
| unary-operator: one of |
| * & + - ! |
| |
| GNU extensions: |
| __alignof__ unary-expression |
| __alignof__ ( type-id ) */ |
| |
| void |
| cxx_pretty_printer::unary_expression (tree t) |
| { |
| enum tree_code code = TREE_CODE (t); |
| switch (code) |
| { |
| case NEW_EXPR: |
| case VEC_NEW_EXPR: |
| pp_cxx_new_expression (this, t); |
| break; |
| |
| case DELETE_EXPR: |
| case VEC_DELETE_EXPR: |
| pp_cxx_delete_expression (this, t); |
| break; |
| |
| case SIZEOF_EXPR: |
| if (PACK_EXPANSION_P (TREE_OPERAND (t, 0))) |
| { |
| pp_cxx_ws_string (this, "sizeof"); |
| pp_cxx_ws_string (this, "..."); |
| pp_cxx_whitespace (this); |
| pp_cxx_left_paren (this); |
| if (TYPE_P (TREE_OPERAND (t, 0))) |
| type_id (TREE_OPERAND (t, 0)); |
| else |
| unary_expression (TREE_OPERAND (t, 0)); |
| pp_cxx_right_paren (this); |
| break; |
| } |
| /* Fall through */ |
| |
| case ALIGNOF_EXPR: |
| pp_cxx_ws_string (this, code == SIZEOF_EXPR ? "sizeof" : "__alignof__"); |
| pp_cxx_whitespace (this); |
| if (TREE_CODE (t) == SIZEOF_EXPR && SIZEOF_EXPR_TYPE_P (t)) |
| { |
| pp_cxx_left_paren (this); |
| type_id (TREE_TYPE (TREE_OPERAND (t, 0))); |
| pp_cxx_right_paren (this); |
| } |
| else if (TYPE_P (TREE_OPERAND (t, 0))) |
| { |
| pp_cxx_left_paren (this); |
| type_id (TREE_OPERAND (t, 0)); |
| pp_cxx_right_paren (this); |
| } |
| else |
| unary_expression (TREE_OPERAND (t, 0)); |
| break; |
| |
| case AT_ENCODE_EXPR: |
| pp_cxx_ws_string (this, "@encode"); |
| pp_cxx_whitespace (this); |
| pp_cxx_left_paren (this); |
| type_id (TREE_OPERAND (t, 0)); |
| pp_cxx_right_paren (this); |
| break; |
| |
| case NOEXCEPT_EXPR: |
| pp_cxx_ws_string (this, "noexcept"); |
| pp_cxx_whitespace (this); |
| pp_cxx_left_paren (this); |
| expression (TREE_OPERAND (t, 0)); |
| pp_cxx_right_paren (this); |
| break; |
| |
| case UNARY_PLUS_EXPR: |
| pp_plus (this); |
| pp_cxx_cast_expression (this, TREE_OPERAND (t, 0)); |
| break; |
| |
| default: |
| c_pretty_printer::unary_expression (t); |
| break; |
| } |
| } |
| |
| /* cast-expression: |
| unary-expression |
| ( type-id ) cast-expression */ |
| |
| static void |
| pp_cxx_cast_expression (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case CAST_EXPR: |
| case IMPLICIT_CONV_EXPR: |
| pp->type_id (TREE_TYPE (t)); |
| pp_cxx_call_argument_list (pp, TREE_OPERAND (t, 0)); |
| break; |
| |
| default: |
| pp_c_cast_expression (pp, t); |
| break; |
| } |
| } |
| |
| /* pm-expression: |
| cast-expression |
| pm-expression .* cast-expression |
| pm-expression ->* cast-expression */ |
| |
| static void |
| pp_cxx_pm_expression (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| /* Handle unfortunate OFFSET_REF overloading here. */ |
| case OFFSET_REF: |
| if (TYPE_P (TREE_OPERAND (t, 0))) |
| { |
| pp_cxx_qualified_id (pp, t); |
| break; |
| } |
| /* Fall through. */ |
| case MEMBER_REF: |
| case DOTSTAR_EXPR: |
| pp_cxx_pm_expression (pp, TREE_OPERAND (t, 0)); |
| if (TREE_CODE (t) == MEMBER_REF) |
| pp_cxx_arrow (pp); |
| else |
| pp_cxx_dot (pp); |
| pp_star(pp); |
| pp_cxx_cast_expression (pp, TREE_OPERAND (t, 1)); |
| break; |
| |
| |
| default: |
| pp_cxx_cast_expression (pp, t); |
| break; |
| } |
| } |
| |
| /* multiplicative-expression: |
| pm-expression |
| multiplicative-expression * pm-expression |
| multiplicative-expression / pm-expression |
| multiplicative-expression % pm-expression */ |
| |
| void |
| cxx_pretty_printer::multiplicative_expression (tree e) |
| { |
| enum tree_code code = TREE_CODE (e); |
| switch (code) |
| { |
| case MULT_EXPR: |
| case TRUNC_DIV_EXPR: |
| case TRUNC_MOD_EXPR: |
| case EXACT_DIV_EXPR: |
| case RDIV_EXPR: |
| multiplicative_expression (TREE_OPERAND (e, 0)); |
| pp_space (this); |
| if (code == MULT_EXPR) |
| pp_star (this); |
| else if (code != TRUNC_MOD_EXPR) |
| pp_slash (this); |
| else |
| pp_modulo (this); |
| pp_space (this); |
| pp_cxx_pm_expression (this, TREE_OPERAND (e, 1)); |
| break; |
| |
| default: |
| pp_cxx_pm_expression (this, e); |
| break; |
| } |
| } |
| |
| /* conditional-expression: |
| logical-or-expression |
| logical-or-expression ? expression : assignment-expression */ |
| |
| void |
| cxx_pretty_printer::conditional_expression (tree e) |
| { |
| if (TREE_CODE (e) == COND_EXPR) |
| { |
| pp_c_logical_or_expression (this, TREE_OPERAND (e, 0)); |
| pp_space (this); |
| pp_question (this); |
| pp_space (this); |
| expression (TREE_OPERAND (e, 1)); |
| pp_space (this); |
| assignment_expression (TREE_OPERAND (e, 2)); |
| } |
| else |
| pp_c_logical_or_expression (this, e); |
| } |
| |
| /* Pretty-print a compound assignment operator token as indicated by T. */ |
| |
| static void |
| pp_cxx_assignment_operator (cxx_pretty_printer *pp, tree t) |
| { |
| const char *op; |
| |
| switch (TREE_CODE (t)) |
| { |
| case NOP_EXPR: |
| op = "="; |
| break; |
| |
| case PLUS_EXPR: |
| op = "+="; |
| break; |
| |
| case MINUS_EXPR: |
| op = "-="; |
| break; |
| |
| case TRUNC_DIV_EXPR: |
| op = "/="; |
| break; |
| |
| case TRUNC_MOD_EXPR: |
| op = "%="; |
| break; |
| |
| default: |
| op = get_tree_code_name (TREE_CODE (t)); |
| break; |
| } |
| |
| pp_cxx_ws_string (pp, op); |
| } |
| |
| |
| /* assignment-expression: |
| conditional-expression |
| logical-or-expression assignment-operator assignment-expression |
| throw-expression |
| |
| throw-expression: |
| throw assignment-expression(opt) |
| |
| assignment-operator: one of |
| = *= /= %= += -= >>= <<= &= ^= |= */ |
| |
| void |
| cxx_pretty_printer::assignment_expression (tree e) |
| { |
| switch (TREE_CODE (e)) |
| { |
| case MODIFY_EXPR: |
| case INIT_EXPR: |
| pp_c_logical_or_expression (this, TREE_OPERAND (e, 0)); |
| pp_space (this); |
| pp_equal (this); |
| pp_space (this); |
| assignment_expression (TREE_OPERAND (e, 1)); |
| break; |
| |
| case THROW_EXPR: |
| pp_cxx_ws_string (this, "throw"); |
| if (TREE_OPERAND (e, 0)) |
| assignment_expression (TREE_OPERAND (e, 0)); |
| break; |
| |
| case MODOP_EXPR: |
| pp_c_logical_or_expression (this, TREE_OPERAND (e, 0)); |
| pp_cxx_assignment_operator (this, TREE_OPERAND (e, 1)); |
| assignment_expression (TREE_OPERAND (e, 2)); |
| break; |
| |
| default: |
| conditional_expression (e); |
| break; |
| } |
| } |
| |
| void |
| cxx_pretty_printer::expression (tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case STRING_CST: |
| case VOID_CST: |
| case INTEGER_CST: |
| case REAL_CST: |
| case COMPLEX_CST: |
| constant (t); |
| break; |
| |
| case USERDEF_LITERAL: |
| pp_cxx_userdef_literal (this, t); |
| break; |
| |
| case RESULT_DECL: |
| pp_cxx_unqualified_id (this, t); |
| break; |
| |
| #if 0 |
| case OFFSET_REF: |
| #endif |
| case SCOPE_REF: |
| case PTRMEM_CST: |
| pp_cxx_qualified_id (this, t); |
| break; |
| |
| case OVERLOAD: |
| t = OVL_FIRST (t); |
| /* FALLTHRU */ |
| case VAR_DECL: |
| case PARM_DECL: |
| case FIELD_DECL: |
| case CONST_DECL: |
| case FUNCTION_DECL: |
| case BASELINK: |
| case TEMPLATE_DECL: |
| case TEMPLATE_TYPE_PARM: |
| case TEMPLATE_PARM_INDEX: |
| case TEMPLATE_TEMPLATE_PARM: |
| case STMT_EXPR: |
| case REQUIRES_EXPR: |
| primary_expression (t); |
| break; |
| |
| case CALL_EXPR: |
| case DYNAMIC_CAST_EXPR: |
| case STATIC_CAST_EXPR: |
| case REINTERPRET_CAST_EXPR: |
| case CONST_CAST_EXPR: |
| #if 0 |
| case MEMBER_REF: |
| #endif |
| case EMPTY_CLASS_EXPR: |
| case TYPEID_EXPR: |
| case PSEUDO_DTOR_EXPR: |
| case AGGR_INIT_EXPR: |
| case ARROW_EXPR: |
| postfix_expression (t); |
| break; |
| |
| case NEW_EXPR: |
| case VEC_NEW_EXPR: |
| pp_cxx_new_expression (this, t); |
| break; |
| |
| case DELETE_EXPR: |
| case VEC_DELETE_EXPR: |
| pp_cxx_delete_expression (this, t); |
| break; |
| |
| case SIZEOF_EXPR: |
| case ALIGNOF_EXPR: |
| case NOEXCEPT_EXPR: |
| case UNARY_PLUS_EXPR: |
| unary_expression (t); |
| break; |
| |
| case CAST_EXPR: |
| case IMPLICIT_CONV_EXPR: |
| pp_cxx_cast_expression (this, t); |
| break; |
| |
| case OFFSET_REF: |
| case MEMBER_REF: |
| case DOTSTAR_EXPR: |
| pp_cxx_pm_expression (this, t); |
| break; |
| |
| case MULT_EXPR: |
| case TRUNC_DIV_EXPR: |
| case TRUNC_MOD_EXPR: |
| case EXACT_DIV_EXPR: |
| case RDIV_EXPR: |
| multiplicative_expression (t); |
| break; |
| |
| case COND_EXPR: |
| conditional_expression (t); |
| break; |
| |
| case MODIFY_EXPR: |
| case INIT_EXPR: |
| case THROW_EXPR: |
| case MODOP_EXPR: |
| assignment_expression (t); |
| break; |
| |
| case NON_DEPENDENT_EXPR: |
| case MUST_NOT_THROW_EXPR: |
| expression (TREE_OPERAND (t, 0)); |
| break; |
| |
| case EXPR_PACK_EXPANSION: |
| expression (PACK_EXPANSION_PATTERN (t)); |
| pp_cxx_ws_string (this, "..."); |
| break; |
| |
| case UNARY_LEFT_FOLD_EXPR: |
| pp_cxx_unary_left_fold_expression (this, t); |
| break; |
| |
| case UNARY_RIGHT_FOLD_EXPR: |
| pp_cxx_unary_right_fold_expression (this, t); |
| break; |
| |
| case BINARY_LEFT_FOLD_EXPR: |
| case BINARY_RIGHT_FOLD_EXPR: |
| pp_cxx_binary_fold_expression (this, t); |
| break; |
| |
| case TEMPLATE_ID_EXPR: |
| pp_cxx_template_id (this, t); |
| break; |
| |
| case NONTYPE_ARGUMENT_PACK: |
| { |
| tree args = ARGUMENT_PACK_ARGS (t); |
| int i, len = TREE_VEC_LENGTH (args); |
| pp_cxx_left_brace (this); |
| for (i = 0; i < len; ++i) |
| { |
| if (i > 0) |
| pp_cxx_separate_with (this, ','); |
| expression (TREE_VEC_ELT (args, i)); |
| } |
| pp_cxx_right_brace (this); |
| } |
| break; |
| |
| case LAMBDA_EXPR: |
| pp_cxx_ws_string (this, "<lambda>"); |
| break; |
| |
| case TRAIT_EXPR: |
| pp_cxx_trait_expression (this, t); |
| break; |
| |
| case ATOMIC_CONSTR: |
| case CHECK_CONSTR: |
| case CONJ_CONSTR: |
| case DISJ_CONSTR: |
| pp_cxx_constraint (this, t); |
| break; |
| |
| case PAREN_EXPR: |
| pp_cxx_left_paren (this); |
| expression (TREE_OPERAND (t, 0)); |
| pp_cxx_right_paren (this); |
| break; |
| |
| default: |
| c_pretty_printer::expression (t); |
| break; |
| } |
| } |
| |
| |
| /* Declarations. */ |
| |
| /* function-specifier: |
| inline |
| virtual |
| explicit */ |
| |
| void |
| cxx_pretty_printer::function_specifier (tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case FUNCTION_DECL: |
| if (DECL_VIRTUAL_P (t)) |
| pp_cxx_ws_string (this, "virtual"); |
| else if (DECL_CONSTRUCTOR_P (t) && DECL_NONCONVERTING_P (t)) |
| pp_cxx_ws_string (this, "explicit"); |
| else |
| c_pretty_printer::function_specifier (t); |
| |
| default: |
| break; |
| } |
| } |
| |
| /* decl-specifier-seq: |
| decl-specifier-seq(opt) decl-specifier |
| |
| decl-specifier: |
| storage-class-specifier |
| type-specifier |
| function-specifier |
| friend |
| typedef */ |
| |
| void |
| cxx_pretty_printer::declaration_specifiers (tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case VAR_DECL: |
| case PARM_DECL: |
| case CONST_DECL: |
| case FIELD_DECL: |
| storage_class_specifier (t); |
| declaration_specifiers (TREE_TYPE (t)); |
| break; |
| |
| case TYPE_DECL: |
| pp_cxx_ws_string (this, "typedef"); |
| declaration_specifiers (TREE_TYPE (t)); |
| break; |
| |
| case FUNCTION_DECL: |
| /* Constructors don't have return types. And conversion functions |
| do not have a type-specifier in their return types. */ |
| if (DECL_CONSTRUCTOR_P (t) || DECL_CONV_FN_P (t)) |
| function_specifier (t); |
| else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (t)) |
| declaration_specifiers (TREE_TYPE (TREE_TYPE (t))); |
| else |
| c_pretty_printer::declaration_specifiers (t); |
| break; |
| default: |
| c_pretty_printer::declaration_specifiers (t); |
| break; |
| } |
| } |
| |
| /* simple-type-specifier: |
| ::(opt) nested-name-specifier(opt) type-name |
| ::(opt) nested-name-specifier(opt) template(opt) template-id |
| decltype-specifier |
| char |
| wchar_t |
| bool |
| short |
| int |
| long |
| signed |
| unsigned |
| float |
| double |
| void */ |
| |
| void |
| cxx_pretty_printer::simple_type_specifier (tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case RECORD_TYPE: |
| case UNION_TYPE: |
| case ENUMERAL_TYPE: |
| pp_cxx_qualified_id (this, t); |
| break; |
| |
| case TEMPLATE_TYPE_PARM: |
| case TEMPLATE_TEMPLATE_PARM: |
| case TEMPLATE_PARM_INDEX: |
| case BOUND_TEMPLATE_TEMPLATE_PARM: |
| pp_cxx_unqualified_id (this, t); |
| if (tree c = PLACEHOLDER_TYPE_CONSTRAINTS (t)) |
| pp_cxx_constrained_type_spec (this, c); |
| break; |
| |
| case TYPENAME_TYPE: |
| pp_cxx_ws_string (this, "typename"); |
| pp_cxx_nested_name_specifier (this, TYPE_CONTEXT (t)); |
| pp_cxx_unqualified_id (this, TYPENAME_TYPE_FULLNAME (t)); |
| break; |
| |
| case DECLTYPE_TYPE: |
| pp_cxx_ws_string (this, "decltype"); |
| pp_cxx_left_paren (this); |
| this->expression (DECLTYPE_TYPE_EXPR (t)); |
| pp_cxx_right_paren (this); |
| break; |
| |
| case NULLPTR_TYPE: |
| pp_cxx_ws_string (this, "std::nullptr_t"); |
| break; |
| |
| default: |
| c_pretty_printer::simple_type_specifier (t); |
| break; |
| } |
| } |
| |
| /* type-specifier-seq: |
| type-specifier type-specifier-seq(opt) |
| |
| type-specifier: |
| simple-type-specifier |
| class-specifier |
| enum-specifier |
| elaborated-type-specifier |
| cv-qualifier */ |
| |
| static void |
| pp_cxx_type_specifier_seq (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case TEMPLATE_DECL: |
| case TEMPLATE_TYPE_PARM: |
| case TEMPLATE_TEMPLATE_PARM: |
| case TYPE_DECL: |
| case BOUND_TEMPLATE_TEMPLATE_PARM: |
| case DECLTYPE_TYPE: |
| case NULLPTR_TYPE: |
| pp_cxx_cv_qualifier_seq (pp, t); |
| pp->simple_type_specifier (t); |
| break; |
| |
| case METHOD_TYPE: |
| pp_cxx_type_specifier_seq (pp, TREE_TYPE (t)); |
| pp_cxx_space_for_pointer_operator (pp, TREE_TYPE (t)); |
| pp_cxx_nested_name_specifier (pp, TYPE_METHOD_BASETYPE (t)); |
| break; |
| |
| case RECORD_TYPE: |
| if (TYPE_PTRMEMFUNC_P (t)) |
| { |
| tree pfm = TYPE_PTRMEMFUNC_FN_TYPE (t); |
| pp->declaration_specifiers (TREE_TYPE (TREE_TYPE (pfm))); |
| pp_cxx_whitespace (pp); |
| pp_cxx_ptr_operator (pp, t); |
| break; |
| } |
| /* fall through */ |
| |
| case OFFSET_TYPE: |
| if (TYPE_PTRDATAMEM_P (t)) |
| { |
| pp_cxx_type_specifier_seq (pp, TREE_TYPE (t)); |
| pp_cxx_whitespace (pp); |
| pp_cxx_ptr_operator (pp, t); |
| break; |
| } |
| /* fall through */ |
| |
| default: |
| if (!(TREE_CODE (t) == FUNCTION_DECL && DECL_CONSTRUCTOR_P (t))) |
| pp_c_specifier_qualifier_list (pp, t); |
| } |
| } |
| |
| /* ptr-operator: |
| * cv-qualifier-seq(opt) |
| & |
| ::(opt) nested-name-specifier * cv-qualifier-seq(opt) */ |
| |
| static void |
| pp_cxx_ptr_operator (cxx_pretty_printer *pp, tree t) |
| { |
| if (!TYPE_P (t) && TREE_CODE (t) != TYPE_DECL) |
| t = TREE_TYPE (t); |
| switch (TREE_CODE (t)) |
| { |
| case REFERENCE_TYPE: |
| case POINTER_TYPE: |
| if (TYPE_PTR_OR_PTRMEM_P (TREE_TYPE (t))) |
| pp_cxx_ptr_operator (pp, TREE_TYPE (t)); |
| pp_c_attributes_display (pp, TYPE_ATTRIBUTES (TREE_TYPE (t))); |
| if (TYPE_PTR_P (t)) |
| { |
| pp_star (pp); |
| pp_cxx_cv_qualifier_seq (pp, t); |
| } |
| else |
| pp_ampersand (pp); |
| break; |
| |
| case RECORD_TYPE: |
| if (TYPE_PTRMEMFUNC_P (t)) |
| { |
| pp_cxx_left_paren (pp); |
| pp_cxx_nested_name_specifier (pp, TYPE_PTRMEMFUNC_OBJECT_TYPE (t)); |
| pp_star (pp); |
| break; |
| } |
| /* FALLTHRU */ |
| case OFFSET_TYPE: |
| if (TYPE_PTRMEM_P (t)) |
| { |
| if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) |
| pp_cxx_left_paren (pp); |
| pp_cxx_nested_name_specifier (pp, TYPE_PTRMEM_CLASS_TYPE (t)); |
| pp_star (pp); |
| pp_cxx_cv_qualifier_seq (pp, t); |
| break; |
| } |
| /* fall through. */ |
| |
| default: |
| pp_unsupported_tree (pp, t); |
| break; |
| } |
| } |
| |
| static inline tree |
| pp_cxx_implicit_parameter_type (tree mf) |
| { |
| return class_of_this_parm (TREE_TYPE (mf)); |
| } |
| |
| /* |
| parameter-declaration: |
| decl-specifier-seq declarator |
| decl-specifier-seq declarator = assignment-expression |
| decl-specifier-seq abstract-declarator(opt) |
| decl-specifier-seq abstract-declarator(opt) assignment-expression */ |
| |
| static inline void |
| pp_cxx_parameter_declaration (cxx_pretty_printer *pp, tree t) |
| { |
| pp->declaration_specifiers (t); |
| if (TYPE_P (t)) |
| pp->abstract_declarator (t); |
| else |
| pp->declarator (t); |
| } |
| |
| /* parameter-declaration-clause: |
| parameter-declaration-list(opt) ...(opt) |
| parameter-declaration-list , ... |
| |
| parameter-declaration-list: |
| parameter-declaration |
| parameter-declaration-list , parameter-declaration */ |
| |
| static void |
| pp_cxx_parameter_declaration_clause (cxx_pretty_printer *pp, tree t) |
| { |
| gcc_assert (FUNC_OR_METHOD_TYPE_P (t) || TREE_CODE (t) == FUNCTION_DECL); |
| tree types, args; |
| if (TYPE_P (t)) |
| { |
| types = TYPE_ARG_TYPES (t); |
| args = NULL_TREE; |
| } |
| else |
| { |
| types = FUNCTION_FIRST_USER_PARMTYPE (t); |
| args = FUNCTION_FIRST_USER_PARM (t); |
| } |
| bool abstract = !args || (pp->flags & pp_c_flag_abstract); |
| |
| /* Skip artificial parameter for non-static member functions. */ |
| if (TREE_CODE (t) == METHOD_TYPE) |
| types = TREE_CHAIN (types); |
| |
| bool first = true; |
| pp_cxx_left_paren (pp); |
| for (; types != void_list_node; types = TREE_CHAIN (types)) |
| { |
| if (!first) |
| pp_cxx_separate_with (pp, ','); |
| first = false; |
| if (!types) |
| { |
| pp_cxx_ws_string (pp, "..."); |
| break; |
| } |
| pp_cxx_parameter_declaration (pp, abstract ? TREE_VALUE (types) : args); |
| if (!abstract && pp->flags & pp_cxx_flag_default_argument) |
| { |
| pp_cxx_whitespace (pp); |
| pp_equal (pp); |
| pp_cxx_whitespace (pp); |
| pp->assignment_expression (TREE_PURPOSE (types)); |
| } |
| if (!abstract) |
| args = TREE_CHAIN (args); |
| } |
| pp_cxx_right_paren (pp); |
| } |
| |
| /* exception-specification: |
| throw ( type-id-list(opt) ) |
| |
| type-id-list |
| type-id |
| type-id-list , type-id */ |
| |
| static void |
| pp_cxx_exception_specification (cxx_pretty_printer *pp, tree t) |
| { |
| tree ex_spec = TYPE_RAISES_EXCEPTIONS (t); |
| bool need_comma = false; |
| |
| if (ex_spec == NULL) |
| return; |
| if (TREE_PURPOSE (ex_spec)) |
| { |
| pp_cxx_ws_string (pp, "noexcept"); |
| pp_cxx_whitespace (pp); |
| pp_cxx_left_paren (pp); |
| if (DEFERRED_NOEXCEPT_SPEC_P (ex_spec)) |
| pp_cxx_ws_string (pp, "<uninstantiated>"); |
| else |
| pp->expression (TREE_PURPOSE (ex_spec)); |
| pp_cxx_right_paren (pp); |
| return; |
| } |
| pp_cxx_ws_string (pp, "throw"); |
| pp_cxx_left_paren (pp); |
| for (; ex_spec && TREE_VALUE (ex_spec); ex_spec = TREE_CHAIN (ex_spec)) |
| { |
| tree type = TREE_VALUE (ex_spec); |
| tree argpack = NULL_TREE; |
| int i, len = 1; |
| |
| if (ARGUMENT_PACK_P (type)) |
| { |
| argpack = ARGUMENT_PACK_ARGS (type); |
| len = TREE_VEC_LENGTH (argpack); |
| } |
| |
| for (i = 0; i < len; ++i) |
| { |
| if (argpack) |
| type = TREE_VEC_ELT (argpack, i); |
| |
| if (need_comma) |
| pp_cxx_separate_with (pp, ','); |
| else |
| need_comma = true; |
| |
| pp->type_id (type); |
| } |
| } |
| pp_cxx_right_paren (pp); |
| } |
| |
| /* direct-declarator: |
| declarator-id |
| direct-declarator ( parameter-declaration-clause ) cv-qualifier-seq(opt) |
| exception-specification(opt) |
| direct-declaration [ constant-expression(opt) ] |
| ( declarator ) */ |
| |
| void |
| cxx_pretty_printer::direct_declarator (tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case VAR_DECL: |
| case PARM_DECL: |
| case CONST_DECL: |
| case FIELD_DECL: |
| if (DECL_NAME (t)) |
| { |
| pp_cxx_space_for_pointer_operator (this, TREE_TYPE (t)); |
| |
| if ((TREE_CODE (t) == PARM_DECL && DECL_PACK_P (t)) |
| || template_parameter_pack_p (t)) |
| /* A function parameter pack or non-type template |
| parameter pack. */ |
| pp_cxx_ws_string (this, "..."); |
| |
| id_expression (DECL_NAME (t)); |
| } |
| abstract_declarator (TREE_TYPE (t)); |
| break; |
| |
| case FUNCTION_DECL: |
| pp_cxx_space_for_pointer_operator (this, TREE_TYPE (TREE_TYPE (t))); |
| expression (t); |
| pp_cxx_parameter_declaration_clause (this, t); |
| |
| if (DECL_NONSTATIC_MEMBER_FUNCTION_P (t)) |
| { |
| padding = pp_before; |
| pp_cxx_cv_qualifier_seq (this, pp_cxx_implicit_parameter_type (t)); |
| } |
| |
| pp_cxx_exception_specification (this, TREE_TYPE (t)); |
| break; |
| |
| case TYPENAME_TYPE: |
| case TEMPLATE_DECL: |
| case TEMPLATE_TYPE_PARM: |
| case TEMPLATE_PARM_INDEX: |
| case TEMPLATE_TEMPLATE_PARM: |
| break; |
| |
| default: |
| c_pretty_printer::direct_declarator (t); |
| break; |
| } |
| } |
| |
| /* declarator: |
| direct-declarator |
| ptr-operator declarator */ |
| |
| void |
| cxx_pretty_printer::declarator (tree t) |
| { |
| direct_declarator (t); |
| |
| // Print a requires clause. |
| if (flag_concepts) |
| if (tree ci = get_constraints (t)) |
| if (tree reqs = CI_DECLARATOR_REQS (ci)) |
| pp_cxx_requires_clause (this, reqs); |
| } |
| |
| /* ctor-initializer: |
| : mem-initializer-list |
| |
| mem-initializer-list: |
| mem-initializer |
| mem-initializer , mem-initializer-list |
| |
| mem-initializer: |
| mem-initializer-id ( expression-list(opt) ) |
| |
| mem-initializer-id: |
| ::(opt) nested-name-specifier(opt) class-name |
| identifier */ |
| |
| static void |
| pp_cxx_ctor_initializer (cxx_pretty_printer *pp, tree t) |
| { |
| t = TREE_OPERAND (t, 0); |
| pp_cxx_whitespace (pp); |
| pp_colon (pp); |
| pp_cxx_whitespace (pp); |
| for (; t; t = TREE_CHAIN (t)) |
| { |
| tree purpose = TREE_PURPOSE (t); |
| bool is_pack = PACK_EXPANSION_P (purpose); |
| |
| if (is_pack) |
| pp->primary_expression (PACK_EXPANSION_PATTERN (purpose)); |
| else |
| pp->primary_expression (purpose); |
| pp_cxx_call_argument_list (pp, TREE_VALUE (t)); |
| if (is_pack) |
| pp_cxx_ws_string (pp, "..."); |
| if (TREE_CHAIN (t)) |
| pp_cxx_separate_with (pp, ','); |
| } |
| } |
| |
| /* function-definition: |
| decl-specifier-seq(opt) declarator ctor-initializer(opt) function-body |
| decl-specifier-seq(opt) declarator function-try-block */ |
| |
| static void |
| pp_cxx_function_definition (cxx_pretty_printer *pp, tree t) |
| { |
| tree saved_scope = pp->enclosing_scope; |
| pp->declaration_specifiers (t); |
| pp->declarator (t); |
| pp_needs_newline (pp) = true; |
| pp->enclosing_scope = DECL_CONTEXT (t); |
| if (DECL_SAVED_TREE (t)) |
| pp->statement (DECL_SAVED_TREE (t)); |
| else |
| pp_cxx_semicolon (pp); |
| pp_newline_and_flush (pp); |
| pp->enclosing_scope = saved_scope; |
| } |
| |
| /* abstract-declarator: |
| ptr-operator abstract-declarator(opt) |
| direct-abstract-declarator */ |
| |
| void |
| cxx_pretty_printer::abstract_declarator (tree t) |
| { |
| /* pp_cxx_ptr_operator prints '(' for a pointer-to-member function, |
| or a pointer-to-data-member of array type: |
| |
| void (X::*)() |
| int (X::*)[5] |
| |
| but not for a pointer-to-data-member of non-array type: |
| |
| int X::* |
| |
| so be mindful of that. */ |
| if (TYPE_PTRMEMFUNC_P (t) |
| || (TYPE_PTRDATAMEM_P (t) |
| && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)) |
| pp_cxx_right_paren (this); |
| else if (INDIRECT_TYPE_P (t)) |
| { |
| if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE |
| || TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE) |
| pp_cxx_right_paren (this); |
| t = TREE_TYPE (t); |
| } |
| direct_abstract_declarator (t); |
| } |
| |
| /* direct-abstract-declarator: |
| direct-abstract-declarator(opt) ( parameter-declaration-clause ) |
| cv-qualifier-seq(opt) exception-specification(opt) |
| direct-abstract-declarator(opt) [ constant-expression(opt) ] |
| ( abstract-declarator ) */ |
| |
| void |
| cxx_pretty_printer::direct_abstract_declarator (tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case REFERENCE_TYPE: |
| abstract_declarator (t); |
| break; |
| |
| case RECORD_TYPE: |
| if (TYPE_PTRMEMFUNC_P (t)) |
| direct_abstract_declarator (TYPE_PTRMEMFUNC_FN_TYPE (t)); |
| break; |
| |
| case OFFSET_TYPE: |
| if (TYPE_PTRDATAMEM_P (t)) |
| direct_abstract_declarator (TREE_TYPE (t)); |
| break; |
| |
| case METHOD_TYPE: |
| case FUNCTION_TYPE: |
| pp_cxx_parameter_declaration_clause (this, t); |
| direct_abstract_declarator (TREE_TYPE (t)); |
| if (TREE_CODE (t) == METHOD_TYPE) |
| { |
| padding = pp_before; |
| pp_cxx_cv_qualifier_seq (this, class_of_this_parm (t)); |
| } |
| pp_cxx_exception_specification (this, t); |
| break; |
| |
| case TYPENAME_TYPE: |
| case TEMPLATE_TYPE_PARM: |
| case TEMPLATE_TEMPLATE_PARM: |
| case BOUND_TEMPLATE_TEMPLATE_PARM: |
| case UNBOUND_CLASS_TEMPLATE: |
| case DECLTYPE_TYPE: |
| break; |
| |
| default: |
| c_pretty_printer::direct_abstract_declarator (t); |
| break; |
| } |
| } |
| |
| /* type-id: |
| type-specifier-seq abstract-declarator(opt) */ |
| |
| void |
| cxx_pretty_printer::type_id (tree t) |
| { |
| pp_flags saved_flags = flags; |
| flags |= pp_c_flag_abstract; |
| |
| switch (TREE_CODE (t)) |
| { |
| case TYPE_DECL: |
| case UNION_TYPE: |
| case RECORD_TYPE: |
| case ENUMERAL_TYPE: |
| case TYPENAME_TYPE: |
| case BOUND_TEMPLATE_TEMPLATE_PARM: |
| case UNBOUND_CLASS_TEMPLATE: |
| case TEMPLATE_TEMPLATE_PARM: |
| case TEMPLATE_TYPE_PARM: |
| case TEMPLATE_PARM_INDEX: |
| case TEMPLATE_DECL: |
| case TYPEOF_TYPE: |
| case UNDERLYING_TYPE: |
| case DECLTYPE_TYPE: |
| case NULLPTR_TYPE: |
| case TEMPLATE_ID_EXPR: |
| case OFFSET_TYPE: |
| pp_cxx_type_specifier_seq (this, t); |
| if (TYPE_PTRMEM_P (t)) |
| abstract_declarator (t); |
| break; |
| |
| case TYPE_PACK_EXPANSION: |
| type_id (PACK_EXPANSION_PATTERN (t)); |
| pp_cxx_ws_string (this, "..."); |
| break; |
| |
| case TYPE_ARGUMENT_PACK: |
| { |
| tree args = ARGUMENT_PACK_ARGS (t); |
| int len = TREE_VEC_LENGTH (args); |
| pp_cxx_left_brace (this); |
| for (int i = 0; i < len; ++i) |
| { |
| if (i > 0) |
| pp_cxx_separate_with (this, ','); |
| type_id (TREE_VEC_ELT (args, i)); |
| } |
| pp_cxx_right_brace (this); |
| } |
| break; |
| |
| default: |
| c_pretty_printer::type_id (t); |
| break; |
| } |
| |
| flags = saved_flags; |
| } |
| |
| /* template-argument-list: |
| template-argument ...(opt) |
| template-argument-list, template-argument ...(opt) |
| |
| template-argument: |
| assignment-expression |
| type-id |
| template-name */ |
| |
| static void |
| pp_cxx_template_argument_list (cxx_pretty_printer *pp, tree t) |
| { |
| int i; |
| bool need_comma = false; |
| |
| if (t == NULL) |
| return; |
| for (i = 0; i < TREE_VEC_LENGTH (t); ++i) |
| { |
| tree arg = TREE_VEC_ELT (t, i); |
| tree argpack = NULL_TREE; |
| int idx, len = 1; |
| |
| if (ARGUMENT_PACK_P (arg)) |
| { |
| argpack = ARGUMENT_PACK_ARGS (arg); |
| len = TREE_VEC_LENGTH (argpack); |
| } |
| |
| for (idx = 0; idx < len; idx++) |
| { |
| if (argpack) |
| arg = TREE_VEC_ELT (argpack, idx); |
| |
| if (need_comma) |
| pp_cxx_separate_with (pp, ','); |
| else |
| need_comma = true; |
| |
| if (TYPE_P (arg) || (TREE_CODE (arg) == TEMPLATE_DECL |
| && TYPE_P (DECL_TEMPLATE_RESULT (arg)))) |
| pp->type_id (arg); |
| else if (template_parm_object_p (arg)) |
| pp->expression (DECL_INITIAL (arg)); |
| else |
| pp->expression (arg); |
| } |
| } |
| } |
| |
| |
| static void |
| pp_cxx_exception_declaration (cxx_pretty_printer *pp, tree t) |
| { |
| t = DECL_EXPR_DECL (t); |
| pp_cxx_type_specifier_seq (pp, t); |
| if (TYPE_P (t)) |
| pp->abstract_declarator (t); |
| else |
| pp->declarator (t); |
| } |
| |
| /* Statements. */ |
| |
| void |
| cxx_pretty_printer::statement (tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case CTOR_INITIALIZER: |
| pp_cxx_ctor_initializer (this, t); |
| break; |
| |
| case USING_STMT: |
| pp_cxx_ws_string (this, "using"); |
| pp_cxx_ws_string (this, "namespace"); |
| if (DECL_CONTEXT (t)) |
| pp_cxx_nested_name_specifier (this, DECL_CONTEXT (t)); |
| pp_cxx_qualified_id (this, USING_STMT_NAMESPACE (t)); |
| break; |
| |
| case USING_DECL: |
| pp_cxx_ws_string (this, "using"); |
| pp_cxx_nested_name_specifier (this, USING_DECL_SCOPE (t)); |
| pp_cxx_unqualified_id (this, DECL_NAME (t)); |
| break; |
| |
| case EH_SPEC_BLOCK: |
| break; |
| |
| /* try-block: |
| try compound-statement handler-seq */ |
| case TRY_BLOCK: |
| pp_maybe_newline_and_indent (this, 0); |
| pp_cxx_ws_string (this, "try"); |
| pp_newline_and_indent (this, 3); |
| statement (TRY_STMTS (t)); |
| pp_newline_and_indent (this, -3); |
| if (CLEANUP_P (t)) |
| ; |
| else |
| statement (TRY_HANDLERS (t)); |
| break; |
| |
| /* |
| handler-seq: |
| handler handler-seq(opt) |
| |
| handler: |
| catch ( exception-declaration ) compound-statement |
| |
| exception-declaration: |
| type-specifier-seq declarator |
| type-specifier-seq abstract-declarator |
| ... */ |
| case HANDLER: |
| pp_cxx_ws_string (this, "catch"); |
| pp_cxx_left_paren (this); |
| pp_cxx_exception_declaration (this, HANDLER_PARMS (t)); |
| pp_cxx_right_paren (this); |
| pp_indentation (this) += 3; |
| pp_needs_newline (this) = true; |
| statement (HANDLER_BODY (t)); |
| pp_indentation (this) -= 3; |
| pp_needs_newline (this) = true; |
| break; |
| |
| /* selection-statement: |
| if ( expression ) statement |
| if ( expression ) statement else statement */ |
| case IF_STMT: |
| pp_cxx_ws_string (this, "if"); |
| pp_cxx_whitespace (this); |
| pp_cxx_left_paren (this); |
| expression (IF_COND (t)); |
| pp_cxx_right_paren (this); |
| pp_newline_and_indent (this, 2); |
| statement (THEN_CLAUSE (t)); |
| pp_newline_and_indent (this, -2); |
| if (ELSE_CLAUSE (t)) |
| { |
| tree else_clause = ELSE_CLAUSE (t); |
| pp_cxx_ws_string (this, "else"); |
| if (TREE_CODE (else_clause) == IF_STMT) |
| pp_cxx_whitespace (this); |
| else |
| pp_newline_and_indent (this, 2); |
| statement (else_clause); |
| if (TREE_CODE (else_clause) != IF_STMT) |
| pp_newline_and_indent (this, -2); |
| } |
| break; |
| |
| case RANGE_FOR_STMT: |
| pp_cxx_ws_string (this, "for"); |
| pp_space (this); |
| pp_cxx_left_paren (this); |
| if (RANGE_FOR_INIT_STMT (t)) |
| { |
| statement (RANGE_FOR_INIT_STMT (t)); |
| pp_needs_newline (this) = false; |
| pp_cxx_whitespace (this); |
| } |
| statement (RANGE_FOR_DECL (t)); |
| pp_space (this); |
| pp_needs_newline (this) = false; |
| pp_colon (this); |
| pp_space (this); |
| statement (RANGE_FOR_EXPR (t)); |
| pp_cxx_right_paren (this); |
| pp_newline_and_indent (this, 3); |
| statement (FOR_BODY (t)); |
| pp_indentation (this) -= 3; |
| pp_needs_newline (this) = true; |
| break; |
| |
| /* expression-statement: |
| expression(opt) ; */ |
| case EXPR_STMT: |
| expression (EXPR_STMT_EXPR (t)); |
| pp_cxx_semicolon (this); |
| pp_needs_newline (this) = true; |
| break; |
| |
| case CLEANUP_STMT: |
| pp_cxx_ws_string (this, "try"); |
| pp_newline_and_indent (this, 2); |
| statement (CLEANUP_BODY (t)); |
| pp_newline_and_indent (this, -2); |
| pp_cxx_ws_string (this, CLEANUP_EH_ONLY (t) ? "catch" : "finally"); |
| pp_newline_and_indent (this, 2); |
| statement (CLEANUP_EXPR (t)); |
| pp_newline_and_indent (this, -2); |
| break; |
| |
| case STATIC_ASSERT: |
| declaration (t); |
| break; |
| |
| case OMP_DEPOBJ: |
| pp_cxx_ws_string (this, "#pragma omp depobj"); |
| pp_space (this); |
| pp_cxx_left_paren (this); |
| expression (OMP_DEPOBJ_DEPOBJ (t)); |
| pp_cxx_right_paren (this); |
| if (OMP_DEPOBJ_CLAUSES (t) && OMP_DEPOBJ_CLAUSES (t) != error_mark_node) |
| { |
| if (TREE_CODE (OMP_DEPOBJ_CLAUSES (t)) == OMP_CLAUSE) |
| dump_omp_clauses (this, OMP_DEPOBJ_CLAUSES (t), |
| pp_indentation (this), TDF_NONE); |
| else |
| switch (tree_to_uhwi (OMP_DEPOBJ_CLAUSES (t))) |
| { |
| case OMP_CLAUSE_DEPEND_IN: |
| pp_cxx_ws_string (this, " update(in)"); |
| break; |
| case OMP_CLAUSE_DEPEND_INOUT: |
| pp_cxx_ws_string (this, " update(inout)"); |
| break; |
| case OMP_CLAUSE_DEPEND_OUT: |
| pp_cxx_ws_string (this, " update(out)"); |
| break; |
| case OMP_CLAUSE_DEPEND_MUTEXINOUTSET: |
| pp_cxx_ws_string (this, " update(mutexinoutset)"); |
| break; |
| case OMP_CLAUSE_DEPEND_LAST: |
| pp_cxx_ws_string (this, " destroy"); |
| break; |
| default: |
| break; |
| } |
| } |
| pp_needs_newline (this) = true; |
| break; |
| |
| default: |
| c_pretty_printer::statement (t); |
| break; |
| } |
| } |
| |
| /* original-namespace-definition: |
| namespace identifier { namespace-body } |
| |
| As an edge case, we also handle unnamed namespace definition here. */ |
| |
| static void |
| pp_cxx_original_namespace_definition (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_ws_string (pp, "namespace"); |
| if (DECL_CONTEXT (t)) |
| pp_cxx_nested_name_specifier (pp, DECL_CONTEXT (t)); |
| if (DECL_NAME (t)) |
| pp_cxx_unqualified_id (pp, t); |
| pp_cxx_whitespace (pp); |
| pp_cxx_left_brace (pp); |
| /* We do not print the namespace-body. */ |
| pp_cxx_whitespace (pp); |
| pp_cxx_right_brace (pp); |
| } |
| |
| /* namespace-alias: |
| identifier |
| |
| namespace-alias-definition: |
| namespace identifier = qualified-namespace-specifier ; |
| |
| qualified-namespace-specifier: |
| ::(opt) nested-name-specifier(opt) namespace-name */ |
| |
| static void |
| pp_cxx_namespace_alias_definition (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_ws_string (pp, "namespace"); |
| if (DECL_CONTEXT (t)) |
| pp_cxx_nested_name_specifier (pp, DECL_CONTEXT (t)); |
| pp_cxx_unqualified_id (pp, t); |
| pp_cxx_whitespace (pp); |
| pp_equal (pp); |
| pp_cxx_whitespace (pp); |
| if (DECL_CONTEXT (DECL_NAMESPACE_ALIAS (t))) |
| pp_cxx_nested_name_specifier (pp, |
| DECL_CONTEXT (DECL_NAMESPACE_ALIAS (t))); |
| pp_cxx_qualified_id (pp, DECL_NAMESPACE_ALIAS (t)); |
| pp_cxx_semicolon (pp); |
| } |
| |
| /* simple-declaration: |
| decl-specifier-seq(opt) init-declarator-list(opt) */ |
| |
| static void |
| pp_cxx_simple_declaration (cxx_pretty_printer *pp, tree t) |
| { |
| pp->declaration_specifiers (t); |
| pp_cxx_init_declarator (pp, t); |
| pp_cxx_semicolon (pp); |
| pp_needs_newline (pp) = true; |
| } |
| |
| /* |
| template-parameter-list: |
| template-parameter |
| template-parameter-list , template-parameter */ |
| |
| static inline void |
| pp_cxx_template_parameter_list (cxx_pretty_printer *pp, tree t) |
| { |
| const int n = TREE_VEC_LENGTH (t); |
| int i; |
| for (i = 0; i < n; ++i) |
| { |
| if (i) |
| pp_cxx_separate_with (pp, ','); |
| pp_cxx_template_parameter (pp, TREE_VEC_ELT (t, i)); |
| } |
| } |
| |
| /* template-parameter: |
| type-parameter |
| parameter-declaration |
| |
| type-parameter: |
| class ...(opt) identifier(opt) |
| class identifier(opt) = type-id |
| typename identifier(opt) |
| typename ...(opt) identifier(opt) = type-id |
| template < template-parameter-list > class ...(opt) identifier(opt) |
| template < template-parameter-list > class identifier(opt) = template-name */ |
| |
| static void |
| pp_cxx_template_parameter (cxx_pretty_printer *pp, tree t) |
| { |
| tree parameter = TREE_VALUE (t); |
| switch (TREE_CODE (parameter)) |
| { |
| case TYPE_DECL: |
| pp_cxx_ws_string (pp, "class"); |
| if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (t))) |
| pp_cxx_ws_string (pp, "..."); |
| if (DECL_NAME (parameter)) |
| pp_cxx_tree_identifier (pp, DECL_NAME (parameter)); |
| /* FIXME: Check if we should print also default argument. */ |
| break; |
| |
| case PARM_DECL: |
| pp_cxx_parameter_declaration (pp, parameter); |
| break; |
| |
| case TEMPLATE_DECL: |
| break; |
| |
| default: |
| pp_unsupported_tree (pp, t); |
| break; |
| } |
| } |
| |
| /* Pretty-print a template parameter in the canonical form |
| "template-parameter-<level>-<position in parameter list>". */ |
| |
| void |
| pp_cxx_canonical_template_parameter (cxx_pretty_printer *pp, tree parm) |
| { |
| const enum tree_code code = TREE_CODE (parm); |
| |
| /* Brings type template parameters to the canonical forms. */ |
| if (code == TEMPLATE_TYPE_PARM || code == TEMPLATE_TEMPLATE_PARM |
| || code == BOUND_TEMPLATE_TEMPLATE_PARM) |
| parm = TEMPLATE_TYPE_PARM_INDEX (parm); |
| |
| pp_cxx_begin_template_argument_list (pp); |
| pp->translate_string ("template-parameter-"); |
| pp_wide_integer (pp, TEMPLATE_PARM_LEVEL (parm)); |
| pp_minus (pp); |
| pp_wide_integer (pp, TEMPLATE_PARM_IDX (parm) + 1); |
| pp_cxx_end_template_argument_list (pp); |
| } |
| |
| /* Print a constrained-type-specifier. */ |
| |
| void |
| pp_cxx_constrained_type_spec (cxx_pretty_printer *pp, tree c) |
| { |
| pp_cxx_whitespace (pp); |
| pp_cxx_left_bracket (pp); |
| pp->translate_string ("requires"); |
| pp_cxx_whitespace (pp); |
| if (c == error_mark_node) |
| { |
| pp_cxx_ws_string(pp, "<unsatisfied-type-constraint>"); |
| return; |
| } |
| tree t, a; |
| placeholder_extract_concept_and_args (c, t, a); |
| pp->id_expression (t); |
| pp_cxx_begin_template_argument_list (pp); |
| pp_cxx_ws_string (pp, "<placeholder>"); |
| pp_cxx_separate_with (pp, ','); |
| tree args = make_tree_vec (TREE_VEC_LENGTH (a) - 1); |
| for (int i = 0; i < TREE_VEC_LENGTH (a) - 1; ++i) |
| TREE_VEC_ELT (args, i) = TREE_VEC_ELT (a, i + 1); |
| pp_cxx_template_argument_list (pp, args); |
| ggc_free (args); |
| pp_cxx_end_template_argument_list (pp); |
| pp_cxx_right_bracket (pp); |
| } |
| |
| /* |
| template-declaration: |
| export(opt) template < template-parameter-list > declaration |
| |
| Concept extensions: |
| |
| template-declaration: |
| export(opt) template < template-parameter-list > |
| requires-clause(opt) declaration */ |
| |
| static void |
| pp_cxx_template_declaration (cxx_pretty_printer *pp, tree t) |
| { |
| tree tmpl = most_general_template (t); |
| tree level; |
| |
| pp_maybe_newline_and_indent (pp, 0); |
| for (level = DECL_TEMPLATE_PARMS (tmpl); level; level = TREE_CHAIN (level)) |
| { |
| pp_cxx_ws_string (pp, "template"); |
| pp_cxx_begin_template_argument_list (pp); |
| pp_cxx_template_parameter_list (pp, TREE_VALUE (level)); |
| pp_cxx_end_template_argument_list (pp); |
| pp_newline_and_indent (pp, 3); |
| } |
| |
| if (flag_concepts) |
| if (tree ci = get_constraints (t)) |
| if (tree reqs = CI_TEMPLATE_REQS (ci)) |
| { |
| pp_cxx_requires_clause (pp, reqs); |
| pp_newline_and_indent (pp, 6); |
| } |
| |
| if (TREE_CODE (t) == FUNCTION_DECL && DECL_SAVED_TREE (t)) |
| pp_cxx_function_definition (pp, t); |
| else if (TREE_CODE (t) == CONCEPT_DECL) |
| pp_cxx_concept_definition (pp, t); |
| else |
| pp_cxx_simple_declaration (pp, t); |
| } |
| |
| static void |
| pp_cxx_explicit_specialization (cxx_pretty_printer *pp, tree t) |
| { |
| pp_unsupported_tree (pp, t); |
| } |
| |
| static void |
| pp_cxx_explicit_instantiation (cxx_pretty_printer *pp, tree t) |
| { |
| pp_unsupported_tree (pp, t); |
| } |
| |
| static void |
| pp_cxx_concept_definition (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_unqualified_id (pp, DECL_NAME (t)); |
| pp_cxx_whitespace (pp); |
| pp_cxx_ws_string (pp, "="); |
| pp_cxx_whitespace (pp); |
| pp->expression (DECL_INITIAL (t)); |
| pp_cxx_semicolon (pp); |
| } |
| |
| /* |
| declaration: |
| block-declaration |
| function-definition |
| template-declaration |
| explicit-instantiation |
| explicit-specialization |
| linkage-specification |
| namespace-definition |
| |
| block-declaration: |
| simple-declaration |
| asm-definition |
| namespace-alias-definition |
| using-declaration |
| using-directive |
| static_assert-declaration */ |
| void |
| cxx_pretty_printer::declaration (tree t) |
| { |
| if (TREE_CODE (t) == STATIC_ASSERT) |
| { |
| pp_cxx_ws_string (this, "static_assert"); |
| pp_cxx_left_paren (this); |
| expression (STATIC_ASSERT_CONDITION (t)); |
| pp_cxx_separate_with (this, ','); |
| expression (STATIC_ASSERT_MESSAGE (t)); |
| pp_cxx_right_paren (this); |
| } |
| else if (!DECL_LANG_SPECIFIC (t)) |
| pp_cxx_simple_declaration (this, t); |
| else if (DECL_USE_TEMPLATE (t)) |
| switch (DECL_USE_TEMPLATE (t)) |
| { |
| case 1: |
| pp_cxx_template_declaration (this, t); |
| break; |
| |
| case 2: |
| pp_cxx_explicit_specialization (this, t); |
| break; |
| |
| case 3: |
| pp_cxx_explicit_instantiation (this, t); |
| break; |
| |
| default: |
| break; |
| } |
| else switch (TREE_CODE (t)) |
| { |
| case VAR_DECL: |
| case TYPE_DECL: |
| pp_cxx_simple_declaration (this, t); |
| break; |
| |
| case FUNCTION_DECL: |
| if (DECL_SAVED_TREE (t)) |
| pp_cxx_function_definition (this, t); |
| else |
| pp_cxx_simple_declaration (this, t); |
| break; |
| |
| case NAMESPACE_DECL: |
| if (DECL_NAMESPACE_ALIAS (t)) |
| pp_cxx_namespace_alias_definition (this, t); |
| else |
| pp_cxx_original_namespace_definition (this, t); |
| break; |
| |
| default: |
| pp_unsupported_tree (this, t); |
| break; |
| } |
| } |
| |
| static void |
| pp_cxx_typeid_expression (cxx_pretty_printer *pp, tree t) |
| { |
| t = TREE_OPERAND (t, 0); |
| pp_cxx_ws_string (pp, "typeid"); |
| pp_cxx_left_paren (pp); |
| if (TYPE_P (t)) |
| pp->type_id (t); |
| else |
| pp->expression (t); |
| pp_cxx_right_paren (pp); |
| } |
| |
| void |
| pp_cxx_va_arg_expression (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_ws_string (pp, "va_arg"); |
| pp_cxx_left_paren (pp); |
| pp->assignment_expression (TREE_OPERAND (t, 0)); |
| pp_cxx_separate_with (pp, ','); |
| pp->type_id (TREE_TYPE (t)); |
| pp_cxx_right_paren (pp); |
| } |
| |
| static bool |
| pp_cxx_offsetof_expression_1 (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case ARROW_EXPR: |
| if (TREE_CODE (TREE_OPERAND (t, 0)) == STATIC_CAST_EXPR |
| && INDIRECT_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 0)))) |
| { |
| pp->type_id (TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)))); |
| pp_cxx_separate_with (pp, ','); |
| return true; |
| } |
| return false; |
| case COMPONENT_REF: |
| if (!pp_cxx_offsetof_expression_1 (pp, TREE_OPERAND (t, 0))) |
| return false; |
| if (TREE_CODE (TREE_OPERAND (t, 0)) != ARROW_EXPR) |
| pp_cxx_dot (pp); |
| pp->expression (TREE_OPERAND (t, 1)); |
| return true; |
| case ARRAY_REF: |
| if (!pp_cxx_offsetof_expression_1 (pp, TREE_OPERAND (t, 0))) |
| return false; |
| pp_left_bracket (pp); |
| pp->expression (TREE_OPERAND (t, 1)); |
| pp_right_bracket (pp); |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| void |
| pp_cxx_offsetof_expression (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_ws_string (pp, "offsetof"); |
| pp_cxx_left_paren (pp); |
| if (!pp_cxx_offsetof_expression_1 (pp, TREE_OPERAND (t, 0))) |
| pp->expression (TREE_OPERAND (t, 0)); |
| pp_cxx_right_paren (pp); |
| } |
| |
| void |
| pp_cxx_addressof_expression (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_ws_string (pp, "__builtin_addressof"); |
| pp_cxx_left_paren (pp); |
| pp->expression (TREE_OPERAND (t, 0)); |
| pp_cxx_right_paren (pp); |
| } |
| |
| static char const* |
| get_fold_operator (tree t) |
| { |
| int op = int_cst_value (FOLD_EXPR_OP (t)); |
| ovl_op_info_t *info = OVL_OP_INFO (FOLD_EXPR_MODIFY_P (t), op); |
| return info->name; |
| } |
| |
| void |
| pp_cxx_unary_left_fold_expression (cxx_pretty_printer *pp, tree t) |
| { |
| char const* op = get_fold_operator (t); |
| tree expr = PACK_EXPANSION_PATTERN (FOLD_EXPR_PACK (t)); |
| pp_cxx_left_paren (pp); |
| pp_cxx_ws_string (pp, "..."); |
| pp_cxx_ws_string (pp, op); |
| pp->expression (expr); |
| pp_cxx_right_paren (pp); |
| } |
| |
| void |
| pp_cxx_unary_right_fold_expression (cxx_pretty_printer *pp, tree t) |
| { |
| char const* op = get_fold_operator (t); |
| tree expr = PACK_EXPANSION_PATTERN (FOLD_EXPR_PACK (t)); |
| pp_cxx_left_paren (pp); |
| pp->expression (expr); |
| pp_space (pp); |
| pp_cxx_ws_string (pp, op); |
| pp_cxx_ws_string (pp, "..."); |
| pp_cxx_right_paren (pp); |
| } |
| |
| void |
| pp_cxx_binary_fold_expression (cxx_pretty_printer *pp, tree t) |
| { |
| char const* op = get_fold_operator (t); |
| tree t1 = TREE_OPERAND (t, 1); |
| tree t2 = TREE_OPERAND (t, 2); |
| if (t1 == FOLD_EXPR_PACK (t)) |
| t1 = PACK_EXPANSION_PATTERN (t1); |
| else |
| t2 = PACK_EXPANSION_PATTERN (t2); |
| pp_cxx_left_paren (pp); |
| pp->expression (t1); |
| pp_cxx_ws_string (pp, op); |
| pp_cxx_ws_string (pp, "..."); |
| pp_cxx_ws_string (pp, op); |
| pp->expression (t2); |
| pp_cxx_right_paren (pp); |
| } |
| |
| void |
| pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) |
| { |
| cp_trait_kind kind = TRAIT_EXPR_KIND (t); |
| |
| switch (kind) |
| { |
| case CPTK_HAS_NOTHROW_ASSIGN: |
| pp_cxx_ws_string (pp, "__has_nothrow_assign"); |
| break; |
| case CPTK_HAS_TRIVIAL_ASSIGN: |
| pp_cxx_ws_string (pp, "__has_trivial_assign"); |
| break; |
| case CPTK_HAS_NOTHROW_CONSTRUCTOR: |
| pp_cxx_ws_string (pp, "__has_nothrow_constructor"); |
| break; |
| case CPTK_HAS_TRIVIAL_CONSTRUCTOR: |
| pp_cxx_ws_string (pp, "__has_trivial_constructor"); |
| break; |
| case CPTK_HAS_NOTHROW_COPY: |
| pp_cxx_ws_string (pp, "__has_nothrow_copy"); |
| break; |
| case CPTK_HAS_TRIVIAL_COPY: |
| pp_cxx_ws_string (pp, "__has_trivial_copy"); |
| break; |
| case CPTK_HAS_TRIVIAL_DESTRUCTOR: |
| pp_cxx_ws_string (pp, "__has_trivial_destructor"); |
| break; |
| case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS: |
| pp_cxx_ws_string (pp, "__has_unique_object_representations"); |
| break; |
| case CPTK_HAS_VIRTUAL_DESTRUCTOR: |
| pp_cxx_ws_string (pp, "__has_virtual_destructor"); |
| break; |
| case CPTK_IS_ABSTRACT: |
| pp_cxx_ws_string (pp, "__is_abstract"); |
| break; |
| case CPTK_IS_AGGREGATE: |
| pp_cxx_ws_string (pp, "__is_aggregate"); |
| break; |
| case CPTK_IS_BASE_OF: |
| pp_cxx_ws_string (pp, "__is_base_of"); |
| break; |
| case CPTK_IS_CLASS: |
| pp_cxx_ws_string (pp, "__is_class"); |
| break; |
| case CPTK_IS_EMPTY: |
| pp_cxx_ws_string (pp, "__is_empty"); |
| break; |
| case CPTK_IS_ENUM: |
| pp_cxx_ws_string (pp, "__is_enum"); |
| break; |
| case CPTK_IS_FINAL: |
| pp_cxx_ws_string (pp, "__is_final"); |
| break; |
| case CPTK_IS_LAYOUT_COMPATIBLE: |
| pp_cxx_ws_string (pp, "__is_layout_compatible"); |
| break; |
| case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF: |
| pp_cxx_ws_string (pp, "__is_pointer_interconvertible_base_of"); |
| break; |
| case CPTK_IS_POD: |
| pp_cxx_ws_string (pp, "__is_pod"); |
| break; |
| case CPTK_IS_POLYMORPHIC: |
| pp_cxx_ws_string (pp, "__is_polymorphic"); |
| break; |
| case CPTK_IS_SAME_AS: |
| pp_cxx_ws_string (pp, "__is_same"); |
| break; |
| case CPTK_IS_STD_LAYOUT: |
| pp_cxx_ws_string (pp, "__is_std_layout"); |
| break; |
| case CPTK_IS_TRIVIAL: |
| pp_cxx_ws_string (pp, "__is_trivial"); |
| break; |
| case CPTK_IS_TRIVIALLY_ASSIGNABLE: |
| pp_cxx_ws_string (pp, "__is_trivially_assignable"); |
| break; |
| case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE: |
| pp_cxx_ws_string (pp, "__is_trivially_constructible"); |
| break; |
| case CPTK_IS_TRIVIALLY_COPYABLE: |
| pp_cxx_ws_string (pp, "__is_trivially_copyable"); |
| break; |
| case CPTK_IS_UNION: |
| pp_cxx_ws_string (pp, "__is_union"); |
| break; |
| case CPTK_IS_LITERAL_TYPE: |
| pp_cxx_ws_string (pp, "__is_literal_type"); |
| break; |
| case CPTK_IS_ASSIGNABLE: |
| pp_cxx_ws_string (pp, "__is_assignable"); |
| break; |
| case CPTK_IS_CONSTRUCTIBLE: |
| pp_cxx_ws_string (pp, "__is_constructible"); |
| break; |
| case CPTK_IS_NOTHROW_ASSIGNABLE: |
| pp_cxx_ws_string (pp, "__is_nothrow_assignable"); |
| break; |
| case CPTK_IS_NOTHROW_CONSTRUCTIBLE: |
| pp_cxx_ws_string (pp, "__is_nothrow_constructible"); |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| pp_cxx_left_paren (pp); |
| pp->type_id (TRAIT_EXPR_TYPE1 (t)); |
| |
| if (kind == CPTK_IS_BASE_OF |
| || kind == CPTK_IS_SAME_AS |
| || kind == CPTK_IS_LAYOUT_COMPATIBLE |
| || kind == CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF) |
| { |
| pp_cxx_separate_with (pp, ','); |
| pp->type_id (TRAIT_EXPR_TYPE2 (t)); |
| } |
| |
| pp_cxx_right_paren (pp); |
| } |
| |
| // requires-clause: |
| // 'requires' logical-or-expression |
| void |
| pp_cxx_requires_clause (cxx_pretty_printer *pp, tree t) |
| { |
| if (!t) |
| return; |
| pp->padding = pp_before; |
| pp_cxx_ws_string (pp, "requires"); |
| pp_space (pp); |
| pp->expression (t); |
| } |
| |
| /* requirement: |
| simple-requirement |
| compound-requirement |
| type-requirement |
| nested-requirement */ |
| static void |
| pp_cxx_requirement (cxx_pretty_printer *pp, tree t) |
| { |
| switch (TREE_CODE (t)) |
| { |
| case SIMPLE_REQ: |
| pp_cxx_simple_requirement (pp, t); |
| break; |
| |
| case TYPE_REQ: |
| pp_cxx_type_requirement (pp, t); |
| break; |
| |
| case COMPOUND_REQ: |
| pp_cxx_compound_requirement (pp, t); |
| break; |
| |
| case NESTED_REQ: |
| pp_cxx_nested_requirement (pp, t); |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| // requirement-list: |
| // requirement |
| // requirement-list ';' requirement[opt] |
| // |
| static void |
| pp_cxx_requirement_list (cxx_pretty_printer *pp, tree t) |
| { |
| for (; t; t = TREE_CHAIN (t)) |
| pp_cxx_requirement (pp, TREE_VALUE (t)); |
| } |
| |
| // requirement-body: |
| // '{' requirement-list '}' |
| static void |
| pp_cxx_requirement_body (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_left_brace (pp); |
| pp_cxx_requirement_list (pp, t); |
| pp_cxx_right_brace (pp); |
| } |
| |
| // requires-expression: |
| // 'requires' requirement-parameter-list requirement-body |
| void |
| pp_cxx_requires_expr (cxx_pretty_printer *pp, tree t) |
| { |
| pp_string (pp, "requires"); |
| if (tree parms = REQUIRES_EXPR_PARMS (t)) |
| { |
| bool first = true; |
| pp_cxx_left_paren (pp); |
| for (; parms; parms = TREE_CHAIN (parms)) |
| { |
| if (!first) |
| pp_cxx_separate_with (pp, ',' ); |
| first = false; |
| pp_cxx_parameter_declaration (pp, parms); |
| } |
| pp_cxx_right_paren (pp); |
| pp_cxx_whitespace (pp); |
| } |
| pp_cxx_requirement_body (pp, TREE_OPERAND (t, 1)); |
| } |
| |
| /* simple-requirement: |
| expression ';' */ |
| void |
| pp_cxx_simple_requirement (cxx_pretty_printer *pp, tree t) |
| { |
| pp->expression (TREE_OPERAND (t, 0)); |
| pp_cxx_semicolon (pp); |
| } |
| |
| /* type-requirement: |
| typename type-name ';' */ |
| void |
| pp_cxx_type_requirement (cxx_pretty_printer *pp, tree t) |
| { |
| pp->type_id (TREE_OPERAND (t, 0)); |
| pp_cxx_semicolon (pp); |
| } |
| |
| /* compound-requirement: |
| '{' expression '}' 'noexcept' [opt] trailing-return-type [opt] */ |
| void |
| pp_cxx_compound_requirement (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_left_brace (pp); |
| pp->expression (TREE_OPERAND (t, 0)); |
| pp_cxx_right_brace (pp); |
| |
| if (COMPOUND_REQ_NOEXCEPT_P (t)) |
| pp_cxx_ws_string (pp, "noexcept"); |
| |
| if (tree type = TREE_OPERAND (t, 1)) |
| { |
| pp_cxx_whitespace (pp); |
| pp_cxx_ws_string (pp, "->"); |
| pp->type_id (type); |
| } |
| pp_cxx_semicolon (pp); |
| } |
| |
| /* nested requirement: |
| 'requires' constraint-expression */ |
| void |
| pp_cxx_nested_requirement (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_ws_string (pp, "requires"); |
| pp->expression (TREE_OPERAND (t, 0)); |
| pp_cxx_semicolon (pp); |
| } |
| |
| void |
| pp_cxx_check_constraint (cxx_pretty_printer *pp, tree t) |
| { |
| tree decl = CHECK_CONSTR_CONCEPT (t); |
| tree tmpl = DECL_TI_TEMPLATE (decl); |
| tree args = CHECK_CONSTR_ARGS (t); |
| tree id = build_nt (TEMPLATE_ID_EXPR, tmpl, args); |
| |
| if (TREE_CODE (decl) == CONCEPT_DECL) |
| pp->expression (id); |
| else if (VAR_P (decl)) |
| pp->expression (id); |
| else if (TREE_CODE (decl) == FUNCTION_DECL) |
| { |
| tree call = build_vl_exp (CALL_EXPR, 2); |
| TREE_OPERAND (call, 0) = integer_two_node; |
| TREE_OPERAND (call, 1) = id; |
| pp->expression (call); |
| } |
| else |
| gcc_unreachable (); |
| } |
| |
| /* Output the "[with ...]" clause for a parameter mapping of an atomic |
| constraint. */ |
| |
| void |
| pp_cxx_parameter_mapping (cxx_pretty_printer *pp, tree map) |
| { |
| pp_cxx_whitespace (pp); |
| pp_cxx_left_bracket (pp); |
| pp->translate_string ("with"); |
| pp_cxx_whitespace (pp); |
| |
| for (tree p = map; p; p = TREE_CHAIN (p)) |
| { |
| tree parm = TREE_VALUE (p); |
| tree arg = TREE_PURPOSE (p); |
| |
| if (TYPE_P (parm)) |
| pp->type_id (parm); |
| else |
| pp_cxx_tree_identifier (pp, DECL_NAME (TEMPLATE_PARM_DECL (parm))); |
| |
| pp_cxx_whitespace (pp); |
| pp_equal (pp); |
| pp_cxx_whitespace (pp); |
| |
| if (TYPE_P (arg) || DECL_TEMPLATE_TEMPLATE_PARM_P (arg)) |
| pp->type_id (arg); |
| else |
| pp->expression (arg); |
| |
| if (TREE_CHAIN (p) != NULL_TREE) |
| pp_cxx_separate_with (pp, ';'); |
| } |
| |
| pp_cxx_right_bracket (pp); |
| } |
| |
| void |
| pp_cxx_atomic_constraint (cxx_pretty_printer *pp, tree t) |
| { |
| /* Emit the expression. */ |
| pp->expression (ATOMIC_CONSTR_EXPR (t)); |
| |
| /* Emit the parameter mapping. */ |
| tree map = ATOMIC_CONSTR_MAP (t); |
| if (map && map != error_mark_node) |
| pp_cxx_parameter_mapping (pp, map); |
| } |
| |
| void |
| pp_cxx_conjunction (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_constraint (pp, TREE_OPERAND (t, 0)); |
| pp_string (pp, " /\\ "); |
| pp_cxx_constraint (pp, TREE_OPERAND (t, 1)); |
| } |
| |
| void |
| pp_cxx_disjunction (cxx_pretty_printer *pp, tree t) |
| { |
| pp_cxx_constraint (pp, TREE_OPERAND (t, 0)); |
| pp_string (pp, " \\/ "); |
| pp_cxx_constraint (pp, TREE_OPERAND (t, 1)); |
| } |
| |
| void |
| pp_cxx_constraint (cxx_pretty_printer *pp, tree t) |
| { |
| if (t == error_mark_node) |
| return pp->expression (t); |
| |
| switch (TREE_CODE (t)) |
| { |
| case ATOMIC_CONSTR: |
| pp_cxx_atomic_constraint (pp, t); |
| break; |
| |
| case CHECK_CONSTR: |
| pp_cxx_check_constraint (pp, t); |
| break; |
| |
| case CONJ_CONSTR: |
| pp_cxx_conjunction (pp, t); |
| break; |
| |
| case DISJ_CONSTR: |
| pp_cxx_disjunction (pp, t); |
| break; |
| |
| case EXPR_PACK_EXPANSION: |
| pp->expression (TREE_OPERAND (t, 0)); |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| |
| typedef c_pretty_print_fn pp_fun; |
| |
| /* Initialization of a C++ pretty-printer object. */ |
| |
| cxx_pretty_printer::cxx_pretty_printer () |
| : c_pretty_printer (), |
| enclosing_scope (global_namespace) |
| { |
| type_specifier_seq = (pp_fun) pp_cxx_type_specifier_seq; |
| parameter_list = (pp_fun) pp_cxx_parameter_declaration_clause; |
| } |
| |
| /* cxx_pretty_printer's implementation of pretty_printer::clone vfunc. */ |
| |
| pretty_printer * |
| cxx_pretty_printer::clone () const |
| { |
| return new cxx_pretty_printer (*this); |
| } |