diff options
Diffstat (limited to 'gcc')
24 files changed, 922 insertions, 28 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e8f83027bf2..7acb781f7db 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,47 @@ +2009-08-31 Dodji Seketeli <dodji@redhat.com> + + PR debug/30161 + * cgraph.h (cgraph_get_node): Declare ... + * cgraph.c (cgraph_get_node): ... new function. + * dwarf2out.c (gen_generic_params_dies, + generic_parameter_die, tree_add_const_value_attribute_for_decl, + make_ith_pack_parameter_name, + append_entry_to_tmpl_value_parm_die_table, + gen_remaining_tmpl_value_param_die_attribute): New functions. + (gen_subprogram_die): Generate debug info for template parameters + if debug info level is higher than DINFO_LEVEL_TERSE. + Use tree_add_const_value_attribute_for_decl instead of + tree_add_const_value_attribute. + (gen_const_die): Use tree_add_const_value_attribute_for_decl + instead of tree_add_const_value_attribute. + (gen_struct_or_union_type_die): Generate debug + info for template parameters if debug info level is higher than + DINFO_LEVEL_TERSE. + (tree_add_const_value_attribute): Handle integral and pointer + constants. Update comment. + (dwarf_tag_name): Support DW_TAG_GNU_template_template_param. + (dwarf_attr_name): Support DW_AT_GNU_template_name. + (reference_to_unused): Fix thinko. Remove redundant predicates from + tests. + (tree_add_const_value_attribute): Make this work for constant + expressions only. + tree_add_const_value_attribute_for_decl is to be used for variable + DECLs now. + (add_location_or_const_value_attribute): Use + tree_add_const_value_attribute_for_decl now. + (dwarf2out_finish): Emit the DW_AT_const_value attribute of + DW_TAG_template_value_param DIEs after function DIEs have been + emitted. + * langhooks.h (lang_hooks_for_types): Add + get_argument_pack_elems. + (lang_hooks_for_decls): Add generic_generic_parameter_decl_p. + (lang_hooks): Added get_innermost_generic_parms, + get_innermost_generic_args. + * langhooks-def.h (LANG_HOOKS_GET_INNERMOST_GENERIC_PARMS, + LANG_HOOKS_GET_INNERMOST_GENERIC_ARGS, + LANG_HOOKS_GET_ARGUMENT_PACK_ELEMS, + LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P): New language hooks. + 2009-08-31 DJ Delorie <dj@redhat.com> * config/mep/mep.c (machine_function): Add frame_locked flag. Set @@ -11,6 +55,7 @@ (mep_return_in_memory): Zero-sized objects are passed in memory. (mep_reorg_noframe): Make sure we have accurate REG_DEAD notes. + 2009-08-31 Richard Guenther <rguenther@suse.de> * builtins.c (fold_builtin_memory_op): Use the alias oracle diff --git a/gcc/cgraph.c b/gcc/cgraph.c index ded99f9cb81..f7a0f96245f 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -493,6 +493,29 @@ cgraph_node (tree decl) return node; } +/* Returns the cgraph node assigned to DECL or NULL if no cgraph node + is assigned. */ + +struct cgraph_node * +cgraph_get_node (tree decl) +{ + struct cgraph_node key, *node = NULL, **slot; + + gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); + + if (!cgraph_hash) + cgraph_hash = htab_create_ggc (10, hash_node, eq_node, NULL); + + key.decl = decl; + + slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, + NO_INSERT); + + if (slot && *slot) + node = *slot; + return node; +} + /* Insert already constructed node into hashtable. */ void diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 3e195208805..6eadc27f230 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -388,6 +388,8 @@ void cgraph_node_remove_callees (struct cgraph_node *node); struct cgraph_edge *cgraph_create_edge (struct cgraph_node *, struct cgraph_node *, gimple, gcov_type, int, int); + +struct cgraph_node * cgraph_get_node (tree); struct cgraph_node *cgraph_node (tree); struct cgraph_node *cgraph_node_for_asm (tree asmname); struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple); diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 78d075eca7d..fa5bc97ba0a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,26 @@ +2009-08-31 Dodji Seketeli <dodji@redhat.com> + + PR debug/30161 + * cp-tree.h (get_template_info): Parameter should be const. + (CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P): Fix typo. + (get_template_argument_pack_elems, + get_primary_template_innermost_parameters, + get_template_innermost_arguments, template_template_parameter_p): + Declare ... + * pt.c (get_template_argument_pack_elems, + get_template_innermost_parameters, get_template_innermost_arguments, + template_template_parameter_p): + ... New C++ front end implementation of new language hooks. + (primary_template_instantiation_p): New private helper. + (make_ith_pack_parameter_name): Use snprintf and strnlen instead of + printf and strlen. + (get_template_info): Const-ify parameter. + * cp-lang.c (LANG_HOOKS_GET_INNERMOST_GENERIC_PARMS, + LANG_HOOKS_GET_INNERMOST_GENERIC_ARGS, + LANG_HOOKS_GET_ARGUMENT_PACK_ELEMS, + LANG_HOOKS_GENERIC_TYPE_PARAMETER_DECL_P): Initialize these + interfaces for the C++ front-end. + 2009-08-31 Jason Merrill <jason@redhat.com> PR c++/41127 diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c index c8fa77c2099..bd35a65c031 100644 --- a/gcc/cp/cp-lang.c +++ b/gcc/cp/cp-lang.c @@ -49,6 +49,20 @@ static enum classify_record cp_classify_record (tree type); #define LANG_HOOKS_CLASSIFY_RECORD cp_classify_record #undef LANG_HOOKS_GENERIC_TYPE_P #define LANG_HOOKS_GENERIC_TYPE_P class_tmpl_impl_spec_p + +#undef LANG_HOOKS_GET_INNERMOST_GENERIC_PARMS +#define LANG_HOOKS_GET_INNERMOST_GENERIC_PARMS \ + get_primary_template_innermost_parameters +#undef LANG_HOOKS_GET_INNERMOST_GENERIC_ARGS +#define LANG_HOOKS_GET_INNERMOST_GENERIC_ARGS \ + get_template_innermost_arguments +#undef LANG_HOOKS_GET_ARGUMENT_PACK_ELEMS +#define LANG_HOOKS_GET_ARGUMENT_PACK_ELEMS \ + get_template_argument_pack_elems +#undef LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P +#define LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P \ + template_template_parameter_p + #undef LANG_HOOKS_DECL_PRINTABLE_NAME #define LANG_HOOKS_DECL_PRINTABLE_NAME cxx_printable_name #undef LANG_HOOKS_DWARF_NAME diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ff9ca7b45a6..44801032dcf 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3283,7 +3283,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P(NODE) \ (CLASS_TYPE_P (NODE) \ && CLASSTYPE_USE_TEMPLATE (NODE) \ - && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (arg))) + && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE))) #define DECL_TEMPLATE_INSTANTIATION(NODE) (DECL_USE_TEMPLATE (NODE) & 1) #define CLASSTYPE_TEMPLATE_INSTANTIATION(NODE) \ @@ -4638,7 +4638,7 @@ extern bool uses_parameter_packs (tree); extern bool template_parameter_pack_p (const_tree); extern tree make_pack_expansion (tree); extern bool check_for_bare_parameter_packs (tree); -extern tree get_template_info (tree); +extern tree get_template_info (const_tree); extern tree get_types_needing_access_check (tree); extern int template_class_depth (tree); extern int is_specialization_of (tree, tree); @@ -4680,6 +4680,10 @@ extern bool explicit_class_specialization_p (tree); extern struct tinst_level *outermost_tinst_level(void); extern bool parameter_of_template_p (tree, tree); extern void init_template_processing (void); +bool template_template_parameter_p (const_tree); +extern tree get_primary_template_innermost_parameters (const_tree); +extern tree get_template_innermost_arguments (const_tree); +extern tree get_template_argument_pack_elems (const_tree); /* in repo.c */ extern void init_repo (void); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b8561401881..03b89fa35a5 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -191,6 +191,7 @@ static tree tsubst_decl (tree, tree, tsubst_flags_t); static void perform_typedefs_access_check (tree tmpl, tree targs); static void append_type_to_template_for_access_check_1 (tree, tree, tree); static hashval_t iterative_hash_template_arg (tree arg, hashval_t val); +static bool primary_template_instantiation_p (const_tree); /* Make the current scope suitable for access checking when we are processing T. T can be FUNCTION_DECL for instantiated function @@ -287,7 +288,7 @@ finish_member_template_decl (tree decl) /* Return the template info node corresponding to T, whatever T is. */ tree -get_template_info (tree t) +get_template_info (const_tree t) { tree tinfo = NULL_TREE; @@ -2660,15 +2661,90 @@ static tree make_ith_pack_parameter_name (tree name, int i) { /* Munge the name to include the parameter index. */ - char numbuf[128]; +#define NUMBUF_LEN 128 + char numbuf[NUMBUF_LEN]; char* newname; - - sprintf(numbuf, "%i", i); - newname = (char*)alloca (IDENTIFIER_LENGTH (name) + strlen(numbuf) + 2); - sprintf(newname, "%s#%i", IDENTIFIER_POINTER (name), i); + int newname_len; + + snprintf (numbuf, NUMBUF_LEN, "%i", i); + newname_len = IDENTIFIER_LENGTH (name) + + strnlen (numbuf, NUMBUF_LEN) + 2; + newname = (char*)alloca (newname_len); + snprintf (newname, newname_len, + "%s#%i", IDENTIFIER_POINTER (name), i); return get_identifier (newname); } +/* Return true if T is a primary function + or class template instantiation. */ + +static bool +primary_template_instantiation_p (const_tree t) +{ + if (!t) + return false; + + if (TREE_CODE (t) == FUNCTION_DECL) + return DECL_LANG_SPECIFIC (t) + && DECL_TEMPLATE_INSTANTIATION (t) + && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t)); + else if (CLASS_TYPE_P (t)) + return CLASSTYPE_TEMPLATE_INSTANTIATION (t) + && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t)); + return false; +} + +/* Return true if PARM is a template template parameter. */ + +bool +template_template_parameter_p (const_tree parm) +{ + return DECL_TEMPLATE_TEMPLATE_PARM_P (parm); +} + +/* Return the template parameters of T if T is a + primary template instantiation, NULL otherwise. */ + +tree +get_primary_template_innermost_parameters (const_tree t) +{ + tree parms = NULL, template_info = NULL; + + if ((template_info = get_template_info (t)) + && primary_template_instantiation_p (t)) + parms = INNERMOST_TEMPLATE_PARMS + (DECL_TEMPLATE_PARMS (TI_TEMPLATE (template_info))); + + return parms; +} + +/* Returns the template arguments of T if T is a template instantiation, + NULL otherwise. */ + +tree +get_template_innermost_arguments (const_tree t) +{ + tree args = NULL, template_info = NULL; + + if ((template_info = get_template_info (t)) + && TI_ARGS (template_info)) + args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (template_info)); + + return args; +} + +/* Return the arguments pack of T if T is a template, NULL otherwise. */ + +tree +get_template_argument_pack_elems (const_tree t) +{ + if (TREE_CODE (t) != TYPE_ARGUMENT_PACK + && TREE_CODE (t) != NONTYPE_ARGUMENT_PACK) + return NULL; + + return ARGUMENT_PACK_ARGS (t); +} + /* Structure used to track the progress of find_parameter_packs_r. */ struct find_parameter_pack_data { diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 9ff6a172a08..c9c0188b4d1 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -5551,6 +5551,14 @@ static GTY ((param_is (struct die_struct))) htab_t decl_die_table; The key is DECL_UID() ^ die_parent. */ static GTY ((param_is (struct die_struct))) htab_t common_block_die_table; +typedef struct GTY(()) die_arg_entry_struct { + dw_die_ref die; + tree arg; +} die_arg_entry; + +DEF_VEC_O(die_arg_entry); +DEF_VEC_ALLOC_O(die_arg_entry,gc); + /* Node of the variable location list. */ struct GTY ((chain_next ("%h.next"))) var_loc_node { rtx GTY (()) var_loc_note; @@ -5691,6 +5699,8 @@ static GTY(()) struct dwarf_file_data * file_table_last_lookup; within the current function. */ static HOST_WIDE_INT frame_pointer_fb_offset; +static GTY(()) VEC(die_arg_entry,gc) *tmpl_value_parm_die_table; + /* Forward declarations for functions defined in this file. */ static int is_pseudo_reg (const_rtx); @@ -5826,6 +5836,7 @@ static dw_die_ref base_type_die (tree); static int is_base_type (tree); static dw_die_ref subrange_type_die (tree, tree, tree, dw_die_ref); static dw_die_ref modified_type_die (tree, int, int, dw_die_ref); +static dw_die_ref generic_parameter_die (tree, tree, dw_die_ref, int); static int type_is_enum (const_tree); static unsigned int dbx_reg_number (const_rtx); static void add_loc_descr_op_piece (dw_loc_descr_ref *, int); @@ -5861,6 +5872,7 @@ static rtx rtl_for_decl_location (tree); static void add_location_or_const_value_attribute (dw_die_ref, tree, enum dwarf_attribute); static void tree_add_const_value_attribute (dw_die_ref, tree); +static void tree_add_const_value_attribute_for_decl (dw_die_ref, tree); static void add_name_attribute (dw_die_ref, const char *); static void add_comp_dir_attribute (dw_die_ref); static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree); @@ -5924,6 +5936,8 @@ static dw_die_ref declare_in_namespace (tree, dw_die_ref); static struct dwarf_file_data * lookup_filename (const char *); static void retry_incomplete_types (void); static void gen_type_die_for_member (tree, tree, dw_die_ref); +static tree make_ith_pack_parameter_name (tree, int); +static void gen_generic_params_dies (tree); static void splice_child_die (dw_die_ref, dw_die_ref); static int file_info_cmp (const void *, const void *); static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *, @@ -5941,6 +5955,8 @@ static void prune_unused_types_walk_attribs (dw_die_ref); static void prune_unused_types_prune (dw_die_ref); static void prune_unused_types (void); static int maybe_emit_file (struct dwarf_file_data *fd); +static void append_entry_to_tmpl_value_parm_die_table (dw_die_ref, tree); +static void gen_remaining_tmpl_value_param_die_attribute (void); /* Section names used to hold DWARF debugging information. */ #ifndef DEBUG_INFO_SECTION @@ -6237,6 +6253,8 @@ dwarf_tag_name (unsigned int tag) return "DW_TAG_GNU_BINCL"; case DW_TAG_GNU_EINCL: return "DW_TAG_GNU_EINCL"; + case DW_TAG_GNU_template_template_param: + return "DW_TAG_GNU_template_template_param"; default: return "DW_TAG_<unknown>"; } @@ -6438,6 +6456,8 @@ dwarf_attr_name (unsigned int attr) return "DW_AT_body_end"; case DW_AT_GNU_vector: return "DW_AT_GNU_vector"; + case DW_AT_GNU_template_name: + return "DW_AT_GNU_template_name"; case DW_AT_VMS_rtnbeg_pd_address: return "DW_AT_VMS_rtnbeg_pd_address"; @@ -10353,6 +10373,189 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, return mod_type_die; } +/* Generate a new name for the parameter pack name NAME (an + IDENTIFIER_NODE) that incorporates its */ + +static tree +make_ith_pack_parameter_name (tree name, int i) +{ + /* Munge the name to include the parameter index. */ +#define NUMBUF_LEN 128 + char numbuf[NUMBUF_LEN]; + char* newname; + int newname_len; + + snprintf (numbuf, NUMBUF_LEN, "%i", i); + newname_len = IDENTIFIER_LENGTH (name) + + strnlen (numbuf, NUMBUF_LEN) + 2; + newname = (char*) alloca (newname_len); + snprintf (newname, newname_len, + "%s#%i", IDENTIFIER_POINTER (name), i); + return get_identifier (newname); +} + +/* Generate DIEs for the generic parameters of T. + T must be either a generic type or a generic function. + See http://gcc.gnu.org/wiki/TemplateParmsDwarf for more. */ + +static void +gen_generic_params_dies (tree t) +{ + tree parms, args; + int parms_num, i; + dw_die_ref die = NULL; + + if (!t || (TYPE_P (t) && !COMPLETE_TYPE_P (t))) + return; + + if (TYPE_P (t)) + die = lookup_type_die (t); + else if (DECL_P (t)) + die = lookup_decl_die (t); + + gcc_assert (die); + + parms = lang_hooks.get_innermost_generic_parms (t); + if (!parms) + /* T has no generic parameter. It means T is neither a generic type + or function. End of story. */ + return; + + parms_num = TREE_VEC_LENGTH (parms); + args = lang_hooks.get_innermost_generic_args (t); + for (i = 0; i < parms_num; i++) + { + tree parm, arg; + + parm = TREE_VEC_ELT (parms, i); + arg = TREE_VEC_ELT (args, i); + if (parm && TREE_VALUE (parm) && arg) + { + tree pack_elems = + lang_hooks.types.get_argument_pack_elems (arg); + if (pack_elems) + { + /* So ARG is an argument pack and the elements of that pack + are stored in PACK_ELEMS. */ + int i, len; + + len = TREE_VEC_LENGTH (pack_elems); + for (i = 0; i < len; i++) + generic_parameter_die (TREE_VALUE (parm), + TREE_VEC_ELT (pack_elems, i), + die, i); + } + else /* Arg is not an argument pack. */ + generic_parameter_die (TREE_VALUE (parm), + arg, die, + -1/* Not a param pack. */); + } + } +} + +/* Create and return a DIE for PARM which should be + the representation of a generic type parameter. + For instance, in the C++ front end, PARM would be a template parameter. + ARG is the argument to PARM. + PARENT_DIE is the parent DIE which the new created DIE should be added to, + as a child node. + PACK_ELEM_INDEX is >= 0 if PARM is a generic parameter pack, and if ARG + is one of the unpacked elements of the parameter PACK. In that case, + PACK_ELEM_INDEX is the index of ARG in the parameter pack. */ + +static dw_die_ref +generic_parameter_die (tree parm, tree arg, dw_die_ref parent_die, + int pack_elem_index) +{ + dw_die_ref tmpl_die = NULL; + const char *name = NULL; + + if (!parm || !DECL_NAME (parm) || !arg) + return NULL; + + /* We support non-type generic parameters and arguments, + type generic parameters and arguments, as well as + generic generic parameters (a.k.a. template template parameters in C++) + and arguments. */ + if (TREE_CODE (parm) == PARM_DECL) + /* PARM is a nontype generic parameter */ + tmpl_die = new_die (DW_TAG_template_value_param, parent_die, parm); + else if (TREE_CODE (parm) == TYPE_DECL) + /* PARM is a type generic parameter. */ + tmpl_die = new_die (DW_TAG_template_type_param, parent_die, parm); + else if (lang_hooks.decls.generic_generic_parameter_decl_p (parm)) + /* PARM is a generic generic parameter. + Its DIE is a GNU extension. It shall have a + DW_AT_name attribute to represent the name of the template template + parameter, and a DW_AT_GNU_template_name attribute to represent the + name of the template template argument. */ + tmpl_die = new_die (DW_TAG_GNU_template_template_param, + parent_die, parm); + else + gcc_unreachable (); + + if (tmpl_die) + { + tree tmpl_type; + + if (pack_elem_index >= 0) + { + /* PARM is an element of a parameter pack. + Generate a name for it. */ + tree identifier = make_ith_pack_parameter_name (DECL_NAME (parm), + pack_elem_index); + if (identifier) + name = IDENTIFIER_POINTER (identifier); + } + else + name = IDENTIFIER_POINTER (DECL_NAME (parm)); + + gcc_assert (name); + add_AT_string (tmpl_die, DW_AT_name, name); + + if (!lang_hooks.decls.generic_generic_parameter_decl_p (parm)) + { + /* DWARF3, 5.6.8 says if PARM is a non-type generic parameter + TMPL_DIE should have a child DW_AT_type attribute that is set + to the type of the argument to PARM, which is ARG. + If PARM is a type generic parameter, TMPL_DIE should have a + child DW_AT_type that is set to ARG. */ + tmpl_type = TYPE_P (arg) ? arg : TREE_TYPE (arg); + add_type_attribute (tmpl_die, tmpl_type, 0, + TREE_THIS_VOLATILE (tmpl_type), + parent_die); + } + else + { + /* So TMPL_DIE is a DIE representing a + a generic generic template parameter, a.k.a template template + parameter in C++ and arg is a template. */ + + /* The DW_AT_GNU_template_name attribute of the DIE must be set + to the name of the argument. */ + name = dwarf2_name (TYPE_P (arg) ? TYPE_NAME (arg) : arg, 1); + add_AT_string (tmpl_die, DW_AT_GNU_template_name, name); + } + + if (TREE_CODE (parm) == PARM_DECL) + /* So PARM is a non-type generic parameter. + DWARF3 5.6.8 says we must set a DW_AT_const_value child + attribute of TMPL_DIE which value represents the value + of ARG. + We must be careful here: + The value of ARG might reference some function decls. + We might currently be emitting debug info for a generic + type and types are emitted before function decls, we don't + know if the function decls referenced by ARG will actually be + emitted after cgraph computations. + So must defer the generation of the DW_AT_const_value to + after cgraph is ready. */ + append_entry_to_tmpl_value_parm_die_table (tmpl_die, arg); + } + + return tmpl_die; +} + /* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is an enumerated type. */ @@ -12057,17 +12260,20 @@ reference_to_unused (tree * tp, int * walk_subtrees, else if (!cgraph_global_info_ready && (TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == FUNCTION_DECL)) return *tp; - else if (DECL_P (*tp) && TREE_CODE (*tp) == VAR_DECL) + else if (TREE_CODE (*tp) == VAR_DECL) { struct varpool_node *node = varpool_node (*tp); if (!node->needed) return *tp; } - else if (DECL_P (*tp) && TREE_CODE (*tp) == FUNCTION_DECL + else if (TREE_CODE (*tp) == FUNCTION_DECL && (!DECL_EXTERNAL (*tp) || DECL_DECLARED_INLINE_P (*tp))) { - struct cgraph_node *node = cgraph_node (*tp); - if (node->process || TREE_ASM_WRITTEN (*tp)) + /* The call graph machinery must have finished analyzing, + optimizing and gimplifying the CU by now. + So if *TP has no call graph node associated + to it, it means *TP will not be emitted. */ + if (!cgraph_get_node (*tp)) return *tp; } else if (TREE_CODE (*tp) == STRING_CST && !TREE_ASM_WRITTEN (*tp)) @@ -12639,7 +12845,7 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, } /* None of that worked, so it must not really have a location; try adding a constant value attribute from the DECL_INITIAL. */ - tree_add_const_value_attribute (die, decl); + tree_add_const_value_attribute_for_decl (die, decl); } /* Add VARIABLE and DIE into deferred locations list. */ @@ -12800,29 +13006,25 @@ native_encode_initializer (tree init, unsigned char *array, int size) } } -/* If we don't have a copy of this variable in memory for some reason (such - as a C++ member constant that doesn't have an out-of-line definition), - we should tell the debugger about the constant value. */ +/* Attach a DW_AT_const_value attribute to DIE. The value of the + attribute is the const value T. */ static void -tree_add_const_value_attribute (dw_die_ref var_die, tree decl) +tree_add_const_value_attribute (dw_die_ref die, tree t) { tree init; - tree type = TREE_TYPE (decl); + tree type = TREE_TYPE (t); rtx rtl; - if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL) + if (!t || !TREE_TYPE (t) || TREE_TYPE (t) == error_mark_node) return; - init = DECL_INITIAL (decl); - if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl) && init) - /* OK */; - else - return; + init = t; + gcc_assert (!DECL_P (init)); rtl = rtl_for_decl_init (init, type); if (rtl) - add_const_value_attribute (var_die, rtl); + add_const_value_attribute (die, rtl); /* If the host and target are sane, try harder. */ else if (CHAR_BIT == 8 && BITS_PER_UNIT == 8 && initializer_constant_valid_p (init, type)) @@ -12833,11 +13035,35 @@ tree_add_const_value_attribute (dw_die_ref var_die, tree decl) unsigned char *array = GGC_CNEWVEC (unsigned char, size); if (native_encode_initializer (init, array, size)) - add_AT_vec (var_die, DW_AT_const_value, size, 1, array); + add_AT_vec (die, DW_AT_const_value, size, 1, array); } } } +/* Attach a DW_AT_const_value attribute to VAR_DIE. The value of the + attribute is the const value of T, where T is an integral constant + variable with static storage duration + (so it can't be a PARM_DECL or a RESULT_DECL). */ + +static void +tree_add_const_value_attribute_for_decl (dw_die_ref var_die, tree decl) +{ + + if (!decl + || (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != CONST_DECL)) + return; + + if (TREE_READONLY (decl) + && ! TREE_THIS_VOLATILE (decl) + && DECL_INITIAL (decl)) + /* OK */; + else + return; + + tree_add_const_value_attribute (var_die, DECL_INITIAL (decl)); +} + /* Convert the CFI instructions for the current function into a location list. This is used for DW_AT_frame_base when we targeting a dwarf2 consumer that does not support the dwarf3 @@ -14534,6 +14760,10 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) loc_descriptor_from_tree (cfun->static_chain_decl)); } + /* Generate child dies for template paramaters. */ + if (debug_info_level > DINFO_LEVEL_TERSE) + gen_generic_params_dies (decl); + /* Now output descriptions of the arguments for this function. This gets (unnecessarily?) complex because of the fact that the DECL_ARGUMENT list for a FUNCTION_DECL doesn't indicate cases where there was a trailing @@ -14895,7 +15125,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) add_pubname (decl_or_origin, var_die); } else - tree_add_const_value_attribute (var_die, decl_or_origin); + tree_add_const_value_attribute_for_decl (var_die, decl_or_origin); } /* Generate a DIE to represent a named constant. */ @@ -14913,7 +15143,7 @@ gen_const_die (tree decl, dw_die_ref context_die) add_AT_flag (const_die, DW_AT_external, 1); if (DECL_ARTIFICIAL (decl)) add_AT_flag (const_die, DW_AT_artificial, 1); - tree_add_const_value_attribute (const_die, decl); + tree_add_const_value_attribute_for_decl (const_die, decl); } /* Generate a DIE to represent a label identifier. */ @@ -15332,6 +15562,11 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die, else remove_AT (type_die, DW_AT_declaration); + /* Generate child dies for template paramaters. */ + if (debug_info_level > DINFO_LEVEL_TERSE + && COMPLETE_TYPE_P (type)) + gen_generic_params_dies (type); + /* If this type has been completed, then give it a byte_size attribute and then give a list of members. */ if (complete && !ns_decl) @@ -16587,6 +16822,49 @@ maybe_emit_file (struct dwarf_file_data * fd) return fd->emitted_number; } +/* Schedule generation of a DW_AT_const_value attribute to DIE. + That generation should happen after function debug info has been + generated. The value of the attribute is the constant value of ARG. */ + +static void +append_entry_to_tmpl_value_parm_die_table (dw_die_ref die, tree arg) +{ + die_arg_entry entry; + + if (!die || !arg) + return; + + if (!tmpl_value_parm_die_table) + tmpl_value_parm_die_table + = VEC_alloc (die_arg_entry, gc, 32); + + entry.die = die; + entry.arg = arg; + VEC_safe_push (die_arg_entry, gc, + tmpl_value_parm_die_table, + &entry); +} + +/* Add a DW_AT_const_value attribute to DIEs that were scheduled + by append_entry_to_tmpl_value_parm_die_table. This function must + be called after function DIEs have been generated. */ + +static void +gen_remaining_tmpl_value_param_die_attribute (void) +{ + if (tmpl_value_parm_die_table) + { + unsigned i; + die_arg_entry *e; + + for (i = 0; + VEC_iterate (die_arg_entry, tmpl_value_parm_die_table, i, e); + i++) + tree_add_const_value_attribute (e->die, e->arg); + } +} + + /* Replace DW_AT_name for the decl with name. */ static void @@ -17346,6 +17624,8 @@ dwarf2out_finish (const char *filename) dw_die_ref die = 0; unsigned int i; + gen_remaining_tmpl_value_param_die_attribute (); + /* Add the name for the main input file now. We delayed this from dwarf2out_init to avoid complications with PCH. */ add_name_attribute (comp_unit_die, remap_debug_filename (filename)); diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index 2631ff8db7f..25d96e92fa2 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -153,6 +153,10 @@ extern tree lhd_make_node (enum tree_code); #define LANG_HOOKS_CLASSIFY_RECORD NULL #define LANG_HOOKS_INCOMPLETE_TYPE_ERROR lhd_incomplete_type_error #define LANG_HOOKS_GENERIC_TYPE_P hook_bool_const_tree_false +#define LANG_HOOKS_GET_INNERMOST_GENERIC_PARMS hook_tree_const_tree_null +#define LANG_HOOKS_GET_INNERMOST_GENERIC_ARGS hook_tree_const_tree_null +#define LANG_HOOKS_GET_ARGUMENT_PACK_ELEMS hook_tree_const_tree_null +#define LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P hook_bool_const_tree_false #define LANG_HOOKS_TYPE_PROMOTES_TO lhd_type_promotes_to #define LANG_HOOKS_REGISTER_BUILTIN_TYPE lhd_register_builtin_type #define LANG_HOOKS_TYPE_MAX_SIZE lhd_return_null_const_tree @@ -170,6 +174,7 @@ extern tree lhd_make_node (enum tree_code); LANG_HOOKS_TYPE_FOR_MODE, \ LANG_HOOKS_TYPE_FOR_SIZE, \ LANG_HOOKS_GENERIC_TYPE_P, \ + LANG_HOOKS_GET_ARGUMENT_PACK_ELEMS, \ LANG_HOOKS_TYPE_PROMOTES_TO, \ LANG_HOOKS_REGISTER_BUILTIN_TYPE, \ LANG_HOOKS_INCOMPLETE_TYPE_ERROR, \ @@ -206,6 +211,7 @@ extern tree lhd_make_node (enum tree_code); LANG_HOOKS_PUSHDECL, \ LANG_HOOKS_GETDECLS, \ LANG_HOOKS_FUNCTION_DECL_EXPLICIT_P, \ + LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P, \ LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL, \ LANG_HOOKS_WRITE_GLOBALS, \ LANG_HOOKS_DECL_OK_FOR_SIBCALL, \ @@ -259,6 +265,8 @@ extern tree lhd_make_node (enum tree_code); LANG_HOOKS_TREE_DUMP_INITIALIZER, \ LANG_HOOKS_DECLS, \ LANG_HOOKS_FOR_TYPES_INITIALIZER, \ + LANG_HOOKS_GET_INNERMOST_GENERIC_PARMS, \ + LANG_HOOKS_GET_INNERMOST_GENERIC_ARGS, \ LANG_HOOKS_GIMPLIFY_EXPR, \ LANG_HOOKS_FOLD_OBJ_TYPE_REF, \ LANG_HOOKS_BUILTIN_FUNCTION, \ diff --git a/gcc/langhooks.h b/gcc/langhooks.h index ed3e7e72919..d708bb2f867 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -91,6 +91,9 @@ struct lang_hooks_for_types e.g. C++ template implicit specializations. */ bool (*generic_p) (const_tree); + /* Returns the TREE_VEC of elements of a given generic argument pack. */ + tree (*get_argument_pack_elems) (const_tree); + /* Given a type, apply default promotions to unnamed function arguments and return the new type. Return the same type if no change. Required by any language that supports variadic @@ -165,6 +168,10 @@ struct lang_hooks_for_decls /* Returns true if DECL is explicit member function. */ bool (*function_decl_explicit_p) (tree); + /* Returns True if the parameter is a generic parameter decl + of a generic type, e.g a template template parameter for the C++ FE. */ + bool (*generic_generic_parameter_decl_p) (const_tree); + /* Returns true when we should warn for an unused global DECL. We will already have checked that it has static binding. */ bool (*warn_unused_global) (const_tree); @@ -380,6 +387,14 @@ struct lang_hooks struct lang_hooks_for_types types; + /* Retuns the generic parameters of an instantiation of + a generic type or decl, e.g. C++ template instantiation. */ + tree (*get_innermost_generic_parms) (const_tree); + + /* Returns the TREE_VEC of arguments of an instantiation + of a generic type of decl, e.g. C++ template instantiation. */ + tree (*get_innermost_generic_args) (const_tree); + /* Perform language-specific gimplification on the argument. Returns an enum gimplify_status, though we can't see that type here. */ int (*gimplify_expr) (tree *, gimple_seq *, gimple_seq *); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 67ea0ef5fc8..ff025948042 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,20 @@ +2009-08-31 Dodji Seketeli <dodji@redhat.com> + + PR debug/30161 + * g++.dg/debug/dwarf2/template-params-1.C: New test. + * g++.dg/debug/dwarf2/template-params-2.C: Likewise. + * g++.dg/debug/dwarf2/template-params-3.C: Likewise. + * g++.dg/debug/dwarf2/template-params-4.C: Likewise. + * g++.dg/debug/dwarf2/template-params-5.C: Likewise. + * g++.dg/debug/dwarf2/template-params-6.C: Likewise. + * g++.dg/debug/dwarf2/template-func-params-1.C: Likewise. + * g++.dg/debug/dwarf2/template-func-params-2.C: Likewise. + * g++.dg/debug/dwarf2/template-func-params-3.C: Likewise. + * g++.dg/debug/dwarf2/template-func-params-4.C: Likewise. + * g++.dg/debug/dwarf2/template-func-params-5.C: Likewise. + * g++.dg/debug/dwarf2/template-func-params-6.C: Likewise. + * g++.dg/debug/dwarf2/template-func-params-7.C: Likewise. + 2009-08-31 Jason Merrill <jason@redhat.com> PR c++/41127 diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-1.C new file mode 100644 index 00000000000..3a43d9fa571 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-1.C @@ -0,0 +1,16 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// origin PR debug/30161 +// { dg-options "-g -dA" } +// { dg-do compile } +// { dg-final { scan-assembler "DW_TAG_template_type_param" } } +// { dg-final { scan-assembler "U.*DW_AT_name" } } + +template <class U> +U +func(U m) +{ + return m; +} + +int i = func<int>(2); + diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-2.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-2.C new file mode 100644 index 00000000000..27c68d79643 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-2.C @@ -0,0 +1,22 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// origin PR debug/30161 +// { dg-options "-g -dA" } +// { dg-do compile } +// { dg-final { scan-assembler "DW_TAG_template_value_param" } } +// { dg-final { scan-assembler "i.*DW_AT_name" } } +// { dg-final { scan-assembler "3.*DW_AT_const_value" } } + + +template <int i> +int +func() +{ + int j = i; + return j; +} + +const int foo = 1; +const int bar = 2; + +int h = func<foo+bar>(); + diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-3.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-3.C new file mode 100644 index 00000000000..9f3dc8c2870 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-3.C @@ -0,0 +1,24 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin PR debug/30161 +// { dg-options "-g -dA" } +// { dg-final { scan-assembler "DW_TAG_template_value_param" } } +// { dg-final { scan-assembler "f.*DW_AT_name" } } +// { dg-final { scan-assembler "_Z4blehv.*DW_AT_const_value" } } + +typedef void (*func_ptr)(); + +template <func_ptr f> +int +func() +{ + f(); + return 0; +} + +void +bleh() +{ +} + +int c = func<bleh>(); + diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-4.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-4.C new file mode 100644 index 00000000000..0eb0fe5f138 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-4.C @@ -0,0 +1,32 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin PR debug/30161 +// { dg-options "-std=c++0x -g -dA" } +// { dg-final { scan-assembler "DW_TAG_template_type_param" } } +// { dg-final { scan-assembler "DW_AT_name.*P#0" } } +// { dg-final { scan-assembler "DW_AT_name.*P#1" } } +// { dg-final { scan-assembler "DW_AT_name.*P#2" } } + + +template <typename... Args> struct count; + +template <> +struct count<> +{ + static const int value = 0; +}; + +template <typename T, typename... Args> +struct count<T, Args...> +{ + static const int value = 1 + count<Args...>::value; +}; + +template<typename... P> +int +do_count() +{ + return count<P...>::value; +} + +int c = do_count<int, char, long>(); + diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-5.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-5.C new file mode 100644 index 00000000000..c4fd8dc3e77 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-5.C @@ -0,0 +1,28 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin PR debug/30161 +// { dg-options "-g -dA" } +// { dg-final { scan-assembler "DW_TAG_template_type_param" } } +// { dg-final { scan-assembler "T.*DW_AT_name" } } + +template <class T> +struct vector +{ + int size; + + vector () : size (0) + { + } +}; + + +template<template <class T> class U> +int +bar() +{ + U<int> u; + return u.size; +} + +vector<int> v; +int j = bar<vector>(); + diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-6.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-6.C new file mode 100644 index 00000000000..155add48ef4 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-6.C @@ -0,0 +1,38 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin PR debug/30161 +// { dg-options "-g -dA" } +// { dg-final { scan-assembler-times "DW_TAG_GNU_template_template_param" 2 } } +// { dg-final { scan-assembler-times "DW_AT_GNU_template_name: \"vector\"" 1 } } +// { dg-final { scan-assembler-times ".ascii \"U.0\".*?DW_AT_name" 1 } } + +template <class T> +struct vector_base +{ + + static int get_sizeof_t() + { + return 0; + } +}; + +template <class T> +struct vector : public vector_base<T> +{ + static int get_sizeof_t() + { + return sizeof (T); + } + T member1; + T member2; +}; + +template <template <class T> class U> +int +bar() +{ + return U<int>::get_sizeof_t(); +} + +int i = bar<vector>(); + + diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-7.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-7.C new file mode 100644 index 00000000000..07aece6917f --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-7.C @@ -0,0 +1,61 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin PR debug/30161 +// { dg-options "-g -dA -std=c++0x" } +// { dg-do compile } + +// There must be 5 subprograms generated: +// printf(const char*), printf<int, char, int>, +// printf<char, int>, printf<int> and foo(). +// { dg-final {scan-assembler-times "DIE \\(0x.*?\\) DW_TAG_subprogram" 5 } } + +// That makes 6 template type parameters. +// { dg-final {scan-assembler-times "DIE \\(0x.*?\\) DW_TAG_template_type_param" 6 } } +// { dg-final {scan-assembler-times "DW_AT_name: \"printf<int, char, int>\"" 1 } } +// { dg-final {scan-assembler-times "DW_AT_name: \"printf<char, int>\"" 1 } } +// { dg-final {scan-assembler-times "DW_AT_name: \"printf<int>\"" 1 } } +// { dg-final {scan-assembler-times "DW_AT_name: \"printf\"" 1 } } + +// printf<int, char, int> and printf<char, int> have a pack expansion as +// function parameters. In the former, the elements of the parameter pack +// expansion are PackTypes#0, PackTypes#1 and the arguments are args#0 and +// args#1. In the later, the element of the parameter pack expansion +// is PackTypes#0 and the argument is args#0. +// { dg-final {scan-assembler-times "DW_AT_name: \"PackTypes#0\"" 2 } } +// { dg-final {scan-assembler-times "DW_AT_name: \"args#0\"" 2 } } +// { dg-final {scan-assembler-times "DW_AT_name: \"PackTypes#1\"" 1 } } +// { dg-final {scan-assembler-times "DW_AT_name: \"args#1\"" 1 } } + +// { dg_final {scan-assembler-times "\.ascii \"T.0\"\[\t \]+.*?DW_AT_name" 3 } } + +void +printf(const char* s) +{ + /* Commented this to not pull std::cout into what should be + a simple test. + while (*s) + std::cout << *s++; + */ +} + +template<typename T, typename... PackTypes> +void +printf(const char* s, + T value, + PackTypes... args) +{ + while (*s) + { + if (*s == '%' && *++s != '%') + { + /* std::cout << value; */ + return printf(++s, args...); + } + } +} + +void +foo () +{ + int x; + printf("%c %d", x, 'x', 3); +} diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-1.C new file mode 100644 index 00000000000..e28297b5591 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-1.C @@ -0,0 +1,15 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// origin PR debug/30161 +// { dg-options "-g -dA" } +// { dg-do compile } +// { dg-final { scan-assembler "DW_TAG_template_type_param" } } +// { dg-final { scan-assembler "U.*DW_AT_name" } } + +template <class U> +class A +{ + U m; +}; + +A<int> a; + diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-2.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-2.C new file mode 100644 index 00000000000..ce5fbab74b0 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-2.C @@ -0,0 +1,23 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// origin PR debug/30161 +// { dg-options "-g -dA" } +// { dg-do compile } +// { dg-final { scan-assembler "DW_TAG_template_value_param" } } +// { dg-final { scan-assembler "i.*DW_AT_name" } } +// { dg-final { scan-assembler "3.*DW_AT_const_value" } } + +template <int i> +struct A +{ + int m; + A () + { + m = i; + } +}; + +const int foo = 1; +const int bar = 2; + +A<foo+bar> a; + diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-3.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-3.C new file mode 100644 index 00000000000..06b0e2b821a --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-3.C @@ -0,0 +1,25 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin PR debug/30161 +// { dg-options "-g -dA" } +// { dg-final { scan-assembler "DW_TAG_template_value_param" } } +// { dg-final { scan-assembler "f.*DW_AT_name" } } +// { dg-final { scan-assembler "_Z4blehv.*DW_AT_const_value" } } + +typedef void (*func_ptr) (); + +template <func_ptr f> +struct A +{ + A () + { + f (); + } +}; + +void +bleh () +{ +} + +A<bleh> a; + diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-4.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-4.C new file mode 100644 index 00000000000..09d1d95de6b --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-4.C @@ -0,0 +1,30 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin PR debug/30161 +// { dg-options "-std=c++0x -g -dA" } +// { dg-final { scan-assembler "DW_TAG_template_type_param" } } +// { dg-final { scan-assembler "DW_AT_name.*Args#0" } } +// { dg-final { scan-assembler "DW_AT_name.*Args#1" } } +// { dg-final { scan-assembler "DW_AT_name.*Args#2" } } + +template <typename... Args> struct count; + +template <> +struct count<> +{ + static const int value = 0; +}; + +template <typename T, typename... Args> +struct count<T, Args...> +{ + static const int value = 1 + count<Args...>::value; +}; + +int +foo () +{ + count<int, char, long> c; + int nb = count<int, char, long>::value; + return nb; +} + diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-5.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-5.C new file mode 100644 index 00000000000..f36eac5f334 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-5.C @@ -0,0 +1,29 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin PR debug/30161 +// { dg-options "-g -dA" } +// { dg-final { scan-assembler "DW_TAG_template_type_param" } } +// { dg-final { scan-assembler "T.*DW_AT_name" } } + +template <class T> +struct vector +{ + int size; + + vector () : size (0) + { + } +}; + +template<template <class T> class U> +struct bar +{ + U<int> u; + int m; + bar () : m (u.size) + { + } +}; + +vector<int> v; +bar<vector> b; + diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-6.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-6.C new file mode 100644 index 00000000000..dc401fa06e7 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-6.C @@ -0,0 +1,44 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin PR debug/30161 +// { dg-options "-g -dA" } +// { dg-final { scan-assembler-times "DW_TAG_GNU_template_template_param" 2 } } +// { dg-final { scan-assembler-times "DW_AT_GNU_template_name: \"vector\"" 1 } } +// { dg-final { scan-assembler-times ".ascii \"U.0\".*?DW_AT_name" 1 } } + +template <class T> +struct vector_base +{ + T tab[3 + 1]; + static int get_sizeof_t() + { + return sizeof (tab); + } +}; + +template <class T> +struct vector : public vector_base<T> +{ + static int get_sizeof_t() + { + return sizeof (T); + } + T member1; + T member2; +}; + +template <template <class T> class U> +struct bar +{ + int foo() + { + return U<int>::get_sizeof_t (); + } +}; + + +int +foo_func () +{ + bar<vector> b; + return b.foo (); +} |