static tree handle_latent_entropy_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) { tree type; unsigned long long mask; #if BUILDING_GCC_VERSION <= 4007 VEC(constructor_elt, gc) *vals; #else vec<constructor_elt, va_gc> *vals; #endif switch (TREE_CODE(*node)) { default: *no_add_attrs = true; error("%qE attribute only applies to functions and variables", name); break; case VAR_DECL: if (DECL_INITIAL(*node)) { *no_add_attrs = true; error("variable %qD with %qE attribute must not be initialized", *node, name); break; } if (!TREE_STATIC(*node)) { *no_add_attrs = true; error("variable %qD with %qE attribute must not be local", *node, name); break; } type = TREE_TYPE(*node); switch (TREE_CODE(type)) { default: *no_add_attrs = true; error("variable %qD with %qE attribute must be an integer or a fixed length integer array type or a fixed sized structure with integer fields", *node, name); break; case RECORD_TYPE: { tree field; unsigned int nelt = 0; for (field = TYPE_FIELDS(type); field; nelt++, field = TREE_CHAIN(field)) { tree fieldtype; fieldtype = TREE_TYPE(field); if (TREE_CODE(fieldtype) != INTEGER_TYPE) { *no_add_attrs = true; error("structure variable %qD with %qE attribute has a non-integer field %qE", *node, name, field); break; } } if (field) break; #if BUILDING_GCC_VERSION <= 4007 vals = VEC_alloc(constructor_elt, gc, nelt); #else vec_alloc(vals, nelt); #endif for (field = TYPE_FIELDS(type); field; field = TREE_CHAIN(field)) { tree fieldtype; fieldtype = TREE_TYPE(field); mask = 1ULL << (TREE_INT_CST_LOW(TYPE_SIZE(fieldtype)) - 1); mask = 2 * (mask - 1) + 1; if (TYPE_UNSIGNED(fieldtype)) CONSTRUCTOR_APPEND_ELT(vals, field, build_int_cstu(fieldtype, mask & get_random_const())); else CONSTRUCTOR_APPEND_ELT(vals, field, build_int_cst(fieldtype, mask & get_random_const())); } DECL_INITIAL(*node) = build_constructor(type, vals); //debug_tree(DECL_INITIAL(*node)); break; } case INTEGER_TYPE: mask = 1ULL << (TREE_INT_CST_LOW(TYPE_SIZE(type)) - 1); mask = 2 * (mask - 1) + 1; if (TYPE_UNSIGNED(type)) DECL_INITIAL(*node) = build_int_cstu(type, mask & get_random_const()); else DECL_INITIAL(*node) = build_int_cst(type, mask & get_random_const()); break; case ARRAY_TYPE: { tree elt_type, array_size, elt_size; unsigned int i, nelt; elt_type = TREE_TYPE(type); elt_size = TYPE_SIZE_UNIT(TREE_TYPE(type)); array_size = TYPE_SIZE_UNIT(type); if (TREE_CODE(elt_type) != INTEGER_TYPE || !array_size || TREE_CODE(array_size) != INTEGER_CST) { *no_add_attrs = true; error("array variable %qD with %qE attribute must be a fixed length integer array type", *node, name); break; } nelt = TREE_INT_CST_LOW(array_size) / TREE_INT_CST_LOW(elt_size); #if BUILDING_GCC_VERSION <= 4007 vals = VEC_alloc(constructor_elt, gc, nelt); #else vec_alloc(vals, nelt); #endif mask = 1ULL << (TREE_INT_CST_LOW(TYPE_SIZE(elt_type)) - 1); mask = 2 * (mask - 1) + 1; for (i = 0; i < nelt; i++) if (TYPE_UNSIGNED(elt_type)) CONSTRUCTOR_APPEND_ELT(vals, size_int(i), build_int_cstu(elt_type, mask & get_random_const())); else CONSTRUCTOR_APPEND_ELT(vals, size_int(i), build_int_cst(elt_type, mask & get_random_const())); DECL_INITIAL(*node) = build_constructor(type, vals); //debug_tree(DECL_INITIAL(*node)); break; } } break; case FUNCTION_DECL: break; } return NULL_TREE; }
void print_node (FILE *file, const char *prefix, tree node, int indent) { int hash; struct bucket *b; machine_mode mode; enum tree_code_class tclass; int len; int i; expanded_location xloc; enum tree_code code; if (node == 0) return; code = TREE_CODE (node); tclass = TREE_CODE_CLASS (code); /* Don't get too deep in nesting. If the user wants to see deeper, it is easy to use the address of a lowest-level node as an argument in another call to debug_tree. */ if (indent > 24) { print_node_brief (file, prefix, node, indent); return; } if (indent > 8 && (tclass == tcc_type || tclass == tcc_declaration)) { print_node_brief (file, prefix, node, indent); return; } /* It is unsafe to look at any other fields of an ERROR_MARK node. */ if (code == ERROR_MARK) { print_node_brief (file, prefix, node, indent); return; } /* Allow this function to be called if the table is not there. */ if (table) { hash = ((uintptr_t) node) % HASH_SIZE; /* If node is in the table, just mention its address. */ for (b = table[hash]; b; b = b->next) if (b->node == node) { print_node_brief (file, prefix, node, indent); return; } /* Add this node to the table. */ b = XNEW (struct bucket); b->node = node; b->next = table[hash]; table[hash] = b; } /* Indent to the specified column, since this is the long form. */ indent_to (file, indent); /* Print the slot this node is in, and its code, and address. */ fprintf (file, "%s <%s", prefix, get_tree_code_name (code)); dump_addr (file, " ", node); /* Print the name, if any. */ if (tclass == tcc_declaration) { if (DECL_NAME (node)) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node))); else if (code == LABEL_DECL && LABEL_DECL_UID (node) != -1) { if (dump_flags & TDF_NOUID) fprintf (file, " L.xxxx"); else fprintf (file, " L.%d", (int) LABEL_DECL_UID (node)); } else { if (dump_flags & TDF_NOUID) fprintf (file, " %c.xxxx", code == CONST_DECL ? 'C' : 'D'); else fprintf (file, " %c.%u", code == CONST_DECL ? 'C' : 'D', DECL_UID (node)); } } else if (tclass == tcc_type) { if (TYPE_NAME (node)) { if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) fprintf (file, " %s", IDENTIFIER_POINTER (TYPE_NAME (node))); else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL && DECL_NAME (TYPE_NAME (node))) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node)))); } } if (code == IDENTIFIER_NODE) fprintf (file, " %s", IDENTIFIER_POINTER (node)); if (code == INTEGER_CST) { if (indent <= 4) print_node_brief (file, "type", TREE_TYPE (node), indent + 4); } else if (CODE_CONTAINS_STRUCT (code, TS_TYPED)) { print_node (file, "type", TREE_TYPE (node), indent + 4); if (TREE_TYPE (node)) indent_to (file, indent + 3); } if (!TYPE_P (node) && TREE_SIDE_EFFECTS (node)) fputs (" side-effects", file); if (TYPE_P (node) ? TYPE_READONLY (node) : TREE_READONLY (node)) fputs (" readonly", file); if (TYPE_P (node) && TYPE_ATOMIC (node)) fputs (" atomic", file); if (!TYPE_P (node) && TREE_CONSTANT (node)) fputs (" constant", file); else if (TYPE_P (node) && TYPE_SIZES_GIMPLIFIED (node)) fputs (" sizes-gimplified", file); if (TYPE_P (node) && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node))) fprintf (file, " address-space-%d", TYPE_ADDR_SPACE (node)); if (TREE_ADDRESSABLE (node)) fputs (" addressable", file); if (TREE_THIS_VOLATILE (node)) fputs (" volatile", file); if (TREE_ASM_WRITTEN (node)) fputs (" asm_written", file); if (TREE_USED (node)) fputs (" used", file); if (TREE_NOTHROW (node)) fputs (TYPE_P (node) ? " align-ok" : " nothrow", file); if (TREE_PUBLIC (node)) fputs (" public", file); if (TREE_PRIVATE (node)) fputs (" private", file); if (TREE_PROTECTED (node)) fputs (" protected", file); if (TREE_STATIC (node)) fputs (" static", file); if (TREE_DEPRECATED (node)) fputs (" deprecated", file); if (TREE_VISITED (node)) fputs (" visited", file); if (code != TREE_VEC && code != INTEGER_CST && code != SSA_NAME) { if (TREE_LANG_FLAG_0 (node)) fputs (" tree_0", file); if (TREE_LANG_FLAG_1 (node)) fputs (" tree_1", file); if (TREE_LANG_FLAG_2 (node)) fputs (" tree_2", file); if (TREE_LANG_FLAG_3 (node)) fputs (" tree_3", file); if (TREE_LANG_FLAG_4 (node)) fputs (" tree_4", file); if (TREE_LANG_FLAG_5 (node)) fputs (" tree_5", file); if (TREE_LANG_FLAG_6 (node)) fputs (" tree_6", file); } /* DECL_ nodes have additional attributes. */ switch (TREE_CODE_CLASS (code)) { case tcc_declaration: if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { if (DECL_UNSIGNED (node)) fputs (" unsigned", file); if (DECL_IGNORED_P (node)) fputs (" ignored", file); if (DECL_ABSTRACT_P (node)) fputs (" abstract", file); if (DECL_EXTERNAL (node)) fputs (" external", file); if (DECL_NONLOCAL (node)) fputs (" nonlocal", file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) { if (DECL_WEAK (node)) fputs (" weak", file); if (DECL_IN_SYSTEM_HEADER (node)) fputs (" in_system_header", file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL) && code != LABEL_DECL && code != FUNCTION_DECL && DECL_REGISTER (node)) fputs (" regdecl", file); if (code == TYPE_DECL && TYPE_DECL_SUPPRESS_DEBUG (node)) fputs (" suppress-debug", file); if (code == FUNCTION_DECL && DECL_FUNCTION_SPECIFIC_TARGET (node)) fputs (" function-specific-target", file); if (code == FUNCTION_DECL && DECL_FUNCTION_SPECIFIC_OPTIMIZATION (node)) fputs (" function-specific-opt", file); if (code == FUNCTION_DECL && DECL_DECLARED_INLINE_P (node)) fputs (" autoinline", file); if (code == FUNCTION_DECL && DECL_BUILT_IN (node)) fputs (" built-in", file); if (code == FUNCTION_DECL && DECL_STATIC_CHAIN (node)) fputs (" static-chain", file); if (TREE_CODE (node) == FUNCTION_DECL && decl_is_tm_clone (node)) fputs (" tm-clone", file); if (code == FIELD_DECL && DECL_PACKED (node)) fputs (" packed", file); if (code == FIELD_DECL && DECL_BIT_FIELD (node)) fputs (" bit-field", file); if (code == FIELD_DECL && DECL_NONADDRESSABLE_P (node)) fputs (" nonaddressable", file); if (code == LABEL_DECL && EH_LANDING_PAD_NR (node)) fprintf (file, " landing-pad:%d", EH_LANDING_PAD_NR (node)); if (code == VAR_DECL && DECL_IN_TEXT_SECTION (node)) fputs (" in-text-section", file); if (code == VAR_DECL && DECL_IN_CONSTANT_POOL (node)) fputs (" in-constant-pool", file); if (code == VAR_DECL && DECL_COMMON (node)) fputs (" common", file); if (code == VAR_DECL && DECL_THREAD_LOCAL_P (node)) { fputs (" ", file); fputs (tls_model_names[DECL_TLS_MODEL (node)], file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { if (DECL_VIRTUAL_P (node)) fputs (" virtual", file); if (DECL_PRESERVE_P (node)) fputs (" preserve", file); if (DECL_LANG_FLAG_0 (node)) fputs (" decl_0", file); if (DECL_LANG_FLAG_1 (node)) fputs (" decl_1", file); if (DECL_LANG_FLAG_2 (node)) fputs (" decl_2", file); if (DECL_LANG_FLAG_3 (node)) fputs (" decl_3", file); if (DECL_LANG_FLAG_4 (node)) fputs (" decl_4", file); if (DECL_LANG_FLAG_5 (node)) fputs (" decl_5", file); if (DECL_LANG_FLAG_6 (node)) fputs (" decl_6", file); if (DECL_LANG_FLAG_7 (node)) fputs (" decl_7", file); mode = DECL_MODE (node); fprintf (file, " %s", GET_MODE_NAME (mode)); } if ((code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL) && DECL_BY_REFERENCE (node)) fputs (" passed-by-reference", file); if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS) && DECL_DEFER_OUTPUT (node)) fputs (" defer-output", file); xloc = expand_location (DECL_SOURCE_LOCATION (node)); fprintf (file, " file %s line %d col %d", xloc.file, xloc.line, xloc.column); if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { print_node (file, "size", DECL_SIZE (node), indent + 4); print_node (file, "unit size", DECL_SIZE_UNIT (node), indent + 4); if (code != FUNCTION_DECL || DECL_BUILT_IN (node)) indent_to (file, indent + 3); if (DECL_USER_ALIGN (node)) fprintf (file, " user"); fprintf (file, " align %d", DECL_ALIGN (node)); if (code == FIELD_DECL) fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED, DECL_OFFSET_ALIGN (node)); if (code == FUNCTION_DECL && DECL_BUILT_IN (node)) { if (DECL_BUILT_IN_CLASS (node) == BUILT_IN_MD) fprintf (file, " built-in BUILT_IN_MD %d", DECL_FUNCTION_CODE (node)); else fprintf (file, " built-in %s:%s", built_in_class_names[(int) DECL_BUILT_IN_CLASS (node)], built_in_names[(int) DECL_FUNCTION_CODE (node)]); } } if (code == FIELD_DECL) { print_node (file, "offset", DECL_FIELD_OFFSET (node), indent + 4); print_node (file, "bit offset", DECL_FIELD_BIT_OFFSET (node), indent + 4); if (DECL_BIT_FIELD_TYPE (node)) print_node (file, "bit_field_type", DECL_BIT_FIELD_TYPE (node), indent + 4); } print_node_brief (file, "context", DECL_CONTEXT (node), indent + 4); if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { print_node_brief (file, "attributes", DECL_ATTRIBUTES (node), indent + 4); if (code != PARM_DECL) print_node_brief (file, "initial", DECL_INITIAL (node), indent + 4); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL)) { print_node_brief (file, "abstract_origin", DECL_ABSTRACT_ORIGIN (node), indent + 4); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON)) { print_node (file, "result", DECL_RESULT_FLD (node), indent + 4); } lang_hooks.print_decl (file, node, indent); if (DECL_RTL_SET_P (node)) { indent_to (file, indent + 4); print_rtl (file, DECL_RTL (node)); } if (code == PARM_DECL) { print_node (file, "arg-type", DECL_ARG_TYPE (node), indent + 4); if (DECL_INCOMING_RTL (node) != 0) { indent_to (file, indent + 4); fprintf (file, "incoming-rtl "); print_rtl (file, DECL_INCOMING_RTL (node)); } } else if (code == FUNCTION_DECL && DECL_STRUCT_FUNCTION (node) != 0) { print_node (file, "arguments", DECL_ARGUMENTS (node), indent + 4); indent_to (file, indent + 4); dump_addr (file, "struct-function ", DECL_STRUCT_FUNCTION (node)); } if ((code == VAR_DECL || code == PARM_DECL) && DECL_HAS_VALUE_EXPR_P (node)) print_node (file, "value-expr", DECL_VALUE_EXPR (node), indent + 4); /* Print the decl chain only if decl is at second level. */ if (indent == 4) print_node (file, "chain", TREE_CHAIN (node), indent + 4); else print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4); break; case tcc_type: if (TYPE_UNSIGNED (node)) fputs (" unsigned", file); if (TYPE_NO_FORCE_BLK (node)) fputs (" no-force-blk", file); if (TYPE_STRING_FLAG (node)) fputs (" string-flag", file); if (TYPE_NEEDS_CONSTRUCTING (node)) fputs (" needs-constructing", file); /* The transparent-union flag is used for different things in different nodes. */ if ((code == UNION_TYPE || code == RECORD_TYPE) && TYPE_TRANSPARENT_AGGR (node)) fputs (" transparent-aggr", file); else if (code == ARRAY_TYPE && TYPE_NONALIASED_COMPONENT (node)) fputs (" nonaliased-component", file); if (TYPE_PACKED (node)) fputs (" packed", file); if (TYPE_RESTRICT (node)) fputs (" restrict", file); if (TYPE_LANG_FLAG_0 (node)) fputs (" type_0", file); if (TYPE_LANG_FLAG_1 (node)) fputs (" type_1", file); if (TYPE_LANG_FLAG_2 (node)) fputs (" type_2", file); if (TYPE_LANG_FLAG_3 (node)) fputs (" type_3", file); if (TYPE_LANG_FLAG_4 (node)) fputs (" type_4", file); if (TYPE_LANG_FLAG_5 (node)) fputs (" type_5", file); if (TYPE_LANG_FLAG_6 (node)) fputs (" type_6", file); mode = TYPE_MODE (node); fprintf (file, " %s", GET_MODE_NAME (mode)); print_node (file, "size", TYPE_SIZE (node), indent + 4); print_node (file, "unit size", TYPE_SIZE_UNIT (node), indent + 4); indent_to (file, indent + 3); if (TYPE_USER_ALIGN (node)) fprintf (file, " user"); fprintf (file, " align %d symtab %d alias set " HOST_WIDE_INT_PRINT_DEC, TYPE_ALIGN (node), TYPE_SYMTAB_ADDRESS (node), (HOST_WIDE_INT) TYPE_ALIAS_SET (node)); if (TYPE_STRUCTURAL_EQUALITY_P (node)) fprintf (file, " structural equality"); else dump_addr (file, " canonical type ", TYPE_CANONICAL (node)); print_node (file, "attributes", TYPE_ATTRIBUTES (node), indent + 4); if (INTEGRAL_TYPE_P (node) || code == REAL_TYPE || code == FIXED_POINT_TYPE) { fprintf (file, " precision %d", TYPE_PRECISION (node)); print_node_brief (file, "min", TYPE_MIN_VALUE (node), indent + 4); print_node_brief (file, "max", TYPE_MAX_VALUE (node), indent + 4); } if (code == ENUMERAL_TYPE) print_node (file, "values", TYPE_VALUES (node), indent + 4); else if (code == ARRAY_TYPE) print_node (file, "domain", TYPE_DOMAIN (node), indent + 4); else if (code == VECTOR_TYPE) fprintf (file, " nunits %d", (int) TYPE_VECTOR_SUBPARTS (node)); else if (code == RECORD_TYPE || code == UNION_TYPE || code == QUAL_UNION_TYPE) print_node (file, "fields", TYPE_FIELDS (node), indent + 4); else if (code == FUNCTION_TYPE || code == METHOD_TYPE) { if (TYPE_METHOD_BASETYPE (node)) print_node_brief (file, "method basetype", TYPE_METHOD_BASETYPE (node), indent + 4); print_node (file, "arg-types", TYPE_ARG_TYPES (node), indent + 4); } else if (code == OFFSET_TYPE) print_node_brief (file, "basetype", TYPE_OFFSET_BASETYPE (node), indent + 4); if (TYPE_CONTEXT (node)) print_node_brief (file, "context", TYPE_CONTEXT (node), indent + 4); lang_hooks.print_type (file, node, indent); if (TYPE_POINTER_TO (node) || TREE_CHAIN (node)) indent_to (file, indent + 3); print_node_brief (file, "pointer_to_this", TYPE_POINTER_TO (node), indent + 4); print_node_brief (file, "reference_to_this", TYPE_REFERENCE_TO (node), indent + 4); print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4); break; case tcc_expression: case tcc_comparison: case tcc_unary: case tcc_binary: case tcc_reference: case tcc_statement: case tcc_vl_exp: if (code == BIND_EXPR) { print_node (file, "vars", TREE_OPERAND (node, 0), indent + 4); print_node (file, "body", TREE_OPERAND (node, 1), indent + 4); print_node (file, "block", TREE_OPERAND (node, 2), indent + 4); break; } if (code == CALL_EXPR) { call_expr_arg_iterator iter; tree arg; print_node (file, "fn", CALL_EXPR_FN (node), indent + 4); print_node (file, "static_chain", CALL_EXPR_STATIC_CHAIN (node), indent + 4); i = 0; FOR_EACH_CALL_EXPR_ARG (arg, iter, node) { char temp[10]; sprintf (temp, "arg %d", i); print_node (file, temp, arg, indent + 4); i++; } }
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; }
/* Synthesize a CALL_EXPR and a TRY_FINALLY_EXPR, for this chain of _DECLs if appropriate. Arrange to call the __mf_register function now, and the __mf_unregister function later for each. */ static void mx_register_decls (tree decl, tree *stmt_list) { tree finally_stmts = NULL_TREE; tree_stmt_iterator initially_stmts = tsi_start (*stmt_list); while (decl != NULL_TREE) { if (mf_decl_eligible_p (decl) /* Not already processed. */ && ! mf_marked_p (decl) /* Automatic variable. */ && ! DECL_EXTERNAL (decl) && ! TREE_STATIC (decl)) { tree size = NULL_TREE, variable_name; tree unregister_fncall, unregister_fncall_params; tree register_fncall, register_fncall_params; size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl))); /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */ unregister_fncall_params = tree_cons (NULL_TREE, convert (ptr_type_node, mf_mark (build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (decl)), decl))), tree_cons (NULL_TREE, size, tree_cons (NULL_TREE, /* __MF_TYPE_STACK */ build_int_cst (NULL_TREE, 3), NULL_TREE))); /* __mf_unregister (...) */ unregister_fncall = build_function_call_expr (mf_unregister_fndecl, unregister_fncall_params); /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK, "name") */ variable_name = mf_varname_tree (decl); register_fncall_params = tree_cons (NULL_TREE, convert (ptr_type_node, mf_mark (build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (decl)), decl))), tree_cons (NULL_TREE, size, tree_cons (NULL_TREE, /* __MF_TYPE_STACK */ build_int_cst (NULL_TREE, 3), tree_cons (NULL_TREE, variable_name, NULL_TREE)))); /* __mf_register (...) */ register_fncall = build_function_call_expr (mf_register_fndecl, register_fncall_params); /* Accumulate the two calls. */ /* ??? Set EXPR_LOCATION. */ gimplify_stmt (®ister_fncall); gimplify_stmt (&unregister_fncall); /* Add the __mf_register call at the current appending point. */ if (tsi_end_p (initially_stmts)) warning (0, "mudflap cannot track %qs in stub function", IDENTIFIER_POINTER (DECL_NAME (decl))); else { tsi_link_before (&initially_stmts, register_fncall, TSI_SAME_STMT); /* Accumulate the FINALLY piece. */ append_to_statement_list (unregister_fncall, &finally_stmts); } mf_mark (decl); } decl = TREE_CHAIN (decl); } /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */ if (finally_stmts != NULL_TREE) { tree t = build (TRY_FINALLY_EXPR, void_type_node, *stmt_list, finally_stmts); *stmt_list = NULL; append_to_statement_list (t, stmt_list); } }
static void create_common (gfc_common_head *com) { segment_info *s, *next_s; tree union_type; tree *field_link; record_layout_info rli; tree decl; bool is_init = false; /* Declare the variables inside the common block. */ union_type = make_node (UNION_TYPE); rli = start_record_layout (union_type); field_link = &TYPE_FIELDS (union_type); for (s = current_common; s; s = s->next) { build_field (s, union_type, rli); /* Link the field into the type. */ *field_link = s->field; field_link = &TREE_CHAIN (s->field); /* Has initial value. */ if (s->sym->value) is_init = true; } finish_record_layout (rli, true); if (com) decl = build_common_decl (com, union_type, is_init); else decl = build_equiv_decl (union_type, is_init); if (is_init) { tree list, ctor, tmp; HOST_WIDE_INT offset = 0; list = NULL_TREE; for (s = current_common; s; s = s->next) { if (s->sym->value) { if (s->offset < offset) { /* We have overlapping initializers. It could either be partially initialized arrays (legal), or the user specified multiple initial values (illegal). We don't implement this yet, so bail out. */ gfc_todo_error ("Initialization of overlapping variables"); } /* Add the initializer for this field. */ tmp = gfc_conv_initializer (s->sym->value, &s->sym->ts, TREE_TYPE (s->field), s->sym->attr.dimension, s->sym->attr.pointer || s->sym->attr.allocatable); list = tree_cons (s->field, tmp, list); offset = s->offset + s->length; } } gcc_assert (list); ctor = build1 (CONSTRUCTOR, union_type, nreverse(list)); TREE_CONSTANT (ctor) = 1; TREE_INVARIANT (ctor) = 1; TREE_STATIC (ctor) = 1; DECL_INITIAL (decl) = ctor; #ifdef ENABLE_CHECKING for (tmp = CONSTRUCTOR_ELTS (ctor); tmp; tmp = TREE_CHAIN (tmp)) gcc_assert (TREE_CODE (TREE_PURPOSE (tmp)) == FIELD_DECL); #endif } /* Build component reference for each variable. */ for (s = current_common; s; s = next_s) { s->sym->backend_decl = build3 (COMPONENT_REF, TREE_TYPE (s->field), decl, s->field, NULL_TREE); next_s = s->next; gfc_free (s); } }
static tree cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) { tree stmt = *stmt_p; struct cp_genericize_data *wtd = (struct cp_genericize_data *) data; struct pointer_set_t *p_set = wtd->p_set; /* If in an OpenMP context, note var uses. */ if (__builtin_expect (wtd->omp_ctx != NULL, 0) && (TREE_CODE (stmt) == VAR_DECL || TREE_CODE (stmt) == PARM_DECL || TREE_CODE (stmt) == RESULT_DECL) && omp_var_to_track (stmt)) omp_cxx_notice_variable (wtd->omp_ctx, stmt); if (is_invisiref_parm (stmt) /* Don't dereference parms in a thunk, pass the references through. */ && !(DECL_THUNK_P (current_function_decl) && TREE_CODE (stmt) == PARM_DECL)) { *stmt_p = convert_from_reference (stmt); *walk_subtrees = 0; return NULL; } /* Map block scope extern declarations to visible declarations with the same name and type in outer scopes if any. */ if (cp_function_chain->extern_decl_map && (TREE_CODE (stmt) == FUNCTION_DECL || TREE_CODE (stmt) == VAR_DECL) && DECL_EXTERNAL (stmt)) { struct cxx_int_tree_map *h, in; in.uid = DECL_UID (stmt); h = (struct cxx_int_tree_map *) htab_find_with_hash (cp_function_chain->extern_decl_map, &in, in.uid); if (h) { *stmt_p = h->to; *walk_subtrees = 0; return NULL; } } /* Other than invisiref parms, don't walk the same tree twice. */ if (pointer_set_contains (p_set, stmt)) { *walk_subtrees = 0; return NULL_TREE; } if (TREE_CODE (stmt) == ADDR_EXPR && is_invisiref_parm (TREE_OPERAND (stmt, 0))) { /* If in an OpenMP context, note var uses. */ if (__builtin_expect (wtd->omp_ctx != NULL, 0) && omp_var_to_track (TREE_OPERAND (stmt, 0))) omp_cxx_notice_variable (wtd->omp_ctx, TREE_OPERAND (stmt, 0)); *stmt_p = convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0)); *walk_subtrees = 0; } else if (TREE_CODE (stmt) == RETURN_EXPR && TREE_OPERAND (stmt, 0) && is_invisiref_parm (TREE_OPERAND (stmt, 0))) /* Don't dereference an invisiref RESULT_DECL inside a RETURN_EXPR. */ *walk_subtrees = 0; else if (TREE_CODE (stmt) == OMP_CLAUSE) switch (OMP_CLAUSE_CODE (stmt)) { case OMP_CLAUSE_LASTPRIVATE: /* Don't dereference an invisiref in OpenMP clauses. */ if (is_invisiref_parm (OMP_CLAUSE_DECL (stmt))) { *walk_subtrees = 0; if (OMP_CLAUSE_LASTPRIVATE_STMT (stmt)) cp_walk_tree (&OMP_CLAUSE_LASTPRIVATE_STMT (stmt), cp_genericize_r, data, NULL); } break; case OMP_CLAUSE_PRIVATE: /* Don't dereference an invisiref in OpenMP clauses. */ if (is_invisiref_parm (OMP_CLAUSE_DECL (stmt))) *walk_subtrees = 0; else if (wtd->omp_ctx != NULL) { /* Private clause doesn't cause any references to the var in outer contexts, avoid calling omp_cxx_notice_variable for it. */ struct cp_genericize_omp_taskreg *old = wtd->omp_ctx; wtd->omp_ctx = NULL; cp_walk_tree (&OMP_CLAUSE_DECL (stmt), cp_genericize_r, data, NULL); wtd->omp_ctx = old; *walk_subtrees = 0; } break; case OMP_CLAUSE_SHARED: case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_COPYIN: case OMP_CLAUSE_COPYPRIVATE: /* Don't dereference an invisiref in OpenMP clauses. */ if (is_invisiref_parm (OMP_CLAUSE_DECL (stmt))) *walk_subtrees = 0; break; case OMP_CLAUSE_REDUCTION: gcc_assert (!is_invisiref_parm (OMP_CLAUSE_DECL (stmt))); break; default: break; } else if (IS_TYPE_OR_DECL_P (stmt)) *walk_subtrees = 0; /* Due to the way voidify_wrapper_expr is written, we don't get a chance to lower this construct before scanning it, so we need to lower these before doing anything else. */ else if (TREE_CODE (stmt) == CLEANUP_STMT) *stmt_p = build2 (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR, void_type_node, CLEANUP_BODY (stmt), CLEANUP_EXPR (stmt)); else if (TREE_CODE (stmt) == IF_STMT) { genericize_if_stmt (stmt_p); /* *stmt_p has changed, tail recurse to handle it again. */ return cp_genericize_r (stmt_p, walk_subtrees, data); } /* COND_EXPR might have incompatible types in branches if one or both arms are bitfields. Fix it up now. */ else if (TREE_CODE (stmt) == COND_EXPR) { tree type_left = (TREE_OPERAND (stmt, 1) ? is_bitfield_expr_with_lowered_type (TREE_OPERAND (stmt, 1)) : NULL_TREE); tree type_right = (TREE_OPERAND (stmt, 2) ? is_bitfield_expr_with_lowered_type (TREE_OPERAND (stmt, 2)) : NULL_TREE); if (type_left && !useless_type_conversion_p (TREE_TYPE (stmt), TREE_TYPE (TREE_OPERAND (stmt, 1)))) { TREE_OPERAND (stmt, 1) = fold_convert (type_left, TREE_OPERAND (stmt, 1)); gcc_assert (useless_type_conversion_p (TREE_TYPE (stmt), type_left)); } if (type_right && !useless_type_conversion_p (TREE_TYPE (stmt), TREE_TYPE (TREE_OPERAND (stmt, 2)))) { TREE_OPERAND (stmt, 2) = fold_convert (type_right, TREE_OPERAND (stmt, 2)); gcc_assert (useless_type_conversion_p (TREE_TYPE (stmt), type_right)); } } else if (TREE_CODE (stmt) == BIND_EXPR) { if (__builtin_expect (wtd->omp_ctx != NULL, 0)) { tree decl; for (decl = BIND_EXPR_VARS (stmt); decl; decl = DECL_CHAIN (decl)) if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl) && omp_var_to_track (decl)) { splay_tree_node n = splay_tree_lookup (wtd->omp_ctx->variables, (splay_tree_key) decl); if (n == NULL) splay_tree_insert (wtd->omp_ctx->variables, (splay_tree_key) decl, TREE_STATIC (decl) ? OMP_CLAUSE_DEFAULT_SHARED : OMP_CLAUSE_DEFAULT_PRIVATE); } } VEC_safe_push (tree, heap, wtd->bind_expr_stack, stmt); cp_walk_tree (&BIND_EXPR_BODY (stmt), cp_genericize_r, data, NULL); VEC_pop (tree, wtd->bind_expr_stack); } else if (TREE_CODE (stmt) == USING_STMT) { tree block = NULL_TREE; /* Get the innermost inclosing GIMPLE_BIND that has a non NULL BLOCK, and append an IMPORTED_DECL to its BLOCK_VARS chained list. */ if (wtd->bind_expr_stack) { int i; for (i = VEC_length (tree, wtd->bind_expr_stack) - 1; i >= 0; i--) if ((block = BIND_EXPR_BLOCK (VEC_index (tree, wtd->bind_expr_stack, i)))) break; } if (block) { tree using_directive; gcc_assert (TREE_OPERAND (stmt, 0)); using_directive = make_node (IMPORTED_DECL); TREE_TYPE (using_directive) = void_type_node; IMPORTED_DECL_ASSOCIATED_DECL (using_directive) = TREE_OPERAND (stmt, 0); DECL_CHAIN (using_directive) = BLOCK_VARS (block); BLOCK_VARS (block) = using_directive; } /* The USING_STMT won't appear in GENERIC. */ *stmt_p = build1 (NOP_EXPR, void_type_node, integer_zero_node); *walk_subtrees = 0; } else if (TREE_CODE (stmt) == DECL_EXPR && TREE_CODE (DECL_EXPR_DECL (stmt)) == USING_DECL) { /* Using decls inside DECL_EXPRs are just dropped on the floor. */ *stmt_p = build1 (NOP_EXPR, void_type_node, integer_zero_node); *walk_subtrees = 0; } else if (TREE_CODE (stmt) == OMP_PARALLEL || TREE_CODE (stmt) == OMP_TASK) { struct cp_genericize_omp_taskreg omp_ctx; tree c, decl; splay_tree_node n; *walk_subtrees = 0; cp_walk_tree (&OMP_CLAUSES (stmt), cp_genericize_r, data, NULL); omp_ctx.is_parallel = TREE_CODE (stmt) == OMP_PARALLEL; omp_ctx.default_shared = omp_ctx.is_parallel; omp_ctx.outer = wtd->omp_ctx; omp_ctx.variables = splay_tree_new (splay_tree_compare_decl_uid, 0, 0); wtd->omp_ctx = &omp_ctx; for (c = OMP_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c)) switch (OMP_CLAUSE_CODE (c)) { case OMP_CLAUSE_SHARED: case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_LASTPRIVATE: decl = OMP_CLAUSE_DECL (c); if (decl == error_mark_node || !omp_var_to_track (decl)) break; n = splay_tree_lookup (omp_ctx.variables, (splay_tree_key) decl); if (n != NULL) break; splay_tree_insert (omp_ctx.variables, (splay_tree_key) decl, OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED ? OMP_CLAUSE_DEFAULT_SHARED : OMP_CLAUSE_DEFAULT_PRIVATE); if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_PRIVATE && omp_ctx.outer) omp_cxx_notice_variable (omp_ctx.outer, decl); break; case OMP_CLAUSE_DEFAULT: if (OMP_CLAUSE_DEFAULT_KIND (c) == OMP_CLAUSE_DEFAULT_SHARED) omp_ctx.default_shared = true; default: break; } cp_walk_tree (&OMP_BODY (stmt), cp_genericize_r, data, NULL); wtd->omp_ctx = omp_ctx.outer; splay_tree_delete (omp_ctx.variables); } else if (TREE_CODE (stmt) == CONVERT_EXPR) gcc_assert (!CONVERT_EXPR_VBASE_PATH (stmt)); pointer_set_insert (p_set, *stmt_p); return NULL; }
tree build_throw (tree exp) { tree fn; if (exp == error_mark_node) return exp; if (processing_template_decl) { if (cfun) current_function_returns_abnormally = 1; exp = build_min (THROW_EXPR, void_type_node, exp); SET_EXPR_LOCATION (exp, input_location); return exp; } if (exp == null_node) warning (0, "throwing NULL, which has integral, not pointer type"); if (exp != NULL_TREE) { if (!is_admissible_throw_operand_or_catch_parameter (exp, true)) return error_mark_node; } if (! doing_eh ()) return error_mark_node; if (exp && decl_is_java_type (TREE_TYPE (exp), 1)) { tree fn = get_identifier ("_Jv_Throw"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void _Jv_Throw (void *). */ tree tmp; tmp = build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE); fn = push_throw_library_fn (fn, tmp); } else if (really_overloaded_fn (fn)) { error ("%qD should never be overloaded", fn); return error_mark_node; } fn = OVL_CURRENT (fn); exp = cp_build_function_call_nary (fn, tf_warning_or_error, exp, NULL_TREE); } else if (exp) { tree throw_type; tree temp_type; tree cleanup; tree object, ptr; tree tmp; tree allocate_expr; /* The CLEANUP_TYPE is the internal type of a destructor. */ if (!cleanup_type) { tmp = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); cleanup_type = build_pointer_type (tmp); } fn = get_identifier ("__cxa_throw"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void __cxa_throw (void*, void*, void (*)(void*)). */ /* ??? Second argument is supposed to be "std::type_info*". */ tmp = build_function_type_list (void_type_node, ptr_type_node, ptr_type_node, cleanup_type, NULL_TREE); fn = push_throw_library_fn (fn, tmp); if (flag_tm) { tree fn2 = get_identifier ("_ITM_cxa_throw"); if (!get_global_value_if_present (fn2, &fn2)) fn2 = push_throw_library_fn (fn2, tmp); apply_tm_attr (fn2, get_identifier ("transaction_pure")); record_tm_replacement (fn, fn2); } } /* [except.throw] A throw-expression initializes a temporary object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throw and adjusting the type from "array of T" or "function return T" to "pointer to T" or "pointer to function returning T" respectively. */ temp_type = is_bitfield_expr_with_lowered_type (exp); if (!temp_type) temp_type = cv_unqualified (type_decays_to (TREE_TYPE (exp))); /* OK, this is kind of wacky. The standard says that we call terminate when the exception handling mechanism, after completing evaluation of the expression to be thrown but before the exception is caught (_except.throw_), calls a user function that exits via an uncaught exception. So we have to protect the actual initialization of the exception object with terminate(), but evaluate the expression first. Since there could be temps in the expression, we need to handle that, too. We also expand the call to __cxa_allocate_exception first (which doesn't matter, since it can't throw). */ /* Allocate the space for the exception. */ allocate_expr = do_allocate_exception (temp_type); allocate_expr = get_target_expr (allocate_expr); ptr = TARGET_EXPR_SLOT (allocate_expr); TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr); CLEANUP_EH_ONLY (allocate_expr) = 1; object = build_nop (build_pointer_type (temp_type), ptr); object = cp_build_indirect_ref (object, RO_NULL, tf_warning_or_error); /* And initialize the exception object. */ if (CLASS_TYPE_P (temp_type)) { int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING; vec<tree, va_gc> *exp_vec; /* Under C++0x [12.8/16 class.copy], a thrown lvalue is sometimes treated as an rvalue for the purposes of overload resolution to favor move constructors over copy constructors. */ if (/* Must be a local, automatic variable. */ VAR_P (exp) && DECL_CONTEXT (exp) == current_function_decl && ! TREE_STATIC (exp) /* The variable must not have the `volatile' qualifier. */ && !(cp_type_quals (TREE_TYPE (exp)) & TYPE_QUAL_VOLATILE)) flags = flags | LOOKUP_PREFER_RVALUE; /* Call the copy constructor. */ exp_vec = make_tree_vector_single (exp); exp = (build_special_member_call (object, complete_ctor_identifier, &exp_vec, TREE_TYPE (object), flags, tf_warning_or_error)); release_tree_vector (exp_vec); if (exp == error_mark_node) { error (" in thrown expression"); return error_mark_node; } } else { tmp = decay_conversion (exp, tf_warning_or_error); if (tmp == error_mark_node) return error_mark_node; exp = build2 (INIT_EXPR, temp_type, object, tmp); } /* Mark any cleanups from the initialization as MUST_NOT_THROW, since they are run after the exception object is initialized. */ cp_walk_tree_without_duplicates (&exp, wrap_cleanups_r, 0); /* Prepend the allocation. */ exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); /* Force all the cleanups to be evaluated here so that we don't have to do them during unwinding. */ exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp); throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object))); cleanup = NULL_TREE; if (type_build_dtor_call (TREE_TYPE (object))) { tree fn = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), complete_dtor_identifier, 0); fn = BASELINK_FUNCTIONS (fn); mark_used (fn); if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (object))) { cxx_mark_addressable (fn); /* Pretend it's a normal function. */ cleanup = build1 (ADDR_EXPR, cleanup_type, fn); } } if (cleanup == NULL_TREE) cleanup = build_int_cst (cleanup_type, 0); /* ??? Indicate that this function call throws throw_type. */ tmp = cp_build_function_call_nary (fn, tf_warning_or_error, ptr, throw_type, cleanup, NULL_TREE); /* Tack on the initialization stuff. */ exp = build2 (COMPOUND_EXPR, TREE_TYPE (tmp), exp, tmp); } else { /* Rethrow current exception. */ tree fn = get_identifier ("__cxa_rethrow"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void __cxa_rethrow (void). */ fn = push_throw_library_fn (fn, build_function_type_list (void_type_node, NULL_TREE)); } if (flag_tm) apply_tm_attr (fn, get_identifier ("transaction_pure")); /* ??? Indicate that this function call allows exceptions of the type of the enclosing catch block (if known). */ exp = cp_build_function_call_vec (fn, NULL, tf_warning_or_error); } exp = build1 (THROW_EXPR, void_type_node, exp); SET_EXPR_LOCATION (exp, input_location); return exp; }
static void create_common (gfc_common_head *com, segment_info *head, bool saw_equiv) { segment_info *s, *next_s; tree union_type; tree *field_link; tree field; tree field_init = NULL_TREE; record_layout_info rli; tree decl; bool is_init = false; bool is_saved = false; /* Declare the variables inside the common block. If the current common block contains any equivalence object, then make a UNION_TYPE node, otherwise RECORD_TYPE. This will let the alias analyzer work well when there is no address overlapping for common variables in the current common block. */ if (saw_equiv) union_type = make_node (UNION_TYPE); else union_type = make_node (RECORD_TYPE); rli = start_record_layout (union_type); field_link = &TYPE_FIELDS (union_type); /* Check for overlapping initializers and replace them with a single, artificial field that contains all the data. */ if (saw_equiv) field = get_init_field (head, union_type, &field_init, rli); else field = NULL_TREE; if (field != NULL_TREE) { is_init = true; *field_link = field; field_link = &TREE_CHAIN (field); } for (s = head; s; s = s->next) { build_field (s, union_type, rli); /* Link the field into the type. */ *field_link = s->field; field_link = &TREE_CHAIN (s->field); /* Has initial value. */ if (s->sym->value) is_init = true; /* Has SAVE attribute. */ if (s->sym->attr.save) is_saved = true; } finish_record_layout (rli, true); if (com) decl = build_common_decl (com, union_type, is_init); else decl = build_equiv_decl (union_type, is_init, is_saved); if (is_init) { tree ctor, tmp; HOST_WIDE_INT offset = 0; VEC(constructor_elt,gc) *v = NULL; if (field != NULL_TREE && field_init != NULL_TREE) CONSTRUCTOR_APPEND_ELT (v, field, field_init); else for (s = head; s; s = s->next) { if (s->sym->value) { /* Add the initializer for this field. */ tmp = gfc_conv_initializer (s->sym->value, &s->sym->ts, TREE_TYPE (s->field), s->sym->attr.dimension, s->sym->attr.pointer || s->sym->attr.allocatable); CONSTRUCTOR_APPEND_ELT (v, s->field, tmp); offset = s->offset + s->length; } } gcc_assert (!VEC_empty (constructor_elt, v)); ctor = build_constructor (union_type, v); TREE_CONSTANT (ctor) = 1; TREE_STATIC (ctor) = 1; DECL_INITIAL (decl) = ctor; #ifdef ENABLE_CHECKING { tree field, value; unsigned HOST_WIDE_INT idx; FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, field, value) gcc_assert (TREE_CODE (field) == FIELD_DECL); } #endif } /* Build component reference for each variable. */ for (s = head; s; s = next_s) { tree var_decl; var_decl = build_decl (s->sym->declared_at.lb->location, VAR_DECL, DECL_NAME (s->field), TREE_TYPE (s->field)); TREE_PUBLIC (var_decl) = TREE_PUBLIC (decl); TREE_STATIC (var_decl) = TREE_STATIC (decl); TREE_USED (var_decl) = TREE_USED (decl); if (s->sym->attr.use_assoc) DECL_IGNORED_P (var_decl) = 1; if (s->sym->attr.target) TREE_ADDRESSABLE (var_decl) = 1; /* This is a fake variable just for debugging purposes. */ TREE_ASM_WRITTEN (var_decl) = 1; /* To preserve identifier names in COMMON, chain to procedure scope unless at top level in a module definition. */ if (com && s->sym->ns->proc_name && s->sym->ns->proc_name->attr.flavor == FL_MODULE) var_decl = pushdecl_top_level (var_decl); else gfc_add_decl_to_function (var_decl); SET_DECL_VALUE_EXPR (var_decl, fold_build3 (COMPONENT_REF, TREE_TYPE (s->field), decl, s->field, NULL_TREE)); DECL_HAS_VALUE_EXPR_P (var_decl) = 1; GFC_DECL_COMMON_OR_EQUIV (var_decl) = 1; if (s->sym->attr.assign) { gfc_allocate_lang_decl (var_decl); GFC_DECL_ASSIGN (var_decl) = 1; GFC_DECL_STRING_LEN (var_decl) = GFC_DECL_STRING_LEN (s->field); GFC_DECL_ASSIGN_ADDR (var_decl) = GFC_DECL_ASSIGN_ADDR (s->field); } s->sym->backend_decl = var_decl; next_s = s->next; gfc_free (s); } }
/* Add code: __thread gcov* __gcov_indirect_call_counters; // pointer to actual counter __thread void* __gcov_indirect_call_callee; // actual callee address */ static void init_ic_make_global_vars (void) { tree gcov_type_ptr; ptr_void = build_pointer_type (void_type_node); /* Workaround for binutils bug 14342. Once it is fixed, remove lto path. */ if (flag_lto) { ic_void_ptr_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier ("__gcov_indirect_call_callee_ltopriv"), ptr_void); TREE_PUBLIC (ic_void_ptr_var) = 1; DECL_COMMON (ic_void_ptr_var) = 1; DECL_VISIBILITY (ic_void_ptr_var) = VISIBILITY_HIDDEN; DECL_VISIBILITY_SPECIFIED (ic_void_ptr_var) = true; } else { ic_void_ptr_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier ("__gcov_indirect_call_callee"), ptr_void); TREE_PUBLIC (ic_void_ptr_var) = 1; DECL_EXTERNAL (ic_void_ptr_var) = 1; } TREE_STATIC (ic_void_ptr_var) = 1; DECL_ARTIFICIAL (ic_void_ptr_var) = 1; DECL_INITIAL (ic_void_ptr_var) = NULL; if (targetm.have_tls) DECL_TLS_MODEL (ic_void_ptr_var) = decl_default_tls_model (ic_void_ptr_var); varpool_finalize_decl (ic_void_ptr_var); gcov_type_ptr = build_pointer_type (get_gcov_type ()); /* Workaround for binutils bug 14342. Once it is fixed, remove lto path. */ if (flag_lto) { ic_gcov_type_ptr_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier ("__gcov_indirect_call_counters_ltopriv"), gcov_type_ptr); TREE_PUBLIC (ic_gcov_type_ptr_var) = 1; DECL_COMMON (ic_gcov_type_ptr_var) = 1; DECL_VISIBILITY (ic_gcov_type_ptr_var) = VISIBILITY_HIDDEN; DECL_VISIBILITY_SPECIFIED (ic_gcov_type_ptr_var) = true; } else { ic_gcov_type_ptr_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier ("__gcov_indirect_call_counters"), gcov_type_ptr); TREE_PUBLIC (ic_gcov_type_ptr_var) = 1; DECL_EXTERNAL (ic_gcov_type_ptr_var) = 1; } TREE_STATIC (ic_gcov_type_ptr_var) = 1; DECL_ARTIFICIAL (ic_gcov_type_ptr_var) = 1; DECL_INITIAL (ic_gcov_type_ptr_var) = NULL; if (targetm.have_tls) DECL_TLS_MODEL (ic_gcov_type_ptr_var) = decl_default_tls_model (ic_gcov_type_ptr_var); varpool_finalize_decl (ic_gcov_type_ptr_var); }
/* Synthesize a CALL_EXPR and a TRY_FINALLY_EXPR, for this chain of _DECLs if appropriate. Arrange to call the __mf_register function now, and the __mf_unregister function later for each. Return the gimple sequence after synthesis. */ gimple_seq mx_register_decls (tree decl, gimple_seq seq, location_t location) { gimple_seq finally_stmts = NULL; gimple_stmt_iterator initially_stmts = gsi_start (seq); while (decl != NULL_TREE) { if (mf_decl_eligible_p (decl) /* Not already processed. */ && ! mf_marked_p (decl) /* Automatic variable. */ && ! DECL_EXTERNAL (decl) && ! TREE_STATIC (decl)) { tree size = NULL_TREE, variable_name; gimple unregister_fncall, register_fncall; tree unregister_fncall_param, register_fncall_param; /* Variable-sized objects should have sizes already been gimplified when we got here. */ size = fold_convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl))); gcc_assert (is_gimple_val (size)); unregister_fncall_param = mf_mark (build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (decl)), decl)); /* __mf_unregister (&VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */ unregister_fncall = gimple_build_call (mf_unregister_fndecl, 3, unregister_fncall_param, size, integer_three_node); variable_name = mf_varname_tree (decl); register_fncall_param = mf_mark (build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (decl)), decl)); /* __mf_register (&VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK, "name") */ register_fncall = gimple_build_call (mf_register_fndecl, 4, register_fncall_param, size, integer_three_node, variable_name); /* Accumulate the two calls. */ gimple_set_location (register_fncall, location); gimple_set_location (unregister_fncall, location); /* Add the __mf_register call at the current appending point. */ if (gsi_end_p (initially_stmts)) { if (!mf_artificial (decl)) warning (OPT_Wmudflap, "mudflap cannot track %qE in stub function", DECL_NAME (decl)); } else { gsi_insert_before (&initially_stmts, register_fncall, GSI_SAME_STMT); /* Accumulate the FINALLY piece. */ gimple_seq_add_stmt (&finally_stmts, unregister_fncall); } mf_mark (decl); } decl = DECL_CHAIN (decl); } /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */ if (finally_stmts != NULL) { gimple stmt = gimple_build_try (seq, finally_stmts, GIMPLE_TRY_FINALLY); gimple_seq new_seq = NULL; gimple_seq_add_stmt (&new_seq, stmt); return new_seq; } else return seq; }
tree ubsan_create_data (const char *name, location_t loc, const struct ubsan_mismatch_data *mismatch, ...) { va_list args; tree ret, t; tree fields[5]; vec<tree, va_gc> *saved_args = NULL; size_t i = 0; /* Firstly, create a pointer to type descriptor type. */ tree td_type = ubsan_type_descriptor_type (); TYPE_READONLY (td_type) = 1; td_type = build_pointer_type (td_type); loc = LOCATION_LOCUS (loc); /* Create the structure type. */ ret = make_node (RECORD_TYPE); if (loc != UNKNOWN_LOCATION) { fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, ubsan_source_location_type ()); DECL_CONTEXT (fields[i]) = ret; i++; } va_start (args, mismatch); for (t = va_arg (args, tree); t != NULL_TREE; i++, t = va_arg (args, tree)) { gcc_checking_assert (i < 3); /* Save the tree arguments for later use. */ vec_safe_push (saved_args, t); fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, td_type); DECL_CONTEXT (fields[i]) = ret; if (i) DECL_CHAIN (fields[i - 1]) = fields[i]; } va_end (args); if (mismatch != NULL) { /* We have to add two more decls. */ fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, pointer_sized_int_node); DECL_CONTEXT (fields[i]) = ret; DECL_CHAIN (fields[i - 1]) = fields[i]; i++; fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, unsigned_char_type_node); DECL_CONTEXT (fields[i]) = ret; DECL_CHAIN (fields[i - 1]) = fields[i]; i++; } TYPE_FIELDS (ret) = fields[0]; TYPE_NAME (ret) = get_identifier (name); layout_type (ret); /* Now, fill in the type. */ char tmp_name[32]; static unsigned int ubsan_var_id_num; ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_data", ubsan_var_id_num++); tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name), ret); TREE_STATIC (var) = 1; TREE_PUBLIC (var) = 0; DECL_ARTIFICIAL (var) = 1; DECL_IGNORED_P (var) = 1; DECL_EXTERNAL (var) = 0; vec<constructor_elt, va_gc> *v; vec_alloc (v, i); tree ctor = build_constructor (ret, v); /* If desirable, set the __ubsan_source_location element. */ if (loc != UNKNOWN_LOCATION) CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, ubsan_source_location (loc)); size_t nelts = vec_safe_length (saved_args); for (i = 0; i < nelts; i++) { t = (*saved_args)[i]; CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, t); } if (mismatch != NULL) { /* Append the pointer data. */ CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, mismatch->align); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, mismatch->ckind); } TREE_CONSTANT (ctor) = 1; TREE_STATIC (ctor) = 1; DECL_INITIAL (var) = ctor; rest_of_decl_compilation (var, 1, 0); return var; }
tree ubsan_type_descriptor (tree type, bool want_pointer_type_p) { /* See through any typedefs. */ type = TYPE_MAIN_VARIANT (type); tree decl = decl_for_type_lookup (type); /* It is possible that some of the earlier created DECLs were found unused, in that case they weren't emitted and varpool_get_node returns NULL node on them. But now we really need them. Thus, renew them here. */ if (decl != NULL_TREE && varpool_get_node (decl)) return build_fold_addr_expr (decl); tree dtype = ubsan_type_descriptor_type (); tree type2 = type; const char *tname = NULL; char *pretty_name; unsigned char deref_depth = 0; unsigned short tkind, tinfo; /* Get the name of the type, or the name of the pointer type. */ if (want_pointer_type_p) { gcc_assert (POINTER_TYPE_P (type)); type2 = TREE_TYPE (type); /* Remove any '*' operators from TYPE. */ while (POINTER_TYPE_P (type2)) deref_depth++, type2 = TREE_TYPE (type2); if (TREE_CODE (type2) == METHOD_TYPE) type2 = TYPE_METHOD_BASETYPE (type2); } /* If an array, get its type. */ type2 = strip_array_types (type2); if (TYPE_NAME (type2) != NULL) { if (TREE_CODE (TYPE_NAME (type2)) == IDENTIFIER_NODE) tname = IDENTIFIER_POINTER (TYPE_NAME (type2)); else tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type2))); } if (tname == NULL) /* We weren't able to determine the type name. */ tname = "<unknown>"; /* Decorate the type name with '', '*', "struct", or "union". */ pretty_name = (char *) alloca (strlen (tname) + 16 + deref_depth); if (want_pointer_type_p) { int pos = sprintf (pretty_name, "'%s%s%s%s%s%s%s", TYPE_VOLATILE (type2) ? "volatile " : "", TYPE_READONLY (type2) ? "const " : "", TYPE_RESTRICT (type2) ? "restrict " : "", TYPE_ATOMIC (type2) ? "_Atomic " : "", TREE_CODE (type2) == RECORD_TYPE ? "struct " : TREE_CODE (type2) == UNION_TYPE ? "union " : "", tname, deref_depth == 0 ? "" : " "); while (deref_depth-- > 0) pretty_name[pos++] = '*'; pretty_name[pos++] = '\''; pretty_name[pos] = '\0'; } else sprintf (pretty_name, "'%s'", tname); switch (TREE_CODE (type)) { case BOOLEAN_TYPE: case ENUMERAL_TYPE: case INTEGER_TYPE: tkind = 0x0000; break; case REAL_TYPE: tkind = 0x0001; break; default: tkind = 0xffff; break; } tinfo = get_ubsan_type_info_for_type (type); /* Create a new VAR_DECL of type descriptor. */ char tmp_name[32]; static unsigned int type_var_id_num; ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_type", type_var_id_num++); decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name), dtype); TREE_STATIC (decl) = 1; TREE_PUBLIC (decl) = 0; DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; DECL_EXTERNAL (decl) = 0; size_t len = strlen (pretty_name); tree str = build_string (len + 1, pretty_name); TREE_TYPE (str) = build_array_type (char_type_node, build_index_type (size_int (len))); TREE_READONLY (str) = 1; TREE_STATIC (str) = 1; tree ctor = build_constructor_va (dtype, 3, NULL_TREE, build_int_cst (short_unsigned_type_node, tkind), NULL_TREE, build_int_cst (short_unsigned_type_node, tinfo), NULL_TREE, str); TREE_CONSTANT (ctor) = 1; TREE_STATIC (ctor) = 1; DECL_INITIAL (decl) = ctor; rest_of_decl_compilation (decl, 1, 0); /* Save the VAR_DECL into the hash table. */ decl_for_type_insert (type, decl); return build_fold_addr_expr (decl); }
bool i386_pe_type_dllimport_p (tree decl) { gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL); if (TARGET_NOP_FUN_DLLIMPORT && TREE_CODE (decl) == FUNCTION_DECL) return false; /* We ignore the dllimport attribute for inline member functions. This differs from MSVC behavior which treats it like GNUC 'extern inline' extension. Also ignore for template instantiations with linkonce semantics and artificial methods. */ if (TREE_CODE (decl) == FUNCTION_DECL && (DECL_DECLARED_INLINE_P (decl) || DECL_TEMPLATE_INSTANTIATION (decl) || DECL_ARTIFICIAL (decl))) return false; /* Since we can't treat a pointer to a dllimport'd symbol as a constant address, we turn off the attribute on C++ virtual methods to allow creation of vtables using thunks. */ else if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE && DECL_VIRTUAL_P (decl)) { /* Even though we ignore the attribute from the start, warn if we later see an out-of class definition, as we do for other member functions in tree.c:merge_dllimport_decl_attributes. If this is the key method, the definition may affect the import-export status of vtables, depending on how we handle MULTIPLE_SYMBOL_SPACES in cp/decl2.c. */ if (DECL_INITIAL (decl)) { warning ("%q+D redeclared without dllimport attribute: " "previous dllimport ignored", decl); #ifdef PE_DLL_DEBUG if (decl == CLASSTYPE_KEY_METHOD (DECL_CONTEXT (decl))) warning ("key method %q+D of dllimport'd class defined" decl); #endif } return false; } /* Don't mark defined functions as dllimport. This code will only be reached if we see a non-inline function defined out-of-class. */ else if (TREE_CODE (decl) == FUNCTION_DECL && (DECL_INITIAL (decl))) return false; /* Don't allow definitions of static data members in dllimport class, If vtable data is marked as DECL_EXTERNAL, import it; otherwise just ignore the class attribute. */ else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl) && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl)) { if (!DECL_VIRTUAL_P (decl)) error ("definition of static data member %q+D of " "dllimport'd class", decl); return false; } return true; }
static inline void check_decl (funct_state local, tree t, bool checking_write, bool ipa) { /* Do not want to do anything with volatile except mark any function that uses one to be not const or pure. */ if (TREE_THIS_VOLATILE (t)) { local->pure_const_state = IPA_NEITHER; if (dump_file) fprintf (dump_file, " Volatile operand is not const/pure"); return; } /* Do not care about a local automatic that is not static. */ if (!TREE_STATIC (t) && !DECL_EXTERNAL (t)) return; /* If the variable has the "used" attribute, treat it as if it had a been touched by the devil. */ if (DECL_PRESERVE_P (t)) { local->pure_const_state = IPA_NEITHER; if (dump_file) fprintf (dump_file, " Used static/global variable is not const/pure\n"); return; } /* In IPA mode we are not interested in checking actual loads and stores; they will be processed at propagation time using ipa_ref. */ if (ipa) return; /* Since we have dealt with the locals and params cases above, if we are CHECKING_WRITE, this cannot be a pure or constant function. */ if (checking_write) { local->pure_const_state = IPA_NEITHER; if (dump_file) fprintf (dump_file, " static/global memory write is not const/pure\n"); return; } if (DECL_EXTERNAL (t) || TREE_PUBLIC (t)) { /* Readonly reads are safe. */ if (TREE_READONLY (t) && !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (t))) return; /* Read of a constant, do not change the function state. */ else { if (dump_file) fprintf (dump_file, " global memory read is not const\n"); /* Just a regular read. */ if (local->pure_const_state == IPA_CONST) local->pure_const_state = IPA_PURE; } } else { /* Compilation level statics can be read if they are readonly variables. */ if (TREE_READONLY (t)) return; if (dump_file) fprintf (dump_file, " static memory read is not const\n"); /* Just a regular read. */ if (local->pure_const_state == IPA_CONST) local->pure_const_state = IPA_PURE; } }
static void build_field (segment_info *h, tree union_type, record_layout_info rli) { tree field; tree name; HOST_WIDE_INT offset = h->offset; unsigned HOST_WIDE_INT desired_align, known_align; name = get_identifier (h->sym->name); field = build_decl (h->sym->declared_at.lb->location, FIELD_DECL, name, h->field); known_align = (offset & -offset) * BITS_PER_UNIT; if (known_align == 0 || known_align > BIGGEST_ALIGNMENT) known_align = BIGGEST_ALIGNMENT; desired_align = update_alignment_for_field (rli, field, known_align); if (desired_align > known_align) DECL_PACKED (field) = 1; DECL_FIELD_CONTEXT (field) = union_type; DECL_FIELD_OFFSET (field) = size_int (offset); DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node; SET_DECL_OFFSET_ALIGN (field, known_align); rli->offset = size_binop (MAX_EXPR, rli->offset, size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (field), DECL_SIZE_UNIT (field))); /* If this field is assigned to a label, we create another two variables. One will hold the address of target label or format label. The other will hold the length of format label string. */ if (h->sym->attr.assign) { tree len; tree addr; gfc_allocate_lang_decl (field); GFC_DECL_ASSIGN (field) = 1; len = gfc_create_var_np (gfc_charlen_type_node,h->sym->name); addr = gfc_create_var_np (pvoid_type_node, h->sym->name); TREE_STATIC (len) = 1; TREE_STATIC (addr) = 1; DECL_INITIAL (len) = build_int_cst (gfc_charlen_type_node, -2); gfc_set_decl_location (len, &h->sym->declared_at); gfc_set_decl_location (addr, &h->sym->declared_at); GFC_DECL_STRING_LEN (field) = pushdecl_top_level (len); GFC_DECL_ASSIGN_ADDR (field) = pushdecl_top_level (addr); } /* If this field is volatile, mark it. */ if (h->sym->attr.volatile_) { tree new_type; TREE_THIS_VOLATILE (field) = 1; TREE_SIDE_EFFECTS (field) = 1; new_type = build_qualified_type (TREE_TYPE (field), TYPE_QUAL_VOLATILE); TREE_TYPE (field) = new_type; } h->field = field; }
static tree build_common_decl (gfc_common_head *com, tree union_type, bool is_init) { gfc_symbol *common_sym; tree decl; /* Create a namespace to store symbols for common blocks. */ if (gfc_common_ns == NULL) gfc_common_ns = gfc_get_namespace (NULL, 0); gfc_get_symbol (com->name, gfc_common_ns, &common_sym); decl = common_sym->backend_decl; /* Update the size of this common block as needed. */ if (decl != NULL_TREE) { tree size = TYPE_SIZE_UNIT (union_type); if (tree_int_cst_lt (DECL_SIZE_UNIT (decl), size)) { /* Named common blocks of the same name shall be of the same size in all scoping units of a program in which they appear, but blank common blocks may be of different sizes. */ if (strcmp (com->name, BLANK_COMMON_NAME)) gfc_warning ("Named COMMON block '%s' at %L shall be of the " "same size", com->name, &com->where); DECL_SIZE_UNIT (decl) = size; TREE_TYPE (decl) = union_type; } } /* If this common block has been declared in a previous program unit, and either it is already initialized or there is no new initialization for it, just return. */ if ((decl != NULL_TREE) && (!is_init || DECL_INITIAL (decl))) return decl; /* If there is no backend_decl for the common block, build it. */ if (decl == NULL_TREE) { decl = build_decl (input_location, VAR_DECL, get_identifier (com->name), union_type); gfc_set_decl_assembler_name (decl, gfc_sym_mangled_common_id (com)); TREE_PUBLIC (decl) = 1; TREE_STATIC (decl) = 1; DECL_IGNORED_P (decl) = 1; if (!com->is_bind_c) DECL_ALIGN (decl) = BIGGEST_ALIGNMENT; else { /* Do not set the alignment for bind(c) common blocks to BIGGEST_ALIGNMENT because that won't match what C does. Also, for common blocks with one element, the alignment must be that of the field within the common block in order to match what C will do. */ tree field = NULL_TREE; field = TYPE_FIELDS (TREE_TYPE (decl)); if (TREE_CHAIN (field) == NULL_TREE) DECL_ALIGN (decl) = TYPE_ALIGN (TREE_TYPE (field)); } DECL_USER_ALIGN (decl) = 0; GFC_DECL_COMMON_OR_EQUIV (decl) = 1; gfc_set_decl_location (decl, &com->where); if (com->threadprivate) DECL_TLS_MODEL (decl) = decl_default_tls_model (decl); /* Place the back end declaration for this common block in GLOBAL_BINDING_LEVEL. */ common_sym->backend_decl = pushdecl_top_level (decl); } /* Has no initial values. */ if (!is_init) { DECL_INITIAL (decl) = NULL_TREE; DECL_COMMON (decl) = 1; DECL_DEFER_OUTPUT (decl) = 1; } else { DECL_INITIAL (decl) = error_mark_node; DECL_COMMON (decl) = 0; DECL_DEFER_OUTPUT (decl) = 0; } return decl; }
void sdbout_symbol (tree decl, int local) { tree type = TREE_TYPE (decl); tree context = NULL_TREE; rtx value; int regno = -1; const char *name; /* If we are called before sdbout_init is run, just save the symbol for later. */ if (!sdbout_initialized) { preinit_symbols = tree_cons (0, decl, preinit_symbols); return; } sdbout_one_type (type); switch (TREE_CODE (decl)) { case CONST_DECL: /* Enum values are defined by defining the enum type. */ return; case FUNCTION_DECL: /* Don't mention a nested function under its parent. */ context = decl_function_context (decl); if (context == current_function_decl) return; /* Check DECL_INITIAL to distinguish declarations from definitions. Don't output debug info here for declarations; they will have a DECL_INITIAL value of 0. */ if (! DECL_INITIAL (decl)) return; if (!MEM_P (DECL_RTL (decl)) || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF) return; PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); PUT_SDB_VAL (XEXP (DECL_RTL (decl), 0)); PUT_SDB_SCL (TREE_PUBLIC (decl) ? C_EXT : C_STAT); break; case TYPE_DECL: /* Done with tagged types. */ if (DECL_NAME (decl) == 0) return; if (DECL_IGNORED_P (decl)) return; /* Don't output intrinsic types. GAS chokes on SDB .def statements that contain identifiers with embedded spaces (eg "unsigned long"). */ if (DECL_IS_BUILTIN (decl)) return; /* Output typedef name. */ if (template_name_p (DECL_NAME (decl))) PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); else PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (decl))); PUT_SDB_SCL (C_TPDEF); break; case PARM_DECL: /* Parm decls go in their own separate chains and are output by sdbout_reg_parms and sdbout_parms. */ gcc_unreachable (); case VAR_DECL: /* Don't mention a variable that is external. Let the file that defines it describe it. */ if (DECL_EXTERNAL (decl)) return; /* Ignore __FUNCTION__, etc. */ if (DECL_IGNORED_P (decl)) return; /* If there was an error in the declaration, don't dump core if there is no RTL associated with the variable doesn't exist. */ if (!DECL_RTL_SET_P (decl)) return; SET_DECL_RTL (decl, eliminate_regs (DECL_RTL (decl), VOIDmode, NULL_RTX)); #ifdef LEAF_REG_REMAP if (crtl->uses_only_leaf_regs) leaf_renumber_regs_insn (DECL_RTL (decl)); #endif value = DECL_RTL (decl); /* Don't mention a variable at all if it was completely optimized into nothingness. If DECL was from an inline function, then its rtl is not identically the rtl that was used in this particular compilation. */ if (REG_P (value)) { regno = REGNO (value); if (regno >= FIRST_PSEUDO_REGISTER) return; } else if (GET_CODE (value) == SUBREG) { while (GET_CODE (value) == SUBREG) value = SUBREG_REG (value); if (REG_P (value)) { if (REGNO (value) >= FIRST_PSEUDO_REGISTER) return; } regno = REGNO (alter_subreg (&value, true)); SET_DECL_RTL (decl, value); } /* Don't output anything if an auto variable gets RTL that is static. GAS version 2.2 can't handle such output. */ else if (MEM_P (value) && CONSTANT_P (XEXP (value, 0)) && ! TREE_STATIC (decl)) return; /* Emit any structure, union, or enum type that has not been output. This occurs for tag-less structs (et al) used to declare variables within functions. */ if (TREE_CODE (type) == ENUMERAL_TYPE || TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == QUAL_UNION_TYPE) { if (COMPLETE_TYPE_P (type) /* not a forward reference */ && KNOWN_TYPE_TAG (type) == 0) /* not yet declared */ sdbout_one_type (type); } /* Defer SDB information for top-level initialized variables! */ if (! local && MEM_P (value) && DECL_INITIAL (decl)) return; /* C++ in 2.3 makes nameless symbols. That will be fixed later. For now, avoid crashing. */ if (DECL_NAME (decl) == NULL_TREE) return; /* Record the name for, starting a symtab entry. */ if (local) name = IDENTIFIER_POINTER (DECL_NAME (decl)); else name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); if (MEM_P (value) && GET_CODE (XEXP (value, 0)) == SYMBOL_REF) { PUT_SDB_DEF (name); if (TREE_PUBLIC (decl)) { PUT_SDB_VAL (XEXP (value, 0)); PUT_SDB_SCL (C_EXT); } else { PUT_SDB_VAL (XEXP (value, 0)); PUT_SDB_SCL (C_STAT); } } else if (regno >= 0) { PUT_SDB_DEF (name); PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (regno)); PUT_SDB_SCL (C_REG); } else if (MEM_P (value) && (MEM_P (XEXP (value, 0)) || (REG_P (XEXP (value, 0)) && REGNO (XEXP (value, 0)) != HARD_FRAME_POINTER_REGNUM && REGNO (XEXP (value, 0)) != STACK_POINTER_REGNUM))) /* If the value is indirect by memory or by a register that isn't the frame pointer then it means the object is variable-sized and address through that register or stack slot. COFF has no way to represent this so all we can do is output the variable as a pointer. */ { PUT_SDB_DEF (name); if (REG_P (XEXP (value, 0))) { PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (REGNO (XEXP (value, 0)))); PUT_SDB_SCL (C_REG); } else { /* DECL_RTL looks like (MEM (MEM (PLUS (REG...) (CONST_INT...)))). We want the value of that CONST_INT. */ /* Encore compiler hates a newline in a macro arg, it seems. */ PUT_SDB_INT_VAL (DEBUGGER_AUTO_OFFSET (XEXP (XEXP (value, 0), 0))); PUT_SDB_SCL (C_AUTO); } /* Effectively do build_pointer_type, but don't cache this type, since it might be temporary whereas the type it points to might have been saved for inlining. */ /* Don't use REFERENCE_TYPE because dbx can't handle that. */ type = make_node (POINTER_TYPE); TREE_TYPE (type) = TREE_TYPE (decl); } else if (MEM_P (value) && ((GET_CODE (XEXP (value, 0)) == PLUS && REG_P (XEXP (XEXP (value, 0), 0)) && CONST_INT_P (XEXP (XEXP (value, 0), 1))) /* This is for variables which are at offset zero from the frame pointer. This happens on the Alpha. Non-frame pointer registers are excluded above. */ || (REG_P (XEXP (value, 0))))) { /* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...))) or (MEM (REG...)). We want the value of that CONST_INT or zero. */ PUT_SDB_DEF (name); PUT_SDB_INT_VAL (DEBUGGER_AUTO_OFFSET (XEXP (value, 0))); PUT_SDB_SCL (C_AUTO); } else { /* It is something we don't know how to represent for SDB. */ return; } break; default: break; } PUT_SDB_TYPE (plain_type (type)); PUT_SDB_ENDEF; }
static tree build_common_decl (gfc_common_head *com, tree union_type, bool is_init) { gfc_symbol *common_sym; tree decl; /* Create a namespace to store symbols for common blocks. */ if (gfc_common_ns == NULL) gfc_common_ns = gfc_get_namespace (NULL); gfc_get_symbol (com->name, gfc_common_ns, &common_sym); decl = common_sym->backend_decl; /* Update the size of this common block as needed. */ if (decl != NULL_TREE) { tree size = TYPE_SIZE_UNIT (union_type); if (tree_int_cst_lt (DECL_SIZE_UNIT (decl), size)) { /* Named common blocks of the same name shall be of the same size in all scoping units of a program in which they appear, but blank common blocks may be of different sizes. */ if (strcmp (com->name, BLANK_COMMON_NAME)) gfc_warning ("Named COMMON block '%s' at %L shall be of the " "same size", com->name, &com->where); DECL_SIZE_UNIT (decl) = size; } } /* If this common block has been declared in a previous program unit, and either it is already initialized or there is no new initialization for it, just return. */ if ((decl != NULL_TREE) && (!is_init || DECL_INITIAL (decl))) return decl; /* If there is no backend_decl for the common block, build it. */ if (decl == NULL_TREE) { decl = build_decl (VAR_DECL, get_identifier (com->name), union_type); SET_DECL_ASSEMBLER_NAME (decl, gfc_sym_mangled_common_id (com->name)); TREE_PUBLIC (decl) = 1; TREE_STATIC (decl) = 1; DECL_ALIGN (decl) = BIGGEST_ALIGNMENT; DECL_USER_ALIGN (decl) = 0; gfc_set_decl_location (decl, &com->where); /* Place the back end declaration for this common block in GLOBAL_BINDING_LEVEL. */ common_sym->backend_decl = pushdecl_top_level (decl); } /* Has no initial values. */ if (!is_init) { DECL_INITIAL (decl) = NULL_TREE; DECL_COMMON (decl) = 1; DECL_DEFER_OUTPUT (decl) = 1; } else { DECL_INITIAL (decl) = error_mark_node; DECL_COMMON (decl) = 0; DECL_DEFER_OUTPUT (decl) = 0; } return decl; }
static inline void unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr) { /* Note that the code for EXPR has already been unpacked to create EXPR in streamer_alloc_tree. */ if (!TYPE_P (expr)) { TREE_SIDE_EFFECTS (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_CONSTANT (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1); /* TREE_PUBLIC is used on types to indicate that the type has a TYPE_CACHED_VALUES vector. This is not streamed out, so we skip it here. */ TREE_PUBLIC (expr) = (unsigned) bp_unpack_value (bp, 1); } else bp_unpack_value (bp, 4); TREE_ADDRESSABLE (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_THIS_VOLATILE (expr) = (unsigned) bp_unpack_value (bp, 1); if (DECL_P (expr)) { DECL_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_NAMELESS (expr) = (unsigned) bp_unpack_value (bp, 1); } else if (TYPE_P (expr)) TYPE_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1); else bp_unpack_value (bp, 1); TREE_ASM_WRITTEN (expr) = (unsigned) bp_unpack_value (bp, 1); if (TYPE_P (expr)) TYPE_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1); else TREE_NO_WARNING (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_NOTHROW (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_STATIC (expr) = (unsigned) bp_unpack_value (bp, 1); if (TREE_CODE (expr) != TREE_BINFO) TREE_PRIVATE (expr) = (unsigned) bp_unpack_value (bp, 1); else bp_unpack_value (bp, 1); TREE_PROTECTED (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_DEPRECATED (expr) = (unsigned) bp_unpack_value (bp, 1); if (TYPE_P (expr)) { if (AGGREGATE_TYPE_P (expr)) TYPE_REVERSE_STORAGE_ORDER (expr) = (unsigned) bp_unpack_value (bp, 1); else TYPE_SATURATING (expr) = (unsigned) bp_unpack_value (bp, 1); TYPE_ADDR_SPACE (expr) = (unsigned) bp_unpack_value (bp, 8); } else if (TREE_CODE (expr) == BIT_FIELD_REF || TREE_CODE (expr) == MEM_REF) { REF_REVERSE_STORAGE_ORDER (expr) = (unsigned) bp_unpack_value (bp, 1); bp_unpack_value (bp, 8); } else if (TREE_CODE (expr) == SSA_NAME) { SSA_NAME_IS_DEFAULT_DEF (expr) = (unsigned) bp_unpack_value (bp, 1); bp_unpack_value (bp, 8); } else bp_unpack_value (bp, 9); }
bool cp_dump_tree (void* dump_info, tree t) { enum tree_code code; dump_info_p di = (dump_info_p) dump_info; /* Figure out what kind of node this is. */ code = TREE_CODE (t); if (DECL_P (t)) { if (DECL_LANG_SPECIFIC (t) && DECL_LANGUAGE (t) != lang_cplusplus) dump_string_field (di, "lang", language_to_string (DECL_LANGUAGE (t))); } switch (code) { case IDENTIFIER_NODE: if (IDENTIFIER_OPNAME_P (t)) { dump_string_field (di, "note", "operator"); return true; } else if (IDENTIFIER_TYPENAME_P (t)) { dump_child ("tynm", TREE_TYPE (t)); return true; } break; case OFFSET_TYPE: dump_string_field (di, "note", "ptrmem"); dump_child ("ptd", TYPE_PTRMEM_POINTED_TO_TYPE (t)); dump_child ("cls", TYPE_PTRMEM_CLASS_TYPE (t)); return true; case RECORD_TYPE: if (TYPE_PTRMEMFUNC_P (t)) { dump_string_field (di, "note", "ptrmem"); dump_child ("ptd", TYPE_PTRMEM_POINTED_TO_TYPE (t)); dump_child ("cls", TYPE_PTRMEM_CLASS_TYPE (t)); return true; } /* Fall through. */ case UNION_TYPE: /* Is it a type used as a base? */ if (TYPE_CONTEXT (t) && TREE_CODE (TYPE_CONTEXT (t)) == TREE_CODE (t) && CLASSTYPE_AS_BASE (TYPE_CONTEXT (t)) == t) { dump_child ("bfld", TYPE_CONTEXT (t)); return true; } if (! MAYBE_CLASS_TYPE_P (t)) break; dump_child ("vfld", TYPE_VFIELD (t)); if (CLASSTYPE_TEMPLATE_SPECIALIZATION(t)) dump_string(di, "spec"); if (!dump_flag (di, TDF_SLIM, t) && TYPE_BINFO (t)) { int i; tree binfo; tree base_binfo; for (binfo = TYPE_BINFO (t), i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i) { dump_child ("base", BINFO_TYPE (base_binfo)); if (BINFO_VIRTUAL_P (base_binfo)) dump_string_field (di, "spec", "virt"); dump_access (di, base_binfo); } } break; case FIELD_DECL: dump_access (di, t); if (DECL_MUTABLE_P (t)) dump_string_field (di, "spec", "mutable"); break; case VAR_DECL: if (TREE_CODE (CP_DECL_CONTEXT (t)) == RECORD_TYPE) dump_access (di, t); if (TREE_STATIC (t) && !TREE_PUBLIC (t)) dump_string_field (di, "link", "static"); break; case FUNCTION_DECL: if (!DECL_THUNK_P (t)) { if (DECL_OVERLOADED_OPERATOR_P (t)) { dump_string_field (di, "note", "operator"); dump_op (di, t); } if (DECL_FUNCTION_MEMBER_P (t)) { dump_string_field (di, "note", "member"); dump_access (di, t); } if (DECL_PURE_VIRTUAL_P (t)) dump_string_field (di, "spec", "pure"); if (DECL_VIRTUAL_P (t)) dump_string_field (di, "spec", "virt"); if (DECL_CONSTRUCTOR_P (t)) dump_string_field (di, "note", "constructor"); if (DECL_DESTRUCTOR_P (t)) dump_string_field (di, "note", "destructor"); if (DECL_CONV_FN_P (t)) dump_string_field (di, "note", "conversion"); if (DECL_GLOBAL_CTOR_P (t)) dump_string_field (di, "note", "global init"); if (DECL_GLOBAL_DTOR_P (t)) dump_string_field (di, "note", "global fini"); if (DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (t)) dump_string_field (di, "note", "pseudo tmpl"); } else { tree virt = THUNK_VIRTUAL_OFFSET (t); dump_string_field (di, "note", "thunk"); if (DECL_THIS_THUNK_P (t)) dump_string_field (di, "note", "this adjusting"); else { dump_string_field (di, "note", "result adjusting"); if (virt) virt = BINFO_VPTR_FIELD (virt); } dump_int (di, "fixd", THUNK_FIXED_OFFSET (t)); if (virt) dump_int (di, "virt", tree_low_cst (virt, 0)); dump_child ("fn", DECL_INITIAL (t)); } break; case NAMESPACE_DECL: if (DECL_NAMESPACE_ALIAS (t)) dump_child ("alis", DECL_NAMESPACE_ALIAS (t)); else if (!dump_flag (di, TDF_SLIM, t)) dump_child ("dcls", cp_namespace_decls (t)); break; case TEMPLATE_DECL: dump_child ("rslt", DECL_TEMPLATE_RESULT (t)); dump_child ("inst", DECL_TEMPLATE_INSTANTIATIONS (t)); dump_child ("spcs", DECL_TEMPLATE_SPECIALIZATIONS (t)); dump_child ("prms", DECL_TEMPLATE_PARMS (t)); break; case OVERLOAD: dump_child ("crnt", OVL_CURRENT (t)); dump_child ("chan", OVL_CHAIN (t)); break; case TRY_BLOCK: dump_stmt (di, t); if (CLEANUP_P (t)) dump_string_field (di, "note", "cleanup"); dump_child ("body", TRY_STMTS (t)); dump_child ("hdlr", TRY_HANDLERS (t)); break; case EH_SPEC_BLOCK: dump_stmt (di, t); dump_child ("body", EH_SPEC_STMTS (t)); dump_child ("raises", EH_SPEC_RAISES (t)); break; case PTRMEM_CST: dump_child ("clas", PTRMEM_CST_CLASS (t)); dump_child ("mbr", PTRMEM_CST_MEMBER (t)); break; case THROW_EXPR: /* These nodes are unary, but do not have code class `1'. */ dump_child ("op 0", TREE_OPERAND (t, 0)); break; case AGGR_INIT_EXPR: { int i = 0; tree arg; aggr_init_expr_arg_iterator iter; dump_int (di, "ctor", AGGR_INIT_VIA_CTOR_P (t)); dump_child ("fn", AGGR_INIT_EXPR_FN (t)); FOR_EACH_AGGR_INIT_EXPR_ARG (arg, iter, t) { char buffer[32]; sprintf (buffer, "%u", i); dump_child (buffer, arg); i++; } dump_child ("decl", AGGR_INIT_EXPR_SLOT (t)); } break; case HANDLER: dump_stmt (di, t); dump_child ("parm", HANDLER_PARMS (t)); dump_child ("body", HANDLER_BODY (t)); break; case MUST_NOT_THROW_EXPR: dump_stmt (di, t); dump_child ("body", TREE_OPERAND (t, 0)); break; case USING_STMT: dump_stmt (di, t); dump_child ("nmsp", USING_STMT_NAMESPACE (t)); break; case CLEANUP_STMT: dump_stmt (di, t); dump_child ("decl", CLEANUP_DECL (t)); dump_child ("expr", CLEANUP_EXPR (t)); dump_child ("body", CLEANUP_BODY (t)); break; case IF_STMT: dump_stmt (di, t); dump_child ("cond", IF_COND (t)); dump_child ("then", THEN_CLAUSE (t)); dump_child ("else", ELSE_CLAUSE (t)); break; case BREAK_STMT: case CONTINUE_STMT: dump_stmt (di, t); break; case DO_STMT: dump_stmt (di, t); dump_child ("body", DO_BODY (t)); dump_child ("cond", DO_COND (t)); break; case FOR_STMT: dump_stmt (di, t); dump_child ("init", FOR_INIT_STMT (t)); dump_child ("cond", FOR_COND (t)); dump_child ("expr", FOR_EXPR (t)); dump_child ("body", FOR_BODY (t)); break; case SWITCH_STMT: dump_stmt (di, t); dump_child ("cond", SWITCH_STMT_COND (t)); dump_child ("body", SWITCH_STMT_BODY (t)); break; case WHILE_STMT: dump_stmt (di, t); dump_child ("cond", WHILE_COND (t)); dump_child ("body", WHILE_BODY (t)); break; case STMT_EXPR: dump_child ("stmt", STMT_EXPR_STMT (t)); break; case EXPR_STMT: dump_stmt (di, t); dump_child ("expr", EXPR_STMT_EXPR (t)); break; default: break; }
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); }