static bool gimple_check_call_args (gimple stmt, tree fndecl, bool args_count_match) { tree parms, p; unsigned int i, nargs; /* Calls to internal functions always match their signature. */ if (gimple_call_internal_p (stmt)) return true; nargs = gimple_call_num_args (stmt); /* Get argument types for verification. */ if (fndecl) parms = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); else parms = TYPE_ARG_TYPES (gimple_call_fntype (stmt)); /* Verify if the type of the argument matches that of the function declaration. If we cannot verify this or there is a mismatch, return false. */ if (fndecl && DECL_ARGUMENTS (fndecl)) { for (i = 0, p = DECL_ARGUMENTS (fndecl); i < nargs; i++, p = DECL_CHAIN (p)) { tree arg; /* We cannot distinguish a varargs function from the case of excess parameters, still deferring the inlining decision to the callee is possible. */ if (!p) break; arg = gimple_call_arg (stmt, i); if (p == error_mark_node || arg == error_mark_node || (!types_compatible_p (DECL_ARG_TYPE (p), TREE_TYPE (arg)) && !fold_convertible_p (DECL_ARG_TYPE (p), arg))) return false; } if (args_count_match && p) return false; } else if (parms) { for (i = 0, p = parms; i < nargs; i++, p = TREE_CHAIN (p)) { tree arg; /* If this is a varargs function defer inlining decision to callee. */ if (!p) break; arg = gimple_call_arg (stmt, i); if (TREE_VALUE (p) == error_mark_node || arg == error_mark_node || TREE_CODE (TREE_VALUE (p)) == VOID_TYPE || (!types_compatible_p (TREE_VALUE (p), TREE_TYPE (arg)) && !fold_convertible_p (TREE_VALUE (p), arg))) return false; } } else { if (nargs != 0) return false; } return true; }
static bool lto_symtab_merge_p (tree prevailing, tree decl) { if (TREE_CODE (prevailing) != TREE_CODE (decl)) { if (symtab->dump_file) fprintf (symtab->dump_file, "Not merging decls; " "TREE_CODE mismatch\n"); return false; } gcc_checking_assert (TREE_CHAIN (prevailing) == TREE_CHAIN (decl)); if (TREE_CODE (prevailing) == FUNCTION_DECL) { if (DECL_BUILT_IN (prevailing) != DECL_BUILT_IN (decl)) { if (symtab->dump_file) fprintf (symtab->dump_file, "Not merging decls; " "DECL_BUILT_IN mismatch\n"); return false; } if (DECL_BUILT_IN (prevailing) && (DECL_BUILT_IN_CLASS (prevailing) != DECL_BUILT_IN_CLASS (decl) || DECL_FUNCTION_CODE (prevailing) != DECL_FUNCTION_CODE (decl))) { if (symtab->dump_file) fprintf (symtab->dump_file, "Not merging decls; " "DECL_BUILT_IN_CLASS or CODE mismatch\n"); return false; } } if (DECL_ATTRIBUTES (prevailing) != DECL_ATTRIBUTES (decl)) { tree prev_attr = lookup_attribute ("error", DECL_ATTRIBUTES (prevailing)); tree attr = lookup_attribute ("error", DECL_ATTRIBUTES (decl)); if ((prev_attr == NULL) != (attr == NULL) || (prev_attr && TREE_VALUE (TREE_VALUE (prev_attr)) != TREE_VALUE (TREE_VALUE (attr)))) { if (symtab->dump_file) fprintf (symtab->dump_file, "Not merging decls; " "error attribute mismatch\n"); return false; } prev_attr = lookup_attribute ("warning", DECL_ATTRIBUTES (prevailing)); attr = lookup_attribute ("warning", DECL_ATTRIBUTES (decl)); if ((prev_attr == NULL) != (attr == NULL) || (prev_attr && TREE_VALUE (TREE_VALUE (prev_attr)) != TREE_VALUE (TREE_VALUE (attr)))) { if (symtab->dump_file) fprintf (symtab->dump_file, "Not merging decls; " "warning attribute mismatch\n"); return false; } } return true; }
tree build_expr_type_conversion (int desires, tree expr, bool complain) { tree basetype = TREE_TYPE (expr); tree conv = NULL_TREE; tree winner = NULL_TREE; if (expr == null_node && (desires & WANT_INT) && !(desires & WANT_NULL)) warning_at (input_location, OPT_Wconversion_null, "converting NULL to non-pointer type"); basetype = TREE_TYPE (expr); if (basetype == error_mark_node) return error_mark_node; if (! MAYBE_CLASS_TYPE_P (basetype)) switch (TREE_CODE (basetype)) { case INTEGER_TYPE: if ((desires & WANT_NULL) && null_ptr_cst_p (expr)) return expr; /* else fall through... */ case BOOLEAN_TYPE: return (desires & WANT_INT) ? expr : NULL_TREE; case ENUMERAL_TYPE: return (desires & WANT_ENUM) ? expr : NULL_TREE; case REAL_TYPE: return (desires & WANT_FLOAT) ? expr : NULL_TREE; case POINTER_TYPE: return (desires & WANT_POINTER) ? expr : NULL_TREE; case FUNCTION_TYPE: case ARRAY_TYPE: return (desires & WANT_POINTER) ? decay_conversion (expr) : NULL_TREE; case COMPLEX_TYPE: case VECTOR_TYPE: if ((desires & WANT_VECTOR_OR_COMPLEX) == 0) return NULL_TREE; switch (TREE_CODE (TREE_TYPE (basetype))) { case INTEGER_TYPE: case BOOLEAN_TYPE: return (desires & WANT_INT) ? expr : NULL_TREE; case ENUMERAL_TYPE: return (desires & WANT_ENUM) ? expr : NULL_TREE; case REAL_TYPE: return (desires & WANT_FLOAT) ? expr : NULL_TREE; default: return NULL_TREE; } default: return NULL_TREE; } /* The code for conversions from class type is currently only used for delete expressions. Other expressions are handled by build_new_op. */ if (!complete_type_or_else (basetype, expr)) return error_mark_node; if (!TYPE_HAS_CONVERSION (basetype)) return NULL_TREE; for (conv = lookup_conversions (basetype, /*lookup_template_convs_p=*/true); conv; conv = TREE_CHAIN (conv)) { int win = 0; tree candidate; tree cand = TREE_VALUE (conv); cand = OVL_CURRENT (cand); if (winner && winner == cand) continue; if (DECL_NONCONVERTING_P (cand)) continue; candidate = non_reference (TREE_TYPE (TREE_TYPE (cand))); switch (TREE_CODE (candidate)) { case BOOLEAN_TYPE: case INTEGER_TYPE: win = (desires & WANT_INT); break; case ENUMERAL_TYPE: win = (desires & WANT_ENUM); break; case REAL_TYPE: win = (desires & WANT_FLOAT); break; case POINTER_TYPE: win = (desires & WANT_POINTER); break; case COMPLEX_TYPE: case VECTOR_TYPE: if ((desires & WANT_VECTOR_OR_COMPLEX) == 0) break; switch (TREE_CODE (TREE_TYPE (candidate))) { case BOOLEAN_TYPE: case INTEGER_TYPE: win = (desires & WANT_INT); break; case ENUMERAL_TYPE: win = (desires & WANT_ENUM); break; case REAL_TYPE: win = (desires & WANT_FLOAT); break; default: break; } break; default: break; } if (win) { if (winner) { if (complain) { error ("ambiguous default type conversion from %qT", basetype); error (" candidate conversions include %qD and %qD", winner, cand); } return error_mark_node; } else winner = cand; } } if (winner) { tree type = non_reference (TREE_TYPE (TREE_TYPE (winner))); return build_user_type_conversion (type, expr, LOOKUP_NORMAL); } return NULL_TREE; }
static void check_call (funct_state local, tree call_expr) { int flags = call_expr_flags(call_expr); tree operand_list = TREE_OPERAND (call_expr, 1); tree operand; tree callee_t = get_callee_fndecl (call_expr); struct cgraph_node* callee; enum availability avail = AVAIL_NOT_AVAILABLE; for (operand = operand_list; operand != NULL_TREE; operand = TREE_CHAIN (operand)) { tree argument = TREE_VALUE (operand); check_rhs_var (local, argument); } /* The const and pure flags are set by a variety of places in the compiler (including here). If someone has already set the flags for the callee, (such as for some of the builtins) we will use them, otherwise we will compute our own information. Const and pure functions have less clobber effects than other functions so we process these first. Otherwise if it is a call outside the compilation unit or an indirect call we punt. This leaves local calls which will be processed by following the call graph. */ if (callee_t) { callee = cgraph_node(callee_t); avail = cgraph_function_body_availability (callee); /* When bad things happen to bad functions, they cannot be const or pure. */ if (setjmp_call_p (callee_t)) local->pure_const_state = IPA_NEITHER; if (DECL_BUILT_IN_CLASS (callee_t) == BUILT_IN_NORMAL) switch (DECL_FUNCTION_CODE (callee_t)) { case BUILT_IN_LONGJMP: case BUILT_IN_NONLOCAL_GOTO: local->pure_const_state = IPA_NEITHER; break; default: break; } } /* The callee is either unknown (indirect call) or there is just no scannable code for it (external call) . We look to see if there are any bits available for the callee (such as by declaration or because it is builtin) and process solely on the basis of those bits. */ if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE) { if (flags & ECF_PURE) { if (local->pure_const_state == IPA_CONST) local->pure_const_state = IPA_PURE; } else local->pure_const_state = IPA_NEITHER; } else { /* We have the code and we will scan it for the effects. */ if (flags & ECF_PURE) { if (local->pure_const_state == IPA_CONST) local->pure_const_state = IPA_PURE; } } }
static tree cxx_omp_clause_apply_fn (tree fn, tree arg1, tree arg2) { tree defparm, parm, t; int i = 0; int nargs; tree *argarray; if (fn == NULL) return NULL; nargs = list_length (DECL_ARGUMENTS (fn)); argarray = XALLOCAVEC (tree, nargs); defparm = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn))); if (arg2) defparm = TREE_CHAIN (defparm); if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE) { tree inner_type = TREE_TYPE (arg1); tree start1, end1, p1; tree start2 = NULL, p2 = NULL; tree ret = NULL, lab; start1 = arg1; start2 = arg2; do { inner_type = TREE_TYPE (inner_type); start1 = build4 (ARRAY_REF, inner_type, start1, size_zero_node, NULL, NULL); if (arg2) start2 = build4 (ARRAY_REF, inner_type, start2, size_zero_node, NULL, NULL); } while (TREE_CODE (inner_type) == ARRAY_TYPE); start1 = build_fold_addr_expr_loc (input_location, start1); if (arg2) start2 = build_fold_addr_expr_loc (input_location, start2); end1 = TYPE_SIZE_UNIT (TREE_TYPE (arg1)); end1 = fold_build_pointer_plus (start1, end1); p1 = create_tmp_var (TREE_TYPE (start1), NULL); t = build2 (MODIFY_EXPR, TREE_TYPE (p1), p1, start1); append_to_statement_list (t, &ret); if (arg2) { p2 = create_tmp_var (TREE_TYPE (start2), NULL); t = build2 (MODIFY_EXPR, TREE_TYPE (p2), p2, start2); append_to_statement_list (t, &ret); } lab = create_artificial_label (input_location); t = build1 (LABEL_EXPR, void_type_node, lab); append_to_statement_list (t, &ret); argarray[i++] = p1; if (arg2) argarray[i++] = p2; /* Handle default arguments. */ for (parm = defparm; parm && parm != void_list_node; parm = TREE_CHAIN (parm), i++) argarray[i] = convert_default_arg (TREE_VALUE (parm), TREE_PURPOSE (parm), fn, i, tf_warning_or_error); t = build_call_a (fn, i, argarray); t = fold_convert (void_type_node, t); t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); append_to_statement_list (t, &ret); t = fold_build_pointer_plus (p1, TYPE_SIZE_UNIT (inner_type)); t = build2 (MODIFY_EXPR, TREE_TYPE (p1), p1, t); append_to_statement_list (t, &ret); if (arg2) { t = fold_build_pointer_plus (p2, TYPE_SIZE_UNIT (inner_type)); t = build2 (MODIFY_EXPR, TREE_TYPE (p2), p2, t); append_to_statement_list (t, &ret); } t = build2 (NE_EXPR, boolean_type_node, p1, end1); t = build3 (COND_EXPR, void_type_node, t, build_and_jump (&lab), NULL); append_to_statement_list (t, &ret); return ret; } else { argarray[i++] = build_fold_addr_expr_loc (input_location, arg1); if (arg2) argarray[i++] = build_fold_addr_expr_loc (input_location, arg2); /* Handle default arguments. */ for (parm = defparm; parm && parm != void_list_node; parm = TREE_CHAIN (parm), i++) argarray[i] = convert_default_arg (TREE_VALUE (parm), TREE_PURPOSE (parm), fn, i, tf_warning_or_error); t = build_call_a (fn, i, argarray); t = fold_convert (void_type_node, t); return fold_build_cleanup_point_expr (TREE_TYPE (t), t); } }
void write_resource_constructor (void) { tree init_name, init_type, init_decl; tree iter; location_t saved_loc = input_location; char *resource_ctor_name; /* Only do work if required. */ if (resources == NULL_TREE) return; resource_ctor_name = concat (IDENTIFIER_POINTER (get_file_function_name ('I')), "_resource", NULL); init_name = get_identifier (resource_ctor_name); free (resource_ctor_name); init_type = build_function_type (void_type_node, end_params_node); init_decl = build_decl (FUNCTION_DECL, init_name, init_type); DECL_SOURCE_LINE (init_decl) = 0; SET_DECL_ASSEMBLER_NAME (init_decl, init_name); TREE_STATIC (init_decl) = 1; current_function_decl = init_decl; DECL_RESULT (init_decl) = build_decl (RESULT_DECL, NULL_TREE, void_type_node); /* It can be a static function as long as collect2 does not have to scan the object file to find its ctor/dtor routine. */ TREE_PUBLIC (init_decl) = ! targetm.have_ctors_dtors; pushlevel (0); make_decl_rtl (init_decl, NULL); init_function_start (init_decl); expand_function_start (init_decl, 0); /* Write out entries in the same order in which they were defined. */ for (iter = nreverse (resources); iter != NULL_TREE; iter = TREE_CHAIN (iter)) { emit_library_call (registerResource_libfunc, 0, VOIDmode, 1, expand_expr (build_address_of (TREE_VALUE (iter)), 0, Pmode, 0), Pmode); } input_location = DECL_SOURCE_LOCATION (init_decl); expand_function_end (); poplevel (1, 0, 1); { /* Force generation, even with -O3 or deeper. Gross hack. FIXME. */ int saved_flag = flag_inline_functions; flag_inline_functions = 0; rest_of_compilation (init_decl); flag_inline_functions = saved_flag; } current_function_decl = NULL_TREE; (* targetm.asm_out.constructor) (XEXP (DECL_RTL (init_decl), 0), DEFAULT_INIT_PRIORITY); input_location = saved_loc; }
void gimple_regimplify_operands (gimple stmt, gimple_stmt_iterator *gsi_p) { size_t i, num_ops; tree lhs; gimple_seq pre = NULL; gimple post_stmt = NULL; push_gimplify_context (gimple_in_ssa_p (cfun)); switch (gimple_code (stmt)) { case GIMPLE_COND: gimplify_expr (gimple_cond_lhs_ptr (stmt), &pre, NULL, is_gimple_val, fb_rvalue); gimplify_expr (gimple_cond_rhs_ptr (stmt), &pre, NULL, is_gimple_val, fb_rvalue); break; case GIMPLE_SWITCH: gimplify_expr (gimple_switch_index_ptr (stmt), &pre, NULL, is_gimple_val, fb_rvalue); break; case GIMPLE_OMP_ATOMIC_LOAD: gimplify_expr (gimple_omp_atomic_load_rhs_ptr (stmt), &pre, NULL, is_gimple_val, fb_rvalue); break; case GIMPLE_ASM: { size_t i, noutputs = gimple_asm_noutputs (stmt); const char *constraint, **oconstraints; bool allows_mem, allows_reg, is_inout; oconstraints = (const char **) alloca ((noutputs) * sizeof (const char *)); for (i = 0; i < noutputs; i++) { tree op = gimple_asm_output_op (stmt, i); constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op))); oconstraints[i] = constraint; parse_output_constraint (&constraint, i, 0, 0, &allows_mem, &allows_reg, &is_inout); gimplify_expr (&TREE_VALUE (op), &pre, NULL, is_inout ? is_gimple_min_lval : is_gimple_lvalue, fb_lvalue | fb_mayfail); } for (i = 0; i < gimple_asm_ninputs (stmt); i++) { tree op = gimple_asm_input_op (stmt, i); constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op))); parse_input_constraint (&constraint, 0, 0, noutputs, 0, oconstraints, &allows_mem, &allows_reg); if (TREE_ADDRESSABLE (TREE_TYPE (TREE_VALUE (op))) && allows_mem) allows_reg = 0; if (!allows_reg && allows_mem) gimplify_expr (&TREE_VALUE (op), &pre, NULL, is_gimple_lvalue, fb_lvalue | fb_mayfail); else gimplify_expr (&TREE_VALUE (op), &pre, NULL, is_gimple_asm_val, fb_rvalue); } } break; default: /* NOTE: We start gimplifying operands from last to first to make sure that side-effects on the RHS of calls, assignments and ASMs are executed before the LHS. The ordering is not important for other statements. */ num_ops = gimple_num_ops (stmt); for (i = num_ops; i > 0; i--) { tree op = gimple_op (stmt, i - 1); if (op == NULL_TREE) continue; if (i == 1 && (is_gimple_call (stmt) || is_gimple_assign (stmt))) gimplify_expr (&op, &pre, NULL, is_gimple_lvalue, fb_lvalue); else if (i == 2 && is_gimple_assign (stmt) && num_ops == 2 && get_gimple_rhs_class (gimple_expr_code (stmt)) == GIMPLE_SINGLE_RHS) gimplify_expr (&op, &pre, NULL, rhs_predicate_for (gimple_assign_lhs (stmt)), fb_rvalue); else if (i == 2 && is_gimple_call (stmt)) { if (TREE_CODE (op) == FUNCTION_DECL) continue; gimplify_expr (&op, &pre, NULL, is_gimple_call_addr, fb_rvalue); } else gimplify_expr (&op, &pre, NULL, is_gimple_val, fb_rvalue); gimple_set_op (stmt, i - 1, op); } lhs = gimple_get_lhs (stmt); /* If the LHS changed it in a way that requires a simple RHS, create temporary. */ if (lhs && !is_gimple_reg (lhs)) { bool need_temp = false; if (is_gimple_assign (stmt) && num_ops == 2 && get_gimple_rhs_class (gimple_expr_code (stmt)) == GIMPLE_SINGLE_RHS) gimplify_expr (gimple_assign_rhs1_ptr (stmt), &pre, NULL, rhs_predicate_for (gimple_assign_lhs (stmt)), fb_rvalue); else if (is_gimple_reg (lhs)) { if (is_gimple_reg_type (TREE_TYPE (lhs))) { if (is_gimple_call (stmt)) { i = gimple_call_flags (stmt); if ((i & ECF_LOOPING_CONST_OR_PURE) || !(i & (ECF_CONST | ECF_PURE))) need_temp = true; } if (stmt_can_throw_internal (stmt)) need_temp = true; } } else { if (is_gimple_reg_type (TREE_TYPE (lhs))) need_temp = true; else if (TYPE_MODE (TREE_TYPE (lhs)) != BLKmode) { if (is_gimple_call (stmt)) { tree fndecl = gimple_call_fndecl (stmt); if (!aggregate_value_p (TREE_TYPE (lhs), fndecl) && !(fndecl && DECL_RESULT (fndecl) && DECL_BY_REFERENCE (DECL_RESULT (fndecl)))) need_temp = true; } else need_temp = true; } } if (need_temp) { tree temp = create_tmp_reg (TREE_TYPE (lhs), NULL); if (gimple_in_ssa_p (cfun)) temp = make_ssa_name (temp, NULL); gimple_set_lhs (stmt, temp); post_stmt = gimple_build_assign (lhs, temp); } } break; } if (!gimple_seq_empty_p (pre)) gsi_insert_seq_before (gsi_p, pre, GSI_SAME_STMT); if (post_stmt) gsi_insert_after (gsi_p, post_stmt, GSI_NEW_STMT); pop_gimplify_context (NULL); update_stmt (stmt); }
static tree cxx_omp_clause_apply_fn (tree fn, tree arg1, tree arg2) { tree defparm, parm; int i; if (fn == NULL) return NULL; defparm = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn))); if (arg2) defparm = TREE_CHAIN (defparm); if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE) { tree inner_type = TREE_TYPE (arg1); tree start1, end1, p1; tree start2 = NULL, p2 = NULL; tree ret = NULL, lab, t; start1 = arg1; start2 = arg2; do { inner_type = TREE_TYPE (inner_type); start1 = build4 (ARRAY_REF, inner_type, start1, size_zero_node, NULL, NULL); if (arg2) start2 = build4 (ARRAY_REF, inner_type, start2, size_zero_node, NULL, NULL); } while (TREE_CODE (inner_type) == ARRAY_TYPE); start1 = build_fold_addr_expr (start1); if (arg2) start2 = build_fold_addr_expr (start2); end1 = TYPE_SIZE_UNIT (TREE_TYPE (arg1)); end1 = fold_convert (TREE_TYPE (start1), end1); end1 = build2 (PLUS_EXPR, TREE_TYPE (start1), start1, end1); p1 = create_tmp_var (TREE_TYPE (start1), NULL); t = build2 (MODIFY_EXPR, void_type_node, p1, start1); append_to_statement_list (t, &ret); if (arg2) { p2 = create_tmp_var (TREE_TYPE (start2), NULL); t = build2 (MODIFY_EXPR, void_type_node, p2, start2); append_to_statement_list (t, &ret); } lab = create_artificial_label (); t = build1 (LABEL_EXPR, void_type_node, lab); append_to_statement_list (t, &ret); t = tree_cons (NULL, p1, NULL); if (arg2) t = tree_cons (NULL, p2, t); /* Handle default arguments. */ i = 1 + (arg2 != NULL); for (parm = defparm; parm != void_list_node; parm = TREE_CHAIN (parm)) t = tree_cons (NULL, convert_default_arg (TREE_VALUE (parm), TREE_PURPOSE (parm), fn, i++), t); t = build_call (fn, nreverse (t)); append_to_statement_list (t, &ret); t = fold_convert (TREE_TYPE (p1), TYPE_SIZE_UNIT (inner_type)); t = build2 (PLUS_EXPR, TREE_TYPE (p1), p1, t); t = build2 (MODIFY_EXPR, void_type_node, p1, t); append_to_statement_list (t, &ret); if (arg2) { t = fold_convert (TREE_TYPE (p2), TYPE_SIZE_UNIT (inner_type)); t = build2 (PLUS_EXPR, TREE_TYPE (p2), p2, t); t = build2 (MODIFY_EXPR, void_type_node, p2, t); append_to_statement_list (t, &ret); } t = build2 (NE_EXPR, boolean_type_node, p1, end1); t = build3 (COND_EXPR, void_type_node, t, build_and_jump (&lab), NULL); append_to_statement_list (t, &ret); return ret; } else { tree t = tree_cons (NULL, build_fold_addr_expr (arg1), NULL); if (arg2) t = tree_cons (NULL, build_fold_addr_expr (arg2), t); /* Handle default arguments. */ i = 1 + (arg2 != NULL); for (parm = defparm; parm != void_list_node; parm = TREE_CHAIN (parm)) t = tree_cons (NULL, convert_default_arg (TREE_VALUE (parm), TREE_PURPOSE (parm), fn, i++), t); return build_call (fn, nreverse (t)); } }
tree decl_attributes (tree *node, tree attributes, int flags) { tree a; tree returned_attrs = NULL_TREE; if (!attributes_initialized) init_attributes (); targetm.insert_attributes (*node, &attributes); for (a = attributes; a; a = TREE_CHAIN (a)) { tree name = TREE_PURPOSE (a); tree args = TREE_VALUE (a); tree *anode = node; const struct attribute_spec *spec = NULL; bool no_add_attrs = 0; tree fn_ptr_tmp = NULL_TREE; size_t i; for (i = 0; i < ARRAY_SIZE (attribute_tables); i++) { int j; for (j = 0; attribute_tables[i][j].name != NULL; j++) { if (is_attribute_p (attribute_tables[i][j].name, name)) { spec = &attribute_tables[i][j]; break; } } if (spec != NULL) break; } if (spec == NULL) { warning (OPT_Wattributes, "%qs attribute directive ignored", IDENTIFIER_POINTER (name)); continue; } else if (list_length (args) < spec->min_length || (spec->max_length >= 0 && list_length (args) > spec->max_length)) { error ("wrong number of arguments specified for %qs attribute", IDENTIFIER_POINTER (name)); continue; } if (spec->decl_required && !DECL_P (*anode)) { if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT | (int) ATTR_FLAG_ARRAY_NEXT)) { /* Pass on this attribute to be tried again. */ returned_attrs = tree_cons (name, args, returned_attrs); continue; } else { warning (OPT_Wattributes, "%qs attribute does not apply to types", IDENTIFIER_POINTER (name)); continue; } } /* If we require a type, but were passed a decl, set up to make a new type and update the one in the decl. ATTR_FLAG_TYPE_IN_PLACE would have applied if we'd been passed a type, but we cannot modify the decl's type in place here. */ if (spec->type_required && DECL_P (*anode)) { anode = &TREE_TYPE (*anode); flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE; } if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE && TREE_CODE (*anode) != METHOD_TYPE) { if (TREE_CODE (*anode) == POINTER_TYPE && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE)) { /* OK, this is a bit convoluted. We can't just make a copy of the pointer type and modify its TREE_TYPE, because if we change the attributes of the target type the pointer type needs to have a different TYPE_MAIN_VARIANT. So we pull out the target type now, frob it as appropriate, and rebuild the pointer type later. This would all be simpler if attributes were part of the declarator, grumble grumble. */ fn_ptr_tmp = TREE_TYPE (*anode); anode = &fn_ptr_tmp; flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE; } else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT) { /* Pass on this attribute to be tried again. */ returned_attrs = tree_cons (name, args, returned_attrs); continue; } if (TREE_CODE (*anode) != FUNCTION_TYPE && TREE_CODE (*anode) != METHOD_TYPE) { warning (OPT_Wattributes, "%qs attribute only applies to function types", IDENTIFIER_POINTER (name)); continue; } } if (TYPE_P (*anode) && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE) && TYPE_SIZE (*anode) != NULL_TREE) { warning (OPT_Wattributes, "type attributes ignored after type is already defined"); continue; } if (spec->handler != NULL) returned_attrs = chainon ((*spec->handler) (anode, name, args, flags, &no_add_attrs), returned_attrs); /* Layout the decl in case anything changed. */ if (spec->type_required && DECL_P (*node) && (TREE_CODE (*node) == VAR_DECL || TREE_CODE (*node) == PARM_DECL || TREE_CODE (*node) == RESULT_DECL)) relayout_decl (*node); if (!no_add_attrs) { tree old_attrs; tree a; if (DECL_P (*anode)) old_attrs = DECL_ATTRIBUTES (*anode); else old_attrs = TYPE_ATTRIBUTES (*anode); for (a = lookup_attribute (spec->name, old_attrs); a != NULL_TREE; a = lookup_attribute (spec->name, TREE_CHAIN (a))) { if (simple_cst_equal (TREE_VALUE (a), args) == 1) break; } if (a == NULL_TREE) { /* This attribute isn't already in the list. */ if (DECL_P (*anode)) DECL_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs); else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE) { TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs); /* If this is the main variant, also push the attributes out to the other variants. */ if (*anode == TYPE_MAIN_VARIANT (*anode)) { tree variant; for (variant = *anode; variant; variant = TYPE_NEXT_VARIANT (variant)) { if (TYPE_ATTRIBUTES (variant) == old_attrs) TYPE_ATTRIBUTES (variant) = TYPE_ATTRIBUTES (*anode); else if (!lookup_attribute (spec->name, TYPE_ATTRIBUTES (variant))) TYPE_ATTRIBUTES (variant) = tree_cons (name, args, TYPE_ATTRIBUTES (variant)); } } } else *anode = build_type_attribute_variant (*anode, tree_cons (name, args, old_attrs)); } } if (fn_ptr_tmp) { /* Rebuild the function pointer type and put it in the appropriate place. */ fn_ptr_tmp = build_pointer_type (fn_ptr_tmp); if (DECL_P (*node)) TREE_TYPE (*node) = fn_ptr_tmp; else { gcc_assert (TREE_CODE (*node) == POINTER_TYPE); *node = fn_ptr_tmp; } } } return returned_attrs; }
static void dequeue_and_dump (dump_info_p di) { dump_queue_p dq; splay_tree_node stn; dump_node_info_p dni; tree t; unsigned int index; enum tree_code code; enum tree_code_class code_class; const char* code_name; /* Get the next node from the queue. */ dq = di->queue; stn = dq->node; t = (tree) stn->key; dni = (dump_node_info_p) stn->value; index = dni->index; /* Remove the node from the queue, and put it on the free list. */ di->queue = dq->next; if (!di->queue) di->queue_end = 0; dq->next = di->free_list; di->free_list = dq; /* Print the node index. */ dump_index (di, index); /* And the type of node this is. */ if (dni->binfo_p) code_name = "binfo"; else code_name = tree_code_name[(int) TREE_CODE (t)]; fprintf (di->stream, "%-16s ", code_name); di->column = 25; /* Figure out what kind of node this is. */ code = TREE_CODE (t); code_class = TREE_CODE_CLASS (code); /* Although BINFOs are TREE_VECs, we dump them specially so as to be more informative. */ if (dni->binfo_p) { unsigned ix; tree base; VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (t); dump_child ("type", BINFO_TYPE (t)); if (BINFO_VIRTUAL_P (t)) dump_string_field (di, "spec", "virt"); dump_int (di, "bases", BINFO_N_BASE_BINFOS (t)); for (ix = 0; BINFO_BASE_ITERATE (t, ix, base); ix++) { tree access = (accesses ? VEC_index (tree, accesses, ix) : access_public_node); const char *string = NULL; if (access == access_public_node) string = "pub"; else if (access == access_protected_node) string = "prot"; else if (access == access_private_node) string = "priv"; else gcc_unreachable (); dump_string_field (di, "accs", string); queue_and_dump_index (di, "binf", base, DUMP_BINFO); } goto done; } /* We can knock off a bunch of expression nodes in exactly the same way. */ if (IS_EXPR_CODE_CLASS (code_class)) { /* If we're dumping children, dump them now. */ queue_and_dump_type (di, t); switch (code_class) { case tcc_unary: dump_child ("op 0", TREE_OPERAND (t, 0)); break; case tcc_binary: case tcc_comparison: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); break; case tcc_expression: case tcc_reference: case tcc_statement: /* These nodes are handled explicitly below. */ break; default: gcc_unreachable (); } } else if (DECL_P (t)) { expanded_location xloc; /* All declarations have names. */ if (DECL_NAME (t)) dump_child ("name", DECL_NAME (t)); if (DECL_ASSEMBLER_NAME_SET_P (t) && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t)) dump_child ("mngl", DECL_ASSEMBLER_NAME (t)); if (DECL_ABSTRACT_ORIGIN (t)) dump_child ("orig", DECL_ABSTRACT_ORIGIN (t)); /* And types. */ queue_and_dump_type (di, t); dump_child ("scpe", DECL_CONTEXT (t)); /* And a source position. */ xloc = expand_location (DECL_SOURCE_LOCATION (t)); if (xloc.file) { const char *filename = strrchr (xloc.file, '/'); if (!filename) filename = xloc.file; else /* Skip the slash. */ ++filename; dump_maybe_newline (di); fprintf (di->stream, "srcp: %s:%-6d ", filename, xloc.line); di->column += 6 + strlen (filename) + 8; } /* And any declaration can be compiler-generated. */ if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_COMMON) && DECL_ARTIFICIAL (t)) dump_string_field (di, "note", "artificial"); if (TREE_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL)) dump_child ("chan", TREE_CHAIN (t)); } else if (code_class == tcc_type) { /* All types have qualifiers. */ int quals = lang_hooks.tree_dump.type_quals (t); if (quals != TYPE_UNQUALIFIED) { fprintf (di->stream, "qual: %c%c%c ", (quals & TYPE_QUAL_CONST) ? 'c' : ' ', (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ', (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' '); di->column += 14; } /* All types have associated declarations. */ dump_child ("name", TYPE_NAME (t)); /* All types have a main variant. */ if (TYPE_MAIN_VARIANT (t) != t) dump_child ("unql", TYPE_MAIN_VARIANT (t)); /* And sizes. */ dump_child ("size", TYPE_SIZE (t)); /* All types have alignments. */ dump_int (di, "algn", TYPE_ALIGN (t)); } else if (code_class == tcc_constant) /* All constants can have types. */ queue_and_dump_type (di, t); /* Give the language-specific code a chance to print something. If it's completely taken care of things, don't bother printing anything more ourselves. */ if (lang_hooks.tree_dump.dump_tree (di, t)) goto done; /* Now handle the various kinds of nodes. */ switch (code) { int i; case IDENTIFIER_NODE: dump_string_field (di, "strg", IDENTIFIER_POINTER (t)); dump_int (di, "lngt", IDENTIFIER_LENGTH (t)); break; case TREE_LIST: dump_child ("purp", TREE_PURPOSE (t)); dump_child ("valu", TREE_VALUE (t)); dump_child ("chan", TREE_CHAIN (t)); break; case STATEMENT_LIST: { tree_stmt_iterator it; for (i = 0, it = tsi_start (t); !tsi_end_p (it); tsi_next (&it), i++) { char buffer[32]; sprintf (buffer, "%u", i); dump_child (buffer, tsi_stmt (it)); } } break; case TREE_VEC: dump_int (di, "lngt", TREE_VEC_LENGTH (t)); for (i = 0; i < TREE_VEC_LENGTH (t); ++i) { char buffer[32]; sprintf (buffer, "%u", i); dump_child (buffer, TREE_VEC_ELT (t, i)); } break; case INTEGER_TYPE: case ENUMERAL_TYPE: dump_int (di, "prec", TYPE_PRECISION (t)); dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed"); dump_child ("min", TYPE_MIN_VALUE (t)); dump_child ("max", TYPE_MAX_VALUE (t)); if (code == ENUMERAL_TYPE) dump_child ("csts", TYPE_VALUES (t)); break; case REAL_TYPE: dump_int (di, "prec", TYPE_PRECISION (t)); break; case POINTER_TYPE: dump_child ("ptd", TREE_TYPE (t)); break; case REFERENCE_TYPE: dump_child ("refd", TREE_TYPE (t)); break; case METHOD_TYPE: dump_child ("clas", TYPE_METHOD_BASETYPE (t)); /* Fall through. */ case FUNCTION_TYPE: dump_child ("retn", TREE_TYPE (t)); dump_child ("prms", TYPE_ARG_TYPES (t)); break; case ARRAY_TYPE: dump_child ("elts", TREE_TYPE (t)); dump_child ("domn", TYPE_DOMAIN (t)); break; case RECORD_TYPE: case UNION_TYPE: if (TREE_CODE (t) == RECORD_TYPE) dump_string_field (di, "tag", "struct"); else dump_string_field (di, "tag", "union"); dump_child ("flds", TYPE_FIELDS (t)); dump_child ("fncs", TYPE_METHODS (t)); queue_and_dump_index (di, "binf", TYPE_BINFO (t), DUMP_BINFO); break; case CONST_DECL: dump_child ("cnst", DECL_INITIAL (t)); break; case SYMBOL_MEMORY_TAG: case NAME_MEMORY_TAG: case STRUCT_FIELD_TAG: break; case VAR_DECL: case PARM_DECL: case FIELD_DECL: case RESULT_DECL: if (TREE_CODE (t) == PARM_DECL) dump_child ("argt", DECL_ARG_TYPE (t)); else dump_child ("init", DECL_INITIAL (t)); dump_child ("size", DECL_SIZE (t)); dump_int (di, "algn", DECL_ALIGN (t)); if (TREE_CODE (t) == FIELD_DECL) { if (DECL_FIELD_OFFSET (t)) dump_child ("bpos", bit_position (t)); } else if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == PARM_DECL) { dump_int (di, "used", TREE_USED (t)); if (DECL_REGISTER (t)) dump_string_field (di, "spec", "register"); } break; case FUNCTION_DECL: dump_child ("args", DECL_ARGUMENTS (t)); if (DECL_EXTERNAL (t)) dump_string_field (di, "body", "undefined"); if (TREE_PUBLIC (t)) dump_string_field (di, "link", "extern"); else dump_string_field (di, "link", "static"); if (DECL_LANG_SPECIFIC (t) && !dump_flag (di, TDF_SLIM, t)) dump_child ("body", DECL_SAVED_TREE (t)); break; case INTEGER_CST: if (TREE_INT_CST_HIGH (t)) dump_int (di, "high", TREE_INT_CST_HIGH (t)); dump_int (di, "low", TREE_INT_CST_LOW (t)); break; case STRING_CST: fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t)); dump_int (di, "lngt", TREE_STRING_LENGTH (t)); break; case REAL_CST: dump_real (di, "valu", TREE_REAL_CST_PTR (t)); break; case TRUTH_NOT_EXPR: case ADDR_EXPR: case INDIRECT_REF: case ALIGN_INDIRECT_REF: case MISALIGNED_INDIRECT_REF: case CLEANUP_POINT_EXPR: case SAVE_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: /* These nodes are unary, but do not have code class `1'. */ dump_child ("op 0", TREE_OPERAND (t, 0)); break; case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: case INIT_EXPR: case MODIFY_EXPR: case COMPOUND_EXPR: case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: /* These nodes are binary, but do not have code class `2'. */ dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); break; case COMPONENT_REF: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); dump_child ("op 2", TREE_OPERAND (t, 2)); break; case ARRAY_REF: case ARRAY_RANGE_REF: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); dump_child ("op 2", TREE_OPERAND (t, 2)); dump_child ("op 3", TREE_OPERAND (t, 3)); break; case COND_EXPR: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); dump_child ("op 2", TREE_OPERAND (t, 2)); break; case TRY_FINALLY_EXPR: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); break; case CALL_EXPR: dump_child ("fn", TREE_OPERAND (t, 0)); dump_child ("args", TREE_OPERAND (t, 1)); break; case CONSTRUCTOR: { unsigned HOST_WIDE_INT cnt; tree index, value; dump_int (di, "lngt", VEC_length (constructor_elt, CONSTRUCTOR_ELTS (t))); FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), cnt, index, value) { dump_child ("idx", index); dump_child ("val", value); } } break; case BIND_EXPR: dump_child ("vars", TREE_OPERAND (t, 0)); dump_child ("body", TREE_OPERAND (t, 1)); break; case LOOP_EXPR: dump_child ("body", TREE_OPERAND (t, 0)); break; case EXIT_EXPR: dump_child ("cond", TREE_OPERAND (t, 0)); break; case RETURN_EXPR: dump_child ("expr", TREE_OPERAND (t, 0)); break; case TARGET_EXPR: dump_child ("decl", TREE_OPERAND (t, 0)); dump_child ("init", TREE_OPERAND (t, 1)); dump_child ("clnp", TREE_OPERAND (t, 2)); /* There really are two possible places the initializer can be. After RTL expansion, the second operand is moved to the position of the fourth operand, and the second operand becomes NULL. */ dump_child ("init", TREE_OPERAND (t, 3)); break; case CASE_LABEL_EXPR: dump_child ("name", CASE_LABEL (t)); if (CASE_LOW (t)) { dump_child ("low ", CASE_LOW (t)); if (CASE_HIGH (t)) { dump_child ("high", CASE_HIGH (t)); } } break; case LABEL_EXPR: dump_child ("name", TREE_OPERAND (t,0)); break; case GOTO_EXPR: dump_child ("labl", TREE_OPERAND (t, 0)); break; case SWITCH_EXPR: dump_child ("cond", TREE_OPERAND (t, 0)); dump_child ("body", TREE_OPERAND (t, 1)); if (TREE_OPERAND (t, 2)) { dump_child ("labl", TREE_OPERAND (t,2)); } break; case OMP_CLAUSE: { int i; fprintf (di->stream, "%s\n", omp_clause_code_name[OMP_CLAUSE_CODE (t)]); for (i = 0; i < omp_clause_num_ops[OMP_CLAUSE_CODE (t)]; i++) dump_child ("op: ", OMP_CLAUSE_OPERAND (t, i)); } break; default: /* There are no additional fields to print. */ break; }
void browse_tree (tree begin) { tree head; TB_CODE tbc = TB_UNUSED_COMMAND; ssize_t rd; char *input = NULL; long input_size = 0; fprintf (TB_OUT_FILE, "\nTree Browser\n"); #define TB_SET_HEAD(N) do { \ vec_safe_push (TB_history_stack, N); \ head = N; \ if (TB_verbose) \ if (head) \ { \ print_generic_expr (TB_OUT_FILE, head, 0); \ fprintf (TB_OUT_FILE, "\n"); \ } \ } while (0) TB_SET_HEAD (begin); /* Store in a hashtable information about previous and upper statements. */ { TB_up_ht.create (1023); TB_update_up (head); } while (24) { fprintf (TB_OUT_FILE, "TB> "); rd = TB_getline (&input, &input_size, TB_IN_FILE); if (rd == -1) /* EOF. */ goto ret; if (rd != 1) /* Get a new command. Otherwise the user just pressed enter, and thus she expects the last command to be reexecuted. */ tbc = TB_get_command (input); switch (tbc) { case TB_UPDATE_UP: TB_update_up (head); break; case TB_MAX: if (head && (INTEGRAL_TYPE_P (head) || TREE_CODE (head) == REAL_TYPE || TREE_CODE (head) == FIXED_POINT_TYPE)) TB_SET_HEAD (TYPE_MAX_VALUE (head)); else TB_WF; break; case TB_MIN: if (head && (INTEGRAL_TYPE_P (head) || TREE_CODE (head) == REAL_TYPE || TREE_CODE (head) == FIXED_POINT_TYPE)) TB_SET_HEAD (TYPE_MIN_VALUE (head)); else TB_WF; break; case TB_ELT: if (head && TREE_CODE (head) == TREE_VEC) { /* This command takes another argument: the element number: for example "elt 1". */ TB_NIY; } else if (head && TREE_CODE (head) == VECTOR_CST) { /* This command takes another argument: the element number: for example "elt 1". */ TB_NIY; } else TB_WF; break; case TB_VALUE: if (head && TREE_CODE (head) == TREE_LIST) TB_SET_HEAD (TREE_VALUE (head)); else TB_WF; break; case TB_PURPOSE: if (head && TREE_CODE (head) == TREE_LIST) TB_SET_HEAD (TREE_PURPOSE (head)); else TB_WF; break; case TB_IMAG: if (head && TREE_CODE (head) == COMPLEX_CST) TB_SET_HEAD (TREE_IMAGPART (head)); else TB_WF; break; case TB_REAL: if (head && TREE_CODE (head) == COMPLEX_CST) TB_SET_HEAD (TREE_REALPART (head)); else TB_WF; break; case TB_BLOCK: if (head && TREE_CODE (head) == BIND_EXPR) TB_SET_HEAD (TREE_OPERAND (head, 2)); else TB_WF; break; case TB_SUBBLOCKS: if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_SUBBLOCKS (head)); else TB_WF; break; case TB_SUPERCONTEXT: if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_SUPERCONTEXT (head)); else TB_WF; break; case TB_VARS: if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_VARS (head)); else if (head && TREE_CODE (head) == BIND_EXPR) TB_SET_HEAD (TREE_OPERAND (head, 0)); else TB_WF; break; case TB_REFERENCE_TO_THIS: if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_REFERENCE_TO (head)); else TB_WF; break; case TB_POINTER_TO_THIS: if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_POINTER_TO (head)); else TB_WF; break; case TB_BASETYPE: if (head && TREE_CODE (head) == OFFSET_TYPE) TB_SET_HEAD (TYPE_OFFSET_BASETYPE (head)); else TB_WF; break; case TB_ARG_TYPES: if (head && (TREE_CODE (head) == FUNCTION_TYPE || TREE_CODE (head) == METHOD_TYPE)) TB_SET_HEAD (TYPE_ARG_TYPES (head)); else TB_WF; break; case TB_METHOD_BASE_TYPE: if (head && (TREE_CODE (head) == FUNCTION_TYPE || TREE_CODE (head) == METHOD_TYPE) && TYPE_METHOD_BASETYPE (head)) TB_SET_HEAD (TYPE_METHOD_BASETYPE (head)); else TB_WF; break; case TB_FIELDS: if (head && (TREE_CODE (head) == RECORD_TYPE || TREE_CODE (head) == UNION_TYPE || TREE_CODE (head) == QUAL_UNION_TYPE)) TB_SET_HEAD (TYPE_FIELDS (head)); else TB_WF; break; case TB_DOMAIN: if (head && TREE_CODE (head) == ARRAY_TYPE) TB_SET_HEAD (TYPE_DOMAIN (head)); else TB_WF; break; case TB_VALUES: if (head && TREE_CODE (head) == ENUMERAL_TYPE) TB_SET_HEAD (TYPE_VALUES (head)); else TB_WF; break; case TB_ARG_TYPE: if (head && TREE_CODE (head) == PARM_DECL) TB_SET_HEAD (DECL_ARG_TYPE (head)); else TB_WF; break; case TB_INITIAL: if (head && DECL_P (head)) TB_SET_HEAD (DECL_INITIAL (head)); else TB_WF; break; case TB_RESULT: if (head && DECL_P (head)) TB_SET_HEAD (DECL_RESULT_FLD (head)); else TB_WF; break; case TB_ARGUMENTS: if (head && DECL_P (head)) TB_SET_HEAD (DECL_ARGUMENTS (head)); else TB_WF; break; case TB_ABSTRACT_ORIGIN: if (head && DECL_P (head)) TB_SET_HEAD (DECL_ABSTRACT_ORIGIN (head)); else if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_ABSTRACT_ORIGIN (head)); else TB_WF; break; case TB_ATTRIBUTES: if (head && DECL_P (head)) TB_SET_HEAD (DECL_ATTRIBUTES (head)); else if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_ATTRIBUTES (head)); else TB_WF; break; case TB_CONTEXT: if (head && DECL_P (head)) TB_SET_HEAD (DECL_CONTEXT (head)); else if (head && TYPE_P (head) && TYPE_CONTEXT (head)) TB_SET_HEAD (TYPE_CONTEXT (head)); else TB_WF; break; case TB_OFFSET: if (head && TREE_CODE (head) == FIELD_DECL) TB_SET_HEAD (DECL_FIELD_OFFSET (head)); else TB_WF; break; case TB_BIT_OFFSET: if (head && TREE_CODE (head) == FIELD_DECL) TB_SET_HEAD (DECL_FIELD_BIT_OFFSET (head)); else TB_WF; break; case TB_UNIT_SIZE: if (head && DECL_P (head)) TB_SET_HEAD (DECL_SIZE_UNIT (head)); else if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_SIZE_UNIT (head)); else TB_WF; break; case TB_SIZE: if (head && DECL_P (head)) TB_SET_HEAD (DECL_SIZE (head)); else if (head && TYPE_P (head)) TB_SET_HEAD (TYPE_SIZE (head)); else TB_WF; break; case TB_TYPE: if (head && TREE_TYPE (head)) TB_SET_HEAD (TREE_TYPE (head)); else TB_WF; break; case TB_DECL_SAVED_TREE: if (head && TREE_CODE (head) == FUNCTION_DECL && DECL_SAVED_TREE (head)) TB_SET_HEAD (DECL_SAVED_TREE (head)); else TB_WF; break; case TB_BODY: if (head && TREE_CODE (head) == BIND_EXPR) TB_SET_HEAD (TREE_OPERAND (head, 1)); else TB_WF; break; case TB_CHILD_0: if (head && EXPR_P (head) && TREE_OPERAND (head, 0)) TB_SET_HEAD (TREE_OPERAND (head, 0)); else TB_WF; break; case TB_CHILD_1: if (head && EXPR_P (head) && TREE_OPERAND (head, 1)) TB_SET_HEAD (TREE_OPERAND (head, 1)); else TB_WF; break; case TB_CHILD_2: if (head && EXPR_P (head) && TREE_OPERAND (head, 2)) TB_SET_HEAD (TREE_OPERAND (head, 2)); else TB_WF; break; case TB_CHILD_3: if (head && EXPR_P (head) && TREE_OPERAND (head, 3)) TB_SET_HEAD (TREE_OPERAND (head, 3)); else TB_WF; break; case TB_PRINT: if (head) debug_tree (head); else TB_WF; break; case TB_PRETTY_PRINT: if (head) { print_generic_stmt (TB_OUT_FILE, head, 0); fprintf (TB_OUT_FILE, "\n"); } else TB_WF; break; case TB_SEARCH_NAME: break; case TB_SEARCH_CODE: { enum tree_code code; char *arg_text; arg_text = strchr (input, ' '); if (arg_text == NULL) { fprintf (TB_OUT_FILE, "First argument is missing. This isn't a valid search command. \n"); break; } code = TB_get_tree_code (arg_text + 1); /* Search in the subtree a node with the given code. */ { tree res; res = walk_tree (&head, find_node_with_code, &code, NULL); if (res == NULL_TREE) { fprintf (TB_OUT_FILE, "There's no node with this code (reachable via the walk_tree function from this node).\n"); } else { fprintf (TB_OUT_FILE, "Achoo! I got this node in the tree.\n"); TB_SET_HEAD (res); } } break; } #define TB_MOVE_HEAD(FCT) do { \ if (head) \ { \ tree t; \ t = FCT (head); \ if (t) \ TB_SET_HEAD (t); \ else \ TB_WF; \ } \ else \ TB_WF; \ } while (0) case TB_FIRST: TB_MOVE_HEAD (TB_first_in_bind); break; case TB_LAST: TB_MOVE_HEAD (TB_last_in_bind); break; case TB_UP: TB_MOVE_HEAD (TB_up_expr); break; case TB_PREV: TB_MOVE_HEAD (TB_prev_expr); break; case TB_NEXT: TB_MOVE_HEAD (TB_next_expr); break; case TB_HPREV: /* This command is a little bit special, since it deals with history stack. For this reason it should keep the "head = ..." statement and not use TB_MOVE_HEAD. */ if (head) { tree t; t = TB_history_prev (); if (t) { head = t; if (TB_verbose) { print_generic_expr (TB_OUT_FILE, head, 0); fprintf (TB_OUT_FILE, "\n"); } } else TB_WF; } else TB_WF; break; case TB_CHAIN: /* Don't go further if it's the last node in this chain. */ if (head && TREE_CODE (head) == BLOCK) TB_SET_HEAD (BLOCK_CHAIN (head)); else if (head && TREE_CHAIN (head)) TB_SET_HEAD (TREE_CHAIN (head)); else TB_WF; break; case TB_FUN: /* Go up to the current function declaration. */ TB_SET_HEAD (current_function_decl); fprintf (TB_OUT_FILE, "Current function declaration.\n"); break; case TB_HELP: /* Display a help message. */ { int i; fprintf (TB_OUT_FILE, "Possible commands are:\n\n"); for (i = 0; i < TB_UNUSED_COMMAND; i++) { fprintf (TB_OUT_FILE, "%20s - %s\n", TB_COMMAND_TEXT (i), TB_COMMAND_HELP (i)); } } break; case TB_VERBOSE: if (TB_verbose == 0) { TB_verbose = 1; fprintf (TB_OUT_FILE, "Verbose on.\n"); } else { TB_verbose = 0; fprintf (TB_OUT_FILE, "Verbose off.\n"); } break; case TB_EXIT: case TB_QUIT: /* Just exit from this function. */ goto ret; default: TB_NIY; } } ret:; TB_up_ht.dispose (); return; }
/* Function to construct isr vectors information array. We DO NOT HAVE TO check if the attributes are valid because those works are supposed to be done on nds32_merge_decl_attributes() and nds32_insert_attributes(). */ void nds32_construct_isr_vectors_information (tree func_attrs, const char *func_name) { tree save_all, partial_save; tree nested, not_nested, nested_ready; tree intr, excp, reset; save_all = lookup_attribute ("save_all", func_attrs); partial_save = lookup_attribute ("partial_save", func_attrs); nested = lookup_attribute ("nested", func_attrs); not_nested = lookup_attribute ("not_nested", func_attrs); nested_ready = lookup_attribute ("nested_ready", func_attrs); intr = lookup_attribute ("interrupt", func_attrs); excp = lookup_attribute ("exception", func_attrs); reset = lookup_attribute ("reset", func_attrs); /* If there is no interrupt/exception/reset, we can return immediately. */ if (!intr && !excp && !reset) return; /* If we are here, either we have interrupt/exception, or reset attribute. */ if (intr || excp) { tree id_list; /* Prepare id list so that we can traverse and set vector id. */ id_list = (intr) ? (TREE_VALUE (intr)) : (TREE_VALUE (excp)); while (id_list) { tree id; int vector_id; unsigned int vector_number_offset; /* The way to handle interrupt or exception is the same, we just need to take care of actual vector number. For interrupt(0..63), the actual vector number is (9..72). For exception(1..8), the actual vector number is (1..8). */ vector_number_offset = (intr) ? (9) : (0); /* Pick up each vector id value. */ id = TREE_VALUE (id_list); /* Add vector_number_offset to get actual vector number. */ vector_id = TREE_INT_CST_LOW (id) + vector_number_offset; /* Enable corresponding vector and set function name. */ nds32_isr_vectors[vector_id].category = (intr) ? (NDS32_ISR_INTERRUPT) : (NDS32_ISR_EXCEPTION); strcpy (nds32_isr_vectors[vector_id].func_name, func_name); /* Set register saving scheme. */ if (save_all) nds32_isr_vectors[vector_id].save_reg = NDS32_SAVE_ALL; else if (partial_save) nds32_isr_vectors[vector_id].save_reg = NDS32_PARTIAL_SAVE; /* Set nested type. */ if (nested) nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED; else if (not_nested) nds32_isr_vectors[vector_id].nested_type = NDS32_NOT_NESTED; else if (nested_ready) nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED_READY; /* Advance to next id. */ id_list = TREE_CHAIN (id_list); } } else { tree id_list; tree id; tree nmi, warm; /* Deal with reset attribute. Its vector number is always 0. */ nds32_isr_vectors[0].category = NDS32_ISR_RESET; /* Prepare id_list and identify id value so that we can set total number of vectors. */ id_list = TREE_VALUE (reset); id = TREE_VALUE (id_list); /* The total vectors = interrupt + exception numbers + reset. There are 8 exception and 1 reset in nds32 architecture. */ nds32_isr_vectors[0].total_n_vectors = TREE_INT_CST_LOW (id) + 8 + 1; strcpy (nds32_isr_vectors[0].func_name, func_name); /* Retrieve nmi and warm function. */ nmi = lookup_attribute ("nmi", func_attrs); warm = lookup_attribute ("warm", func_attrs); if (nmi != NULL_TREE) { tree nmi_func_list; tree nmi_func; nmi_func_list = TREE_VALUE (nmi); nmi_func = TREE_VALUE (nmi_func_list); /* Record nmi function name. */ strcpy (nds32_isr_vectors[0].nmi_name, IDENTIFIER_POINTER (nmi_func)); } if (warm != NULL_TREE) { tree warm_func_list; tree warm_func; warm_func_list = TREE_VALUE (warm); warm_func = TREE_VALUE (warm_func_list); /* Record warm function name. */ strcpy (nds32_isr_vectors[0].warm_name, IDENTIFIER_POINTER (warm_func)); } } }
tree decl_attributes (tree *node, tree attributes, int flags) { tree a; tree returned_attrs = NULL_TREE; if (TREE_TYPE (*node) == error_mark_node) return NULL_TREE; if (!attributes_initialized) init_attributes (); /* If this is a function and the user used #pragma GCC optimize, add the options to the attribute((optimize(...))) list. */ if (TREE_CODE (*node) == FUNCTION_DECL && current_optimize_pragma) { tree cur_attr = lookup_attribute ("optimize", attributes); tree opts = copy_list (current_optimize_pragma); if (! cur_attr) attributes = tree_cons (get_identifier ("optimize"), opts, attributes); else TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr)); } if (TREE_CODE (*node) == FUNCTION_DECL && optimization_current_node != optimization_default_node && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)) DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node) = optimization_current_node; /* If this is a function and the user used #pragma GCC target, add the options to the attribute((target(...))) list. */ if (TREE_CODE (*node) == FUNCTION_DECL && current_target_pragma && targetm.target_option.valid_attribute_p (*node, NULL_TREE, current_target_pragma, 0)) { tree cur_attr = lookup_attribute ("target", attributes); tree opts = copy_list (current_target_pragma); if (! cur_attr) attributes = tree_cons (get_identifier ("target"), opts, attributes); else TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr)); } targetm.insert_attributes (*node, &attributes); for (a = attributes; a; a = TREE_CHAIN (a)) { tree name = TREE_PURPOSE (a); tree args = TREE_VALUE (a); tree *anode = node; const struct attribute_spec *spec = lookup_attribute_spec (name); bool no_add_attrs = 0; tree fn_ptr_tmp = NULL_TREE; if (spec == NULL) { warning (OPT_Wattributes, "%qs attribute directive ignored", IDENTIFIER_POINTER (name)); continue; } else if (list_length (args) < spec->min_length || (spec->max_length >= 0 && list_length (args) > spec->max_length)) { error ("wrong number of arguments specified for %qs attribute", IDENTIFIER_POINTER (name)); continue; } gcc_assert (is_attribute_p (spec->name, name)); /* If this is a lock attribute and the purpose field of the args is an error_mark_node, the attribute arguments have not been parsed yet (as we delay the parsing of the attribute arguments until after the whole class has been parsed). So don't handle this attribute now but simply replace the error_mark_node with the current decl node (which we will need when we call this routine again later). */ if (args && TREE_PURPOSE (args) == error_mark_node && is_lock_attribute_with_args (name)) { TREE_PURPOSE (args) = *node; continue; } if (spec->decl_required && !DECL_P (*anode)) { if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT | (int) ATTR_FLAG_ARRAY_NEXT)) { /* Pass on this attribute to be tried again. */ returned_attrs = tree_cons (name, args, returned_attrs); continue; } else { warning (OPT_Wattributes, "%qs attribute does not apply to types", IDENTIFIER_POINTER (name)); continue; } } /* If we require a type, but were passed a decl, set up to make a new type and update the one in the decl. ATTR_FLAG_TYPE_IN_PLACE would have applied if we'd been passed a type, but we cannot modify the decl's type in place here. */ if (spec->type_required && DECL_P (*anode)) { anode = &TREE_TYPE (*anode); /* Allow ATTR_FLAG_TYPE_IN_PLACE for the type's naming decl. */ if (!(TREE_CODE (*anode) == TYPE_DECL && *anode == TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (*anode))))) flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE; } if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE && TREE_CODE (*anode) != METHOD_TYPE) { if (TREE_CODE (*anode) == POINTER_TYPE && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE)) { /* OK, this is a bit convoluted. We can't just make a copy of the pointer type and modify its TREE_TYPE, because if we change the attributes of the target type the pointer type needs to have a different TYPE_MAIN_VARIANT. So we pull out the target type now, frob it as appropriate, and rebuild the pointer type later. This would all be simpler if attributes were part of the declarator, grumble grumble. */ fn_ptr_tmp = TREE_TYPE (*anode); anode = &fn_ptr_tmp; flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE; } else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT) { /* Pass on this attribute to be tried again. */ returned_attrs = tree_cons (name, args, returned_attrs); continue; } if (TREE_CODE (*anode) != FUNCTION_TYPE && TREE_CODE (*anode) != METHOD_TYPE) { warning (OPT_Wattributes, "%qs attribute only applies to function types", IDENTIFIER_POINTER (name)); continue; } } if (TYPE_P (*anode) && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE) && TYPE_SIZE (*anode) != NULL_TREE) { warning (OPT_Wattributes, "type attributes ignored after type is already defined"); continue; } if (spec->handler != NULL) { tree ret_attr = (*spec->handler) (anode, name, args, flags, &no_add_attrs); if (ret_attr) { /* For the lock attributes whose arguments (i.e. locks) are not supported or the names are not in scope, we would demote the attributes. For example, if 'foo' is not in scope in the attribute "guarded_by(foo->lock), the attribute would be downgraded to a "guarded" attribute. And in this case, the handler would return the new, demoted attribute which is appended to the current one so that it is handled in the next iteration. */ if (is_lock_attribute_with_args (name)) { gcc_assert (no_add_attrs); TREE_CHAIN (ret_attr) = TREE_CHAIN (a); TREE_CHAIN (a) = ret_attr; continue; } else returned_attrs = chainon (ret_attr, returned_attrs); } } /* Layout the decl in case anything changed. */ if (spec->type_required && DECL_P (*node) && (TREE_CODE (*node) == VAR_DECL || TREE_CODE (*node) == PARM_DECL || TREE_CODE (*node) == RESULT_DECL)) relayout_decl (*node); if (!no_add_attrs) { tree old_attrs; tree a; if (DECL_P (*anode)) old_attrs = DECL_ATTRIBUTES (*anode); else old_attrs = TYPE_ATTRIBUTES (*anode); for (a = lookup_attribute (spec->name, old_attrs); a != NULL_TREE; a = lookup_attribute (spec->name, TREE_CHAIN (a))) { if (simple_cst_equal (TREE_VALUE (a), args) == 1) break; /* If a lock attribute of the same kind is already on the decl, don't add this one again. Instead, merge the arguments. */ if (is_lock_attribute_with_args (name)) { merge_lock_attr_args (a, args); break; } } if (a == NULL_TREE) { /* This attribute isn't already in the list. */ if (DECL_P (*anode)) DECL_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs); else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE) { TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs); /* If this is the main variant, also push the attributes out to the other variants. */ if (*anode == TYPE_MAIN_VARIANT (*anode)) { tree variant; for (variant = *anode; variant; variant = TYPE_NEXT_VARIANT (variant)) { if (TYPE_ATTRIBUTES (variant) == old_attrs) TYPE_ATTRIBUTES (variant) = TYPE_ATTRIBUTES (*anode); else if (!lookup_attribute (spec->name, TYPE_ATTRIBUTES (variant))) TYPE_ATTRIBUTES (variant) = tree_cons (name, args, TYPE_ATTRIBUTES (variant)); } } } else *anode = build_type_attribute_variant (*anode, tree_cons (name, args, old_attrs)); } } if (fn_ptr_tmp) { /* Rebuild the function pointer type and put it in the appropriate place. */ fn_ptr_tmp = build_pointer_type (fn_ptr_tmp); if (DECL_P (*node)) TREE_TYPE (*node) = fn_ptr_tmp; else { gcc_assert (TREE_CODE (*node) == POINTER_TYPE); *node = fn_ptr_tmp; } } } return returned_attrs; }
void rest_of_decl_compilation (tree decl, int top_level, int at_end) { /* We deferred calling assemble_alias so that we could collect other attributes such as visibility. Emit the alias now. */ { tree alias; alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl)); if (alias) { alias = TREE_VALUE (TREE_VALUE (alias)); alias = get_identifier (TREE_STRING_POINTER (alias)); assemble_alias (decl, alias); } } /* Can't defer this, because it needs to happen before any later function definitions are processed. */ if (DECL_ASSEMBLER_NAME_SET_P (decl) && DECL_REGISTER (decl)) make_decl_rtl (decl); /* Forward declarations for nested functions are not "external", but we need to treat them as if they were. */ if (TREE_STATIC (decl) || DECL_EXTERNAL (decl) || TREE_CODE (decl) == FUNCTION_DECL) { timevar_push (TV_VARCONST); /* Don't output anything when a tentative file-scope definition is seen. But at end of compilation, do output code for them. We do output all variables when unit-at-a-time is active and rely on callgraph code to defer them except for forward declarations (see gcc.c-torture/compile/920624-1.c) */ if ((at_end || !DECL_DEFER_OUTPUT (decl) || DECL_INITIAL (decl)) && !DECL_EXTERNAL (decl)) { if (TREE_CODE (decl) != FUNCTION_DECL) cgraph_varpool_finalize_decl (decl); else assemble_variable (decl, top_level, at_end, 0); } #ifdef ASM_FINISH_DECLARE_OBJECT if (decl == last_assemble_variable_decl) { ASM_FINISH_DECLARE_OBJECT (asm_out_file, decl, top_level, at_end); } #endif timevar_pop (TV_VARCONST); } else if (TREE_CODE (decl) == TYPE_DECL /* Like in rest_of_type_compilation, avoid confusing the debug information machinery when there are errors. */ && !(sorrycount || errorcount)) { timevar_push (TV_SYMOUT); debug_hooks->type_decl (decl, !top_level); timevar_pop (TV_SYMOUT); } /* Let cgraph know about the existence of variables. */ if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)) cgraph_varpool_node (decl); }
static void sdbout_one_type (tree type) { if (current_function_decl != NULL_TREE && DECL_SECTION_NAME (current_function_decl) != NULL_TREE) ; /* Don't change section amid function. */ else switch_to_section (text_section); switch (TREE_CODE (type)) { case RECORD_TYPE: case UNION_TYPE: case QUAL_UNION_TYPE: case ENUMERAL_TYPE: type = TYPE_MAIN_VARIANT (type); /* Don't output a type twice. */ if (TREE_ASM_WRITTEN (type)) /* James said test TREE_ASM_BEING_WRITTEN here. */ return; /* Output nothing if type is not yet defined. */ if (!COMPLETE_TYPE_P (type)) return; TREE_ASM_WRITTEN (type) = 1; /* This is reputed to cause trouble with the following case, but perhaps checking TYPE_SIZE above will fix it. */ /* Here is a testcase: struct foo { struct badstr *bbb; } forwardref; typedef struct intermediate { int aaaa; } intermediate_ref; typedef struct badstr { int ccccc; } badtype; */ /* This change, which ought to make better output, used to make the COFF assembler unhappy. Changes involving KNOWN_TYPE_TAG may fix the problem. */ /* Before really doing anything, output types we want to refer to. */ /* Note that in version 1 the following two lines are not used if forward references are in use. */ if (TREE_CODE (type) != ENUMERAL_TYPE) sdbout_field_types (type); /* Output a structure type. */ { int size = int_size_in_bytes (type); int member_scl = 0; tree tem; /* Record the type tag, but not in its permanent place just yet. */ sdbout_record_type_name (type); PUT_SDB_DEF (KNOWN_TYPE_TAG (type)); switch (TREE_CODE (type)) { case UNION_TYPE: case QUAL_UNION_TYPE: PUT_SDB_SCL (C_UNTAG); PUT_SDB_TYPE (T_UNION); member_scl = C_MOU; break; case RECORD_TYPE: PUT_SDB_SCL (C_STRTAG); PUT_SDB_TYPE (T_STRUCT); member_scl = C_MOS; break; case ENUMERAL_TYPE: PUT_SDB_SCL (C_ENTAG); PUT_SDB_TYPE (T_ENUM); member_scl = C_MOE; break; default: break; } PUT_SDB_SIZE (size); PUT_SDB_ENDEF; /* Print out the base class information with fields named after the types they hold. */ /* This is only relevant to aggregate types. TYPE_BINFO is used for other purposes in an ENUMERAL_TYPE, so we must exclude that case. */ if (TREE_CODE (type) != ENUMERAL_TYPE && TYPE_BINFO (type)) { int i; tree binfo, child; for (binfo = TYPE_BINFO (type), i = 0; BINFO_BASE_ITERATE (binfo, i, child); i++) { tree child_type = BINFO_TYPE (child); tree child_type_name; if (TYPE_NAME (child_type) == 0) continue; if (TREE_CODE (TYPE_NAME (child_type)) == IDENTIFIER_NODE) child_type_name = TYPE_NAME (child_type); else if (TREE_CODE (TYPE_NAME (child_type)) == TYPE_DECL) { child_type_name = DECL_NAME (TYPE_NAME (child_type)); if (child_type_name && template_name_p (child_type_name)) child_type_name = DECL_ASSEMBLER_NAME (TYPE_NAME (child_type)); } else continue; PUT_SDB_DEF (IDENTIFIER_POINTER (child_type_name)); PUT_SDB_INT_VAL (tree_low_cst (BINFO_OFFSET (child), 0)); PUT_SDB_SCL (member_scl); sdbout_type (BINFO_TYPE (child)); PUT_SDB_ENDEF; } } /* Output the individual fields. */ if (TREE_CODE (type) == ENUMERAL_TYPE) { for (tem = TYPE_VALUES (type); tem; tem = TREE_CHAIN (tem)) { tree value = TREE_VALUE (tem); if (TREE_CODE (value) == CONST_DECL) value = DECL_INITIAL (value); if (host_integerp (value, 0)) { PUT_SDB_DEF (IDENTIFIER_POINTER (TREE_PURPOSE (tem))); PUT_SDB_INT_VAL (tree_low_cst (value, 0)); PUT_SDB_SCL (C_MOE); PUT_SDB_TYPE (T_MOE); PUT_SDB_ENDEF; } } } else /* record or union type */ for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) /* Output the name, type, position (in bits), size (in bits) of each field. */ /* Omit here the nameless fields that are used to skip bits. Also omit fields with variable size or position. Also omit non FIELD_DECL nodes that GNU C++ may put here. */ if (TREE_CODE (tem) == FIELD_DECL && DECL_NAME (tem) && DECL_SIZE (tem) && host_integerp (DECL_SIZE (tem), 1) && host_integerp (bit_position (tem), 0)) { const char *name; name = IDENTIFIER_POINTER (DECL_NAME (tem)); PUT_SDB_DEF (name); if (DECL_BIT_FIELD_TYPE (tem)) { PUT_SDB_INT_VAL (int_bit_position (tem)); PUT_SDB_SCL (C_FIELD); sdbout_type (DECL_BIT_FIELD_TYPE (tem)); PUT_SDB_SIZE (tree_low_cst (DECL_SIZE (tem), 1)); } else { PUT_SDB_INT_VAL (int_bit_position (tem) / BITS_PER_UNIT); PUT_SDB_SCL (member_scl); sdbout_type (TREE_TYPE (tem)); } PUT_SDB_ENDEF; } /* Output end of a structure,union, or enumeral definition. */ PUT_SDB_PLAIN_DEF ("eos"); PUT_SDB_INT_VAL (size); PUT_SDB_SCL (C_EOS); PUT_SDB_TAG (KNOWN_TYPE_TAG (type)); PUT_SDB_SIZE (size); PUT_SDB_ENDEF; break; } default: break; } }
static inline tree pp_cxx_implicit_parameter_type (tree mf) { return TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (mf)))); }
{ *no_add_attrs = true; return NULL_TREE; } /* Handle a "fn spec" attribute; arguments as in struct attribute_spec.handler. */ static tree handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name), tree args, int ARG_UNUSED (flags), bool *no_add_attrs ATTRIBUTE_UNUSED) { gcc_assert (args && TREE_CODE (TREE_VALUE (args)) == STRING_CST && !TREE_CHAIN (args)); return NULL_TREE; } /* Cribbed from c-common.c. */ static void def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...) { tree t; tree *args = XALLOCAVEC (tree, n); va_list list; int i; va_start (list, n);
static void pp_cxx_postfix_expression (cxx_pretty_printer *pp, tree t) { enum tree_code code = TREE_CODE (t); switch (code) { case AGGR_INIT_EXPR: case CALL_EXPR: { tree fun = TREE_OPERAND (t, 0); tree args = TREE_OPERAND (t, 1); tree saved_scope = pp->enclosing_scope; if (TREE_CODE (fun) == ADDR_EXPR) fun = TREE_OPERAND (fun, 0); /* In templates, where there is no way to tell whether a given call uses an actual member function. So the parser builds FUN as a COMPONENT_REF or a plain IDENTIFIER_NODE until instantiation time. */ if (TREE_CODE (fun) != FUNCTION_DECL) ; else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)) { tree object = code == AGGR_INIT_EXPR && AGGR_INIT_VIA_CTOR_P (t) ? TREE_OPERAND (t, 2) : TREE_VALUE (args); while (TREE_CODE (object) == NOP_EXPR) object = TREE_OPERAND (object, 0); if (TREE_CODE (object) == ADDR_EXPR) object = TREE_OPERAND (object, 0); if (TREE_CODE (TREE_TYPE (object)) != POINTER_TYPE) { pp_cxx_postfix_expression (pp, object); pp_cxx_dot (pp); } else { pp_cxx_postfix_expression (pp, object); pp_cxx_arrow (pp); } args = TREE_CHAIN (args); pp->enclosing_scope = strip_pointer_operator (TREE_TYPE (object)); } pp_cxx_postfix_expression (pp, fun); pp->enclosing_scope = saved_scope; pp_cxx_call_argument_list (pp, args); } if (code == AGGR_INIT_EXPR && AGGR_INIT_VIA_CTOR_P (t)) { pp_cxx_separate_with (pp, ','); pp_cxx_postfix_expression (pp, TREE_OPERAND (t, 2)); } break; case BASELINK: case VAR_DECL: case PARM_DECL: case FIELD_DECL: case FUNCTION_DECL: case OVERLOAD: case CONST_DECL: case TEMPLATE_DECL: case RESULT_DECL: pp_cxx_primary_expression (pp, t); break; case DYNAMIC_CAST_EXPR: case STATIC_CAST_EXPR: case REINTERPRET_CAST_EXPR: case CONST_CAST_EXPR: if (code == DYNAMIC_CAST_EXPR) pp_cxx_identifier (pp, "dynamic_cast"); else if (code == STATIC_CAST_EXPR) pp_cxx_identifier (pp, "static_cast"); else if (code == REINTERPRET_CAST_EXPR) pp_cxx_identifier (pp, "reinterpret_cast"); else pp_cxx_identifier (pp, "const_cast"); pp_cxx_begin_template_argument_list (pp); pp_cxx_type_id (pp, TREE_TYPE (t)); pp_cxx_end_template_argument_list (pp); pp_left_paren (pp); pp_cxx_expression (pp, TREE_OPERAND (t, 0)); pp_right_paren (pp); break; case EMPTY_CLASS_EXPR: pp_cxx_type_id (pp, TREE_TYPE (t)); pp_left_paren (pp); pp_right_paren (pp); break; case TYPEID_EXPR: t = TREE_OPERAND (t, 0); pp_cxx_identifier (pp, "typeid"); pp_left_paren (pp); if (TYPE_P (t)) pp_cxx_type_id (pp, t); else pp_cxx_expression (pp, t); pp_right_paren (pp); break; case PSEUDO_DTOR_EXPR: pp_cxx_postfix_expression (pp, TREE_OPERAND (t, 0)); pp_cxx_dot (pp); pp_cxx_qualified_id (pp, TREE_OPERAND (t, 1)); pp_cxx_colon_colon (pp); pp_complement (pp); pp_cxx_unqualified_id (pp, TREE_OPERAND (t, 2)); break; case ARROW_EXPR: pp_cxx_postfix_expression (pp, TREE_OPERAND (t, 0)); pp_cxx_arrow (pp); break; default: pp_c_postfix_expression (pp_c_base (pp), t); break; } }
static void do_build_copy_constructor (tree fndecl) { tree parm = FUNCTION_FIRST_USER_PARM (fndecl); tree t; parm = convert_from_reference (parm); if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type) && is_empty_class (current_class_type)) /* Don't copy the padding byte; it might not have been allocated if *this is a base subobject. */; else if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)) { t = build (INIT_EXPR, void_type_node, current_class_ref, parm); finish_expr_stmt (t); } else { tree fields = TYPE_FIELDS (current_class_type); int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type); tree binfos = TYPE_BINFO_BASETYPES (current_class_type); tree member_init_list = NULL_TREE; int cvquals = cp_type_quals (TREE_TYPE (parm)); int i; /* Initialize all the base-classes with the parameter converted to their type so that we get their copy constructor and not another constructor that takes current_class_type. We must deal with the binfo's directly as a direct base might be inaccessible due to ambiguity. */ for (t = CLASSTYPE_VBASECLASSES (current_class_type); t; t = TREE_CHAIN (t)) { tree binfo = TREE_VALUE (t); member_init_list = tree_cons (binfo, build_tree_list (NULL_TREE, build_base_path (PLUS_EXPR, parm, binfo, 1)), member_init_list); } for (i = 0; i < n_bases; ++i) { tree binfo = TREE_VEC_ELT (binfos, i); if (TREE_VIA_VIRTUAL (binfo)) continue; member_init_list = tree_cons (binfo, build_tree_list (NULL_TREE, build_base_path (PLUS_EXPR, parm, binfo, 1)), member_init_list); } for (; fields; fields = TREE_CHAIN (fields)) { tree init = parm; tree field = fields; tree expr_type; if (TREE_CODE (field) != FIELD_DECL) continue; expr_type = TREE_TYPE (field); if (DECL_NAME (field)) { if (VFIELD_NAME_P (DECL_NAME (field))) continue; /* True for duplicate members. */ if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field) continue; } else if (ANON_AGGR_TYPE_P (expr_type) && TYPE_FIELDS (expr_type)) /* Just use the field; anonymous types can't have nontrivial copy ctors or assignment ops. */; else continue; /* Compute the type of "init->field". If the copy-constructor parameter is, for example, "const S&", and the type of the field is "T", then the type will usually be "const T". (There are no cv-qualified variants of reference types.) */ if (TREE_CODE (expr_type) != REFERENCE_TYPE) { int quals = cvquals; if (DECL_MUTABLE_P (field)) quals &= ~TYPE_QUAL_CONST; expr_type = cp_build_qualified_type (expr_type, quals); } init = build (COMPONENT_REF, expr_type, init, field); init = build_tree_list (NULL_TREE, init); member_init_list = tree_cons (field, init, member_init_list); } finish_mem_initializers (member_init_list); } }
static tree gfc_trans_omp_do (gfc_code *code, stmtblock_t *pblock, gfc_omp_clauses *do_clauses, tree par_clauses) { gfc_se se; tree dovar, stmt, from, to, step, type, init, cond, incr; tree count = NULL_TREE, cycle_label, tmp, omp_clauses; stmtblock_t block; stmtblock_t body; gfc_omp_clauses *clauses = code->ext.omp_clauses; int i, collapse = clauses->collapse; tree dovar_init = NULL_TREE; if (collapse <= 0) collapse = 1; code = code->block->next; gcc_assert (code->op == EXEC_DO); init = make_tree_vec (collapse); cond = make_tree_vec (collapse); incr = make_tree_vec (collapse); if (pblock == NULL) { gfc_start_block (&block); pblock = █ } omp_clauses = gfc_trans_omp_clauses (pblock, do_clauses, code->loc); for (i = 0; i < collapse; i++) { int simple = 0; int dovar_found = 0; tree dovar_decl; if (clauses) { gfc_namelist *n; for (n = clauses->lists[OMP_LIST_LASTPRIVATE]; n != NULL; n = n->next) if (code->ext.iterator->var->symtree->n.sym == n->sym) break; if (n != NULL) dovar_found = 1; else if (n == NULL) for (n = clauses->lists[OMP_LIST_PRIVATE]; n != NULL; n = n->next) if (code->ext.iterator->var->symtree->n.sym == n->sym) break; if (n != NULL) dovar_found++; } /* Evaluate all the expressions in the iterator. */ gfc_init_se (&se, NULL); gfc_conv_expr_lhs (&se, code->ext.iterator->var); gfc_add_block_to_block (pblock, &se.pre); dovar = se.expr; type = TREE_TYPE (dovar); gcc_assert (TREE_CODE (type) == INTEGER_TYPE); gfc_init_se (&se, NULL); gfc_conv_expr_val (&se, code->ext.iterator->start); gfc_add_block_to_block (pblock, &se.pre); from = gfc_evaluate_now (se.expr, pblock); gfc_init_se (&se, NULL); gfc_conv_expr_val (&se, code->ext.iterator->end); gfc_add_block_to_block (pblock, &se.pre); to = gfc_evaluate_now (se.expr, pblock); gfc_init_se (&se, NULL); gfc_conv_expr_val (&se, code->ext.iterator->step); gfc_add_block_to_block (pblock, &se.pre); step = gfc_evaluate_now (se.expr, pblock); dovar_decl = dovar; /* Special case simple loops. */ if (TREE_CODE (dovar) == VAR_DECL) { if (integer_onep (step)) simple = 1; else if (tree_int_cst_equal (step, integer_minus_one_node)) simple = -1; } else dovar_decl = gfc_trans_omp_variable (code->ext.iterator->var->symtree->n.sym); /* Loop body. */ if (simple) { TREE_VEC_ELT (init, i) = build2_v (MODIFY_EXPR, dovar, from); TREE_VEC_ELT (cond, i) = fold_build2 (simple > 0 ? LE_EXPR : GE_EXPR, boolean_type_node, dovar, to); TREE_VEC_ELT (incr, i) = fold_build2 (PLUS_EXPR, type, dovar, step); TREE_VEC_ELT (incr, i) = fold_build2 (MODIFY_EXPR, type, dovar, TREE_VEC_ELT (incr, i)); } else { /* STEP is not 1 or -1. Use: for (count = 0; count < (to + step - from) / step; count++) { dovar = from + count * step; body; cycle_label:; } */ tmp = fold_build2 (MINUS_EXPR, type, step, from); tmp = fold_build2 (PLUS_EXPR, type, to, tmp); tmp = fold_build2 (TRUNC_DIV_EXPR, type, tmp, step); tmp = gfc_evaluate_now (tmp, pblock); count = gfc_create_var (type, "count"); TREE_VEC_ELT (init, i) = build2_v (MODIFY_EXPR, count, build_int_cst (type, 0)); TREE_VEC_ELT (cond, i) = fold_build2 (LT_EXPR, boolean_type_node, count, tmp); TREE_VEC_ELT (incr, i) = fold_build2 (PLUS_EXPR, type, count, build_int_cst (type, 1)); TREE_VEC_ELT (incr, i) = fold_build2 (MODIFY_EXPR, type, count, TREE_VEC_ELT (incr, i)); /* Initialize DOVAR. */ tmp = fold_build2 (MULT_EXPR, type, count, step); tmp = fold_build2 (PLUS_EXPR, type, from, tmp); dovar_init = tree_cons (dovar, tmp, dovar_init); } if (!dovar_found) { tmp = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE); OMP_CLAUSE_DECL (tmp) = dovar_decl; omp_clauses = gfc_trans_add_clause (tmp, omp_clauses); } else if (dovar_found == 2) { tree c = NULL; tmp = NULL; if (!simple) { /* If dovar is lastprivate, but different counter is used, dovar += step needs to be added to OMP_CLAUSE_LASTPRIVATE_STMT, otherwise the copied dovar will have the value on entry of the last loop, rather than value after iterator increment. */ tmp = gfc_evaluate_now (step, pblock); tmp = fold_build2 (PLUS_EXPR, type, dovar, tmp); tmp = fold_build2 (MODIFY_EXPR, type, dovar, tmp); for (c = omp_clauses; c ; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE && OMP_CLAUSE_DECL (c) == dovar_decl) { OMP_CLAUSE_LASTPRIVATE_STMT (c) = tmp; break; } } if (c == NULL && par_clauses != NULL) { for (c = par_clauses; c ; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE && OMP_CLAUSE_DECL (c) == dovar_decl) { tree l = build_omp_clause (input_location, OMP_CLAUSE_LASTPRIVATE); OMP_CLAUSE_DECL (l) = dovar_decl; OMP_CLAUSE_CHAIN (l) = omp_clauses; OMP_CLAUSE_LASTPRIVATE_STMT (l) = tmp; omp_clauses = l; OMP_CLAUSE_SET_CODE (c, OMP_CLAUSE_SHARED); break; } } gcc_assert (simple || c != NULL); } if (!simple) { tmp = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE); OMP_CLAUSE_DECL (tmp) = count; omp_clauses = gfc_trans_add_clause (tmp, omp_clauses); } if (i + 1 < collapse) code = code->block->next; } if (pblock != &block) { pushlevel (0); gfc_start_block (&block); } gfc_start_block (&body); dovar_init = nreverse (dovar_init); while (dovar_init) { gfc_add_modify (&body, TREE_PURPOSE (dovar_init), TREE_VALUE (dovar_init)); dovar_init = TREE_CHAIN (dovar_init); } /* Cycle statement is implemented with a goto. Exit statement must not be present for this loop. */ cycle_label = gfc_build_label_decl (NULL_TREE); /* Put these labels where they can be found later. We put the labels in a TREE_LIST node (because TREE_CHAIN is already used). cycle_label goes in TREE_PURPOSE (backend_decl), exit label in TREE_VALUE (backend_decl). */ code->block->backend_decl = tree_cons (cycle_label, NULL, NULL); /* Main loop body. */ tmp = gfc_trans_omp_code (code->block->next, true); gfc_add_expr_to_block (&body, tmp); /* Label for cycle statements (if needed). */ if (TREE_USED (cycle_label)) { tmp = build1_v (LABEL_EXPR, cycle_label); gfc_add_expr_to_block (&body, tmp); } /* End of loop body. */ stmt = make_node (OMP_FOR); TREE_TYPE (stmt) = void_type_node; OMP_FOR_BODY (stmt) = gfc_finish_block (&body); OMP_FOR_CLAUSES (stmt) = omp_clauses; OMP_FOR_INIT (stmt) = init; OMP_FOR_COND (stmt) = cond; OMP_FOR_INCR (stmt) = incr; gfc_add_expr_to_block (&block, stmt); return gfc_finish_block (&block); }
static gimple input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in, struct function *fn, enum LTO_tags tag) { gimple stmt; enum gimple_code code; unsigned HOST_WIDE_INT num_ops; size_t i; struct bitpack_d bp; code = lto_tag_to_gimple_code (tag); /* Read the tuple header. */ bp = streamer_read_bitpack (ib); num_ops = bp_unpack_var_len_unsigned (&bp); stmt = gimple_alloc (code, num_ops); stmt->gsbase.no_warning = bp_unpack_value (&bp, 1); if (is_gimple_assign (stmt)) stmt->gsbase.nontemporal_move = bp_unpack_value (&bp, 1); stmt->gsbase.has_volatile_ops = bp_unpack_value (&bp, 1); stmt->gsbase.subcode = bp_unpack_var_len_unsigned (&bp); /* Read location information. */ gimple_set_location (stmt, lto_input_location (ib, data_in)); /* Read lexical block reference. */ gimple_set_block (stmt, stream_read_tree (ib, data_in)); /* Read in all the operands. */ switch (code) { case GIMPLE_RESX: gimple_resx_set_region (stmt, streamer_read_hwi (ib)); break; case GIMPLE_EH_MUST_NOT_THROW: gimple_eh_must_not_throw_set_fndecl (stmt, stream_read_tree (ib, data_in)); break; case GIMPLE_EH_DISPATCH: gimple_eh_dispatch_set_region (stmt, streamer_read_hwi (ib)); break; case GIMPLE_ASM: { /* FIXME lto. Move most of this into a new gimple_asm_set_string(). */ tree str; stmt->gimple_asm.ni = streamer_read_uhwi (ib); stmt->gimple_asm.no = streamer_read_uhwi (ib); stmt->gimple_asm.nc = streamer_read_uhwi (ib); stmt->gimple_asm.nl = streamer_read_uhwi (ib); str = streamer_read_string_cst (data_in, ib); stmt->gimple_asm.string = TREE_STRING_POINTER (str); } /* Fallthru */ case GIMPLE_ASSIGN: case GIMPLE_CALL: case GIMPLE_RETURN: case GIMPLE_SWITCH: case GIMPLE_LABEL: case GIMPLE_COND: case GIMPLE_GOTO: case GIMPLE_DEBUG: for (i = 0; i < num_ops; i++) { tree op = stream_read_tree (ib, data_in); gimple_set_op (stmt, i, op); if (!op) continue; /* Fixup FIELD_DECLs in COMPONENT_REFs, they are not handled by decl merging. */ if (TREE_CODE (op) == ADDR_EXPR) op = TREE_OPERAND (op, 0); while (handled_component_p (op)) { if (TREE_CODE (op) == COMPONENT_REF) { tree field, type, tem; tree closest_match = NULL_TREE; field = TREE_OPERAND (op, 1); type = DECL_CONTEXT (field); for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) { if (TREE_CODE (tem) != FIELD_DECL) continue; if (tem == field) break; if (DECL_NONADDRESSABLE_P (tem) == DECL_NONADDRESSABLE_P (field) && gimple_compare_field_offset (tem, field)) { if (types_compatible_p (TREE_TYPE (tem), TREE_TYPE (field))) break; else closest_match = tem; } } /* In case of type mismatches across units we can fail to unify some types and thus not find a proper field-decl here. */ if (tem == NULL_TREE) { /* Thus, emit a ODR violation warning. */ if (warning_at (gimple_location (stmt), 0, "use of type %<%E%> with two mismatching " "declarations at field %<%E%>", type, TREE_OPERAND (op, 1))) { if (TYPE_FIELDS (type)) inform (DECL_SOURCE_LOCATION (TYPE_FIELDS (type)), "original type declared here"); inform (DECL_SOURCE_LOCATION (TREE_OPERAND (op, 1)), "field in mismatching type declared here"); if (TYPE_NAME (TREE_TYPE (field)) && (TREE_CODE (TYPE_NAME (TREE_TYPE (field))) == TYPE_DECL)) inform (DECL_SOURCE_LOCATION (TYPE_NAME (TREE_TYPE (field))), "type of field declared here"); if (closest_match && TYPE_NAME (TREE_TYPE (closest_match)) && (TREE_CODE (TYPE_NAME (TREE_TYPE (closest_match))) == TYPE_DECL)) inform (DECL_SOURCE_LOCATION (TYPE_NAME (TREE_TYPE (closest_match))), "type of mismatching field declared here"); } /* And finally fixup the types. */ TREE_OPERAND (op, 0) = build1 (VIEW_CONVERT_EXPR, type, TREE_OPERAND (op, 0)); } else TREE_OPERAND (op, 1) = tem; } op = TREE_OPERAND (op, 0); } } if (is_gimple_call (stmt)) { if (gimple_call_internal_p (stmt)) gimple_call_set_internal_fn (stmt, streamer_read_enum (ib, internal_fn, IFN_LAST)); else gimple_call_set_fntype (stmt, stream_read_tree (ib, data_in)); } break; case GIMPLE_NOP: case GIMPLE_PREDICT: break; case GIMPLE_TRANSACTION: gimple_transaction_set_label (stmt, stream_read_tree (ib, data_in)); break; default: internal_error ("bytecode stream: unknown GIMPLE statement tag %s", lto_tag_name (tag)); } /* Update the properties of symbols, SSA names and labels associated with STMT. */ if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL) { tree lhs = gimple_get_lhs (stmt); if (lhs && TREE_CODE (lhs) == SSA_NAME) SSA_NAME_DEF_STMT (lhs) = stmt; } else if (code == GIMPLE_LABEL) gcc_assert (emit_label_in_global_context_p (gimple_label_label (stmt)) || DECL_CONTEXT (gimple_label_label (stmt)) == fn->decl); else if (code == GIMPLE_ASM) { unsigned i; for (i = 0; i < gimple_asm_noutputs (stmt); i++) { tree op = TREE_VALUE (gimple_asm_output_op (stmt, i)); if (TREE_CODE (op) == SSA_NAME) SSA_NAME_DEF_STMT (op) = stmt; } } /* Reset alias information. */ if (code == GIMPLE_CALL) gimple_call_reset_alias_info (stmt); /* Mark the statement modified so its operand vectors can be filled in. */ gimple_set_modified (stmt, true); return stmt; }
void make_friend_class (tree type, tree friend_type, bool complain) { tree classes; /* CLASS_TEMPLATE_DEPTH counts the number of template headers for the enclosing class. FRIEND_DEPTH counts the number of template headers used for this friend declaration. TEMPLATE_MEMBER_P, defined inside the `if' block for TYPENAME_TYPE case, is true if a template header in FRIEND_DEPTH is intended for DECLARATOR. For example, the code template <class T> struct A { template <class U> struct B { template <class V> template <class W> friend class C<V>::D; }; }; will eventually give the following results 1. CLASS_TEMPLATE_DEPTH equals 2 (for `T' and `U'). 2. FRIEND_DEPTH equals 2 (for `V' and `W'). 3. TEMPLATE_MEMBER_P is true (for `W'). The friend is a template friend iff FRIEND_DEPTH is nonzero. */ int class_template_depth = template_class_depth (type); int friend_depth = processing_template_decl - class_template_depth; if (! MAYBE_CLASS_TYPE_P (friend_type) && TREE_CODE (friend_type) != TEMPLATE_TEMPLATE_PARM) { /* N1791: If the type specifier in a friend declaration designates a (possibly cv-qualified) class type, that class is declared as a friend; otherwise, the friend declaration is ignored. So don't complain in C++11 mode. */ if (cxx_dialect < cxx11) pedwarn (input_location, complain ? 0 : OPT_Wpedantic, "invalid type %qT declared %<friend%>", friend_type); return; } friend_type = cv_unqualified (friend_type); if (check_for_bare_parameter_packs (friend_type)) return; if (friend_depth) /* If the TYPE is a template then it makes sense for it to be friends with itself; this means that each instantiation is friends with all other instantiations. */ { if (CLASS_TYPE_P (friend_type) && CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type) && uses_template_parms (friend_type)) { /* [temp.friend] Friend declarations shall not declare partial specializations. */ error ("partial specialization %qT declared %<friend%>", friend_type); return; } } else if (same_type_p (type, friend_type)) { if (complain) warning (0, "class %qT is implicitly friends with itself", type); return; } /* [temp.friend] A friend of a class or class template can be a function or class template, a specialization of a function template or class template, or an ordinary (nontemplate) function or class. */ if (!friend_depth) ;/* ok */ else if (TREE_CODE (friend_type) == TYPENAME_TYPE) { if (TREE_CODE (TYPENAME_TYPE_FULLNAME (friend_type)) == TEMPLATE_ID_EXPR) { /* template <class U> friend class T::X<U>; */ /* [temp.friend] Friend declarations shall not declare partial specializations. */ error ("partial specialization %qT declared %<friend%>", friend_type); return; } else { /* We will figure this out later. */ bool template_member_p = false; tree ctype = TYPE_CONTEXT (friend_type); tree name = TYPE_IDENTIFIER (friend_type); tree decl; if (!uses_template_parms_level (ctype, class_template_depth + friend_depth)) template_member_p = true; if (class_template_depth) { /* We rely on tsubst_friend_class to check the validity of the declaration later. */ if (template_member_p) friend_type = make_unbound_class_template (ctype, name, current_template_parms, tf_error); else friend_type = make_typename_type (ctype, name, class_type, tf_error); } else { decl = lookup_member (ctype, name, 0, true, tf_warning_or_error); if (!decl) { error ("%qT is not a member of %qT", name, ctype); return; } if (template_member_p && !DECL_CLASS_TEMPLATE_P (decl)) { error ("%qT is not a member class template of %qT", name, ctype); inform (input_location, "%q+D declared here", decl); return; } if (!template_member_p && (TREE_CODE (decl) != TYPE_DECL || !CLASS_TYPE_P (TREE_TYPE (decl)))) { error ("%qT is not a nested class of %qT", name, ctype); inform (input_location, "%q+D declared here", decl); return; } friend_type = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl)); } } } else if (TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM) { /* template <class T> friend class T; */ error ("template parameter type %qT declared %<friend%>", friend_type); return; } else if (TREE_CODE (friend_type) == TEMPLATE_TEMPLATE_PARM) friend_type = TYPE_NAME (friend_type); else if (!CLASSTYPE_TEMPLATE_INFO (friend_type)) { /* template <class T> friend class A; where A is not a template */ error ("%q#T is not a template", friend_type); return; } else /* template <class T> friend class A; where A is a template */ friend_type = CLASSTYPE_TI_TEMPLATE (friend_type); if (friend_type == error_mark_node) return; /* See if it is already a friend. */ for (classes = CLASSTYPE_FRIEND_CLASSES (type); classes; classes = TREE_CHAIN (classes)) { tree probe = TREE_VALUE (classes); if (TREE_CODE (friend_type) == TEMPLATE_DECL) { if (friend_type == probe) { if (complain) warning (OPT_Wredundant_decls, "%qD is already a friend of %qT", probe, type); break; } } else if (TREE_CODE (probe) != TEMPLATE_DECL) { if (same_type_p (probe, friend_type)) { if (complain) warning (OPT_Wredundant_decls, "%qT is already a friend of %qT", probe, type); break; } } } if (!classes) { maybe_add_class_template_decl_list (type, friend_type, /*friend_p=*/1); CLASSTYPE_FRIEND_CLASSES (type) = tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type)); if (TREE_CODE (friend_type) == TEMPLATE_DECL) friend_type = TREE_TYPE (friend_type); if (!uses_template_parms (type)) CLASSTYPE_BEFRIENDING_CLASSES (friend_type) = tree_cons (NULL_TREE, type, CLASSTYPE_BEFRIENDING_CLASSES (friend_type)); } }
static gimple * input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in, enum LTO_tags tag) { gimple *stmt; enum gimple_code code; unsigned HOST_WIDE_INT num_ops; size_t i; struct bitpack_d bp; bool has_hist; code = lto_tag_to_gimple_code (tag); /* Read the tuple header. */ bp = streamer_read_bitpack (ib); num_ops = bp_unpack_var_len_unsigned (&bp); stmt = gimple_alloc (code, num_ops); stmt->no_warning = bp_unpack_value (&bp, 1); if (is_gimple_assign (stmt)) stmt->nontemporal_move = bp_unpack_value (&bp, 1); stmt->has_volatile_ops = bp_unpack_value (&bp, 1); has_hist = bp_unpack_value (&bp, 1); stmt->subcode = bp_unpack_var_len_unsigned (&bp); /* Read location information. Caching here makes no sense until streamer cache can handle the following gimple_set_block. */ gimple_set_location (stmt, stream_input_location_now (&bp, data_in)); /* Read lexical block reference. */ gimple_set_block (stmt, stream_read_tree (ib, data_in)); /* Read in all the operands. */ switch (code) { case GIMPLE_RESX: gimple_resx_set_region (as_a <gresx *> (stmt), streamer_read_hwi (ib)); break; case GIMPLE_EH_MUST_NOT_THROW: gimple_eh_must_not_throw_set_fndecl ( as_a <geh_mnt *> (stmt), stream_read_tree (ib, data_in)); break; case GIMPLE_EH_DISPATCH: gimple_eh_dispatch_set_region (as_a <geh_dispatch *> (stmt), streamer_read_hwi (ib)); break; case GIMPLE_ASM: { /* FIXME lto. Move most of this into a new gimple_asm_set_string(). */ gasm *asm_stmt = as_a <gasm *> (stmt); tree str; asm_stmt->ni = streamer_read_uhwi (ib); asm_stmt->no = streamer_read_uhwi (ib); asm_stmt->nc = streamer_read_uhwi (ib); asm_stmt->nl = streamer_read_uhwi (ib); str = streamer_read_string_cst (data_in, ib); asm_stmt->string = TREE_STRING_POINTER (str); } /* Fallthru */ case GIMPLE_ASSIGN: case GIMPLE_CALL: case GIMPLE_RETURN: case GIMPLE_SWITCH: case GIMPLE_LABEL: case GIMPLE_COND: case GIMPLE_GOTO: case GIMPLE_DEBUG: for (i = 0; i < num_ops; i++) { tree *opp, op = stream_read_tree (ib, data_in); gimple_set_op (stmt, i, op); if (!op) continue; opp = gimple_op_ptr (stmt, i); if (TREE_CODE (*opp) == ADDR_EXPR) opp = &TREE_OPERAND (*opp, 0); while (handled_component_p (*opp)) opp = &TREE_OPERAND (*opp, 0); /* At LTO output time we wrap all global decls in MEM_REFs to allow seamless replacement with prevailing decls. Undo this here if the prevailing decl allows for this. ??? Maybe we should simply fold all stmts. */ if (TREE_CODE (*opp) == MEM_REF && TREE_CODE (TREE_OPERAND (*opp, 0)) == ADDR_EXPR && integer_zerop (TREE_OPERAND (*opp, 1)) && (TREE_THIS_VOLATILE (*opp) == TREE_THIS_VOLATILE (TREE_OPERAND (TREE_OPERAND (*opp, 0), 0))) && !TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (*opp, 1))) && (TREE_TYPE (*opp) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (*opp, 1)))) && (TREE_TYPE (*opp) == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*opp, 0), 0)))) *opp = TREE_OPERAND (TREE_OPERAND (*opp, 0), 0); } if (gcall *call_stmt = dyn_cast <gcall *> (stmt)) { if (gimple_call_internal_p (call_stmt)) gimple_call_set_internal_fn (call_stmt, streamer_read_enum (ib, internal_fn, IFN_LAST)); else gimple_call_set_fntype (call_stmt, stream_read_tree (ib, data_in)); } break; case GIMPLE_NOP: case GIMPLE_PREDICT: break; case GIMPLE_TRANSACTION: gimple_transaction_set_label (as_a <gtransaction *> (stmt), stream_read_tree (ib, data_in)); break; default: internal_error ("bytecode stream: unknown GIMPLE statement tag %s", lto_tag_name (tag)); } /* Update the properties of symbols, SSA names and labels associated with STMT. */ if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL) { tree lhs = gimple_get_lhs (stmt); if (lhs && TREE_CODE (lhs) == SSA_NAME) SSA_NAME_DEF_STMT (lhs) = stmt; } else if (code == GIMPLE_ASM) { gasm *asm_stmt = as_a <gasm *> (stmt); unsigned i; for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++) { tree op = TREE_VALUE (gimple_asm_output_op (asm_stmt, i)); if (TREE_CODE (op) == SSA_NAME) SSA_NAME_DEF_STMT (op) = stmt; } } /* Reset alias information. */ if (code == GIMPLE_CALL) gimple_call_reset_alias_info (as_a <gcall *> (stmt)); /* Mark the statement modified so its operand vectors can be filled in. */ gimple_set_modified (stmt, true); if (has_hist) stream_in_histogram_value (ib, stmt); return stmt; }
int is_friend (tree type, tree supplicant) { int declp; tree list; tree context; if (supplicant == NULL_TREE || type == NULL_TREE) return 0; declp = DECL_P (supplicant); if (declp) /* It's a function decl. */ { tree list = DECL_FRIENDLIST (TYPE_MAIN_DECL (type)); tree name = DECL_NAME (supplicant); for (; list ; list = TREE_CHAIN (list)) { if (name == FRIEND_NAME (list)) { tree friends = FRIEND_DECLS (list); for (; friends ; friends = TREE_CHAIN (friends)) { tree this_friend = TREE_VALUE (friends); if (this_friend == NULL_TREE) continue; if (supplicant == this_friend) return 1; if (is_specialization_of_friend (supplicant, this_friend)) return 1; } break; } } } else /* It's a type. */ { if (same_type_p (supplicant, type)) return 1; list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_MAIN_DECL (type))); for (; list ; list = TREE_CHAIN (list)) { tree t = TREE_VALUE (list); if (TREE_CODE (t) == TEMPLATE_DECL ? is_specialization_of_friend (TYPE_MAIN_DECL (supplicant), t) : same_type_p (supplicant, t)) return 1; } } if (declp) { if (DECL_FUNCTION_MEMBER_P (supplicant)) context = DECL_CONTEXT (supplicant); else context = NULL_TREE; } else { if (TYPE_CLASS_SCOPE_P (supplicant)) /* Nested classes get the same access as their enclosing types, as per DR 45 (this is a change from the standard). */ context = TYPE_CONTEXT (supplicant); else /* Local classes have the same access as the enclosing function. */ context = decl_function_context (TYPE_MAIN_DECL (supplicant)); } /* A namespace is not friend to anybody. */ if (context && TREE_CODE (context) == NAMESPACE_DECL) context = NULL_TREE; if (context) return is_friend (type, context); return 0; }
static int warn_type_compatibility_p (tree prevailing_type, tree type, bool common_or_extern) { int lev = 0; bool odr_p = odr_or_derived_type_p (prevailing_type) && odr_or_derived_type_p (type); if (prevailing_type == type) return 0; /* C++ provide a robust way to check for type compatibility via the ODR rule. */ if (odr_p && !odr_types_equivalent_p (prevailing_type, type)) lev |= 2; /* Function types needs special care, because types_compatible_p never thinks prototype is compatible to non-prototype. */ if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) { if (TREE_CODE (type) != TREE_CODE (prevailing_type)) lev |= 1; lev |= warn_type_compatibility_p (TREE_TYPE (prevailing_type), TREE_TYPE (type), false); if (TREE_CODE (type) == METHOD_TYPE && TREE_CODE (prevailing_type) == METHOD_TYPE) lev |= warn_type_compatibility_p (TYPE_METHOD_BASETYPE (prevailing_type), TYPE_METHOD_BASETYPE (type), false); if (prototype_p (prevailing_type) && prototype_p (type) && TYPE_ARG_TYPES (prevailing_type) != TYPE_ARG_TYPES (type)) { tree parm1, parm2; for (parm1 = TYPE_ARG_TYPES (prevailing_type), parm2 = TYPE_ARG_TYPES (type); parm1 && parm2; parm1 = TREE_CHAIN (parm1), parm2 = TREE_CHAIN (parm2)) lev |= warn_type_compatibility_p (TREE_VALUE (parm1), TREE_VALUE (parm2), false); if (parm1 || parm2) lev |= odr_p ? 3 : 1; } if (comp_type_attributes (prevailing_type, type) == 0) lev |= 1; return lev; } /* Get complete type. */ prevailing_type = TYPE_MAIN_VARIANT (prevailing_type); type = TYPE_MAIN_VARIANT (type); /* We can not use types_compatible_p because we permit some changes across types. For example unsigned size_t and "signed size_t" may be compatible when merging C and Fortran types. */ if (COMPLETE_TYPE_P (prevailing_type) && COMPLETE_TYPE_P (type) /* While global declarations are never variadic, we can recurse here for function parameter types. */ && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST && TREE_CODE (TYPE_SIZE (prevailing_type)) == INTEGER_CST && !tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (prevailing_type))) { /* As a special case do not warn about merging int a[]; and int a[]={1,2,3}; here the first declaration is COMMON or EXTERN and sizeof(a) == sizeof (int). */ if (!common_or_extern || TREE_CODE (type) != ARRAY_TYPE || TYPE_SIZE (type) != TYPE_SIZE (TREE_TYPE (type))) lev |= 1; } /* Verify TBAA compatibility. Take care of alias set 0 and the fact that we make ptr_type_node to TBAA compatible with every other type. */ if (type_with_alias_set_p (type) && type_with_alias_set_p (prevailing_type)) { alias_set_type set1 = get_alias_set (type); alias_set_type set2 = get_alias_set (prevailing_type); if (set1 && set2 && set1 != set2 && (!POINTER_TYPE_P (type) || !POINTER_TYPE_P (prevailing_type) || (set1 != TYPE_ALIAS_SET (ptr_type_node) && set2 != TYPE_ALIAS_SET (ptr_type_node)))) lev |= 5; } return lev; }
tree decl_attributes (tree *node, tree attributes, int flags) { tree a; tree returned_attrs = NULL_TREE; if (TREE_TYPE (*node) == error_mark_node || attributes == error_mark_node) return NULL_TREE; if (!attributes_initialized) init_attributes (); /* If this is a function and the user used #pragma GCC optimize, add the options to the attribute((optimize(...))) list. */ if (TREE_CODE (*node) == FUNCTION_DECL && current_optimize_pragma) { tree cur_attr = lookup_attribute ("optimize", attributes); tree opts = copy_list (current_optimize_pragma); if (! cur_attr) attributes = tree_cons (get_identifier ("optimize"), opts, attributes); else TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr)); } if (TREE_CODE (*node) == FUNCTION_DECL && optimization_current_node != optimization_default_node && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)) DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node) = optimization_current_node; /* If this is a function and the user used #pragma GCC target, add the options to the attribute((target(...))) list. */ if (TREE_CODE (*node) == FUNCTION_DECL && current_target_pragma && targetm.target_option.valid_attribute_p (*node, NULL_TREE, current_target_pragma, 0)) { tree cur_attr = lookup_attribute ("target", attributes); tree opts = copy_list (current_target_pragma); if (! cur_attr) attributes = tree_cons (get_identifier ("target"), opts, attributes); else TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr)); } /* A "naked" function attribute implies "noinline" and "noclone" for those targets that support it. */ if (TREE_CODE (*node) == FUNCTION_DECL && attributes && lookup_attribute_spec (get_identifier ("naked")) && lookup_attribute ("naked", attributes) != NULL) { if (lookup_attribute ("noinline", attributes) == NULL) attributes = tree_cons (get_identifier ("noinline"), NULL, attributes); if (lookup_attribute ("noclone", attributes) == NULL) attributes = tree_cons (get_identifier ("noclone"), NULL, attributes); } targetm.insert_attributes (*node, &attributes); for (a = attributes; a; a = TREE_CHAIN (a)) { tree ns = get_attribute_namespace (a); tree name = get_attribute_name (a); tree args = TREE_VALUE (a); tree *anode = node; const struct attribute_spec *spec = lookup_scoped_attribute_spec (ns, name); bool no_add_attrs = 0; int fn_ptr_quals = 0; tree fn_ptr_tmp = NULL_TREE; if (spec == NULL) { if (!(flags & (int) ATTR_FLAG_BUILT_IN)) { if (ns == NULL_TREE || !cxx11_attribute_p (a)) warning (OPT_Wattributes, "%qE attribute directive ignored", name); else warning (OPT_Wattributes, "%<%E::%E%> scoped attribute directive ignored", ns, name); } continue; } else if (list_length (args) < spec->min_length || (spec->max_length >= 0 && list_length (args) > spec->max_length)) { error ("wrong number of arguments specified for %qE attribute", name); continue; } gcc_assert (is_attribute_p (spec->name, name)); if (TYPE_P (*node) && cxx11_attribute_p (a) && !(flags & ATTR_FLAG_TYPE_IN_PLACE)) { /* This is a c++11 attribute that appertains to a type-specifier, outside of the definition of, a class type. Ignore it. */ if (warning (OPT_Wattributes, "attribute ignored")) inform (input_location, "an attribute that appertains to a type-specifier " "is ignored"); continue; } if (spec->decl_required && !DECL_P (*anode)) { if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT | (int) ATTR_FLAG_ARRAY_NEXT)) { /* Pass on this attribute to be tried again. */ returned_attrs = tree_cons (name, args, returned_attrs); continue; } else { warning (OPT_Wattributes, "%qE attribute does not apply to types", name); continue; } } /* If we require a type, but were passed a decl, set up to make a new type and update the one in the decl. ATTR_FLAG_TYPE_IN_PLACE would have applied if we'd been passed a type, but we cannot modify the decl's type in place here. */ if (spec->type_required && DECL_P (*anode)) { anode = &TREE_TYPE (*anode); flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE; } if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE && TREE_CODE (*anode) != METHOD_TYPE) { if (TREE_CODE (*anode) == POINTER_TYPE && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE)) { /* OK, this is a bit convoluted. We can't just make a copy of the pointer type and modify its TREE_TYPE, because if we change the attributes of the target type the pointer type needs to have a different TYPE_MAIN_VARIANT. So we pull out the target type now, frob it as appropriate, and rebuild the pointer type later. This would all be simpler if attributes were part of the declarator, grumble grumble. */ fn_ptr_tmp = TREE_TYPE (*anode); fn_ptr_quals = TYPE_QUALS (*anode); anode = &fn_ptr_tmp; flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE; } else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT) { /* Pass on this attribute to be tried again. */ returned_attrs = tree_cons (name, args, returned_attrs); continue; } if (TREE_CODE (*anode) != FUNCTION_TYPE && TREE_CODE (*anode) != METHOD_TYPE) { warning (OPT_Wattributes, "%qE attribute only applies to function types", name); continue; } } if (TYPE_P (*anode) && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE) && TYPE_SIZE (*anode) != NULL_TREE) { warning (OPT_Wattributes, "type attributes ignored after type is already defined"); continue; } if (spec->handler != NULL) { int cxx11_flag = cxx11_attribute_p (a) ? ATTR_FLAG_CXX11 : 0; returned_attrs = chainon ((*spec->handler) (anode, name, args, flags|cxx11_flag, &no_add_attrs), returned_attrs); } /* Layout the decl in case anything changed. */ if (spec->type_required && DECL_P (*node) && (TREE_CODE (*node) == VAR_DECL || TREE_CODE (*node) == PARM_DECL || TREE_CODE (*node) == RESULT_DECL)) relayout_decl (*node); if (!no_add_attrs) { tree old_attrs; tree a; if (DECL_P (*anode)) old_attrs = DECL_ATTRIBUTES (*anode); else old_attrs = TYPE_ATTRIBUTES (*anode); for (a = lookup_attribute (spec->name, old_attrs); a != NULL_TREE; a = lookup_attribute (spec->name, TREE_CHAIN (a))) { if (simple_cst_equal (TREE_VALUE (a), args) == 1) break; } if (a == NULL_TREE) { /* This attribute isn't already in the list. */ if (DECL_P (*anode)) DECL_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs); else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE) { TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs); /* If this is the main variant, also push the attributes out to the other variants. */ if (*anode == TYPE_MAIN_VARIANT (*anode)) { tree variant; for (variant = *anode; variant; variant = TYPE_NEXT_VARIANT (variant)) { if (TYPE_ATTRIBUTES (variant) == old_attrs) TYPE_ATTRIBUTES (variant) = TYPE_ATTRIBUTES (*anode); else if (!lookup_attribute (spec->name, TYPE_ATTRIBUTES (variant))) TYPE_ATTRIBUTES (variant) = tree_cons (name, args, TYPE_ATTRIBUTES (variant)); } } } else *anode = build_type_attribute_variant (*anode, tree_cons (name, args, old_attrs)); } } if (fn_ptr_tmp) { /* Rebuild the function pointer type and put it in the appropriate place. */ fn_ptr_tmp = build_pointer_type (fn_ptr_tmp); if (fn_ptr_quals) fn_ptr_tmp = build_qualified_type (fn_ptr_tmp, fn_ptr_quals); if (DECL_P (*node)) TREE_TYPE (*node) = fn_ptr_tmp; else { gcc_assert (TREE_CODE (*node) == POINTER_TYPE); *node = fn_ptr_tmp; } } } return returned_attrs; }
static tree walk_gimple_asm (gasm *stmt, walk_tree_fn callback_op, struct walk_stmt_info *wi) { tree ret, op; unsigned noutputs; const char **oconstraints; unsigned i, n; const char *constraint; bool allows_mem, allows_reg, is_inout; noutputs = gimple_asm_noutputs (stmt); oconstraints = (const char **) alloca ((noutputs) * sizeof (const char *)); for (i = 0; i < noutputs; i++) { op = gimple_asm_output_op (stmt, i); constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op))); oconstraints[i] = constraint; if (wi) { if (parse_output_constraint (&constraint, i, 0, 0, &allows_mem, &allows_reg, &is_inout)) wi->val_only = (allows_reg || !allows_mem); } if (wi) wi->is_lhs = true; ret = walk_tree (&TREE_VALUE (op), callback_op, wi, NULL); if (ret) return ret; } n = gimple_asm_ninputs (stmt); for (i = 0; i < n; i++) { op = gimple_asm_input_op (stmt, i); constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op))); if (wi) { if (parse_input_constraint (&constraint, 0, 0, noutputs, 0, oconstraints, &allows_mem, &allows_reg)) { wi->val_only = (allows_reg || !allows_mem); /* Although input "m" is not really a LHS, we need a lvalue. */ wi->is_lhs = !wi->val_only; } } ret = walk_tree (&TREE_VALUE (op), callback_op, wi, NULL); if (ret) return ret; } if (wi) { wi->is_lhs = false; wi->val_only = true; } n = gimple_asm_nlabels (stmt); for (i = 0; i < n; i++) { op = gimple_asm_label_op (stmt, i); ret = walk_tree (&TREE_VALUE (op), callback_op, wi, NULL); if (ret) return ret; } return NULL_TREE; }
/* target hook for resolve_overloaded_builtin(). Returns a function call RTX if we can resolve the overloaded builtin */ tree spu_resolve_overloaded_builtin (tree fndecl, tree fnargs) { #define SCALAR_TYPE_P(t) (INTEGRAL_TYPE_P (t) \ || SCALAR_FLOAT_TYPE_P (t) \ || POINTER_TYPE_P (t)) int new_fcode, fcode = DECL_FUNCTION_CODE (fndecl) - END_BUILTINS; struct spu_builtin_description *desc; tree match = NULL_TREE; /* The vector types are not available if the backend is not initialized. */ gcc_assert (!flag_preprocess_only); desc = &spu_builtins[fcode]; if (desc->type != B_OVERLOAD) return NULL_TREE; /* Compare the signature of each internal builtin function with the function arguments until a match is found. */ for (new_fcode = fcode + 1; spu_builtins[new_fcode].type == B_INTERNAL; new_fcode++) { tree decl = spu_builtins[new_fcode].fndecl; tree params = TYPE_ARG_TYPES (TREE_TYPE (decl)); tree arg, param; bool all_scalar; int p; /* Check whether all parameters are scalar. */ all_scalar = true; for (param = params; param != void_list_node; param = TREE_CHAIN (param)) if (!SCALAR_TYPE_P (TREE_VALUE (param))) all_scalar = false; for (param = params, arg = fnargs, p = 0; param != void_list_node; param = TREE_CHAIN (param), arg = TREE_CHAIN (arg), p++) { tree var, arg_type, param_type = TREE_VALUE (param); if (!arg) { error ("insufficient arguments to overloaded function %s", desc->name); return error_mark_node; } var = TREE_VALUE (arg); if (TREE_CODE (var) == NON_LVALUE_EXPR) var = TREE_OPERAND (var, 0); if (TREE_CODE (var) == ERROR_MARK) return NULL_TREE; /* Let somebody else deal with the problem. */ arg_type = TREE_TYPE (var); /* The intrinsics spec does not specify precisely how to resolve generic intrinsics. We require an exact match for vector types and let C do it's usual parameter type checking/promotions for scalar arguments, except for the first argument of intrinsics which don't have a vector parameter. */ if ((!SCALAR_TYPE_P (param_type) || !SCALAR_TYPE_P (arg_type) || (all_scalar && p == 0)) && !comptypes (TYPE_MAIN_VARIANT (param_type), TYPE_MAIN_VARIANT (arg_type))) break; } if (param == void_list_node) { if (arg) { error ("too many arguments to overloaded function %s", desc->name); return error_mark_node; } match = decl; break; } } if (match == NULL_TREE) { error ("parameter list does not match a valid signature for %s()", desc->name); return error_mark_node; } return build_function_call (match, fnargs); #undef SCALAR_TYPE_P }
static const char * gen_formal_list_for_type (tree fntype, formals_style style) { const char *formal_list = ""; tree formal_type; if (style != ansi) return "()"; formal_type = TYPE_ARG_TYPES (fntype); while (formal_type && TREE_VALUE (formal_type) != void_type_node) { const char *this_type; if (*formal_list) formal_list = concat (formal_list, ", ", NULL); this_type = gen_type ("", TREE_VALUE (formal_type), ansi); formal_list = ((strlen (this_type)) ? concat (formal_list, affix_data_type (this_type), NULL) : concat (formal_list, data_type, NULL)); formal_type = TREE_CHAIN (formal_type); } /* If we got to here, then we are trying to generate an ANSI style formal parameters list. New style prototyped ANSI formal parameter lists should in theory always contain some stuff between the opening and closing parens, even if it is only "void". The brutal truth though is that there is lots of old K&R code out there which contains declarations of "pointer-to-function" parameters and these almost never have fully specified formal parameter lists associated with them. That is, the pointer-to-function parameters are declared with just empty parameter lists. In cases such as these, protoize should really insert *something* into the vacant parameter lists, but what? It has no basis on which to insert anything in particular. Here, we make life easy for protoize by trying to distinguish between K&R empty parameter lists and new-style prototyped parameter lists that actually contain "void". In the latter case we (obviously) want to output the "void" verbatim, and that what we do. In the former case, we do our best to give protoize something nice to insert. This "something nice" should be something that is still valid (when re-compiled) but something that can clearly indicate to the user that more typing information (for the parameter list) should be added (by hand) at some convenient moment. The string chosen here is a comment with question marks in it. */ if (!*formal_list) { if (prototype_p (fntype)) /* assert (TREE_VALUE (TYPE_ARG_TYPES (fntype)) == void_type_node); */ formal_list = "void"; else formal_list = "/* ??? */"; } else { /* If there were at least some parameters, and if the formals-types-list petered out to a NULL (i.e. without being terminated by a void_type_node) then we need to tack on an ellipsis. */ if (!formal_type) formal_list = concat (formal_list, ", ...", NULL); } return concat (" (", formal_list, ")", NULL); }
tree build_lambda_object (tree lambda_expr) { /* Build aggregate constructor call. - cp_parser_braced_list - cp_parser_functional_cast */ vec<constructor_elt, va_gc> *elts = NULL; tree node, expr, type; location_t saved_loc; if (processing_template_decl) return lambda_expr; /* Make sure any error messages refer to the lambda-introducer. */ saved_loc = input_location; input_location = LAMBDA_EXPR_LOCATION (lambda_expr); for (node = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); node; node = TREE_CHAIN (node)) { tree field = TREE_PURPOSE (node); tree val = TREE_VALUE (node); if (field == error_mark_node) { expr = error_mark_node; goto out; } if (DECL_P (val)) mark_used (val); /* Mere mortals can't copy arrays with aggregate initialization, so do some magic to make it work here. */ if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE) val = build_array_copy (val); else if (DECL_NORMAL_CAPTURE_P (field) && !DECL_VLA_CAPTURE_P (field) && TREE_CODE (TREE_TYPE (field)) != REFERENCE_TYPE) { /* "the entities that are captured by copy are used to direct-initialize each corresponding non-static data member of the resulting closure object." There's normally no way to express direct-initialization from an element of a CONSTRUCTOR, so we build up a special TARGET_EXPR to bypass the usual copy-initialization. */ val = force_rvalue (val, tf_warning_or_error); if (TREE_CODE (val) == TARGET_EXPR) TARGET_EXPR_DIRECT_INIT_P (val) = true; } CONSTRUCTOR_APPEND_ELT (elts, DECL_NAME (field), val); } expr = build_constructor (init_list_type_node, elts); CONSTRUCTOR_IS_DIRECT_INIT (expr) = 1; /* N2927: "[The closure] class type is not an aggregate." But we briefly treat it as an aggregate to make this simpler. */ type = LAMBDA_EXPR_CLOSURE (lambda_expr); CLASSTYPE_NON_AGGREGATE (type) = 0; expr = finish_compound_literal (type, expr, tf_warning_or_error); CLASSTYPE_NON_AGGREGATE (type) = 1; out: input_location = saved_loc; return expr; }