| /* Language-dependent node constructors for parse phase of GNU compiler. |
| Copyright (C) 1987-2021 Free Software Foundation, Inc. |
| Hacked by Michael Tiemann (tiemann@cygnus.com) |
| |
| 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 "tree.h" |
| #include "cp-tree.h" |
| #include "gimple-expr.h" |
| #include "cgraph.h" |
| #include "stor-layout.h" |
| #include "print-tree.h" |
| #include "tree-iterator.h" |
| #include "tree-inline.h" |
| #include "debug.h" |
| #include "convert.h" |
| #include "gimplify.h" |
| #include "stringpool.h" |
| #include "attribs.h" |
| #include "flags.h" |
| #include "selftest.h" |
| |
| static tree bot_manip (tree *, int *, void *); |
| static tree bot_replace (tree *, int *, void *); |
| static hashval_t list_hash_pieces (tree, tree, tree); |
| static tree build_target_expr (tree, tree, tsubst_flags_t); |
| static tree count_trees_r (tree *, int *, void *); |
| static tree verify_stmt_tree_r (tree *, int *, void *); |
| |
| static tree handle_init_priority_attribute (tree *, tree, tree, int, bool *); |
| static tree handle_abi_tag_attribute (tree *, tree, tree, int, bool *); |
| |
| /* If REF is an lvalue, returns the kind of lvalue that REF is. |
| Otherwise, returns clk_none. */ |
| |
| cp_lvalue_kind |
| lvalue_kind (const_tree ref) |
| { |
| cp_lvalue_kind op1_lvalue_kind = clk_none; |
| cp_lvalue_kind op2_lvalue_kind = clk_none; |
| |
| /* Expressions of reference type are sometimes wrapped in |
| INDIRECT_REFs. INDIRECT_REFs are just internal compiler |
| representation, not part of the language, so we have to look |
| through them. */ |
| if (REFERENCE_REF_P (ref)) |
| return lvalue_kind (TREE_OPERAND (ref, 0)); |
| |
| if (TREE_TYPE (ref) |
| && TYPE_REF_P (TREE_TYPE (ref))) |
| { |
| /* unnamed rvalue references are rvalues */ |
| if (TYPE_REF_IS_RVALUE (TREE_TYPE (ref)) |
| && TREE_CODE (ref) != PARM_DECL |
| && !VAR_P (ref) |
| && TREE_CODE (ref) != COMPONENT_REF |
| /* Functions are always lvalues. */ |
| && TREE_CODE (TREE_TYPE (TREE_TYPE (ref))) != FUNCTION_TYPE) |
| { |
| op1_lvalue_kind = clk_rvalueref; |
| if (implicit_rvalue_p (ref)) |
| op1_lvalue_kind |= clk_implicit_rval; |
| return op1_lvalue_kind; |
| } |
| |
| /* lvalue references and named rvalue references are lvalues. */ |
| return clk_ordinary; |
| } |
| |
| if (ref == current_class_ptr) |
| return clk_none; |
| |
| /* Expressions with cv void type are prvalues. */ |
| if (TREE_TYPE (ref) && VOID_TYPE_P (TREE_TYPE (ref))) |
| return clk_none; |
| |
| switch (TREE_CODE (ref)) |
| { |
| case SAVE_EXPR: |
| return clk_none; |
| |
| /* preincrements and predecrements are valid lvals, provided |
| what they refer to are valid lvals. */ |
| case PREINCREMENT_EXPR: |
| case PREDECREMENT_EXPR: |
| case TRY_CATCH_EXPR: |
| case REALPART_EXPR: |
| case IMAGPART_EXPR: |
| case VIEW_CONVERT_EXPR: |
| return lvalue_kind (TREE_OPERAND (ref, 0)); |
| |
| case ARRAY_REF: |
| { |
| tree op1 = TREE_OPERAND (ref, 0); |
| if (TREE_CODE (TREE_TYPE (op1)) == ARRAY_TYPE) |
| { |
| op1_lvalue_kind = lvalue_kind (op1); |
| if (op1_lvalue_kind == clk_class) |
| /* in the case of an array operand, the result is an lvalue if |
| that operand is an lvalue and an xvalue otherwise */ |
| op1_lvalue_kind = clk_rvalueref; |
| return op1_lvalue_kind; |
| } |
| else |
| return clk_ordinary; |
| } |
| |
| case MEMBER_REF: |
| case DOTSTAR_EXPR: |
| if (TREE_CODE (ref) == MEMBER_REF) |
| op1_lvalue_kind = clk_ordinary; |
| else |
| op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 0)); |
| if (TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (ref, 1)))) |
| op1_lvalue_kind = clk_none; |
| else if (op1_lvalue_kind == clk_class) |
| /* The result of a .* expression whose second operand is a pointer to a |
| data member is an lvalue if the first operand is an lvalue and an |
| xvalue otherwise. */ |
| op1_lvalue_kind = clk_rvalueref; |
| return op1_lvalue_kind; |
| |
| case COMPONENT_REF: |
| if (BASELINK_P (TREE_OPERAND (ref, 1))) |
| { |
| tree fn = BASELINK_FUNCTIONS (TREE_OPERAND (ref, 1)); |
| |
| /* For static member function recurse on the BASELINK, we can get |
| here e.g. from reference_binding. If BASELINK_FUNCTIONS is |
| OVERLOAD, the overload is resolved first if possible through |
| resolve_address_of_overloaded_function. */ |
| if (TREE_CODE (fn) == FUNCTION_DECL && DECL_STATIC_FUNCTION_P (fn)) |
| return lvalue_kind (TREE_OPERAND (ref, 1)); |
| } |
| op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 0)); |
| if (op1_lvalue_kind == clk_class) |
| /* If E1 is an lvalue, then E1.E2 is an lvalue; |
| otherwise E1.E2 is an xvalue. */ |
| op1_lvalue_kind = clk_rvalueref; |
| |
| /* Look at the member designator. */ |
| if (!op1_lvalue_kind) |
| ; |
| else if (is_overloaded_fn (TREE_OPERAND (ref, 1))) |
| /* The "field" can be a FUNCTION_DECL or an OVERLOAD in some |
| situations. If we're seeing a COMPONENT_REF, it's a non-static |
| member, so it isn't an lvalue. */ |
| op1_lvalue_kind = clk_none; |
| else if (TREE_CODE (TREE_OPERAND (ref, 1)) != FIELD_DECL) |
| /* This can be IDENTIFIER_NODE in a template. */; |
| else if (DECL_C_BIT_FIELD (TREE_OPERAND (ref, 1))) |
| { |
| /* Clear the ordinary bit. If this object was a class |
| rvalue we want to preserve that information. */ |
| op1_lvalue_kind &= ~clk_ordinary; |
| /* The lvalue is for a bitfield. */ |
| op1_lvalue_kind |= clk_bitfield; |
| } |
| else if (DECL_PACKED (TREE_OPERAND (ref, 1))) |
| op1_lvalue_kind |= clk_packed; |
| |
| return op1_lvalue_kind; |
| |
| case STRING_CST: |
| case COMPOUND_LITERAL_EXPR: |
| return clk_ordinary; |
| |
| case CONST_DECL: |
| /* CONST_DECL without TREE_STATIC are enumeration values and |
| thus not lvalues. With TREE_STATIC they are used by ObjC++ |
| in objc_build_string_object and need to be considered as |
| lvalues. */ |
| if (! TREE_STATIC (ref)) |
| return clk_none; |
| /* FALLTHRU */ |
| case VAR_DECL: |
| if (VAR_P (ref) && DECL_HAS_VALUE_EXPR_P (ref)) |
| return lvalue_kind (DECL_VALUE_EXPR (CONST_CAST_TREE (ref))); |
| |
| if (TREE_READONLY (ref) && ! TREE_STATIC (ref) |
| && DECL_LANG_SPECIFIC (ref) |
| && DECL_IN_AGGR_P (ref)) |
| return clk_none; |
| /* FALLTHRU */ |
| case INDIRECT_REF: |
| case ARROW_EXPR: |
| case PARM_DECL: |
| case RESULT_DECL: |
| case PLACEHOLDER_EXPR: |
| return clk_ordinary; |
| |
| /* A scope ref in a template, left as SCOPE_REF to support later |
| access checking. */ |
| case SCOPE_REF: |
| gcc_assert (!type_dependent_expression_p (CONST_CAST_TREE (ref))); |
| { |
| tree op = TREE_OPERAND (ref, 1); |
| if (TREE_CODE (op) == FIELD_DECL) |
| return (DECL_C_BIT_FIELD (op) ? clk_bitfield : clk_ordinary); |
| else |
| return lvalue_kind (op); |
| } |
| |
| case MAX_EXPR: |
| case MIN_EXPR: |
| /* Disallow <? and >? as lvalues if either argument side-effects. */ |
| if (TREE_SIDE_EFFECTS (TREE_OPERAND (ref, 0)) |
| || TREE_SIDE_EFFECTS (TREE_OPERAND (ref, 1))) |
| return clk_none; |
| op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 0)); |
| op2_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 1)); |
| break; |
| |
| case COND_EXPR: |
| if (processing_template_decl) |
| { |
| /* Within templates, a REFERENCE_TYPE will indicate whether |
| the COND_EXPR result is an ordinary lvalue or rvalueref. |
| Since REFERENCE_TYPEs are handled above, if we reach this |
| point, we know we got a plain rvalue. Unless we have a |
| type-dependent expr, that is, but we shouldn't be testing |
| lvalueness if we can't even tell the types yet! */ |
| gcc_assert (!type_dependent_expression_p (CONST_CAST_TREE (ref))); |
| goto default_; |
| } |
| { |
| tree op1 = TREE_OPERAND (ref, 1); |
| if (!op1) op1 = TREE_OPERAND (ref, 0); |
| tree op2 = TREE_OPERAND (ref, 2); |
| op1_lvalue_kind = lvalue_kind (op1); |
| op2_lvalue_kind = lvalue_kind (op2); |
| if (!op1_lvalue_kind != !op2_lvalue_kind) |
| { |
| /* The second or the third operand (but not both) is a |
| throw-expression; the result is of the type |
| and value category of the other. */ |
| if (op1_lvalue_kind && TREE_CODE (op2) == THROW_EXPR) |
| op2_lvalue_kind = op1_lvalue_kind; |
| else if (op2_lvalue_kind && TREE_CODE (op1) == THROW_EXPR) |
| op1_lvalue_kind = op2_lvalue_kind; |
| } |
| } |
| break; |
| |
| case MODOP_EXPR: |
| /* We expect to see unlowered MODOP_EXPRs only during |
| template processing. */ |
| gcc_assert (processing_template_decl); |
| return clk_ordinary; |
| |
| case MODIFY_EXPR: |
| case TYPEID_EXPR: |
| return clk_ordinary; |
| |
| case COMPOUND_EXPR: |
| return lvalue_kind (TREE_OPERAND (ref, 1)); |
| |
| case TARGET_EXPR: |
| return clk_class; |
| |
| case VA_ARG_EXPR: |
| return (CLASS_TYPE_P (TREE_TYPE (ref)) ? clk_class : clk_none); |
| |
| case CALL_EXPR: |
| /* We can see calls outside of TARGET_EXPR in templates. */ |
| if (CLASS_TYPE_P (TREE_TYPE (ref))) |
| return clk_class; |
| return clk_none; |
| |
| case FUNCTION_DECL: |
| /* All functions (except non-static-member functions) are |
| lvalues. */ |
| return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref) |
| ? clk_none : clk_ordinary); |
| |
| case BASELINK: |
| /* We now represent a reference to a single static member function |
| with a BASELINK. */ |
| /* This CONST_CAST is okay because BASELINK_FUNCTIONS returns |
| its argument unmodified and we assign it to a const_tree. */ |
| return lvalue_kind (BASELINK_FUNCTIONS (CONST_CAST_TREE (ref))); |
| |
| case NON_DEPENDENT_EXPR: |
| case PAREN_EXPR: |
| return lvalue_kind (TREE_OPERAND (ref, 0)); |
| |
| case TEMPLATE_PARM_INDEX: |
| if (CLASS_TYPE_P (TREE_TYPE (ref))) |
| /* A template parameter object is an lvalue. */ |
| return clk_ordinary; |
| return clk_none; |
| |
| default: |
| default_: |
| if (!TREE_TYPE (ref)) |
| return clk_none; |
| if (CLASS_TYPE_P (TREE_TYPE (ref)) |
| || TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE) |
| return clk_class; |
| return clk_none; |
| } |
| |
| /* If one operand is not an lvalue at all, then this expression is |
| not an lvalue. */ |
| if (!op1_lvalue_kind || !op2_lvalue_kind) |
| return clk_none; |
| |
| /* Otherwise, it's an lvalue, and it has all the odd properties |
| contributed by either operand. */ |
| op1_lvalue_kind = op1_lvalue_kind | op2_lvalue_kind; |
| /* It's not an ordinary lvalue if it involves any other kind. */ |
| if ((op1_lvalue_kind & ~clk_ordinary) != clk_none) |
| op1_lvalue_kind &= ~clk_ordinary; |
| /* It can't be both a pseudo-lvalue and a non-addressable lvalue. |
| A COND_EXPR of those should be wrapped in a TARGET_EXPR. */ |
| if ((op1_lvalue_kind & (clk_rvalueref|clk_class)) |
| && (op1_lvalue_kind & (clk_bitfield|clk_packed))) |
| op1_lvalue_kind = clk_none; |
| return op1_lvalue_kind; |
| } |
| |
| /* Returns the kind of lvalue that REF is, in the sense of [basic.lval]. */ |
| |
| cp_lvalue_kind |
| real_lvalue_p (const_tree ref) |
| { |
| cp_lvalue_kind kind = lvalue_kind (ref); |
| if (kind & (clk_rvalueref|clk_class)) |
| return clk_none; |
| else |
| return kind; |
| } |
| |
| /* c-common wants us to return bool. */ |
| |
| bool |
| lvalue_p (const_tree t) |
| { |
| return real_lvalue_p (t); |
| } |
| |
| /* This differs from lvalue_p in that xvalues are included. */ |
| |
| bool |
| glvalue_p (const_tree ref) |
| { |
| cp_lvalue_kind kind = lvalue_kind (ref); |
| if (kind & clk_class) |
| return false; |
| else |
| return (kind != clk_none); |
| } |
| |
| /* This differs from glvalue_p in that class prvalues are included. */ |
| |
| bool |
| obvalue_p (const_tree ref) |
| { |
| return (lvalue_kind (ref) != clk_none); |
| } |
| |
| /* Returns true if REF is an xvalue (the result of dereferencing an rvalue |
| reference), false otherwise. */ |
| |
| bool |
| xvalue_p (const_tree ref) |
| { |
| return (lvalue_kind (ref) == clk_rvalueref); |
| } |
| |
| /* True if REF is a bit-field. */ |
| |
| bool |
| bitfield_p (const_tree ref) |
| { |
| return (lvalue_kind (ref) & clk_bitfield); |
| } |
| |
| /* C++-specific version of stabilize_reference. */ |
| |
| tree |
| cp_stabilize_reference (tree ref) |
| { |
| STRIP_ANY_LOCATION_WRAPPER (ref); |
| switch (TREE_CODE (ref)) |
| { |
| case NON_DEPENDENT_EXPR: |
| /* We aren't actually evaluating this. */ |
| return ref; |
| |
| /* We need to treat specially anything stabilize_reference doesn't |
| handle specifically. */ |
| case VAR_DECL: |
| case PARM_DECL: |
| case RESULT_DECL: |
| CASE_CONVERT: |
| case FLOAT_EXPR: |
| case FIX_TRUNC_EXPR: |
| case INDIRECT_REF: |
| case COMPONENT_REF: |
| case BIT_FIELD_REF: |
| case ARRAY_REF: |
| case ARRAY_RANGE_REF: |
| case ERROR_MARK: |
| break; |
| default: |
| cp_lvalue_kind kind = lvalue_kind (ref); |
| if ((kind & ~clk_class) != clk_none) |
| { |
| tree type = unlowered_expr_type (ref); |
| bool rval = !!(kind & clk_rvalueref); |
| type = cp_build_reference_type (type, rval); |
| /* This inhibits warnings in, eg, cxx_mark_addressable |
| (c++/60955). */ |
| warning_sentinel s (extra_warnings); |
| ref = build_static_cast (input_location, type, ref, |
| tf_error); |
| } |
| } |
| |
| return stabilize_reference (ref); |
| } |
| |
| /* Test whether DECL is a builtin that may appear in a |
| constant-expression. */ |
| |
| bool |
| builtin_valid_in_constant_expr_p (const_tree decl) |
| { |
| STRIP_ANY_LOCATION_WRAPPER (decl); |
| if (TREE_CODE (decl) != FUNCTION_DECL) |
| /* Not a function. */ |
| return false; |
| if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL) |
| { |
| if (fndecl_built_in_p (decl, BUILT_IN_FRONTEND)) |
| switch (DECL_FE_FUNCTION_CODE (decl)) |
| { |
| case CP_BUILT_IN_IS_CONSTANT_EVALUATED: |
| case CP_BUILT_IN_SOURCE_LOCATION: |
| case CP_BUILT_IN_IS_CORRESPONDING_MEMBER: |
| case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: |
| return true; |
| default: |
| break; |
| } |
| /* Not a built-in. */ |
| return false; |
| } |
| switch (DECL_FUNCTION_CODE (decl)) |
| { |
| /* These always have constant results like the corresponding |
| macros/symbol. */ |
| case BUILT_IN_FILE: |
| case BUILT_IN_FUNCTION: |
| case BUILT_IN_LINE: |
| |
| /* The following built-ins are valid in constant expressions |
| when their arguments are. */ |
| case BUILT_IN_ADD_OVERFLOW_P: |
| case BUILT_IN_SUB_OVERFLOW_P: |
| case BUILT_IN_MUL_OVERFLOW_P: |
| |
| /* These have constant results even if their operands are |
| non-constant. */ |
| case BUILT_IN_CONSTANT_P: |
| case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| /* Build a TARGET_EXPR, initializing the DECL with the VALUE. */ |
| |
| static tree |
| build_target_expr (tree decl, tree value, tsubst_flags_t complain) |
| { |
| tree t; |
| tree type = TREE_TYPE (decl); |
| |
| value = mark_rvalue_use (value); |
| |
| gcc_checking_assert (VOID_TYPE_P (TREE_TYPE (value)) |
| || TREE_TYPE (decl) == TREE_TYPE (value) |
| /* On ARM ctors return 'this'. */ |
| || (TYPE_PTR_P (TREE_TYPE (value)) |
| && TREE_CODE (value) == CALL_EXPR) |
| || useless_type_conversion_p (TREE_TYPE (decl), |
| TREE_TYPE (value))); |
| |
| /* Set TREE_READONLY for optimization, such as gimplify_init_constructor |
| moving a constant aggregate into .rodata. */ |
| if (CP_TYPE_CONST_NON_VOLATILE_P (type) |
| && !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) |
| && !VOID_TYPE_P (TREE_TYPE (value)) |
| && reduced_constant_expression_p (value)) |
| TREE_READONLY (decl) = true; |
| |
| if (complain & tf_no_cleanup) |
| /* The caller is building a new-expr and does not need a cleanup. */ |
| t = NULL_TREE; |
| else |
| { |
| t = cxx_maybe_build_cleanup (decl, complain); |
| if (t == error_mark_node) |
| return error_mark_node; |
| } |
| t = build4 (TARGET_EXPR, type, decl, value, t, NULL_TREE); |
| if (location_t eloc = cp_expr_location (value)) |
| SET_EXPR_LOCATION (t, eloc); |
| /* We always set TREE_SIDE_EFFECTS so that expand_expr does not |
| ignore the TARGET_EXPR. If there really turn out to be no |
| side-effects, then the optimizer should be able to get rid of |
| whatever code is generated anyhow. */ |
| TREE_SIDE_EFFECTS (t) = 1; |
| |
| return t; |
| } |
| |
| /* Return an undeclared local temporary of type TYPE for use in building a |
| TARGET_EXPR. */ |
| |
| tree |
| build_local_temp (tree type) |
| { |
| tree slot = build_decl (input_location, |
| VAR_DECL, NULL_TREE, type); |
| DECL_ARTIFICIAL (slot) = 1; |
| DECL_IGNORED_P (slot) = 1; |
| DECL_CONTEXT (slot) = current_function_decl; |
| layout_decl (slot, 0); |
| return slot; |
| } |
| |
| /* Return whether DECL is such a local temporary (or one from |
| create_tmp_var_raw). */ |
| |
| bool |
| is_local_temp (tree decl) |
| { |
| return (VAR_P (decl) && DECL_ARTIFICIAL (decl) |
| && !TREE_STATIC (decl) |
| && DECL_FUNCTION_SCOPE_P (decl)); |
| } |
| |
| /* Set various status flags when building an AGGR_INIT_EXPR object T. */ |
| |
| static void |
| process_aggr_init_operands (tree t) |
| { |
| bool side_effects; |
| |
| side_effects = TREE_SIDE_EFFECTS (t); |
| if (!side_effects) |
| { |
| int i, n; |
| n = TREE_OPERAND_LENGTH (t); |
| for (i = 1; i < n; i++) |
| { |
| tree op = TREE_OPERAND (t, i); |
| if (op && TREE_SIDE_EFFECTS (op)) |
| { |
| side_effects = 1; |
| break; |
| } |
| } |
| } |
| TREE_SIDE_EFFECTS (t) = side_effects; |
| } |
| |
| /* Build an AGGR_INIT_EXPR of class tcc_vl_exp with the indicated RETURN_TYPE, |
| FN, and SLOT. NARGS is the number of call arguments which are specified |
| as a tree array ARGS. */ |
| |
| static tree |
| build_aggr_init_array (tree return_type, tree fn, tree slot, int nargs, |
| tree *args) |
| { |
| tree t; |
| int i; |
| |
| t = build_vl_exp (AGGR_INIT_EXPR, nargs + 3); |
| TREE_TYPE (t) = return_type; |
| AGGR_INIT_EXPR_FN (t) = fn; |
| AGGR_INIT_EXPR_SLOT (t) = slot; |
| for (i = 0; i < nargs; i++) |
| AGGR_INIT_EXPR_ARG (t, i) = args[i]; |
| process_aggr_init_operands (t); |
| return t; |
| } |
| |
| /* INIT is a CALL_EXPR or AGGR_INIT_EXPR which needs info about its |
| target. TYPE is the type to be initialized. |
| |
| Build an AGGR_INIT_EXPR to represent the initialization. This function |
| differs from build_cplus_new in that an AGGR_INIT_EXPR can only be used |
| to initialize another object, whereas a TARGET_EXPR can either |
| initialize another object or create its own temporary object, and as a |
| result building up a TARGET_EXPR requires that the type's destructor be |
| callable. */ |
| |
| tree |
| build_aggr_init_expr (tree type, tree init) |
| { |
| tree fn; |
| tree slot; |
| tree rval; |
| int is_ctor; |
| |
| gcc_assert (!VOID_TYPE_P (type)); |
| |
| /* Don't build AGGR_INIT_EXPR in a template. */ |
| if (processing_template_decl) |
| return init; |
| |
| fn = cp_get_callee (init); |
| if (fn == NULL_TREE) |
| return convert (type, init); |
| |
| is_ctor = (TREE_CODE (fn) == ADDR_EXPR |
| && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL |
| && DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0))); |
| |
| /* We split the CALL_EXPR into its function and its arguments here. |
| Then, in expand_expr, we put them back together. The reason for |
| this is that this expression might be a default argument |
| expression. In that case, we need a new temporary every time the |
| expression is used. That's what break_out_target_exprs does; it |
| replaces every AGGR_INIT_EXPR with a copy that uses a fresh |
| temporary slot. Then, expand_expr builds up a call-expression |
| using the new slot. */ |
| |
| /* If we don't need to use a constructor to create an object of this |
| type, don't mess with AGGR_INIT_EXPR. */ |
| if (is_ctor || TREE_ADDRESSABLE (type)) |
| { |
| slot = build_local_temp (type); |
| |
| if (TREE_CODE (init) == CALL_EXPR) |
| { |
| rval = build_aggr_init_array (void_type_node, fn, slot, |
| call_expr_nargs (init), |
| CALL_EXPR_ARGP (init)); |
| AGGR_INIT_FROM_THUNK_P (rval) |
| = CALL_FROM_THUNK_P (init); |
| } |
| else |
| { |
| rval = build_aggr_init_array (void_type_node, fn, slot, |
| aggr_init_expr_nargs (init), |
| AGGR_INIT_EXPR_ARGP (init)); |
| AGGR_INIT_FROM_THUNK_P (rval) |
| = AGGR_INIT_FROM_THUNK_P (init); |
| } |
| TREE_SIDE_EFFECTS (rval) = 1; |
| AGGR_INIT_VIA_CTOR_P (rval) = is_ctor; |
| TREE_NOTHROW (rval) = TREE_NOTHROW (init); |
| CALL_EXPR_OPERATOR_SYNTAX (rval) = CALL_EXPR_OPERATOR_SYNTAX (init); |
| CALL_EXPR_ORDERED_ARGS (rval) = CALL_EXPR_ORDERED_ARGS (init); |
| CALL_EXPR_REVERSE_ARGS (rval) = CALL_EXPR_REVERSE_ARGS (init); |
| } |
| else |
| rval = init; |
| |
| return rval; |
| } |
| |
| /* INIT is a CALL_EXPR or AGGR_INIT_EXPR which needs info about its |
| target. TYPE is the type that this initialization should appear to |
| have. |
| |
| Build an encapsulation of the initialization to perform |
| and return it so that it can be processed by language-independent |
| and language-specific expression expanders. */ |
| |
| tree |
| build_cplus_new (tree type, tree init, tsubst_flags_t complain) |
| { |
| /* This function should cope with what build_special_member_call |
| can produce. When performing parenthesized aggregate initialization, |
| it can produce a { }. */ |
| if (BRACE_ENCLOSED_INITIALIZER_P (init)) |
| { |
| gcc_assert (cxx_dialect >= cxx20); |
| return finish_compound_literal (type, init, complain); |
| } |
| |
| tree rval = build_aggr_init_expr (type, init); |
| tree slot; |
| |
| if (init == error_mark_node) |
| return error_mark_node; |
| |
| if (!complete_type_or_maybe_complain (type, init, complain)) |
| return error_mark_node; |
| |
| /* Make sure that we're not trying to create an instance of an |
| abstract class. */ |
| if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain)) |
| return error_mark_node; |
| |
| if (TREE_CODE (rval) == AGGR_INIT_EXPR) |
| slot = AGGR_INIT_EXPR_SLOT (rval); |
| else if (TREE_CODE (rval) == CALL_EXPR |
| || TREE_CODE (rval) == CONSTRUCTOR) |
| slot = build_local_temp (type); |
| else |
| return rval; |
| |
| rval = build_target_expr (slot, rval, complain); |
| |
| if (rval != error_mark_node) |
| TARGET_EXPR_IMPLICIT_P (rval) = 1; |
| |
| return rval; |
| } |
| |
| /* Subroutine of build_vec_init_expr: Build up a single element |
| intialization as a proxy for the full array initialization to get things |
| marked as used and any appropriate diagnostics. |
| |
| Since we're deferring building the actual constructor calls until |
| gimplification time, we need to build one now and throw it away so |
| that the relevant constructor gets mark_used before cgraph decides |
| what functions are needed. Here we assume that init is either |
| NULL_TREE, void_type_node (indicating value-initialization), or |
| another array to copy. */ |
| |
| static tree |
| build_vec_init_elt (tree type, tree init, tsubst_flags_t complain) |
| { |
| tree inner_type = strip_array_types (type); |
| |
| if (integer_zerop (array_type_nelts_total (type)) |
| || !CLASS_TYPE_P (inner_type)) |
| /* No interesting initialization to do. */ |
| return integer_zero_node; |
| else if (init == void_type_node) |
| return build_value_init (inner_type, complain); |
| |
| gcc_assert (init == NULL_TREE |
| || (same_type_ignoring_top_level_qualifiers_p |
| (type, TREE_TYPE (init)))); |
| |
| releasing_vec argvec; |
| if (init) |
| { |
| tree init_type = strip_array_types (TREE_TYPE (init)); |
| tree dummy = build_dummy_object (init_type); |
| if (!lvalue_p (init)) |
| dummy = move (dummy); |
| argvec->quick_push (dummy); |
| } |
| init = build_special_member_call (NULL_TREE, complete_ctor_identifier, |
| &argvec, inner_type, LOOKUP_NORMAL, |
| complain); |
| |
| /* For a trivial constructor, build_over_call creates a TARGET_EXPR. But |
| we don't want one here because we aren't creating a temporary. */ |
| if (TREE_CODE (init) == TARGET_EXPR) |
| init = TARGET_EXPR_INITIAL (init); |
| |
| return init; |
| } |
| |
| /* Return a TARGET_EXPR which expresses the initialization of an array to |
| be named later, either default-initialization or copy-initialization |
| from another array of the same type. */ |
| |
| tree |
| build_vec_init_expr (tree type, tree init, tsubst_flags_t complain) |
| { |
| tree slot; |
| bool value_init = false; |
| tree elt_init; |
| if (init && TREE_CODE (init) == CONSTRUCTOR) |
| { |
| gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (init)); |
| /* We built any needed constructor calls in digest_init. */ |
| elt_init = init; |
| } |
| else |
| elt_init = build_vec_init_elt (type, init, complain); |
| |
| if (init == void_type_node) |
| { |
| value_init = true; |
| init = NULL_TREE; |
| } |
| |
| slot = build_local_temp (type); |
| init = build2 (VEC_INIT_EXPR, type, slot, init); |
| TREE_SIDE_EFFECTS (init) = true; |
| SET_EXPR_LOCATION (init, input_location); |
| |
| if (cxx_dialect >= cxx11 |
| && potential_constant_expression (elt_init)) |
| VEC_INIT_EXPR_IS_CONSTEXPR (init) = true; |
| VEC_INIT_EXPR_VALUE_INIT (init) = value_init; |
| |
| return init; |
| } |
| |
| /* Give a helpful diagnostic for a non-constexpr VEC_INIT_EXPR in a context |
| that requires a constant expression. */ |
| |
| void |
| diagnose_non_constexpr_vec_init (tree expr) |
| { |
| tree type = TREE_TYPE (VEC_INIT_EXPR_SLOT (expr)); |
| tree init, elt_init; |
| if (VEC_INIT_EXPR_VALUE_INIT (expr)) |
| init = void_type_node; |
| else |
| init = VEC_INIT_EXPR_INIT (expr); |
| |
| elt_init = build_vec_init_elt (type, init, tf_warning_or_error); |
| require_potential_constant_expression (elt_init); |
| } |
| |
| tree |
| build_array_copy (tree init) |
| { |
| return build_vec_init_expr (TREE_TYPE (init), init, tf_warning_or_error); |
| } |
| |
| /* Build a TARGET_EXPR using INIT to initialize a new temporary of the |
| indicated TYPE. */ |
| |
| tree |
| build_target_expr_with_type (tree init, tree type, tsubst_flags_t complain) |
| { |
| gcc_assert (!VOID_TYPE_P (type)); |
| gcc_assert (!VOID_TYPE_P (TREE_TYPE (init))); |
| |
| if (TREE_CODE (init) == TARGET_EXPR |
| || init == error_mark_node) |
| return init; |
| else if (CLASS_TYPE_P (type) && type_has_nontrivial_copy_init (type) |
| && TREE_CODE (init) != COND_EXPR |
| && TREE_CODE (init) != CONSTRUCTOR |
| && TREE_CODE (init) != VA_ARG_EXPR |
| && TREE_CODE (init) != CALL_EXPR) |
| /* We need to build up a copy constructor call. COND_EXPR is a special |
| case because we already have copies on the arms and we don't want |
| another one here. A CONSTRUCTOR is aggregate initialization, which |
| is handled separately. A VA_ARG_EXPR is magic creation of an |
| aggregate; there's no additional work to be done. A CALL_EXPR |
| already creates a prvalue. */ |
| return force_rvalue (init, complain); |
| |
| return force_target_expr (type, init, complain); |
| } |
| |
| /* Like the above function, but without the checking. This function should |
| only be used by code which is deliberately trying to subvert the type |
| system, such as call_builtin_trap. Or build_over_call, to avoid |
| infinite recursion. */ |
| |
| tree |
| force_target_expr (tree type, tree init, tsubst_flags_t complain) |
| { |
| tree slot; |
| |
| gcc_assert (!VOID_TYPE_P (type)); |
| |
| slot = build_local_temp (type); |
| return build_target_expr (slot, init, complain); |
| } |
| |
| /* Like build_target_expr_with_type, but use the type of INIT. */ |
| |
| tree |
| get_target_expr_sfinae (tree init, tsubst_flags_t complain) |
| { |
| if (TREE_CODE (init) == AGGR_INIT_EXPR) |
| return build_target_expr (AGGR_INIT_EXPR_SLOT (init), init, complain); |
| else if (TREE_CODE (init) == VEC_INIT_EXPR) |
| return build_target_expr (VEC_INIT_EXPR_SLOT (init), init, complain); |
| else |
| { |
| init = convert_bitfield_to_declared_type (init); |
| return build_target_expr_with_type (init, TREE_TYPE (init), complain); |
| } |
| } |
| |
| tree |
| get_target_expr (tree init) |
| { |
| return get_target_expr_sfinae (init, tf_warning_or_error); |
| } |
| |
| /* If EXPR is a bitfield reference, convert it to the declared type of |
| the bitfield, and return the resulting expression. Otherwise, |
| return EXPR itself. */ |
| |
| tree |
| convert_bitfield_to_declared_type (tree expr) |
| { |
| tree bitfield_type; |
| |
| bitfield_type = is_bitfield_expr_with_lowered_type (expr); |
| if (bitfield_type) |
| expr = convert_to_integer_nofold (TYPE_MAIN_VARIANT (bitfield_type), |
| expr); |
| return expr; |
| } |
| |
| /* EXPR is being used in an rvalue context. Return a version of EXPR |
| that is marked as an rvalue. */ |
| |
| tree |
| rvalue (tree expr) |
| { |
| tree type; |
| |
| if (error_operand_p (expr)) |
| return expr; |
| |
| expr = mark_rvalue_use (expr); |
| |
| /* [basic.lval] |
| |
| Non-class rvalues always have cv-unqualified types. */ |
| type = TREE_TYPE (expr); |
| if (!CLASS_TYPE_P (type) && cv_qualified_p (type)) |
| type = cv_unqualified (type); |
| |
| /* We need to do this for rvalue refs as well to get the right answer |
| from decltype; see c++/36628. */ |
| if (!processing_template_decl && glvalue_p (expr)) |
| { |
| /* But don't use this function for class lvalues; use move (to treat an |
| lvalue as an xvalue) or force_rvalue (to make a prvalue copy). */ |
| gcc_checking_assert (!CLASS_TYPE_P (type)); |
| expr = build1 (NON_LVALUE_EXPR, type, expr); |
| } |
| else if (type != TREE_TYPE (expr)) |
| expr = build_nop (type, expr); |
| |
| return expr; |
| } |
| |
| |
| struct cplus_array_info |
| { |
| tree type; |
| tree domain; |
| }; |
| |
| struct cplus_array_hasher : ggc_ptr_hash<tree_node> |
| { |
| typedef cplus_array_info *compare_type; |
| |
| static hashval_t hash (tree t); |
| static bool equal (tree, cplus_array_info *); |
| }; |
| |
| /* Hash an ARRAY_TYPE. K is really of type `tree'. */ |
| |
| hashval_t |
| cplus_array_hasher::hash (tree t) |
| { |
| hashval_t hash; |
| |
| hash = TYPE_UID (TREE_TYPE (t)); |
| if (TYPE_DOMAIN (t)) |
| hash ^= TYPE_UID (TYPE_DOMAIN (t)); |
| return hash; |
| } |
| |
| /* Compare two ARRAY_TYPEs. K1 is really of type `tree', K2 is really |
| of type `cplus_array_info*'. */ |
| |
| bool |
| cplus_array_hasher::equal (tree t1, cplus_array_info *t2) |
| { |
| return (TREE_TYPE (t1) == t2->type && TYPE_DOMAIN (t1) == t2->domain); |
| } |
| |
| /* Hash table containing dependent array types, which are unsuitable for |
| the language-independent type hash table. */ |
| static GTY (()) hash_table<cplus_array_hasher> *cplus_array_htab; |
| |
| /* Build an ARRAY_TYPE without laying it out. */ |
| |
| static tree |
| build_min_array_type (tree elt_type, tree index_type) |
| { |
| tree t = cxx_make_type (ARRAY_TYPE); |
| TREE_TYPE (t) = elt_type; |
| TYPE_DOMAIN (t) = index_type; |
| return t; |
| } |
| |
| /* Set TYPE_CANONICAL like build_array_type_1, but using |
| build_cplus_array_type. */ |
| |
| static void |
| set_array_type_canon (tree t, tree elt_type, tree index_type, bool dep) |
| { |
| /* Set the canonical type for this new node. */ |
| if (TYPE_STRUCTURAL_EQUALITY_P (elt_type) |
| || (index_type && TYPE_STRUCTURAL_EQUALITY_P (index_type))) |
| SET_TYPE_STRUCTURAL_EQUALITY (t); |
| else if (TYPE_CANONICAL (elt_type) != elt_type |
| || (index_type && TYPE_CANONICAL (index_type) != index_type)) |
| TYPE_CANONICAL (t) |
| = build_cplus_array_type (TYPE_CANONICAL (elt_type), |
| index_type |
| ? TYPE_CANONICAL (index_type) : index_type, |
| dep); |
| else |
| TYPE_CANONICAL (t) = t; |
| } |
| |
| /* Like build_array_type, but handle special C++ semantics: an array of a |
| variant element type is a variant of the array of the main variant of |
| the element type. IS_DEPENDENT is -ve if we should determine the |
| dependency. Otherwise its bool value indicates dependency. */ |
| |
| tree |
| build_cplus_array_type (tree elt_type, tree index_type, int dependent) |
| { |
| tree t; |
| |
| if (elt_type == error_mark_node || index_type == error_mark_node) |
| return error_mark_node; |
| |
| if (dependent < 0) |
| dependent = (uses_template_parms (elt_type) |
| || (index_type && uses_template_parms (index_type))); |
| |
| if (elt_type != TYPE_MAIN_VARIANT (elt_type)) |
| /* Start with an array of the TYPE_MAIN_VARIANT. */ |
| t = build_cplus_array_type (TYPE_MAIN_VARIANT (elt_type), |
| index_type, dependent); |
| else if (dependent) |
| { |
| /* Since type_hash_canon calls layout_type, we need to use our own |
| hash table. */ |
| cplus_array_info cai; |
| hashval_t hash; |
| |
| if (cplus_array_htab == NULL) |
| cplus_array_htab = hash_table<cplus_array_hasher>::create_ggc (61); |
| |
| hash = TYPE_UID (elt_type); |
| if (index_type) |
| hash ^= TYPE_UID (index_type); |
| cai.type = elt_type; |
| cai.domain = index_type; |
| |
| tree *e = cplus_array_htab->find_slot_with_hash (&cai, hash, INSERT); |
| if (*e) |
| /* We have found the type: we're done. */ |
| return (tree) *e; |
| else |
| { |
| /* Build a new array type. */ |
| t = build_min_array_type (elt_type, index_type); |
| |
| /* Store it in the hash table. */ |
| *e = t; |
| |
| /* Set the canonical type for this new node. */ |
| set_array_type_canon (t, elt_type, index_type, dependent); |
| |
| /* Mark it as dependent now, this saves time later. */ |
| TYPE_DEPENDENT_P_VALID (t) = true; |
| TYPE_DEPENDENT_P (t) = true; |
| } |
| } |
| else |
| { |
| bool typeless_storage = is_byte_access_type (elt_type); |
| t = build_array_type (elt_type, index_type, typeless_storage); |
| |
| /* Mark as non-dependenty now, this will save time later. */ |
| TYPE_DEPENDENT_P_VALID (t) = true; |
| } |
| |
| /* Now check whether we already have this array variant. */ |
| if (elt_type != TYPE_MAIN_VARIANT (elt_type)) |
| { |
| tree m = t; |
| for (t = m; t; t = TYPE_NEXT_VARIANT (t)) |
| if (TREE_TYPE (t) == elt_type |
| && TYPE_NAME (t) == NULL_TREE |
| && TYPE_ATTRIBUTES (t) == NULL_TREE) |
| break; |
| if (!t) |
| { |
| t = build_min_array_type (elt_type, index_type); |
| /* Mark dependency now, this saves time later. */ |
| TYPE_DEPENDENT_P_VALID (t) = true; |
| TYPE_DEPENDENT_P (t) = dependent; |
| set_array_type_canon (t, elt_type, index_type, dependent); |
| if (!dependent) |
| { |
| layout_type (t); |
| /* Make sure sizes are shared with the main variant. |
| layout_type can't be called after setting TYPE_NEXT_VARIANT, |
| as it will overwrite alignment etc. of all variants. */ |
| TYPE_SIZE (t) = TYPE_SIZE (m); |
| TYPE_SIZE_UNIT (t) = TYPE_SIZE_UNIT (m); |
| TYPE_TYPELESS_STORAGE (t) = TYPE_TYPELESS_STORAGE (m); |
| } |
| |
| TYPE_MAIN_VARIANT (t) = m; |
| TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m); |
| TYPE_NEXT_VARIANT (m) = t; |
| } |
| } |
| |
| /* Avoid spurious warnings with VLAs (c++/54583). */ |
| if (TYPE_SIZE (t) && EXPR_P (TYPE_SIZE (t))) |
| suppress_warning (TYPE_SIZE (t), OPT_Wunused); |
| |
| /* Push these needs up to the ARRAY_TYPE so that initialization takes |
| place more easily. */ |
| bool needs_ctor = (TYPE_NEEDS_CONSTRUCTING (t) |
| = TYPE_NEEDS_CONSTRUCTING (elt_type)); |
| bool needs_dtor = (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) |
| = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (elt_type)); |
| |
| if (!dependent && t == TYPE_MAIN_VARIANT (t) |
| && !COMPLETE_TYPE_P (t) && COMPLETE_TYPE_P (elt_type)) |
| { |
| /* The element type has been completed since the last time we saw |
| this array type; update the layout and 'tor flags for any variants |
| that need it. */ |
| layout_type (t); |
| for (tree v = TYPE_NEXT_VARIANT (t); v; v = TYPE_NEXT_VARIANT (v)) |
| { |
| TYPE_NEEDS_CONSTRUCTING (v) = needs_ctor; |
| TYPE_HAS_NONTRIVIAL_DESTRUCTOR (v) = needs_dtor; |
| } |
| } |
| |
| return t; |
| } |
| |
| /* Return an ARRAY_TYPE with element type ELT and length N. */ |
| |
| tree |
| build_array_of_n_type (tree elt, int n) |
| { |
| return build_cplus_array_type (elt, build_index_type (size_int (n - 1))); |
| } |
| |
| /* True iff T is an array of unknown bound. */ |
| |
| bool |
| array_of_unknown_bound_p (const_tree t) |
| { |
| return (TREE_CODE (t) == ARRAY_TYPE |
| && !TYPE_DOMAIN (t)); |
| } |
| |
| /* True iff T is an N3639 array of runtime bound (VLA). These were approved |
| for C++14 but then removed. This should only be used for N3639 |
| specifically; code wondering more generally if something is a VLA should use |
| vla_type_p. */ |
| |
| bool |
| array_of_runtime_bound_p (tree t) |
| { |
| if (!t || TREE_CODE (t) != ARRAY_TYPE) |
| return false; |
| if (variably_modified_type_p (TREE_TYPE (t), NULL_TREE)) |
| return false; |
| tree dom = TYPE_DOMAIN (t); |
| if (!dom) |
| return false; |
| tree max = TYPE_MAX_VALUE (dom); |
| return (!potential_rvalue_constant_expression (max) |
| || (!value_dependent_expression_p (max) && !TREE_CONSTANT (max))); |
| } |
| |
| /* True iff T is a variable length array. */ |
| |
| bool |
| vla_type_p (tree t) |
| { |
| for (; t && TREE_CODE (t) == ARRAY_TYPE; |
| t = TREE_TYPE (t)) |
| if (tree dom = TYPE_DOMAIN (t)) |
| { |
| tree max = TYPE_MAX_VALUE (dom); |
| if (!potential_rvalue_constant_expression (max) |
| || (!value_dependent_expression_p (max) && !TREE_CONSTANT (max))) |
| return true; |
| } |
| return false; |
| } |
| |
| |
| /* Return a reference type node of MODE referring to TO_TYPE. If MODE |
| is VOIDmode the standard pointer mode will be picked. If RVAL is |
| true, return an rvalue reference type, otherwise return an lvalue |
| reference type. If a type node exists, reuse it, otherwise create |
| a new one. */ |
| tree |
| cp_build_reference_type_for_mode (tree to_type, machine_mode mode, bool rval) |
| { |
| tree lvalue_ref, t; |
| |
| if (to_type == error_mark_node) |
| return error_mark_node; |
| |
| if (TYPE_REF_P (to_type)) |
| { |
| rval = rval && TYPE_REF_IS_RVALUE (to_type); |
| to_type = TREE_TYPE (to_type); |
| } |
| |
| lvalue_ref = build_reference_type_for_mode (to_type, mode, false); |
| |
| if (!rval) |
| return lvalue_ref; |
| |
| /* This code to create rvalue reference types is based on and tied |
| to the code creating lvalue reference types in the middle-end |
| functions build_reference_type_for_mode and build_reference_type. |
| |
| It works by putting the rvalue reference type nodes after the |
| lvalue reference nodes in the TYPE_NEXT_REF_TO linked list, so |
| they will effectively be ignored by the middle end. */ |
| |
| for (t = lvalue_ref; (t = TYPE_NEXT_REF_TO (t)); ) |
| if (TYPE_REF_IS_RVALUE (t)) |
| return t; |
| |
| t = build_distinct_type_copy (lvalue_ref); |
| |
| TYPE_REF_IS_RVALUE (t) = true; |
| TYPE_NEXT_REF_TO (t) = TYPE_NEXT_REF_TO (lvalue_ref); |
| TYPE_NEXT_REF_TO (lvalue_ref) = t; |
| |
| if (TYPE_STRUCTURAL_EQUALITY_P (to_type)) |
| SET_TYPE_STRUCTURAL_EQUALITY (t); |
| else if (TYPE_CANONICAL (to_type) != to_type) |
| TYPE_CANONICAL (t) |
| = cp_build_reference_type_for_mode (TYPE_CANONICAL (to_type), mode, rval); |
| else |
| TYPE_CANONICAL (t) = t; |
| |
| layout_type (t); |
| |
| return t; |
| |
| } |
| |
| /* Return a reference type node referring to TO_TYPE. If RVAL is |
| true, return an rvalue reference type, otherwise return an lvalue |
| reference type. If a type node exists, reuse it, otherwise create |
| a new one. */ |
| tree |
| cp_build_reference_type (tree to_type, bool rval) |
| { |
| return cp_build_reference_type_for_mode (to_type, VOIDmode, rval); |
| } |
| |
| /* Returns EXPR cast to rvalue reference type, like std::move. */ |
| |
| tree |
| move (tree expr) |
| { |
| tree type = TREE_TYPE (expr); |
| gcc_assert (!TYPE_REF_P (type)); |
| type = cp_build_reference_type (type, /*rval*/true); |
| return build_static_cast (input_location, type, expr, |
| tf_warning_or_error); |
| } |
| |
| /* Used by the C++ front end to build qualified array types. However, |
| the C version of this function does not properly maintain canonical |
| types (which are not used in C). */ |
| tree |
| c_build_qualified_type (tree type, int type_quals, tree /* orig_qual_type */, |
| size_t /* orig_qual_indirect */) |
| { |
| return cp_build_qualified_type (type, type_quals); |
| } |
| |
| |
| /* Make a variant of TYPE, qualified with the TYPE_QUALS. Handles |
| arrays correctly. In particular, if TYPE is an array of T's, and |
| TYPE_QUALS is non-empty, returns an array of qualified T's. |
| |
| FLAGS determines how to deal with ill-formed qualifications. If |
| tf_ignore_bad_quals is set, then bad qualifications are dropped |
| (this is permitted if TYPE was introduced via a typedef or template |
| type parameter). If bad qualifications are dropped and tf_warning |
| is set, then a warning is issued for non-const qualifications. If |
| tf_ignore_bad_quals is not set and tf_error is not set, we |
| return error_mark_node. Otherwise, we issue an error, and ignore |
| the qualifications. |
| |
| Qualification of a reference type is valid when the reference came |
| via a typedef or template type argument. [dcl.ref] No such |
| dispensation is provided for qualifying a function type. [dcl.fct] |
| DR 295 queries this and the proposed resolution brings it into line |
| with qualifying a reference. We implement the DR. We also behave |
| in a similar manner for restricting non-pointer types. */ |
| |
| tree |
| cp_build_qualified_type_real (tree type, |
| int type_quals, |
| tsubst_flags_t complain) |
| { |
| tree result; |
| int bad_quals = TYPE_UNQUALIFIED; |
| |
| if (type == error_mark_node) |
| return type; |
| |
| if (type_quals == cp_type_quals (type)) |
| return type; |
| |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| /* In C++, the qualification really applies to the array element |
| type. Obtain the appropriately qualified element type. */ |
| tree t; |
| tree element_type |
| = cp_build_qualified_type_real (TREE_TYPE (type), |
| type_quals, |
| complain); |
| |
| if (element_type == error_mark_node) |
| return error_mark_node; |
| |
| /* See if we already have an identically qualified type. Tests |
| should be equivalent to those in check_qualified_type. */ |
| for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) |
| if (TREE_TYPE (t) == element_type |
| && TYPE_NAME (t) == TYPE_NAME (type) |
| && TYPE_CONTEXT (t) == TYPE_CONTEXT (type) |
| && attribute_list_equal (TYPE_ATTRIBUTES (t), |
| TYPE_ATTRIBUTES (type))) |
| break; |
| |
| if (!t) |
| { |
| /* If we already know the dependentness, tell the array type |
| constructor. This is important for module streaming, as we cannot |
| dynamically determine that on read in. */ |
| t = build_cplus_array_type (element_type, TYPE_DOMAIN (type), |
| TYPE_DEPENDENT_P_VALID (type) |
| ? int (TYPE_DEPENDENT_P (type)) : -1); |
| |
| /* Keep the typedef name. */ |
| if (TYPE_NAME (t) != TYPE_NAME (type)) |
| { |
| t = build_variant_type_copy (t); |
| TYPE_NAME (t) = TYPE_NAME (type); |
| SET_TYPE_ALIGN (t, TYPE_ALIGN (type)); |
| TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (type); |
| } |
| } |
| |
| /* Even if we already had this variant, we update |
| TYPE_NEEDS_CONSTRUCTING and TYPE_HAS_NONTRIVIAL_DESTRUCTOR in case |
| they changed since the variant was originally created. |
| |
| This seems hokey; if there is some way to use a previous |
| variant *without* coming through here, |
| TYPE_NEEDS_CONSTRUCTING will never be updated. */ |
| TYPE_NEEDS_CONSTRUCTING (t) |
| = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (element_type)); |
| TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) |
| = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (element_type)); |
| return t; |
| } |
| else if (TREE_CODE (type) == TYPE_PACK_EXPANSION) |
| { |
| tree t = PACK_EXPANSION_PATTERN (type); |
| |
| t = cp_build_qualified_type_real (t, type_quals, complain); |
| return make_pack_expansion (t, complain); |
| } |
| |
| /* A reference or method type shall not be cv-qualified. |
| [dcl.ref], [dcl.fct]. This used to be an error, but as of DR 295 |
| (in CD1) we always ignore extra cv-quals on functions. */ |
| |
| /* [dcl.ref/1] Cv-qualified references are ill-formed except when |
| the cv-qualifiers are introduced through the use of a typedef-name |
| ([dcl.typedef], [temp.param]) or decltype-specifier |
| ([dcl.type.decltype]),in which case the cv-qualifiers are |
| ignored. */ |
| if (type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE) |
| && (TYPE_REF_P (type) |
| || FUNC_OR_METHOD_TYPE_P (type))) |
| { |
| if (TYPE_REF_P (type) |
| && (!typedef_variant_p (type) || FUNC_OR_METHOD_TYPE_P (type))) |
| bad_quals |= type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE); |
| type_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE); |
| } |
| |
| /* But preserve any function-cv-quals on a FUNCTION_TYPE. */ |
| if (TREE_CODE (type) == FUNCTION_TYPE) |
| type_quals |= type_memfn_quals (type); |
| |
| /* A restrict-qualified type must be a pointer (or reference) |
| to object or incomplete type. */ |
| if ((type_quals & TYPE_QUAL_RESTRICT) |
| && TREE_CODE (type) != TEMPLATE_TYPE_PARM |
| && TREE_CODE (type) != TYPENAME_TYPE |
| && !INDIRECT_TYPE_P (type)) |
| { |
| bad_quals |= TYPE_QUAL_RESTRICT; |
| type_quals &= ~TYPE_QUAL_RESTRICT; |
| } |
| |
| if (bad_quals == TYPE_UNQUALIFIED |
| || (complain & tf_ignore_bad_quals)) |
| /*OK*/; |
| else if (!(complain & tf_error)) |
| return error_mark_node; |
| else |
| { |
| tree bad_type = build_qualified_type (ptr_type_node, bad_quals); |
| error ("%qV qualifiers cannot be applied to %qT", |
| bad_type, type); |
| } |
| |
| /* Retrieve (or create) the appropriately qualified variant. */ |
| result = build_qualified_type (type, type_quals); |
| |
| return result; |
| } |
| |
| /* Return TYPE with const and volatile removed. */ |
| |
| tree |
| cv_unqualified (tree type) |
| { |
| int quals; |
| |
| if (type == error_mark_node) |
| return type; |
| |
| quals = cp_type_quals (type); |
| quals &= ~(TYPE_QUAL_CONST|TYPE_QUAL_VOLATILE); |
| return cp_build_qualified_type (type, quals); |
| } |
| |
| /* Subroutine of strip_typedefs. We want to apply to RESULT the attributes |
| from ATTRIBS that affect type identity, and no others. If any are not |
| applied, set *remove_attributes to true. */ |
| |
| static tree |
| apply_identity_attributes (tree result, tree attribs, bool *remove_attributes) |
| { |
| tree first_ident = NULL_TREE; |
| tree new_attribs = NULL_TREE; |
| tree *p = &new_attribs; |
| |
| if (OVERLOAD_TYPE_P (result)) |
| { |
| /* On classes and enums all attributes are ingrained. */ |
| gcc_assert (attribs == TYPE_ATTRIBUTES (result)); |
| return result; |
| } |
| |
| for (tree a = attribs; a; a = TREE_CHAIN (a)) |
| { |
| const attribute_spec *as |
| = lookup_attribute_spec (get_attribute_name (a)); |
| if (as && as->affects_type_identity) |
| { |
| if (!first_ident) |
| first_ident = a; |
| else if (first_ident == error_mark_node) |
| { |
| *p = tree_cons (TREE_PURPOSE (a), TREE_VALUE (a), NULL_TREE); |
| p = &TREE_CHAIN (*p); |
| } |
| } |
| else if (first_ident && first_ident != error_mark_node) |
| { |
| for (tree a2 = first_ident; a2 != a; a2 = TREE_CHAIN (a2)) |
| { |
| *p = tree_cons (TREE_PURPOSE (a2), TREE_VALUE (a2), NULL_TREE); |
| p = &TREE_CHAIN (*p); |
| } |
| first_ident = error_mark_node; |
| } |
| } |
| if (first_ident != error_mark_node) |
| new_attribs = first_ident; |
| |
| if (first_ident == attribs) |
| /* All attributes affected type identity. */; |
| else |
| *remove_attributes = true; |
| |
| return cp_build_type_attribute_variant (result, new_attribs); |
| } |
| |
| /* Builds a qualified variant of T that is either not a typedef variant |
| (the default behavior) or not a typedef variant of a user-facing type |
| (if FLAGS contains STF_USER_FACING). |
| |
| E.g. consider the following declarations: |
| typedef const int ConstInt; |
| typedef ConstInt* PtrConstInt; |
| If T is PtrConstInt, this function returns a type representing |
| const int*. |
| In other words, if T is a typedef, the function returns the underlying type. |
| The cv-qualification and attributes of the type returned match the |
| input type. |
| They will always be compatible types. |
| The returned type is built so that all of its subtypes |
| recursively have their typedefs stripped as well. |
| |
| This is different from just returning TYPE_CANONICAL (T) |
| Because of several reasons: |
| * If T is a type that needs structural equality |
| its TYPE_CANONICAL (T) will be NULL. |
| * TYPE_CANONICAL (T) desn't carry type attributes |
| and loses template parameter names. |
| |
| If REMOVE_ATTRIBUTES is non-null, also strip attributes that don't |
| affect type identity, and set the referent to true if any were |
| stripped. */ |
| |
| tree |
| strip_typedefs (tree t, bool *remove_attributes, unsigned int flags) |
| { |
| tree result = NULL, type = NULL, t0 = NULL; |
| |
| if (!t || t == error_mark_node) |
| return t; |
| |
| if (TREE_CODE (t) == TREE_LIST) |
| { |
| bool changed = false; |
| releasing_vec vec; |
| tree r = t; |
| for (; t; t = TREE_CHAIN (t)) |
| { |
| gcc_assert (!TREE_PURPOSE (t)); |
| tree elt = strip_typedefs (TREE_VALUE (t), remove_attributes, flags); |
| if (elt != TREE_VALUE (t)) |
| changed = true; |
| vec_safe_push (vec, elt); |
| } |
| if (changed) |
| r = build_tree_list_vec (vec); |
| return r; |
| } |
| |
| gcc_assert (TYPE_P (t)); |
| |
| if (t == TYPE_CANONICAL (t)) |
| return t; |
| |
| if (!(flags & STF_STRIP_DEPENDENT) |
| && dependent_alias_template_spec_p (t, nt_opaque)) |
| /* DR 1558: However, if the template-id is dependent, subsequent |
| template argument substitution still applies to the template-id. */ |
| return t; |
| |
| switch (TREE_CODE (t)) |
| { |
| case POINTER_TYPE: |
| type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags); |
| result = build_pointer_type_for_mode (type, TYPE_MODE (t), false); |
| break; |
| case REFERENCE_TYPE: |
| type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags); |
| result = cp_build_reference_type_for_mode (type, TYPE_MODE (t), TYPE_REF_IS_RVALUE (t)); |
| break; |
| case OFFSET_TYPE: |
| t0 = strip_typedefs (TYPE_OFFSET_BASETYPE (t), remove_attributes, flags); |
| type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags); |
| result = build_offset_type (t0, type); |
| break; |
| case RECORD_TYPE: |
| if (TYPE_PTRMEMFUNC_P (t)) |
| { |
| t0 = strip_typedefs (TYPE_PTRMEMFUNC_FN_TYPE (t), |
| remove_attributes, flags); |
| result = build_ptrmemfunc_type (t0); |
| } |
| break; |
| case ARRAY_TYPE: |
| type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags); |
| t0 = strip_typedefs (TYPE_DOMAIN (t), remove_attributes, flags); |
| gcc_checking_assert (TYPE_DEPENDENT_P_VALID (t) |
| || !dependent_type_p (t)); |
| result = build_cplus_array_type (type, t0, TYPE_DEPENDENT_P (t)); |
| break; |
| case FUNCTION_TYPE: |
| case METHOD_TYPE: |
| { |
| tree arg_types = NULL, arg_node, arg_node2, arg_type; |
| bool changed; |
| |
| /* Because we stomp on TREE_PURPOSE of TYPE_ARG_TYPES in many places |
| around the compiler (e.g. cp_parser_late_parsing_default_args), we |
| can't expect that re-hashing a function type will find a previous |
| equivalent type, so try to reuse the input type if nothing has |
| changed. If the type is itself a variant, that will change. */ |
| bool is_variant = typedef_variant_p (t); |
| if (remove_attributes |
| && (TYPE_ATTRIBUTES (t) || TYPE_USER_ALIGN (t))) |
| is_variant = true; |
| |
| type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags); |
| tree canon_spec = (flag_noexcept_type |
| ? canonical_eh_spec (TYPE_RAISES_EXCEPTIONS (t)) |
| : NULL_TREE); |
| changed = (type != TREE_TYPE (t) || is_variant |
| || TYPE_RAISES_EXCEPTIONS (t) != canon_spec); |
| |
| for (arg_node = TYPE_ARG_TYPES (t); |
| arg_node; |
| arg_node = TREE_CHAIN (arg_node)) |
| { |
| if (arg_node == void_list_node) |
| break; |
| arg_type = strip_typedefs (TREE_VALUE (arg_node), |
| remove_attributes, flags); |
| gcc_assert (arg_type); |
| if (arg_type == TREE_VALUE (arg_node) && !changed) |
| continue; |
| |
| if (!changed) |
| { |
| changed = true; |
| for (arg_node2 = TYPE_ARG_TYPES (t); |
| arg_node2 != arg_node; |
| arg_node2 = TREE_CHAIN (arg_node2)) |
| arg_types |
| = tree_cons (TREE_PURPOSE (arg_node2), |
| TREE_VALUE (arg_node2), arg_types); |
| } |
| |
| arg_types |
| = tree_cons (TREE_PURPOSE (arg_node), arg_type, arg_types); |
| } |
| |
| if (!changed) |
| return t; |
| |
| if (arg_types) |
| arg_types = nreverse (arg_types); |
| |
| /* A list of parameters not ending with an ellipsis |
| must end with void_list_node. */ |
| if (arg_node) |
| arg_types = chainon (arg_types, void_list_node); |
| |
| if (TREE_CODE (t) == METHOD_TYPE) |
| { |
| tree class_type = TREE_TYPE (TREE_VALUE (arg_types)); |
| gcc_assert (class_type); |
| result = |
| build_method_type_directly (class_type, type, |
| TREE_CHAIN (arg_types)); |
| } |
| else |
| { |
| result = build_function_type (type, arg_types); |
| result = apply_memfn_quals (result, type_memfn_quals (t)); |
| } |
| |
| result = build_cp_fntype_variant (result, |
| type_memfn_rqual (t), canon_spec, |
| TYPE_HAS_LATE_RETURN_TYPE (t)); |
| } |
| break; |
| case TYPENAME_TYPE: |
| { |
| bool changed = false; |
| tree fullname = TYPENAME_TYPE_FULLNAME (t); |
| if (TREE_CODE (fullname) == TEMPLATE_ID_EXPR |
| && TREE_OPERAND (fullname, 1)) |
| { |
| tree args = TREE_OPERAND (fullname, 1); |
| tree new_args = copy_node (args); |
| for (int i = 0; i < TREE_VEC_LENGTH (args); ++i) |
| { |
| tree arg = TREE_VEC_ELT (args, i); |
| tree strip_arg; |
| if (TYPE_P (arg)) |
| strip_arg = strip_typedefs (arg, remove_attributes, flags); |
| else |
| strip_arg = strip_typedefs_expr (arg, remove_attributes, |
| flags); |
| TREE_VEC_ELT (new_args, i) = strip_arg; |
| if (strip_arg != arg) |
| changed = true; |
| } |
| if (changed) |
| { |
| NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_args) |
| = NON_DEFAULT_TEMPLATE_ARGS_COUNT (args); |
| fullname |
| = lookup_template_function (TREE_OPERAND (fullname, 0), |
| new_args); |
| } |
| else |
| ggc_free (new_args); |
| } |
| tree ctx = strip_typedefs (TYPE_CONTEXT (t), remove_attributes, flags); |
| if (!changed && ctx == TYPE_CONTEXT (t) && !typedef_variant_p (t)) |
| return t; |
| tree name = fullname; |
| if (TREE_CODE (fullname) == TEMPLATE_ID_EXPR) |
| name = TREE_OPERAND (fullname, 0); |
| /* Use build_typename_type rather than make_typename_type because we |
| don't want to resolve it here, just strip typedefs. */ |
| result = build_typename_type (ctx, name, fullname, typename_type); |
| } |
| break; |
| case DECLTYPE_TYPE: |
| result = strip_typedefs_expr (DECLTYPE_TYPE_EXPR (t), |
| remove_attributes, flags); |
| if (result == DECLTYPE_TYPE_EXPR (t)) |
| result = NULL_TREE; |
| else |
| result = (finish_decltype_type |
| (result, |
| DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t), |
| tf_none)); |
| break; |
| case UNDERLYING_TYPE: |
| type = strip_typedefs (UNDERLYING_TYPE_TYPE (t), |
| remove_attributes, flags); |
| result = finish_underlying_type (type); |
| break; |
| case TYPE_PACK_EXPANSION: |
| { |
| tree pat = PACK_EXPANSION_PATTERN (t); |
| if (TYPE_P (pat)) |
| { |
| type = strip_typedefs (pat, remove_attributes, flags); |
| if (type != pat) |
| { |
| result = copy_node (t); |
| PACK_EXPANSION_PATTERN (result) = type; |
| } |
| } |
| } |
| break; |
| default: |
| break; |
| } |
| |
| if (!result) |
| { |
| if (typedef_variant_p (t)) |
| { |
| if ((flags & STF_USER_VISIBLE) |
| && !user_facing_original_type_p (t)) |
| return t; |
| /* If T is a non-template alias or typedef, we can assume that |
| instantiating its definition will hit any substitution failure, |
| so we don't need to retain it here as well. */ |
| if (!alias_template_specialization_p (t, nt_opaque)) |
| flags |= STF_STRIP_DEPENDENT; |
| result = strip_typedefs (DECL_ORIGINAL_TYPE (TYPE_NAME (t)), |
| remove_attributes, flags); |
| } |
| else |
| result = TYPE_MAIN_VARIANT (t); |
| } |
| /*gcc_assert (!typedef_variant_p (result) |
| || dependent_alias_template_spec_p (result, nt_opaque) |
| || ((flags & STF_USER_VISIBLE) |
| && !user_facing_original_type_p (result)));*/ |
| |
| if (COMPLETE_TYPE_P (result) && !COMPLETE_TYPE_P (t)) |
| /* If RESULT is complete and T isn't, it's likely the case that T |
| is a variant of RESULT which hasn't been updated yet. Skip the |
| attribute handling. */; |
| else |
| { |
| if (TYPE_USER_ALIGN (t) != TYPE_USER_ALIGN (result) |
| || TYPE_ALIGN (t) != TYPE_ALIGN (result)) |
| { |
| gcc_assert (TYPE_USER_ALIGN (t)); |
| if (remove_attributes) |
| *remove_attributes = true; |
| else |
| { |
| if (TYPE_ALIGN (t) == TYPE_ALIGN (result)) |
| result = build_variant_type_copy (result); |
| else |
| result = build_aligned_type (result, TYPE_ALIGN (t)); |
| TYPE_USER_ALIGN (result) = true; |
| } |
| } |
| |
| if (TYPE_ATTRIBUTES (t)) |
| { |
| if (remove_attributes) |
| result = apply_identity_attributes (result, TYPE_ATTRIBUTES (t), |
| remove_attributes); |
| else |
| result = cp_build_type_attribute_variant (result, |
| TYPE_ATTRIBUTES (t)); |
| } |
| } |
| |
| return cp_build_qualified_type (result, cp_type_quals (t)); |
| } |
| |
| /* Like strip_typedefs above, but works on expressions, so that in |
| |
| template<class T> struct A |
| { |
| typedef T TT; |
| B<sizeof(TT)> b; |
| }; |
| |
| sizeof(TT) is replaced by sizeof(T). */ |
| |
| tree |
| strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags) |
| { |
| unsigned i,n; |
| tree r, type, *ops; |
| enum tree_code code; |
| |
| if (t == NULL_TREE || t == error_mark_node) |
| return t; |
| |
| STRIP_ANY_LOCATION_WRAPPER (t); |
| |
| if (DECL_P (t) || CONSTANT_CLASS_P (t)) |
| return t; |
| |
| /* Some expressions have type operands, so let's handle types here rather |
| than check TYPE_P in multiple places below. */ |
| if (TYPE_P (t)) |
| return strip_typedefs (t, remove_attributes, flags); |
| |
| code = TREE_CODE (t); |
| switch (code) |
| { |
| case IDENTIFIER_NODE: |
| case TEMPLATE_PARM_INDEX: |
| case OVERLOAD: |
| case BASELINK: |
| case ARGUMENT_PACK_SELECT: |
| return t; |
| |
| case TRAIT_EXPR: |
| { |
| tree type1 = strip_typedefs (TRAIT_EXPR_TYPE1 (t), |
| remove_attributes, flags); |
| tree type2 = strip_typedefs (TRAIT_EXPR_TYPE2 (t), |
| remove_attributes, flags); |
| if (type1 == TRAIT_EXPR_TYPE1 (t) |
| && type2 == TRAIT_EXPR_TYPE2 (t)) |
| return t; |
| r = copy_node (t); |
| TRAIT_EXPR_TYPE1 (r) = type1; |
| TRAIT_EXPR_TYPE2 (r) = type2; |
| return r; |
| } |
| |
| case TREE_LIST: |
| { |
| releasing_vec vec; |
| bool changed = false; |
| tree it; |
| for (it = t; it; it = TREE_CHAIN (it)) |
| { |
| tree val = strip_typedefs_expr (TREE_VALUE (it), |
| remove_attributes, flags); |
| vec_safe_push (vec, val); |
| if (val != TREE_VALUE (it)) |
| changed = true; |
| gcc_assert (TREE_PURPOSE (it) == NULL_TREE); |
| } |
| if (changed) |
| { |
| r = NULL_TREE; |
| FOR_EACH_VEC_ELT_REVERSE (*vec, i, it) |
| r = tree_cons (NULL_TREE, it, r); |
| } |
| else |
| r = t; |
| return r; |
| } |
| |
| case TREE_VEC: |
| { |
| bool changed = false; |
| releasing_vec vec; |
| n = TREE_VEC_LENGTH (t); |
| vec_safe_reserve (vec, n); |
| for (i = 0; i < n; ++i) |
| { |
| tree op = strip_typedefs_expr (TREE_VEC_ELT (t, i), |
| remove_attributes, flags); |
| vec->quick_push (op); |
| if (op != TREE_VEC_ELT (t, i)) |
| changed = true; |
| } |
| if (changed) |
| { |
| r = copy_node (t); |
| for (i = 0; i < n; ++i) |
| TREE_VEC_ELT (r, i) = (*vec)[i]; |
| NON_DEFAULT_TEMPLATE_ARGS_COUNT (r) |
| = NON_DEFAULT_TEMPLATE_ARGS_COUNT (t); |
| } |
| else |
| r = t; |
| return r; |
| } |
| |
| case CONSTRUCTOR: |
| { |
| bool changed = false; |
| vec<constructor_elt, va_gc> *vec |
| = vec_safe_copy (CONSTRUCTOR_ELTS (t)); |
| n = CONSTRUCTOR_NELTS (t); |
| type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags); |
| for (i = 0; i < n; ++i) |
| { |
| constructor_elt *e = &(*vec)[i]; |
| tree op = strip_typedefs_expr (e->value, remove_attributes, flags); |
| if (op != e->value) |
| { |
| changed = true; |
| e->value = op; |
| } |
| gcc_checking_assert |
| (e->index == strip_typedefs_expr (e->index, remove_attributes, |
| flags)); |
| } |
| |
| if (!changed && type == TREE_TYPE (t)) |
| { |
| vec_free (vec); |
| return t; |
| } |
| else |
| { |
| r = copy_node (t); |
| TREE_TYPE (r) = type; |
| CONSTRUCTOR_ELTS (r) = vec; |
| return r; |
| } |
| } |
| |
| case LAMBDA_EXPR: |
| return t; |
| |
| case STATEMENT_LIST: |
| error ("statement-expression in a constant expression"); |
| return error_mark_node; |
| |
| default: |
| break; |
| } |
| |
| gcc_assert (EXPR_P (t)); |
| |
| n = cp_tree_operand_length (t); |
| ops = XALLOCAVEC (tree, n); |
| type = TREE_TYPE (t); |
| |
| switch (code) |
| { |
| CASE_CONVERT: |
| case IMPLICIT_CONV_EXPR: |
| case DYNAMIC_CAST_EXPR: |
| case STATIC_CAST_EXPR: |
| case CONST_CAST_EXPR: |
| case REINTERPRET_CAST_EXPR: |
| case CAST_EXPR: |
| case NEW_EXPR: |
| type = strip_typedefs (type, remove_attributes, flags); |
| /* fallthrough */ |
| |
| default: |
| for (i = 0; i < n; ++i) |
| ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i), |
| remove_attributes, flags); |
| break; |
| } |
| |
| /* If nothing changed, return t. */ |
| for (i = 0; i < n; ++i) |
| if (ops[i] != TREE_OPERAND (t, i)) |
| break; |
| if (i == n && type == TREE_TYPE (t)) |
| return t; |
| |
| r = copy_node (t); |
| TREE_TYPE (r) = type; |
| for (i = 0; i < n; ++i) |
| TREE_OPERAND (r, i) = ops[i]; |
| return r; |
| } |
| |
| /* Makes a copy of BINFO and TYPE, which is to be inherited into a |
| graph dominated by T. If BINFO is NULL, TYPE is a dependent base, |
| and we do a shallow copy. If BINFO is non-NULL, we do a deep copy. |
| VIRT indicates whether TYPE is inherited virtually or not. |
| IGO_PREV points at the previous binfo of the inheritance graph |
| order chain. The newly copied binfo's TREE_CHAIN forms this |
| ordering. |
| |
| The CLASSTYPE_VBASECLASSES vector of T is constructed in the |
| correct order. That is in the order the bases themselves should be |
| constructed in. |
| |
| The BINFO_INHERITANCE of a virtual base class points to the binfo |
| of the most derived type. ??? We could probably change this so that |
| BINFO_INHERITANCE becomes synonymous with BINFO_PRIMARY, and hence |
| remove a field. They currently can only differ for primary virtual |
| virtual bases. */ |
| |
| tree |
| copy_binfo (tree binfo, tree type, tree t, tree *igo_prev, int virt) |
| { |
| tree new_binfo; |
| |
| if (virt) |
| { |
| /* See if we've already made this virtual base. */ |
| new_binfo = binfo_for_vbase (type, t); |
| if (new_binfo) |
| return new_binfo; |
| } |
| |
| new_binfo = make_tree_binfo (binfo ? BINFO_N_BASE_BINFOS (binfo) : 0); |
| BINFO_TYPE (new_binfo) = type; |
| |
| /* Chain it into the inheritance graph. */ |
| TREE_CHAIN (*igo_prev) = new_binfo; |
| *igo_prev = new_binfo; |
| |
| if (binfo && !BINFO_DEPENDENT_BASE_P (binfo)) |
| { |
| int ix; |
| tree base_binfo; |
| |
| gcc_assert (SAME_BINFO_TYPE_P (BINFO_TYPE (binfo), type)); |
| |
| BINFO_OFFSET (new_binfo) = BINFO_OFFSET (binfo); |
| BINFO_VIRTUALS (new_binfo) = BINFO_VIRTUALS (binfo); |
| |
| /* We do not need to copy the accesses, as they are read only. */ |
| BINFO_BASE_ACCESSES (new_binfo) = BINFO_BASE_ACCESSES (binfo); |
| |
| /* Recursively copy base binfos of BINFO. */ |
| for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++) |
| { |
| tree new_base_binfo; |
| new_base_binfo = copy_binfo (base_binfo, BINFO_TYPE (base_binfo), |
| t, igo_prev, |
| BINFO_VIRTUAL_P (base_binfo)); |
| |
| if (!BINFO_INHERITANCE_CHAIN (new_base_binfo)) |
| BINFO_INHERITANCE_CHAIN (new_base_binfo) = new_binfo; |
| BINFO_BASE_APPEND (new_binfo, new_base_binfo); |
| } |
| } |
| else |
| BINFO_DEPENDENT_BASE_P (new_binfo) = 1; |
| |
| if (virt) |
| { |
| /* Push it onto the list after any virtual bases it contains |
| will have been pushed. */ |
| CLASSTYPE_VBASECLASSES (t)->quick_push (new_binfo); |
| BINFO_VIRTUAL_P (new_binfo) = 1; |
| BINFO_INHERITANCE_CHAIN (new_binfo) = TYPE_BINFO (t); |
| } |
| |
| return new_binfo; |
| } |
| |
| /* Hashing of lists so that we don't make duplicates. |
| The entry point is `list_hash_canon'. */ |
| |
| struct list_proxy |
| { |
| tree purpose; |
| tree value; |
| tree chain; |
| }; |
| |
| struct list_hasher : ggc_ptr_hash<tree_node> |
| { |
| typedef list_proxy *compare_type; |
| |
| static hashval_t hash (tree); |
| static bool equal (tree, list_proxy *); |
| }; |
| |
| /* Now here is the hash table. When recording a list, it is added |
| to the slot whose index is the hash code mod the table size. |
| Note that the hash table is used for several kinds of lists. |
| While all these live in the same table, they are completely independent, |
| and the hash code is computed differently for each of these. */ |
| |
| static GTY (()) hash_table<list_hasher> *list_hash_table; |
| |
| /* Compare ENTRY (an entry in the hash table) with DATA (a list_proxy |
| for a node we are thinking about adding). */ |
| |
| bool |
| list_hasher::equal (tree t, list_proxy *proxy) |
| { |
| return (TREE_VALUE (t) == proxy->value |
| && TREE_PURPOSE (t) == proxy->purpose |
| && TREE_CHAIN (t) == proxy->chain); |
| } |
| |
| /* Compute a hash code for a list (chain of TREE_LIST nodes |
| with goodies in the TREE_PURPOSE, TREE_VALUE, and bits of the |
| TREE_COMMON slots), by adding the hash codes of the individual entries. */ |
| |
| static hashval_t |
| list_hash_pieces (tree purpose, tree value, tree chain) |
| { |
| hashval_t hashcode = 0; |
| |
| if (chain) |
| hashcode += TREE_HASH (chain); |
| |
| if (value) |
| hashcode += TREE_HASH (value); |
| else |
| hashcode += 1007; |
| if (purpose) |
| hashcode += TREE_HASH (purpose); |
| else |
| hashcode += 1009; |
| return hashcode; |
| } |
| |
| /* Hash an already existing TREE_LIST. */ |
| |
| hashval_t |
| list_hasher::hash (tree t) |
| { |
| return list_hash_pieces (TREE_PURPOSE (t), |
| TREE_VALUE (t), |
| TREE_CHAIN (t)); |
| } |
| |
| /* Given list components PURPOSE, VALUE, AND CHAIN, return the canonical |
| object for an identical list if one already exists. Otherwise, build a |
| new one, and record it as the canonical object. */ |
| |
| tree |
| hash_tree_cons (tree purpose, tree value, tree chain) |
| { |
| int hashcode = 0; |
| tree *slot; |
| struct list_proxy proxy; |
| |
| /* Hash the list node. */ |
| hashcode = list_hash_pieces (purpose, value, chain); |
| /* Create a proxy for the TREE_LIST we would like to create. We |
| don't actually create it so as to avoid creating garbage. */ |
| proxy.purpose = purpose; |
| proxy.value = value; |
| proxy.chain = chain; |
| /* See if it is already in the table. */ |
| slot = list_hash_table->find_slot_with_hash (&proxy, hashcode, INSERT); |
| /* If not, create a new node. */ |
| if (!*slot) |
| *slot = tree_cons (purpose, value, chain); |
| return (tree) *slot; |
| } |
| |
| /* Constructor for hashed lists. */ |
| |
| tree |
| hash_tree_chain (tree value, tree chain) |
| { |
| return hash_tree_cons (NULL_TREE, value, chain); |
| } |
| |
| void |
| debug_binfo (tree elem) |
| { |
| HOST_WIDE_INT n; |
| tree virtuals; |
| |
| fprintf (stderr, "type \"%s\", offset = " HOST_WIDE_INT_PRINT_DEC |
| "\nvtable type:\n", |
| TYPE_NAME_STRING (BINFO_TYPE (elem)), |
| TREE_INT_CST_LOW (BINFO_OFFSET (elem))); |
| debug_tree (BINFO_TYPE (elem)); |
| if (BINFO_VTABLE (elem)) |
| fprintf (stderr, "vtable decl \"%s\"\n", |
| IDENTIFIER_POINTER (DECL_NAME (get_vtbl_decl_for_binfo (elem)))); |
| else |
| fprintf (stderr, "no vtable decl yet\n"); |
| fprintf (stderr, "virtuals:\n"); |
| virtuals = BINFO_VIRTUALS (elem); |
| n = 0; |
| |
| while (virtuals) |
| { |
| tree fndecl = TREE_VALUE (virtuals); |
| fprintf (stderr, "%s [%ld =? %ld]\n", |
| IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)), |
| (long) n, (long) TREE_INT_CST_LOW (DECL_VINDEX (fndecl))); |
| ++n; |
| virtuals = TREE_CHAIN (virtuals); |
| } |
| } |
| |
| /* Build a representation for the qualified name SCOPE::NAME. TYPE is |
| the type of the result expression, if known, or NULL_TREE if the |
| resulting expression is type-dependent. If TEMPLATE_P is true, |
| NAME is known to be a template because the user explicitly used the |
| "template" keyword after the "::". |
| |
| All SCOPE_REFs should be built by use of this function. */ |
| |
| tree |
| build_qualified_name (tree type, tree scope, tree name, bool template_p) |
| { |
| tree t; |
| if (type == error_mark_node |
| || scope == error_mark_node |
| || name == error_mark_node) |
| return error_mark_node; |
| gcc_assert (TREE_CODE (name) != SCOPE_REF); |
| t = build2 (SCOPE_REF, type, scope, name); |
| QUALIFIED_NAME_IS_TEMPLATE (t) = template_p; |
| PTRMEM_OK_P (t) = true; |
| if (type) |
| t = convert_from_reference (t); |
| return t; |
| } |
| |
| /* Like check_qualified_type, but also check ref-qualifier, exception |
| specification, and whether the return type was specified after the |
| parameters. */ |
| |
| static bool |
| cp_check_qualified_type (const_tree cand, const_tree base, int type_quals, |
| cp_ref_qualifier rqual, tree raises, bool late) |
| { |
| return (TYPE_QUALS (cand) == type_quals |
| && check_base_type (cand, base) |
| && comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (cand), |
| ce_exact) |
| && TYPE_HAS_LATE_RETURN_TYPE (cand) == late |
| && type_memfn_rqual (cand) == rqual); |
| } |
| |
| /* Build the FUNCTION_TYPE or METHOD_TYPE with the ref-qualifier RQUAL. */ |
| |
| tree |
| build_ref_qualified_type (tree type, cp_ref_qualifier rqual) |
| { |
| tree raises = TYPE_RAISES_EXCEPTIONS (type); |
| bool late = TYPE_HAS_LATE_RETURN_TYPE (type); |
| return build_cp_fntype_variant (type, rqual, raises, late); |
| } |
| |
| tree |
| make_binding_vec (tree name, unsigned clusters MEM_STAT_DECL) |
| { |
| /* Stored in an unsigned short, but we're limited to the number of |
| modules anyway. */ |
| gcc_checking_assert (clusters <= (unsigned short)(~0)); |
| size_t length = (offsetof (tree_binding_vec, vec) |
| + clusters * sizeof (binding_cluster)); |
| tree vec = ggc_alloc_cleared_tree_node_stat (length PASS_MEM_STAT); |
| TREE_SET_CODE (vec, BINDING_VECTOR); |
| BINDING_VECTOR_NAME (vec) = name; |
| BINDING_VECTOR_ALLOC_CLUSTERS (vec) = clusters; |
| BINDING_VECTOR_NUM_CLUSTERS (vec) = 0; |
| |
| return vec; |
| } |
| |
| /* Make a raw overload node containing FN. */ |
| |
| tree |
| ovl_make (tree fn, tree next) |
| { |
| tree result = make_node (OVERLOAD); |
| |
| if (TREE_CODE (fn) == OVERLOAD) |
| OVL_NESTED_P (result) = true; |
| |
| TREE_TYPE (result) = (next || TREE_CODE (fn) == TEMPLATE_DECL |
| ? unknown_type_node : TREE_TYPE (fn)); |
| if (next && TREE_CODE (next) == OVERLOAD && OVL_DEDUP_P (next)) |
| OVL_DEDUP_P (result) = true; |
| OVL_FUNCTION (result) = fn; |
| OVL_CHAIN (result) = next; |
| return result; |
| } |
| |
| /* Add FN to the (potentially NULL) overload set OVL. USING_OR_HIDDEN is > |
| zero if this is a using-decl. It is > 1 if we're exporting the |
| using decl. USING_OR_HIDDEN is < 0, if FN is hidden. (A decl |
| cannot be both using and hidden.) We keep the hidden decls first, |
| but remaining ones are unordered. */ |
| |
| tree |
| ovl_insert (tree fn, tree maybe_ovl, int using_or_hidden) |
| { |
| tree result = maybe_ovl; |
| tree insert_after = NULL_TREE; |
| |
| /* Skip hidden. */ |
| for (; maybe_ovl && TREE_CODE (maybe_ovl) == OVERLOAD |
| && OVL_HIDDEN_P (maybe_ovl); |
| maybe_ovl = OVL_CHAIN (maybe_ovl)) |
| { |
| gcc_checking_assert (!OVL_LOOKUP_P (maybe_ovl)); |
| insert_after = maybe_ovl; |
| } |
| |
| if (maybe_ovl || using_or_hidden || TREE_CODE (fn) == TEMPLATE_DECL) |
| { |
| maybe_ovl = ovl_make (fn, maybe_ovl); |
| |
| if (using_or_hidden < 0) |
| OVL_HIDDEN_P (maybe_ovl) = true; |
| if (using_or_hidden > 0) |
| { |
| OVL_DEDUP_P (maybe_ovl) = OVL_USING_P (maybe_ovl) = true; |
| if (using_or_hidden > 1) |
| OVL_EXPORT_P (maybe_ovl) = true; |
| } |
| } |
| else |
| maybe_ovl = fn; |
| |
| if (insert_after) |
| { |
| OVL_CHAIN (insert_after) = maybe_ovl; |
| TREE_TYPE (insert_after) = unknown_type_node; |
| } |
| else |
| result = maybe_ovl; |
| |
| return result; |
| } |
| |
| /* Skip any hidden names at the beginning of OVL. */ |
| |
| tree |
| ovl_skip_hidden (tree ovl) |
| { |
| while (ovl && TREE_CODE (ovl) == OVERLOAD && OVL_HIDDEN_P (ovl)) |
| ovl = OVL_CHAIN (ovl); |
| |
| return ovl; |
| } |
| |
| /* NODE is an OVL_HIDDEN_P node that is now revealed. */ |
| |
| tree |
| ovl_iterator::reveal_node (tree overload, tree node) |
| { |
| /* We cannot have returned NODE as part of a lookup overload, so we |
| don't have to worry about preserving that. */ |
| |
| OVL_HIDDEN_P (node) = false; |
| if (tree chain = OVL_CHAIN (node)) |
| if (TREE_CODE (chain) == OVERLOAD) |
| { |
| if (OVL_HIDDEN_P (chain)) |
| { |
| /* The node needs moving, and the simplest way is to remove it |
| and reinsert. */ |
| overload = remove_node (overload, node); |
| overload = ovl_insert (OVL_FUNCTION (node), overload); |
| } |
| else if (OVL_DEDUP_P (chain)) |
| OVL_DEDUP_P (node) = true; |
| } |
| return overload; |
| } |
| |
| /* NODE is on the overloads of OVL. Remove it. |
| The removed node is unaltered and may continue to be iterated |
| from (i.e. it is safe to remove a node from an overload one is |
| currently iterating over). */ |
| |
| tree |
| ovl_iterator::remove_node (tree overload, tree node) |
| { |
| tree *slot = &overload; |
| while (*slot != node) |
| { |
| tree probe = *slot; |
| gcc_checking_assert (!OVL_LOOKUP_P (probe)); |
| |
| slot = &OVL_CHAIN (probe); |
| } |
| |
| /* Stitch out NODE. We don't have to worry about now making a |
| singleton overload (and consequently maybe setting its type), |
| because all uses of this function will be followed by inserting a |
| new node that must follow the place we've cut this out from. */ |
| if (TREE_CODE (node) != OVERLOAD) |
| /* Cloned inherited ctors don't mark themselves as via_using. */ |
| *slot = NULL_TREE; |
| else |
| *slot = OVL_CHAIN (node); |
| |
| return overload; |
| } |
| |
| /* Mark or unmark a lookup set. */ |
| |
| void |
| lookup_mark (tree ovl, bool val) |
| { |
| for (lkp_iterator iter (ovl); iter; ++iter) |
| { |
| gcc_checking_assert (LOOKUP_SEEN_P (*iter) != val); |
| LOOKUP_SEEN_P (*iter) = val; |
| } |
| } |
| |
| /* Add a set of new FNS into a lookup. */ |
| |
| tree |
| lookup_add (tree fns, tree lookup) |
| { |
| if (fns == error_mark_node || lookup == error_mark_node) |
| return error_mark_node; |
| |
| if (lookup || TREE_CODE (fns) == TEMPLATE_DECL) |
| { |
| lookup = ovl_make (fns, lookup); |
| OVL_LOOKUP_P (lookup) = true; |
| } |
| else |
| lookup = fns; |
| |
| return lookup; |
| } |
| |
| /* FNS is a new overload set, add them to LOOKUP, if they are not |
| already present there. */ |
| |
| tree |
| lookup_maybe_add (tree fns, tree lookup, bool deduping) |
| { |
| if (deduping) |
| for (tree next, probe = fns; probe; probe = next) |
| { |
| tree fn = probe; |
| next = NULL_TREE; |
| |
| if (TREE_CODE (probe) == OVERLOAD) |
| { |
| fn = OVL_FUNCTION (probe); |
| next = OVL_CHAIN (probe); |
| } |
| |
| if (!LOOKUP_SEEN_P (fn)) |
| LOOKUP_SEEN_P (fn) = true; |
| else |
| { |
| /* This function was already seen. Insert all the |
| predecessors onto the lookup. */ |
| for (; fns != probe; fns = OVL_CHAIN (fns)) |
| { |
| lookup = lookup_add (OVL_FUNCTION (fns), lookup); |
| /* Propagate OVL_USING, but OVL_HIDDEN & |
| OVL_DEDUP_P don't matter. */ |
| if (OVL_USING_P (fns)) |
| OVL_USING_P (lookup) = true; |
| } |
| |
| /* And now skip this function. */ |
| fns = next; |
| } |
| } |
| |
| if (fns) |
| /* We ended in a set of new functions. Add them all in one go. */ |
| lookup = lookup_add (fns, lookup); |
| |
| return lookup; |
| } |
| |
| /* Returns nonzero if X is an expression for a (possibly overloaded) |
| function. If "f" is a function or function template, "f", "c->f", |
| "c.f", "C::f", and "f<int>" will all be considered possibly |
| overloaded functions. Returns 2 if the function is actually |
| overloaded, i.e., if it is impossible to know the type of the |
| function without performing overload resolution. */ |
| |
| int |
| is_overloaded_fn (tree x) |
| { |
| STRIP_ANY_LOCATION_WRAPPER (x); |
| |
| /* A baselink is also considered an overloaded function. */ |
| if (TREE_CODE (x) == OFFSET_REF |
| || TREE_CODE (x) == COMPONENT_REF) |
| x = TREE_OPERAND (x, 1); |
| x = MAYBE_BASELINK_FUNCTIONS (x); |
| if (TREE_CODE (x) == TEMPLATE_ID_EXPR) |
| x = TREE_OPERAND (x, 0); |
| |
| if (DECL_FUNCTION_TEMPLATE_P (OVL_FIRST (x)) |
| || (TREE_CODE (x) == OVERLOAD && !OVL_SINGLE_P (x))) |
| return 2; |
| |
| return OVL_P (x); |
| } |
| |
| /* X is the CALL_EXPR_FN of a CALL_EXPR. If X represents a dependent name |
| (14.6.2), return the IDENTIFIER_NODE for that name. Otherwise, return |
| NULL_TREE. */ |
| |
| tree |
| dependent_name (tree x) |
| { |
| /* FIXME a dependent name must be unqualified, but this function doesn't |
| distinguish between qualified and unqualified identifiers. */ |
| if (identifier_p (x)) |
| return x; |
| if (TREE_CODE (x) == TEMPLATE_ID_EXPR) |
| x = TREE_OPERAND (x, 0); |
| if (OVL_P (x)) |
| return OVL_NAME (x); |
| return NULL_TREE; |
| } |
| |
| /* Returns true iff X is an expression for an overloaded function |
| whose type cannot be known without performing overload |
| resolution. */ |
| |
| bool |
| really_overloaded_fn (tree x) |
| { |
| return is_overloaded_fn (x) == 2; |
| } |
| |
| /* Get the overload set FROM refers to. Returns NULL if it's not an |
| overload set. */ |
| |
| tree |
| maybe_get_fns (tree from) |
| { |
| STRIP_ANY_LOCATION_WRAPPER (from); |
| |
| /* A baselink is also considered an overloaded function. */ |
| if (TREE_CODE (from) == OFFSET_REF |
| || TREE_CODE (from) == COMPONENT_REF) |
| from = TREE_OPERAND (from, 1); |
| if (BASELINK_P (from)) |
| from = BASELINK_FUNCTIONS (from); |
| if (TREE_CODE (from) == TEMPLATE_ID_EXPR) |
| from = TREE_OPERAND (from, 0); |
| |
| if (OVL_P (from)) |
| return from; |
| |
| return NULL; |
| } |
| |
| /* FROM refers to an overload set. Return that set (or die). */ |
| |
| tree |
| get_fns (tree from) |
| { |
| tree res = maybe_get_fns (from); |
| |
| gcc_assert (res); |
| return res; |
| } |
| |
| /* Return the first function of the overload set FROM refers to. */ |
| |
| tree |
| get_first_fn (tree from) |
| { |
| return OVL_FIRST (get_fns (from)); |
| } |
| |
| /* Return the scope where the overloaded functions OVL were found. */ |
| |
| tree |
| ovl_scope (tree ovl) |
| { |
| if (TREE_CODE (ovl) == OFFSET_REF |
| || TREE_CODE (ovl) == COMPONENT_REF) |
| ovl = TREE_OPERAND (ovl, 1); |
| if (TREE_CODE (ovl) == BASELINK) |
| return BINFO_TYPE (BASELINK_BINFO (ovl)); |
| if (TREE_CODE (ovl) == TEMPLATE_ID_EXPR) |
| ovl = TREE_OPERAND (ovl, 0); |
| /* Skip using-declarations. */ |
| lkp_iterator iter (ovl); |
| do |
| ovl = *iter; |
| while (iter.using_p () && ++iter); |
| |
| return CP_DECL_CONTEXT (ovl); |
| } |
| |
| #define PRINT_RING_SIZE 4 |
| |
| static const char * |
| cxx_printable_name_internal (tree decl, int v, bool translate) |
| { |
| static unsigned int uid_ring[PRINT_RING_SIZE]; |
| static char *print_ring[PRINT_RING_SIZE]; |
| static bool trans_ring[PRINT_RING_SIZE]; |
| static int ring_counter; |
| int i; |
| |
| /* Only cache functions. */ |
| if (v < 2 |
| || TREE_CODE (decl) != FUNCTION_DECL |
| || DECL_LANG_SPECIFIC (decl) == 0) |
| return lang_decl_name (decl, v, translate); |
| |
| /* See if this print name is lying around. */ |
| for (i = 0; i < PRINT_RING_SIZE; i++) |
| if (uid_ring[i] == DECL_UID (decl) && translate == trans_ring[i]) |
| /* yes, so return it. */ |
| return print_ring[i]; |
| |
| if (++ring_counter == PRINT_RING_SIZE) |
| ring_counter = 0; |
| |
| if (current_function_decl != NULL_TREE) |
| { |
| /* There may be both translated and untranslated versions of the |
| name cached. */ |
| for (i = 0; i < 2; i++) |
| { |
| if (uid_ring[ring_counter] == DECL_UID (current_function_decl)) |
| ring_counter += 1; |
| if (ring_counter == PRINT_RING_SIZE) |
| ring_counter = 0; |
| } |
| gcc_assert (uid_ring[ring_counter] != DECL_UID (current_function_decl)); |
| } |
| |
| free (print_ring[ring_counter]); |
| |
| print_ring[ring_counter] = xstrdup (lang_decl_name (decl, v, translate)); |
| uid_ring[ring_counter] = DECL_UID (decl); |
| trans_ring[ring_counter] = translate; |
| return print_ring[ring_counter]; |
| } |
| |
| const char * |
| cxx_printable_name (tree decl, int v) |
| { |
| return cxx_printable_name_internal (decl, v, false); |
| } |
| |
| const char * |
| cxx_printable_name_translate (tree decl, int v) |
| { |
| return cxx_printable_name_internal (decl, v, true); |
| } |
| |
| /* Return the canonical version of exception-specification RAISES for a C++17 |
| function type, for use in type comparison and building TYPE_CANONICAL. */ |
| |
| tree |
| canonical_eh_spec (tree raises) |
| { |
| if (raises == NULL_TREE) |
| return raises; |
| else if (DEFERRED_NOEXCEPT_SPEC_P (raises) |
| || UNPARSED_NOEXCEPT_SPEC_P (raises) |
| || uses_template_parms (raises) |
| || uses_template_parms (TREE_PURPOSE (raises))) |
| /* Keep a dependent or deferred exception specification. */ |
| return raises; |
| else if (nothrow_spec_p (raises)) |
| /* throw() -> noexcept. */ |
| return noexcept_true_spec; |
| else |
| /* For C++17 type matching, anything else -> nothing. */ |
| return NULL_TREE; |
| } |
| |
| tree |
| build_cp_fntype_variant (tree type, cp_ref_qualifier rqual, |
| tree raises, bool late) |
| { |
| cp_cv_quals type_quals = TYPE_QUALS (type); |
| |
| if (cp_check_qualified_type (type, type, type_quals, rqual, raises, late)) |
| return type; |
| |
| tree v = TYPE_MAIN_VARIANT (type); |
| for (; v; v = TYPE_NEXT_VARIANT (v)) |
| if (cp_check_qualified_type (v, type, type_quals, rqual, raises, late)) |
| return v; |
| |
| /* Need to build a new variant. */ |
| v = build_variant_type_copy (type); |
| if (!TYPE_DEPENDENT_P (v)) |
| /* We no longer know that it's not type-dependent. */ |
| TYPE_DEPENDENT_P_VALID (v) = false; |
| TYPE_RAISES_EXCEPTIONS (v) = raises; |
| TYPE_HAS_LATE_RETURN_TYPE (v) = late; |
| switch (rqual) |
| { |
| case REF_QUAL_RVALUE: |
| FUNCTION_RVALUE_QUALIFIED (v) = 1; |
| FUNCTION_REF_QUALIFIED (v) = 1; |
| break; |
| case REF_QUAL_LVALUE: |
| FUNCTION_RVALUE_QUALIFIED (v) = 0; |
| FUNCTION_REF_QUALIFIED (v) = 1; |
| break; |
| default: |
| FUNCTION_REF_QUALIFIED (v) = 0; |
| break; |
| } |
| |
| /* Canonicalize the exception specification. */ |
| tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE; |
| |
| if (TYPE_STRUCTURAL_EQUALITY_P (type)) |
| /* Propagate structural equality. */ |
| SET_TYPE_STRUCTURAL_EQUALITY (v); |
| else if (TYPE_CANONICAL (type) != type || cr != raises || late) |
| /* Build the underlying canonical type, since it is different |
| from TYPE. */ |
| TYPE_CANONICAL (v) = build_cp_fntype_variant (TYPE_CANONICAL (type), |
| rqual, cr, false); |
| else |
| /* T is its own canonical type. */ |
| TYPE_CANONICAL (v) = v; |
| |
| return v; |
| } |
| |
| /* TYPE is a function or method type with a deferred exception |
| specification that has been parsed to RAISES. Fixup all the type |
| variants that are affected in place. Via decltype &| noexcept |
| tricks, the unparsed spec could have escaped into the type system. |
| The general case is hard to fixup canonical types for. */ |
| |
| void |
| fixup_deferred_exception_variants (tree type, tree raises) |
| { |
| tree original = TYPE_RAISES_EXCEPTIONS (type); |
| tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE; |
| |
| gcc_checking_assert (UNPARSED_NOEXCEPT_SPEC_P (original)); |
| |
| /* Though sucky, this walk will process the canonical variants |
| first. */ |
| for (tree variant = TYPE_MAIN_VARIANT (type); |
| variant; variant = TYPE_NEXT_VARIANT (variant)) |
| if (TYPE_RAISES_EXCEPTIONS (variant) == original) |
| { |
| gcc_checking_assert (variant != TYPE_MAIN_VARIANT (type)); |
| |
| if (!TYPE_STRUCTURAL_EQUALITY_P (variant)) |
| { |
| cp_cv_quals var_quals = TYPE_QUALS (variant); |
| cp_ref_qualifier rqual = type_memfn_rqual (variant); |
| |
| tree v = TYPE_MAIN_VARIANT (type); |
| for (; v; v = TYPE_NEXT_VARIANT (v)) |
| if (TYPE_CANONICAL (v) == v |
| && cp_check_qualified_type (v, variant, var_quals, |
| rqual, cr, false)) |
| break; |
| TYPE_RAISES_EXCEPTIONS (variant) = raises; |
| |
| if (!v) |
| v = build_cp_fntype_variant (TYPE_CANONICAL (variant), |
| rqual, cr, false); |
| TYPE_CANONICAL (variant) = v; |
| } |
| else |
| TYPE_RAISES_EXCEPTIONS (variant) = raises; |
| } |
| } |
| |
| /* Build the FUNCTION_TYPE or METHOD_TYPE which may throw exceptions |
| listed in RAISES. */ |
| |
| tree |
| build_exception_variant (tree type, tree raises) |
| { |
| cp_ref_qualifier rqual = type_memfn_rqual (type); |
| bool late = TYPE_HAS_LATE_RETURN_TYPE (type); |
| return build_cp_fntype_variant (type, rqual, raises, late); |
| } |
| |
| /* Given a TEMPLATE_TEMPLATE_PARM node T, create a new |
| BOUND_TEMPLATE_TEMPLATE_PARM bound with NEWARGS as its template |
| arguments. */ |
| |
| tree |
| bind_template_template_parm (tree t, tree newargs) |
| { |
| tree decl = TYPE_NAME (t); |
| tree t2; |
| |
| t2 = cxx_make_type (BOUND_TEMPLATE_TEMPLATE_PARM); |
| decl = build_decl (input_location, |
| TYPE_DECL, DECL_NAME (decl), NULL_TREE); |
| SET_DECL_TEMPLATE_PARM_P (decl); |
| |
| /* These nodes have to be created to reflect new TYPE_DECL and template |
| arguments. */ |
| TEMPLATE_TYPE_PARM_INDEX (t2) = copy_node (TEMPLATE_TYPE_PARM_INDEX (t)); |
| TEMPLATE_PARM_DECL (TEMPLATE_TYPE_PARM_INDEX (t2)) = decl; |
| TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t2) |
| = build_template_info (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t), newargs); |
| |
| TREE_TYPE (decl) = t2; |
| TYPE_NAME (t2) = decl; |
| TYPE_STUB_DECL (t2) = decl; |
| TYPE_SIZE (t2) = 0; |
| SET_TYPE_STRUCTURAL_EQUALITY (t2); |
| |
| return t2; |
| } |
| |
| /* Called from count_trees via walk_tree. */ |
| |
| static tree |
| count_trees_r (tree *tp, int *walk_subtrees, void *data) |
| { |
| ++*((int *) data); |
| |
| if (TYPE_P (*tp)) |
| *walk_subtrees = 0; |
| |
| return NULL_TREE; |
| } |
| |
| /* Debugging function for measuring the rough complexity of a tree |
| representation. */ |
| |
| int |
| count_trees (tree t) |
| { |
| int n_trees = 0; |
| cp_walk_tree_without_duplicates (&t, count_trees_r, &n_trees); |
| return n_trees; |
| } |
| |
| /* Called from verify_stmt_tree via walk_tree. */ |
| |
| static tree |
| verify_stmt_tree_r (tree* tp, int * /*walk_subtrees*/, void* data) |
| { |
| tree t = *tp; |
| hash_table<nofree_ptr_hash <tree_node> > *statements |
| = static_cast <hash_table<nofree_ptr_hash <tree_node> > *> (data); |
| tree_node **slot; |
| |
| if (!STATEMENT_CODE_P (TREE_CODE (t))) |
| return NULL_TREE; |
| |
| /* If this statement is already present in the hash table, then |
| there is a circularity in the statement tree. */ |
| gcc_assert (!statements->find (t)); |
| |
| slot = statements->find_slot (t, INSERT); |
| *slot = t; |
| |
| return NULL_TREE; |
| } |
| |
| /* Debugging function to check that the statement T has not been |
| corrupted. For now, this function simply checks that T contains no |
| circularities. */ |
| |
| void |
| verify_stmt_tree (tree t) |
| { |
| hash_table<nofree_ptr_hash <tree_node> > statements (37); |
| cp_walk_tree (&t, verify_stmt_tree_r, &statements, NULL); |
| } |
| |
| /* Check if the type T depends on a type with no linkage and if so, |
| return it. If RELAXED_P then do not consider a class type declared |
| within a vague-linkage function to have no linkage. Remember: |
| no-linkage is not the same as internal-linkage*/ |
| |
| tree |
| no_linkage_check (tree t, bool relaxed_p) |
| { |
| tree r; |
| |
| /* Lambda types that don't have mangling scope have no linkage. We |
| check CLASSTYPE_LAMBDA_EXPR for error_mark_node because |
| when we get here from pushtag none of the lambda information is |
| set up yet, so we want to assume that the lambda has linkage and |
| fix it up later if not. We need to check this even in templates so |
| that we properly handle a lambda-expression in the signature. */ |
| if (LAMBDA_TYPE_P (t) |
| && CLASSTYPE_LAMBDA_EXPR (t) != error_mark_node) |
| { |
| tree extra = LAMBDA_TYPE_EXTRA_SCOPE (t); |
| if (!extra) |
| return t; |
| } |
| |
| /* Otherwise there's no point in checking linkage on template functions; we |
| can't know their complete types. */ |
| if (processing_template_decl) |
| return NULL_TREE; |
| |
| switch (TREE_CODE (t)) |
| { |
| case RECORD_TYPE: |
| if (TYPE_PTRMEMFUNC_P (t)) |
| goto ptrmem; |
| /* Fall through. */ |
| case UNION_TYPE: |
| if (!CLASS_TYPE_P (t)) |
| return NULL_TREE; |
| /* Fall through. */ |
| case ENUMERAL_TYPE: |
| /* Only treat unnamed types as having no linkage if they're at |
| namespace scope. This is core issue 966. */ |
| if (TYPE_UNNAMED_P (t) && TYPE_NAMESPACE_SCOPE_P (t)) |
| return t; |
| |
| for (r = CP_TYPE_CONTEXT (t); ; ) |
| { |
| /* If we're a nested type of a !TREE_PUBLIC class, we might not |
| have linkage, or we might just be in an anonymous namespace. |
| If we're in a TREE_PUBLIC class, we have linkage. */ |
| if (TYPE_P (r) && !TREE_PUBLIC (TYPE_NAME (r))) |
| return no_linkage_check (TYPE_CONTEXT (t), relaxed_p); |
| else if (TREE_CODE (r) == FUNCTION_DECL) |
| { |
| if (!relaxed_p || !vague_linkage_p (r)) |
| return t; |
| else |
| r = CP_DECL_CONTEXT (r); |
| } |
| else |
| break; |
| } |
| |
| return NULL_TREE; |
| |
| case ARRAY_TYPE: |
| case POINTER_TYPE: |
| case REFERENCE_TYPE: |
| case VECTOR_TYPE: |
| return no_linkage_check (TREE_TYPE (t), relaxed_p); |
| |
| case OFFSET_TYPE: |
| ptrmem: |
| r = no_linkage_check (TYPE_PTRMEM_POINTED_TO_TYPE (t), |
| relaxed_p); |
| if (r) |
| return r; |
| return no_linkage_check (TYPE_PTRMEM_CLASS_TYPE (t), relaxed_p); |
| |
| case METHOD_TYPE: |
| case FUNCTION_TYPE: |
| { |
| tree parm = TYPE_ARG_TYPES (t); |
| if (TREE_CODE (t) == METHOD_TYPE) |
| /* The 'this' pointer isn't interesting; a method has the same |
| linkage (or lack thereof) as its enclosing class. */ |
| parm = TREE_CHAIN (parm); |
| for (; |
| parm && parm != void_list_node; |
| parm = TREE_CHAIN (parm)) |
| { |
| r = no_linkage_check (TREE_VALUE (parm), relaxed_p); |
| if (r) |
| return r; |
| } |
| return no_linkage_check (TREE_TYPE (t), relaxed_p); |
| } |
| |
| default: |
| return NULL_TREE; |
| } |
| } |
| |
| extern int depth_reached; |
| |
| void |
| cxx_print_statistics (void) |
| { |
| print_template_statistics (); |
| if (GATHER_STATISTICS) |
| fprintf (stderr, "maximum template instantiation depth reached: %d\n", |
| depth_reached); |
| } |
| |
| /* Return, as an INTEGER_CST node, the number of elements for TYPE |
| (which is an ARRAY_TYPE). This counts only elements of the top |
| array. */ |
| |
| tree |
| array_type_nelts_top (tree type) |
| { |
| return fold_build2_loc (input_location, |
| PLUS_EXPR, sizetype, |
| array_type_nelts (type), |
| size_one_node); |
| } |
| |
| /* Return, as an INTEGER_CST node, the number of elements for TYPE |
| (which is an ARRAY_TYPE). This one is a recursive count of all |
| ARRAY_TYPEs that are clumped together. */ |
| |
| tree |
| array_type_nelts_total (tree type) |
| { |
| tree sz = array_type_nelts_top (type); |
| type = TREE_TYPE (type); |
| while (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| tree n = array_type_nelts_top (type); |
| sz = fold_build2_loc (input_location, |
| MULT_EXPR, sizetype, sz, n); |
| type = TREE_TYPE (type); |
| } |
| return sz; |
| } |
| |
| /* Return true if FNDECL is std::source_location::current () method. */ |
| |
| bool |
| source_location_current_p (tree fndecl) |
| { |
| gcc_checking_assert (TREE_CODE (fndecl) == FUNCTION_DECL |
| && DECL_IMMEDIATE_FUNCTION_P (fndecl)); |
| if (DECL_NAME (fndecl) == NULL_TREE |
| || TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE |
| || TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != RECORD_TYPE |
| || DECL_CONTEXT (fndecl) != TREE_TYPE (TREE_TYPE (fndecl)) |
| || !id_equal (DECL_NAME (fndecl), "current")) |
| return false; |
| |
| tree source_location = DECL_CONTEXT (fndecl); |
| if (TYPE_NAME (source_location) == NULL_TREE |
| || TREE_CODE (TYPE_NAME (source_location)) != TYPE_DECL |
| || TYPE_IDENTIFIER (source_location) == NULL_TREE |
| || !id_equal (TYPE_IDENTIFIER (source_location), |
| "source_location") |
| || !decl_in_std_namespace_p (TYPE_NAME (source_location))) |
| return false; |
| |
| return true; |
| } |
| |
| struct bot_data |
| { |
| splay_tree target_remap; |
| bool clear_location; |
| }; |
| |
| /* Called from break_out_target_exprs via mapcar. */ |
| |
| static tree |
| bot_manip (tree* tp, int* walk_subtrees, void* data_) |
| { |
| bot_data &data = *(bot_data*)data_; |
| splay_tree target_remap = data.target_remap; |
| tree t = *tp; |
| |
| if (!TYPE_P (t) && TREE_CONSTANT (t) && !TREE_SIDE_EFFECTS (t)) |
| { |
| /* There can't be any TARGET_EXPRs or their slot variables below this |
| point. But we must make a copy, in case subsequent processing |
| alters any part of it. For example, during gimplification a cast |
| of the form (T) &X::f (where "f" is a member function) will lead |
| to replacing the PTRMEM_CST for &X::f with a VAR_DECL. */ |
| *walk_subtrees = 0; |
| *tp = unshare_expr (t); |
| return NULL_TREE; |
| } |
| if (TREE_CODE (t) == TARGET_EXPR) |
| { |
| tree u; |
| |
| if (TREE_CODE (TREE_OPERAND (t, 1)) == AGGR_INIT_EXPR) |
| { |
| u = build_cplus_new (TREE_TYPE (t), TREE_OPERAND (t, 1), |
| tf_warning_or_error); |
| if (u == error_mark_node) |
| return u; |
| if (AGGR_INIT_ZERO_FIRST (TREE_OPERAND (t, 1))) |
| AGGR_INIT_ZERO_FIRST (TREE_OPERAND (u, 1)) = true; |
| } |
| else |
| u = force_target_expr (TREE_TYPE (t), TREE_OPERAND (t, 1), |
| tf_warning_or_error); |
| |
| TARGET_EXPR_IMPLICIT_P (u) = TARGET_EXPR_IMPLICIT_P (t); |
| TARGET_EXPR_LIST_INIT_P (u) = TARGET_EXPR_LIST_INIT_P (t); |
| TARGET_EXPR_DIRECT_INIT_P (u) = TARGET_EXPR_DIRECT_INIT_P (t); |
| |
| /* Map the old variable to the new one. */ |
| splay_tree_insert (target_remap, |
| (splay_tree_key) TREE_OPERAND (t, 0), |
| (splay_tree_value) TREE_OPERAND (u, 0)); |
| |
| TREE_OPERAND (u, 1) = break_out_target_exprs (TREE_OPERAND (u, 1), |
| data.clear_location); |
| if (TREE_OPERAND (u, 1) == error_mark_node) |
| return error_mark_node; |
| |
| /* Replace the old expression with the new version. */ |
| *tp = u; |
| /* We don't have to go below this point; the recursive call to |
| break_out_target_exprs will have handled anything below this |
| point. */ |
| *walk_subtrees = 0; |
| return NULL_TREE; |
| } |
| if (TREE_CODE (*tp) == SAVE_EXPR) |
| { |
| t = *tp; |
| splay_tree_node n = splay_tree_lookup (target_remap, |
| (splay_tree_key) t); |
| if (n) |
| { |
| *tp = (tree)n->value; |
| *walk_subtrees = 0; |
| } |
| else |
| { |
| copy_tree_r (tp, walk_subtrees, NULL); |
| splay_tree_insert (target_remap, |
| (splay_tree_key)t, |
| (splay_tree_value)*tp); |
| /* Make sure we don't remap an already-remapped SAVE_EXPR. */ |
| splay_tree_insert (target_remap, |
| (splay_tree_key)*tp, |
| (splay_tree_value)*tp); |
| } |
| return NULL_TREE; |
| } |
| if (TREE_CODE (*tp) == DECL_EXPR |
| && VAR_P (DECL_EXPR_DECL (*tp)) |
| && DECL_ARTIFICIAL (DECL_EXPR_DECL (*tp)) |
| && !TREE_STATIC (DECL_EXPR_DECL (*tp))) |
| { |
| tree t; |
| splay_tree_node n |
| = splay_tree_lookup (target_remap, |
| (splay_tree_key) DECL_EXPR_DECL (*tp)); |
| if (n) |
| t = (tree) n->value; |
| else |
| { |
| t = create_temporary_var (TREE_TYPE (DECL_EXPR_DECL (*tp))); |
| DECL_INITIAL (t) = DECL_INITIAL (DECL_EXPR_DECL (*tp)); |
| splay_tree_insert (target_remap, |
| (splay_tree_key) DECL_EXPR_DECL (*tp), |
| (splay_tree_value) t); |
| } |
| copy_tree_r (tp, walk_subtrees, NULL); |
| DECL_EXPR_DECL (*tp) = t; |
| if (data.clear_location && EXPR_HAS_LOCATION (*tp)) |
| SET_EXPR_LOCATION (*tp, input_location); |
| return NULL_TREE; |
| } |
| if (TREE_CODE (*tp) == BIND_EXPR && BIND_EXPR_VARS (*tp)) |
| { |
| copy_tree_r (tp, walk_subtrees, NULL); |
| for (tree *p = &BIND_EXPR_VARS (*tp); *p; p = &DECL_CHAIN (*p)) |
| { |
| gcc_assert (VAR_P (*p) && DECL_ARTIFICIAL (*p) && !TREE_STATIC (*p)); |
| tree t = create_temporary_var (TREE_TYPE (*p)); |
| DECL_INITIAL (t) = DECL_INITIAL (*p); |
| DECL_CHAIN (t) = DECL_CHAIN (*p); |
| splay_tree_insert (target_remap, (splay_tree_key) *p, |
| (splay_tree_value) t); |
| *p = t; |
| } |
| if (data.clear_location && EXPR_HAS_LOCATION (*tp)) |
| SET_EXPR_LOCATION (*tp, input_location); |
| return NULL_TREE; |
| } |
| |
| /* Make a copy of this node. */ |
| t = copy_tree_r (tp, walk_subtrees, NULL); |
| if (TREE_CODE (*tp) == CALL_EXPR || TREE_CODE (*tp) == AGGR_INIT_EXPR) |
| if (!processing_template_decl) |
| set_flags_from_callee (*tp); |
| if (data.clear_location && EXPR_HAS_LOCATION (*tp)) |
| SET_EXPR_LOCATION (*tp, input_location); |
| return t; |
| } |
| |
| /* Replace all remapped VAR_DECLs in T with their new equivalents. |
| DATA is really a splay-tree mapping old variables to new |
| variables. */ |
| |
| static tree |
| bot_replace (tree* t, int* /*walk_subtrees*/, void* data_) |
| { |
| bot_data &data = *(bot_data*)data_; |
| splay_tree target_remap = data.target_remap; |
| |
| if (VAR_P (*t)) |
| { |
| splay_tree_node n = splay_tree_lookup (target_remap, |
| (splay_tree_key) *t); |
| if (n) |
| *t = <
|