2960 lines
71 KiB
C
2960 lines
71 KiB
C
/* Implementation of subroutines for the GNU C++ pretty-printer.
|
||
Copyright (C) 2003-2017 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 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. */
|
||
|
||
static inline bool
|
||
is_destructor_name (tree name)
|
||
{
|
||
return name == complete_dtor_identifier
|
||
|| name == base_dtor_identifier
|
||
|| name == deleting_dtor_identifier;
|
||
}
|
||
|
||
/* 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_CURRENT (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_TYPENAME_P (t))
|
||
pp_cxx_conversion_function_id (pp, t);
|
||
else
|
||
{
|
||
if (is_destructor_name (t))
|
||
{
|
||
pp_complement (pp);
|
||
/* FIXME: Why is this necessary? */
|
||
if (TREE_TYPE (t))
|
||
t = constructor_name (TREE_TYPE (t));
|
||
}
|
||
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 (CLASS_TYPE_P (t) && CLASSTYPE_USE_TEMPLATE (t))
|
||
{
|
||
pp_cxx_begin_template_argument_list (pp);
|
||
pp_cxx_template_argument_list (pp, INNERMOST_TEMPLATE_ARGS
|
||
(CLASSTYPE_TI_ARGS (t)));
|
||
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 (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)
|
||
{
|
||
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_CURRENT (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;
|
||
}
|
||
}
|
||
|
||
|
||
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;
|
||
}
|
||
/* 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_CURRENT (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 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:
|
||
multiplicative_expression (TREE_OPERAND (e, 0));
|
||
pp_space (this);
|
||
if (code == MULT_EXPR)
|
||
pp_star (this);
|
||
else if (code == TRUNC_DIV_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_CURRENT (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:
|
||
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);
|
||
for (i = 0; i < len; ++i)
|
||
{
|
||
if (i > 0)
|
||
pp_cxx_separate_with (this, ',');
|
||
expression (TREE_VEC_ELT (args, i));
|
||
}
|
||
}
|
||
break;
|
||
|
||
case LAMBDA_EXPR:
|
||
pp_cxx_ws_string (this, "<lambda>");
|
||
break;
|
||
|
||
case TRAIT_EXPR:
|
||
pp_cxx_trait_expression (this, t);
|
||
break;
|
||
|
||
case PRED_CONSTR:
|
||
case CHECK_CONSTR:
|
||
case EXPR_CONSTR:
|
||
case TYPE_CONSTR:
|
||
case ICONV_CONSTR:
|
||
case DEDUCT_CONSTR:
|
||
case EXCEPT_CONSTR:
|
||
case PARM_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
|
||
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);
|
||
break;
|
||
|
||
case TYPENAME_TYPE:
|
||
pp_cxx_ws_string (this, "typename");
|
||
pp_cxx_nested_name_specifier (this, TYPE_CONTEXT (t));
|
||
pp_cxx_unqualified_id (this, TYPE_NAME (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:
|
||
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 DECLTYPE_TYPE:
|
||
pp_cxx_ws_string (pp, "decltype");
|
||
pp_cxx_left_paren (pp);
|
||
pp->expression (DECLTYPE_TYPE_EXPR (t));
|
||
pp_cxx_right_paren (pp);
|
||
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 */
|
||
|
||
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)
|
||
{
|
||
tree args;
|
||
tree types;
|
||
bool abstract;
|
||
|
||
// For a requires clause or the explicit printing of a parameter list
|
||
// we expect T to be a chain of PARM_DECLs. Otherwise, the list of
|
||
// args and types are taken from the function decl T.
|
||
if (TREE_CODE (t) == PARM_DECL)
|
||
{
|
||
args = t;
|
||
types = t;
|
||
abstract = false;
|
||
}
|
||
else
|
||
{
|
||
bool type_p = TYPE_P (t);
|
||
args = type_p ? NULL : FUNCTION_FIRST_USER_PARM (t);
|
||
types = type_p ? TYPE_ARG_TYPES (t) : FUNCTION_FIRST_USER_PARMTYPE (t);
|
||
abstract = args == NULL || pp->flags & pp_c_flag_abstract;
|
||
}
|
||
bool first = true;
|
||
|
||
/* Skip artificial parameter for nonstatic member functions. */
|
||
if (TREE_CODE (t) == METHOD_TYPE)
|
||
types = TREE_CHAIN (types);
|
||
|
||
pp_cxx_left_paren (pp);
|
||
for (; args; args = TREE_CHAIN (args), types = TREE_CHAIN (types))
|
||
{
|
||
if (!first)
|
||
pp_cxx_separate_with (pp, ',');
|
||
first = false;
|
||
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));
|
||
}
|
||
}
|
||
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)
|
||
{
|
||
if (TYPE_PTRMEM_P (t))
|
||
pp_cxx_right_paren (this);
|
||
else if (POINTER_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 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:
|
||
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 TEMPLATE_ID_EXPR:
|
||
pp_cxx_type_specifier_seq (this, t);
|
||
break;
|
||
|
||
case TYPE_PACK_EXPANSION:
|
||
type_id (PACK_EXPANSION_PATTERN (t));
|
||
pp_cxx_ws_string (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
|
||
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 SWITCH_STMT:
|
||
pp_cxx_ws_string (this, "switch");
|
||
pp_space (this);
|
||
pp_cxx_left_paren (this);
|
||
expression (SWITCH_STMT_COND (t));
|
||
pp_cxx_right_paren (this);
|
||
pp_indentation (this) += 3;
|
||
pp_needs_newline (this) = true;
|
||
statement (SWITCH_STMT_BODY (t));
|
||
pp_newline_and_indent (this, -3);
|
||
break;
|
||
|
||
/* iteration-statement:
|
||
while ( expression ) statement
|
||
do statement while ( expression ) ;
|
||
for ( expression(opt) ; expression(opt) ; expression(opt) ) statement
|
||
for ( declaration expression(opt) ; expression(opt) ) statement */
|
||
case WHILE_STMT:
|
||
pp_cxx_ws_string (this, "while");
|
||
pp_space (this);
|
||
pp_cxx_left_paren (this);
|
||
expression (WHILE_COND (t));
|
||
pp_cxx_right_paren (this);
|
||
pp_newline_and_indent (this, 3);
|
||
statement (WHILE_BODY (t));
|
||
pp_indentation (this) -= 3;
|
||
pp_needs_newline (this) = true;
|
||
break;
|
||
|
||
case DO_STMT:
|
||
pp_cxx_ws_string (this, "do");
|
||
pp_newline_and_indent (this, 3);
|
||
statement (DO_BODY (t));
|
||
pp_newline_and_indent (this, -3);
|
||
pp_cxx_ws_string (this, "while");
|
||
pp_space (this);
|
||
pp_cxx_left_paren (this);
|
||
expression (DO_COND (t));
|
||
pp_cxx_right_paren (this);
|
||
pp_cxx_semicolon (this);
|
||
pp_needs_newline (this) = true;
|
||
break;
|
||
|
||
case FOR_STMT:
|
||
pp_cxx_ws_string (this, "for");
|
||
pp_space (this);
|
||
pp_cxx_left_paren (this);
|
||
if (FOR_INIT_STMT (t))
|
||
statement (FOR_INIT_STMT (t));
|
||
else
|
||
pp_cxx_semicolon (this);
|
||
pp_needs_newline (this) = false;
|
||
pp_cxx_whitespace (this);
|
||
if (FOR_COND (t))
|
||
expression (FOR_COND (t));
|
||
pp_cxx_semicolon (this);
|
||
pp_needs_newline (this) = false;
|
||
pp_cxx_whitespace (this);
|
||
if (FOR_EXPR (t))
|
||
expression (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;
|
||
|
||
case RANGE_FOR_STMT:
|
||
pp_cxx_ws_string (this, "for");
|
||
pp_space (this);
|
||
pp_cxx_left_paren (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;
|
||
|
||
/* jump-statement:
|
||
goto identifier;
|
||
continue ;
|
||
return expression(opt) ; */
|
||
case BREAK_STMT:
|
||
case CONTINUE_STMT:
|
||
pp_string (this, TREE_CODE (t) == BREAK_STMT ? "break" : "continue");
|
||
pp_cxx_semicolon (this);
|
||
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;
|
||
|
||
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)
|
||
{
|
||
tree t, a;
|
||
if (c == error_mark_node)
|
||
{
|
||
pp_cxx_ws_string(pp, "<unsatisfied-constrained-placeholder>");
|
||
return;
|
||
}
|
||
placeholder_extract_concept_and_args (c, t, a);
|
||
pp->id_expression (t);
|
||
if (TREE_VEC_LENGTH (a) > 1)
|
||
{
|
||
pp_cxx_begin_template_argument_list (pp);
|
||
tree args = make_tree_vec (TREE_VEC_LENGTH (a) - 1);
|
||
for (int i = TREE_VEC_LENGTH (a) - 1; i > 0; --i)
|
||
TREE_VEC_ELT (args, i-1) = TREE_VEC_ELT (a, i);
|
||
pp_cxx_template_argument_list (pp, args);
|
||
ggc_free (args);
|
||
pp_cxx_end_template_argument_list (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
|
||
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);
|
||
}
|
||
|
||
/*
|
||
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
|
||
&& POINTER_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));
|
||
if (FOLD_EXPR_MODIFY_P (t))
|
||
{
|
||
switch (op)
|
||
{
|
||
case NOP_EXPR: return "=";
|
||
case PLUS_EXPR: return "+=";
|
||
case MINUS_EXPR: return "-=";
|
||
case MULT_EXPR: return "*=";
|
||
case TRUNC_DIV_EXPR: return "/=";
|
||
case TRUNC_MOD_EXPR: return "%=";
|
||
case BIT_XOR_EXPR: return "^=";
|
||
case BIT_AND_EXPR: return "&=";
|
||
case BIT_IOR_EXPR: return "|=";
|
||
case LSHIFT_EXPR: return "<<=";
|
||
case RSHIFT_EXPR: return ">>=";
|
||
default: gcc_unreachable ();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
switch (op)
|
||
{
|
||
case PLUS_EXPR: return "+";
|
||
case MINUS_EXPR: return "-";
|
||
case MULT_EXPR: return "*";
|
||
case TRUNC_DIV_EXPR: return "/";
|
||
case TRUNC_MOD_EXPR: return "%";
|
||
case BIT_XOR_EXPR: return "^";
|
||
case BIT_AND_EXPR: return "&";
|
||
case BIT_IOR_EXPR: return "|";
|
||
case LSHIFT_EXPR: return "<<";
|
||
case RSHIFT_EXPR: return ">>";
|
||
case EQ_EXPR: return "==";
|
||
case NE_EXPR: return "!=";
|
||
case LT_EXPR: return "<";
|
||
case GT_EXPR: return ">";
|
||
case LE_EXPR: return "<=";
|
||
case GE_EXPR: return ">=";
|
||
case TRUTH_ANDIF_EXPR: return "&&";
|
||
case TRUTH_ORIF_EXPR: return "||";
|
||
case MEMBER_REF: return "->*";
|
||
case DOTSTAR_EXPR: return ".*";
|
||
case OFFSET_REF: return ".*";
|
||
default: return ","; /* FIXME: Not the right default. */
|
||
}
|
||
}
|
||
}
|
||
|
||
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_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_as");
|
||
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;
|
||
|
||
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)
|
||
{
|
||
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 = TREE_OPERAND (t, 0))
|
||
{
|
||
pp_cxx_parameter_declaration_clause (pp, parms);
|
||
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_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_predicate_constraint (cxx_pretty_printer *pp, tree t)
|
||
{
|
||
pp->expression (TREE_OPERAND (t, 0));
|
||
}
|
||
|
||
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 (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 ();
|
||
}
|
||
|
||
void
|
||
pp_cxx_expression_constraint (cxx_pretty_printer *pp, tree t)
|
||
{
|
||
pp_string (pp, "<valid-expression ");
|
||
pp_cxx_left_paren (pp);
|
||
pp->expression (TREE_OPERAND (t, 0));
|
||
pp_cxx_right_paren (pp);
|
||
pp_string (pp, ">");
|
||
}
|
||
|
||
void
|
||
pp_cxx_type_constraint (cxx_pretty_printer *pp, tree t)
|
||
{
|
||
pp_string (pp, "<valid-type ");
|
||
pp->type_id (TREE_OPERAND (t, 0));
|
||
pp_string (pp, ">");
|
||
}
|
||
|
||
void
|
||
pp_cxx_implicit_conversion_constraint (cxx_pretty_printer *pp, tree t)
|
||
{
|
||
pp_string (pp, "<implicitly-conversion ");
|
||
pp_cxx_left_paren (pp);
|
||
pp->expression (ICONV_CONSTR_EXPR (t));
|
||
pp_cxx_right_paren (pp);
|
||
pp_cxx_ws_string (pp, "to");
|
||
pp->type_id (ICONV_CONSTR_TYPE (t));
|
||
pp_string (pp, ">");
|
||
}
|
||
|
||
void
|
||
pp_cxx_argument_deduction_constraint (cxx_pretty_printer *pp, tree t)
|
||
{
|
||
pp_string (pp, "<argument-deduction ");
|
||
pp_cxx_left_paren (pp);
|
||
pp->expression (DEDUCT_CONSTR_EXPR (t));
|
||
pp_cxx_right_paren (pp);
|
||
pp_cxx_ws_string (pp, "as");
|
||
pp->expression (DEDUCT_CONSTR_PATTERN (t));
|
||
pp_string (pp, ">");
|
||
}
|
||
|
||
void
|
||
pp_cxx_exception_constraint (cxx_pretty_printer *pp, tree t)
|
||
{
|
||
pp_cxx_ws_string (pp, "noexcept");
|
||
pp_cxx_whitespace (pp);
|
||
pp_cxx_left_paren (pp);
|
||
pp->expression (TREE_OPERAND (t, 0));
|
||
pp_cxx_right_paren (pp);
|
||
}
|
||
|
||
void
|
||
pp_cxx_parameterized_constraint (cxx_pretty_printer *pp, tree t)
|
||
{
|
||
pp_left_paren (pp);
|
||
pp_string (pp, "<requires ");
|
||
if (tree parms = PARM_CONSTR_PARMS (t))
|
||
{
|
||
pp_cxx_parameter_declaration_clause (pp, parms);
|
||
pp_cxx_whitespace (pp);
|
||
}
|
||
pp_cxx_constraint (pp, PARM_CONSTR_OPERAND (t));
|
||
pp_string (pp, ">");
|
||
}
|
||
|
||
void
|
||
pp_cxx_conjunction (cxx_pretty_printer *pp, tree t)
|
||
{
|
||
pp_cxx_constraint (pp, TREE_OPERAND (t, 0));
|
||
pp_string (pp, " and ");
|
||
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, " or ");
|
||
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 PRED_CONSTR:
|
||
pp_cxx_predicate_constraint (pp, t);
|
||
break;
|
||
|
||
case CHECK_CONSTR:
|
||
pp_cxx_check_constraint (pp, t);
|
||
break;
|
||
|
||
case EXPR_CONSTR:
|
||
pp_cxx_expression_constraint (pp, t);
|
||
break;
|
||
|
||
case TYPE_CONSTR:
|
||
pp_cxx_type_constraint (pp, t);
|
||
break;
|
||
|
||
case ICONV_CONSTR:
|
||
pp_cxx_implicit_conversion_constraint (pp, t);
|
||
break;
|
||
|
||
case DEDUCT_CONSTR:
|
||
pp_cxx_argument_deduction_constraint (pp, t);
|
||
break;
|
||
|
||
case EXCEPT_CONSTR:
|
||
pp_cxx_exception_constraint (pp, t);
|
||
break;
|
||
|
||
case PARM_CONSTR:
|
||
pp_cxx_parameterized_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;
|
||
}
|