From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 20996 invoked by alias); 22 Aug 2016 11:36:00 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 19822 invoked by uid 89); 22 Aug 2016 11:35:59 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.5 required=5.0 tests=AWL,BAYES_00,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.2 spammy=sk:c_commo, iff, UD:safe_push, *iter X-HELO: mail-wm0-f50.google.com Received: from mail-wm0-f50.google.com (HELO mail-wm0-f50.google.com) (74.125.82.50) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 22 Aug 2016 11:35:49 +0000 Received: by mail-wm0-f50.google.com with SMTP id f65so116320117wmi.0 for ; Mon, 22 Aug 2016 04:35:48 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=IUyWTXOoWN93TaeQhzyb69FreePBO+stzzSIGaveYIA=; b=Rr6GvLoxxQczvaBNHNZN/vqpkKizdxvv3Xc6WwmLH2FjhqomZShZrqgjzgegX/2pxg VUnybbCKc3YNVzvy02cXpgeeyZpc7F6NFmscLznFrliyUUE5o5/viTLBihkQ/js+o8K3 KmYnm+1ON+lqEsXlaI/lJ74oejSH2G8UPMavtuqUnI7p4aZjNGubQENLkB3H7Iqw1HjV DWFlIHKEMBgfpI+H3AnxjOCVndUAFFmNIsKmsBGE15k44WRNS7HHmxTnx9ZZZf1THHRB pcO4tQFqkaeCox1KHMlhRSprEs/3g5tVQd1gNTkQi2rY2x9F4kb2LUK+ovmYCq5bo8FL kRzw== X-Gm-Message-State: AEkoouthNjDA7YrXhZy6fAbyzLPh4SR9pP0A2fN1fDoSmtoM2Ymi0YZJ4nvzRxxRD9n2T4HmNBXbyHR3B2X/ug== X-Received: by 10.28.67.198 with SMTP id q189mr8516937wma.71.1471865746601; Mon, 22 Aug 2016 04:35:46 -0700 (PDT) MIME-Version: 1.0 Received: by 10.28.137.202 with HTTP; Mon, 22 Aug 2016 04:35:45 -0700 (PDT) In-Reply-To: References: From: Richard Biener Date: Mon, 22 Aug 2016 11:36:00 -0000 Message-ID: Subject: Re: [PR59319] output friends in debug info To: Alexandre Oliva Cc: GCC Patches Content-Type: text/plain; charset=UTF-8 X-IsSubscribed: yes X-SW-Source: 2016-08/txt/msg01520.txt.bz2 On Fri, Aug 19, 2016 at 8:46 PM, Alexandre Oliva wrote: > This is not a finished patch. There are two issues I'd like feedback > on before a final submission. See them below. First, a general > description. > > Handling non-template friends is kind of easy, but it required a bit > of infrastructure in dwarf2out to avoid (i) forcing debug info for > unused types or functions: DW_TAG_friend DIEs are only emitted if > their DW_AT_friend DIE is emitted, and (ii) creating DIEs for such > types or functions just to have them discarded at the end. To this > end, I introduced a list (vec, actually) of types with friends, > processed at the end of the translation unit, and a list of > DW_TAG_friend DIEs that, when we're pruning unused types, reference > DIEs that are still not known to be used, revisited after we finish > deciding all other DIEs, so that we prune DIEs that would have > referenced pruned types or functions. > > Handlig template friends turned out to be trickier: there's no > representation in DWARF for templates. I decided to give debuggers as > much information as possible, enumerating all specializations of > friend templates and outputting DW_TAG_friend DIEs referencing them as > well, but marking them as DW_AT_artificial to indicate they're not > explicitly stated in the source code. This attribute is not valid for > DW_TAG_friend, so it's only emitted in non-strict mode. The greatest > challenge was to enumerate all specializations of a template. It > looked trivial at first, given DECL_TEMPLATE_INSTANTIATIONS, but in > some of the testcases, cases it wouldn't list any specializations, and > in others it would list only some of them. I couldn't figure out the > logic behind that, and it seemed clear from the documentation of this > macro that at least in some cases it wouldn't hold the list, so I > ended up writing code to look for specializations in the hashtables of > decl or type specializations. That worked fine, but it's not exactly > an efficient way to obtain the desired information, at least in some > cases. > > > > - should we output specializations of friend templates as friends even > in strict mode? Currently we output them with DW_AT_artificial in > non-strict mode, and without the artificial mark in strict mode. > > - is there any way we can use DECL_TEMPLATE_INSTANTIATIONS reliably to > enumerate the specializations of a friend template, or at least tell > when it can be used? > > - I haven't used local_specializations, should I? I was a bit > confused about the apparently unused local_specialization_stack, > too. > > I haven't covered partial and explicit specializations in the > testcases yet. > > > for gcc/ChangeLog > > PR debug/59319 > * dwarf2out.c (class_types_with_friends): New. > (gen_friend_tags_for_type, gen_friend_tags): New. > (gen_member_die): Record class types with friends. > (deferred_marks): New. > (prune_unused_types_defer_undecided_mark_p): New. > (prune_unused_types_defer_mark): New. > (prune_unused_types_deferred_walk): New. > (prune_unused_types_walk): Defer DW_TAG_friend. > (prune_unused_types): Check deferred marks is empty on entry, > empty it after processing. > (dwarf2out_finish): Generate friend tags. Just throwing in a wrench from the side ... you should do this in dwarf2out_early_finish as late there will be no frontend around anymore. Yeah, prune_unused_types is still done in dwarf2out_finish on trunk but I am moving it early for LTO early debug (I didn't try doing this in isolation on trunk now but you may ...;)). In fact I am moving almost all type related post-processing from dwarf2out_finish to dwarf2out_early_finish. Richard. > * langhooks-def.h (LANG_HOOKS_GET_FRIENDS): New. > (LANG_HOOKS_FOR_TYPES_INITIALIZER): Add it. > * langhooks.h (lang_hooks_for_types): Add get_friends. > > for gcc/cp/ChangeLog > > PR debug/59319 > * cp-objcp-common.c (cp_get_friends): New. > * cp-objcp-common.h (cp_get_friends): Declare. > (LANG_HOOKS_GET_FRIENDS): Override. > * cp-tree.h (enumerate_friend_specializations): Declare. > * pt.c (enumerate_friend_specializations): New. > > for gcc/testsuite/ChangeLog > > PR debug/59319 > * g++.dg/debug/dwarf2/friend-1.C: New. > * g++.dg/debug/dwarf2/friend-2.C: New. > * g++.dg/debug/dwarf2/friend-3.C: New. > * g++.dg/debug/dwarf2/friend-4.C: New. > * g++.dg/debug/dwarf2/friend-5.C: New. > * g++.dg/debug/dwarf2/friend-6.C: New. > * g++.dg/debug/dwarf2/friend-7.C: New. > * g++.dg/debug/dwarf2/friend-8.C: New. > * g++.dg/debug/dwarf2/friend-9.C: New. > * g++.dg/debug/dwarf2/friend-10.C: New. > * g++.dg/debug/dwarf2/friend-11.C: New. > * g++.dg/debug/dwarf2/friend-12.C: New. > * g++.dg/debug/dwarf2/friend-13.C: New. > --- > gcc/cp/cp-objcp-common.c | 103 ++++++++++++++++ > gcc/cp/cp-objcp-common.h | 3 > gcc/cp/cp-tree.h | 1 > gcc/cp/pt.c | 73 +++++++++++ > gcc/dwarf2out.c | 161 +++++++++++++++++++++++++ > gcc/langhooks-def.h | 4 - > gcc/langhooks.h | 19 +++ > gcc/testsuite/g++.dg/debug/dwarf2/friend-1.C | 10 ++ > gcc/testsuite/g++.dg/debug/dwarf2/friend-10.C | 13 ++ > gcc/testsuite/g++.dg/debug/dwarf2/friend-11.C | 13 ++ > gcc/testsuite/g++.dg/debug/dwarf2/friend-12.C | 15 ++ > gcc/testsuite/g++.dg/debug/dwarf2/friend-2.C | 11 ++ > gcc/testsuite/g++.dg/debug/dwarf2/friend-3.C | 9 + > gcc/testsuite/g++.dg/debug/dwarf2/friend-4.C | 12 ++ > gcc/testsuite/g++.dg/debug/dwarf2/friend-5.C | 10 ++ > gcc/testsuite/g++.dg/debug/dwarf2/friend-6.C | 11 ++ > gcc/testsuite/g++.dg/debug/dwarf2/friend-7.C | 11 ++ > gcc/testsuite/g++.dg/debug/dwarf2/friend-8.C | 13 ++ > gcc/testsuite/g++.dg/debug/dwarf2/friend-9.C | 13 ++ > 19 files changed, 503 insertions(+), 2 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/friend-1.C > create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/friend-10.C > create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/friend-11.C > create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/friend-12.C > create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/friend-2.C > create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/friend-3.C > create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/friend-4.C > create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/friend-5.C > create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/friend-6.C > create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/friend-7.C > create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/friend-8.C > create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/friend-9.C > > diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c > index e9f9a63..d35632c 100644 > --- a/gcc/cp/cp-objcp-common.c > +++ b/gcc/cp/cp-objcp-common.c > @@ -167,6 +167,109 @@ cp_get_ptrmemfn_type (const_tree type, int selector) > } > } > > +/* At DETAIL level 0, returns non-NULL if the named class TYPE has any > + friends, NULL otherwise. At higher detail levels, return a tree > + list with the friends of the named class type. Each TREE_VALUE > + contains one friend type or function decl. For non-template > + friends, TREE_PURPOSE is NULL. For template friend declarations, > + the returned entries depend on the DETAIL level. At level 1, and > + only at level 1, an entry with NULL TREE_VALUE and non-NULL > + TREE_PURPOSE will START the returned list to indicate the named > + class TYPE has at least one template friend. At level 2, each > + template friend will be in an entry with NULL TREE_VALUE, and with > + the TEMPLATE_DECL in TREE_PURPOSE. At level 3, instead of a NULL > + TREE_VALUE, we add one entry for each instantiation or > + specialization of the template that fits the template friend > + declaration, as long as there is at least one instantiation or > + specialization; if there isn't any, an entry with NULL TREE_VALUE > + is created. A negative detail level will omit non-template friends > + from the returned list. */ > + > +tree > +cp_get_friends (const_tree type, int detail) > +{ > + tree list = NULL_TREE; > + tree typedecl = TYPE_MAIN_DECL (type); > + bool has_templates = false; > + bool non_templates = true; > + > + if (detail == 0) > + { > + if (DECL_FRIENDLIST (typedecl) > + || CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (typedecl))) > + return integer_one_node; > + else > + return NULL_TREE; > + } > + else if (detail < 0) > + { > + detail = -detail; > + non_templates = false; > + } > + > + gcc_assert (detail <= 3); > + > + for (tree fnlist = DECL_FRIENDLIST (typedecl); fnlist; > + fnlist = TREE_CHAIN (fnlist)) > + for (tree fns = FRIEND_DECLS (fnlist); fns; fns = TREE_CHAIN (fns)) > + { > + tree fn = TREE_VALUE (fns); > + if (TREE_CODE (fn) == FUNCTION_DECL > + && (!DECL_TEMPLATE_INFO (fn) || DECL_USE_TEMPLATE (fn))) > + { > + if (non_templates) > + list = tree_cons (NULL_TREE, fn, list); > + continue; > + } > + > + has_templates = true; > + > + if (detail == 2) > + list = tree_cons (fn, NULL_TREE, list); > + > + if (detail <= 2) > + continue; > + > + tree new_list = enumerate_friend_specializations (fn); > + if (new_list) > + list = chainon (new_list, list); > + else > + list = tree_cons (fn, NULL_TREE, list); > + } > + > + for (tree cllist = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (typedecl)); > + cllist; cllist = TREE_CHAIN (cllist)) > + { > + tree cl = TREE_VALUE (cllist); > + > + if (TREE_CODE (cl) == RECORD_TYPE) > + { > + if (non_templates) > + list = tree_cons (NULL_TREE, cl, list); > + continue; > + } > + > + has_templates = true; > + > + if (detail == 2) > + list = tree_cons (cl, NULL_TREE, list); > + > + if (detail <= 2) > + continue; > + > + tree new_list = enumerate_friend_specializations (cl); > + if (new_list) > + list = chainon (new_list, list); > + else > + list = tree_cons (cl, NULL_TREE, list); > + } > + > + if (has_templates && detail == 1) > + list = tree_cons (integer_one_node, NULL_TREE, list); > + > + return list; > +} > + > /* Return true if DECL is explicit member function. */ > > bool > diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h > index 00780c7..d85d357 100644 > --- a/gcc/cp/cp-objcp-common.h > +++ b/gcc/cp/cp-objcp-common.h > @@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see > > extern int cp_get_ref_qualifier (const_tree); > extern tree cp_get_ptrmemfn_type (const_tree, int); > +extern tree cp_get_friends (const_tree, int); > > extern tree objcp_tsubst_copy_and_build (tree, tree, tsubst_flags_t, > tree, bool); > @@ -134,6 +135,8 @@ extern void cp_common_init_ts (void); > #define LANG_HOOKS_GET_REF_QUALIFIER cp_get_ref_qualifier > #undef LANG_HOOKS_GET_PTRMEMFN_TYPE > #define LANG_HOOKS_GET_PTRMEMFN_TYPE cp_get_ptrmemfn_type > +#undef LANG_HOOKS_GET_FRIENDS > +#define LANG_HOOKS_GET_FRIENDS cp_get_friends > #undef LANG_HOOKS_TO_TARGET_CHARSET > #define LANG_HOOKS_TO_TARGET_CHARSET c_common_to_target_charset > #undef LANG_HOOKS_GIMPLIFY_EXPR > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index 8a32f17..66106b5 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -6114,6 +6114,7 @@ extern vec *get_types_needing_access_check (tr > extern int template_class_depth (tree); > extern int is_specialization_of (tree, tree); > extern bool is_specialization_of_friend (tree, tree); > +extern tree enumerate_friend_specializations (tree); > extern tree get_pattern_parm (tree, tree); > extern int comp_template_args (tree, tree, tree * = NULL, > tree * = NULL); > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > index 1ee5fd4..f0bd40b 100644 > --- a/gcc/cp/pt.c > +++ b/gcc/cp/pt.c > @@ -1469,6 +1469,79 @@ is_specialization_of_friend (tree decl, tree friend_decl) > return false; > } > > +/* Return a list of instantiations/specializations that match > + FRIEND_DECL. */ > + > +tree > +enumerate_friend_specializations (tree friend_decl) > +{ > + if (TREE_CODE (friend_decl) != TEMPLATE_DECL) > + friend_decl = DECL_TI_TEMPLATE (friend_decl); > + > + tree opt_decl = friend_decl; > + while (optimize_specialization_lookup_p (opt_decl)) > + opt_decl = CLASSTYPE_TI_TEMPLATE (DECL_CONTEXT (opt_decl)); > + > + gcc_assert (TREE_CODE (opt_decl) == TEMPLATE_DECL); > + > + /* FIXME: This would be much preferred, but it doesn't always list > + all specializations. */ > + if (0 && DECL_TEMPLATE_INSTANTIATIONS (opt_decl)) > + { > + tree list = NULL_TREE; > + for (tree speclist = DECL_TEMPLATE_INSTANTIATIONS (opt_decl); > + speclist; speclist = TREE_CHAIN (speclist)) > + { > + tree spec = TREE_VALUE (speclist); > + if (opt_decl != friend_decl) > + spec = retrieve_specialization > + (friend_decl, CLASSTYPE_TI_ARGS (spec), 0); > + if (TREE_CODE (spec) == TYPE_DECL) > + spec = TREE_TYPE (spec); > + list = tree_cons (friend_decl, spec, list); > + } > + return list; > + } > + > + typedef hash_table specs_t; > + specs_t *specializations; > + tree_code code; > + > + if (DECL_CLASS_TEMPLATE_P (opt_decl)) > + { > + specializations = type_specializations; > + code = RECORD_TYPE; > + } > + else > + { > + specializations = decl_specializations; > + code = FUNCTION_DECL; > + } > + > + tree list = NULL_TREE; > + > + for (specs_t::iterator iter = specializations->begin(), > + end = specializations->end(); > + iter != end; ++iter) > + { > + tree spec = (*iter)->spec; > + if (TREE_CODE (spec) != code) > + continue; > + if (TREE_CODE (spec) == RECORD_TYPE) > + spec = TYPE_NAME (spec); > + if (is_specialization_of_friend (spec, opt_decl)) > + { > + if (opt_decl != friend_decl) > + spec = retrieve_specialization (friend_decl, (*iter)->args, 0); > + if (TREE_CODE (spec) == TYPE_DECL) > + spec = TREE_TYPE (spec); > + list = tree_cons (friend_decl, spec, list); > + } > + } > + > + return list; > +} > + > /* Register the specialization SPEC as a specialization of TMPL with > the indicated ARGS. IS_FRIEND indicates whether the specialization > is actually just a friend declaration. Returns SPEC, or an > diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c > index f40f759..43aa5a0 100644 > --- a/gcc/dwarf2out.c > +++ b/gcc/dwarf2out.c > @@ -22474,6 +22474,57 @@ gen_variant_part (tree variant_part_decl, struct vlr_context *vlr_ctx, > free (discr_lists); > } > > +/* Types that have friends have to be revisited, because we want to > + emit friend attributes for them once we know what types and decls > + have DIEs, and we want to emit friend tags for specializations of > + template friends. We could create DIEs in limbo ourselves, but we > + can't know the specializations before we've seen the entire > + translation unit. */ > + > +static vec class_types_with_friends; > + > +/* Add any friend tags corresponding to the named TYPE. */ > + > +static void > +gen_friend_tags_for_type (tree type) > +{ > + dw_die_ref context_die = lookup_type_die (type); > + gcc_assert (context_die); > + > + for (tree friends = lang_hooks.types.get_friends (type, 3); friends; > + friends = TREE_CHAIN (friends)) > + { > + tree t = TREE_VALUE (friends); > + dw_die_ref die = NULL; > + if (!t) > + /* If it's a friend template without any specializations, we > + can't refer to it in debug information. */ > + continue; > + else if (TYPE_P (t)) > + die = lookup_type_die (t); > + else if (DECL_P (t)) > + die = lookup_decl_die (t); > + else > + gcc_unreachable (); > + if (!die) > + continue; > + dw_die_ref child = new_die (DW_TAG_friend, context_die, type); > + add_AT_die_ref (child, DW_AT_friend, die); > + if (!dwarf_strict && TREE_PURPOSE (friends)) > + add_AT_flag (child, DW_AT_artificial, 1); > + } > +} > + > +/* Add any friend tags corresponding to class TYPEs that were found to > + have friend declarations. */ > + > +static void > +gen_friend_tags () > +{ > + while (!class_types_with_friends.is_empty ()) > + gen_friend_tags_for_type (class_types_with_friends.pop ()); > +} > + > /* Generate a DIE for a class member. */ > > static void > @@ -22559,6 +22610,9 @@ gen_member_die (tree type, dw_die_ref context_die) > else > gen_decl_die (member, NULL, NULL, context_die); > } > + > + if (lang_hooks.types.get_friends (type, 0)) > + class_types_with_friends.safe_push (type); > } > > /* Generate a DIE for a structure or union type. If TYPE_DECL_SUPPRESS_DEBUG > @@ -26031,6 +26085,97 @@ prune_unused_types_walk_local_classes (dw_die_ref die) > FOR_EACH_CHILD (die, c, prune_unused_types_walk_local_classes (c)); > } > > +/* Nodes to revisit after marking everything else, to decide whether > + or not they can/should be emitted. */ > + > +static vec deferred_marks; > + > +/* Return true if the mark is already decided, false otherwise. */ > + > +static bool > +prune_unused_types_defer_undecided_mark_p (dw_die_ref die) > +{ > + gcc_assert (!die->die_mark); > + > + dw_attr_node *a; > + unsigned ix; > + bool can_mark_now = true; > + > + FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a) > + switch (AT_class (a)) > + { > + case dw_val_class_loc: > + case dw_val_class_loc_list: > + /* We don't support attributes of this type now. Deferred > + walking of the location expressions might mark DIEs that > + we've already decided not to output, and we may have > + already based other decisions on it. This is not > + insurmountable, but we don't need to tackle that right > + away. */ > + gcc_unreachable (); > + > + case dw_val_class_die_ref: > + if (!a->dw_attr_val.v.val_die_ref.die->die_mark) > + can_mark_now = false; > + break; > + > + case dw_val_class_str: > + default: > + break; > + } > + > + return !can_mark_now; > +} > + > +/* Return true if we've deferred the decision on whether to mark DIE. > + It must not have children or attributes with location expressions > + or lists. Attributes with strings and other DIEs are ok. If any > + of the DIEs referenced by attributes is not marked, we defer the > + decision to give it a chance to be marked so that we output the > + present DIE too. In this case, we return TRUE, to indicate the > + decision was deferred. If they are all marked already, then we > + know we can output this one as well, so we return FALSE to indicate > + it was NOT deferred. */ > + > +static bool > +prune_unused_types_defer_mark (dw_die_ref die) > +{ > + gcc_assert (die->die_parent->die_mark); > + > + /* We use this for friend DIEs only, and they have no children, so > + don't make things more complicated than needed. */ > + gcc_assert (!die->die_child); > + > + if (die->die_mark || !prune_unused_types_defer_undecided_mark_p (die)) > + return false; > + > + deferred_marks.safe_push (die); > + > + return true; > +} > + > +/* This function revisits a deferred DIE, and marks it iff each DIE > + its attributes reference is also marked. */ > + > +static void > +prune_unused_types_deferred_walk (dw_die_ref die) > +{ > + /* If we're marked, we're done. Otherwise, if referenced DIEs > + remain unmarked, then we don't mark this one either. */ > + if (die->die_mark > + || prune_unused_types_defer_undecided_mark_p (die)) > + return; > + > + gcc_assert (!die->die_mark); > + die->die_mark = 1; > + /* This should do no more than resetting the refcount of > + strings. */ > + prune_unused_types_walk_attribs (die); > + die->die_mark = 2; > + > + /* We don't mark children because we know we have none. */ > +} > + > /* Walk the tree DIE and mark types that we actually use. */ > > static void > @@ -26066,6 +26211,13 @@ prune_unused_types_walk (dw_die_ref die) > /* It's a type node --- don't mark it. */ > return; > > + case DW_TAG_friend: > + if (die->die_perennial_p > + || !prune_unused_types_defer_mark (die)) > + break; > + > + return; > + > case DW_TAG_const_type: > case DW_TAG_packed_type: > case DW_TAG_pointer_type: > @@ -26075,7 +26227,6 @@ prune_unused_types_walk (dw_die_ref die) > case DW_TAG_typedef: > case DW_TAG_array_type: > case DW_TAG_interface_type: > - case DW_TAG_friend: > case DW_TAG_enumeration_type: > case DW_TAG_subroutine_type: > case DW_TAG_string_type: > @@ -26191,6 +26342,8 @@ prune_unused_types (void) > pubname_entry *pub; > dw_die_ref base_type; > > + gcc_assert (deferred_marks.is_empty ()); > + > #if ENABLE_ASSERT_CHECKING > /* All the marks should already be clear. */ > verify_marks_clear (comp_unit_die ()); > @@ -26223,6 +26376,10 @@ prune_unused_types (void) > for (i = 0; base_types.iterate (i, &base_type); i++) > prune_unused_types_mark (base_type, 1); > > + while (!deferred_marks.is_empty ()) > + prune_unused_types_deferred_walk (deferred_marks.pop ()); > + deferred_marks.release (); > + > if (debug_str_hash) > debug_str_hash->empty (); > if (skeleton_debug_str_hash) > @@ -27569,6 +27726,8 @@ dwarf2out_finish (const char *filename) > > gen_remaining_tmpl_value_param_die_attribute (); > > + gen_friend_tags (); > + > /* Add the name for the main input file now. We delayed this from > dwarf2out_init to avoid complications with PCH. > For LTO produced units use a fixed artificial name to avoid > diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h > index 5961c42..b11384f 100644 > --- a/gcc/langhooks-def.h > +++ b/gcc/langhooks-def.h > @@ -182,6 +182,7 @@ extern tree lhd_make_node (enum tree_code); > #define LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO NULL > #define LANG_HOOKS_GET_REF_QUALIFIER hook_int_const_tree_0 > #define LANG_HOOKS_GET_PTRMEMFN_TYPE hook_tree_const_tree_int_null > +#define LANG_HOOKS_GET_FRIENDS hook_tree_const_tree_int_null > > #define LANG_HOOKS_FOR_TYPES_INITIALIZER { \ > LANG_HOOKS_MAKE_TYPE, \ > @@ -206,7 +207,8 @@ extern tree lhd_make_node (enum tree_code); > LANG_HOOKS_GET_DEBUG_TYPE, \ > LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO, \ > LANG_HOOKS_GET_REF_QUALIFIER, \ > - LANG_HOOKS_GET_PTRMEMFN_TYPE \ > + LANG_HOOKS_GET_PTRMEMFN_TYPE, \ > + LANG_HOOKS_GET_FRIENDS \ > } > > /* Declaration hooks. */ > diff --git a/gcc/langhooks.h b/gcc/langhooks.h > index cf8b550..73b7bb8 100644 > --- a/gcc/langhooks.h > +++ b/gcc/langhooks.h > @@ -170,6 +170,25 @@ struct lang_hooks_for_types > Otherwise, return the class type when the selector is 0, or the > member function type when the selector is 1. */ > tree (*get_ptrmemfn_type) (const_tree, int); > + > + /* At DETAIL level 0, returns non-NULL if the named class TYPE has > + any friends, NULL otherwise. At higher detail levels, return a > + tree list with the friends of the named class type. Each > + TREE_VALUE contains one friend type or function decl. For > + non-template friends, TREE_PURPOSE is NULL. For template friend > + declarations, the returned entries depend on the DETAIL level. > + At level 1, and only at level 1, an entry with NULL TREE_VALUE > + and non-NULL TREE_PURPOSE will START the returned list to > + indicate the named class TYPE has at least one template friend. > + At level 2, each template friend will be in an entry with NULL > + TREE_VALUE, and with the TEMPLATE_DECL in TREE_PURPOSE. At level > + 3, instead of a NULL TREE_VALUE, we add one entry for each > + instantiation or specialization of the template that fits the > + template friend declaration, as long as there is at least one > + instantiation or specialization; if there isn't any, an entry > + with NULL TREE_VALUE is created. A negative detail level will > + omit non-template friends from the returned list. */ > + tree (*get_friends) (const_tree, int); > }; > > /* Language hooks related to decls and the symbol table. */ > diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/friend-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/friend-1.C > new file mode 100644 > index 0000000..df06f6f > --- /dev/null > +++ b/gcc/testsuite/g++.dg/debug/dwarf2/friend-1.C > @@ -0,0 +1,10 @@ > +// { dg-do compile } > +// { dg-options "-O -g -dA" } > +// { dg-final { scan-assembler-times " DW_AT_friend" 2 { xfail { powerpc-ibm-aix* } } } } > + > +class foo {}; > +class bar { > + friend class foo; > +}; > +bar t; > +foo l; > diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/friend-10.C b/gcc/testsuite/g++.dg/debug/dwarf2/friend-10.C > new file mode 100644 > index 0000000..dcff721 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/debug/dwarf2/friend-10.C > @@ -0,0 +1,13 @@ > +// { dg-do compile } > +// { dg-options "-O -g -dA" } > +// { dg-final { scan-assembler-times " DW_AT_friend" 3 { xfail { powerpc-ibm-aix* } } } } > + > +template struct foo { > + template void f () {} > +}; > +class bar { > + template template friend void foo::f (); > +}; > +bar t; > +template void foo::f (); > +template void foo::f (); > diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/friend-11.C b/gcc/testsuite/g++.dg/debug/dwarf2/friend-11.C > new file mode 100644 > index 0000000..24382c8 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/debug/dwarf2/friend-11.C > @@ -0,0 +1,13 @@ > +// { dg-do compile } > +// { dg-options "-O -g -dA" } > +// { dg-final { scan-assembler-times " DW_AT_friend" 3 { xfail { powerpc-ibm-aix* } } } } > + > +template struct foo { > + struct f {}; > +}; > +class bar { > + template friend struct foo::f; > +}; > +bar t; > +foo::f i; > +foo::f b; > diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/friend-12.C b/gcc/testsuite/g++.dg/debug/dwarf2/friend-12.C > new file mode 100644 > index 0000000..0c172a7 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/debug/dwarf2/friend-12.C > @@ -0,0 +1,15 @@ > +// { dg-do compile } > +// { dg-options "-O -g -dA" } > +// { dg-final { scan-assembler-times " DW_AT_friend" 5 { xfail { powerpc-ibm-aix* } } } } > + > +template struct foo { > + template struct f {}; > +}; > +class bar { > + template template friend struct foo::f; > +}; > +bar t; > +foo::f i; > +foo::f b; > +foo::f ib; > +foo::f bi; > diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/friend-2.C b/gcc/testsuite/g++.dg/debug/dwarf2/friend-2.C > new file mode 100644 > index 0000000..b4cd04d > --- /dev/null > +++ b/gcc/testsuite/g++.dg/debug/dwarf2/friend-2.C > @@ -0,0 +1,11 @@ > +// { dg-do compile } > +// { dg-options "-O -g -dA" } > +// { dg-final { scan-assembler-not " DW_AT_friend" { xfail { powerpc-ibm-aix* } } } } > +// class foo is unused, so we do NOT output the friend tag. > + > +class foo {}; > +class bar { > + friend class foo; > +}; > +bar t; > +// foo l; > diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/friend-3.C b/gcc/testsuite/g++.dg/debug/dwarf2/friend-3.C > new file mode 100644 > index 0000000..05cdde1 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/debug/dwarf2/friend-3.C > @@ -0,0 +1,9 @@ > +// { dg-do compile } > +// { dg-options "-O -g -dA" } > +// { dg-final { scan-assembler-times " DW_AT_friend" 2 { xfail { powerpc-ibm-aix* } } } } > + > +int f() {} > +class bar { > + friend int f(); > +}; > +bar t; > diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/friend-4.C b/gcc/testsuite/g++.dg/debug/dwarf2/friend-4.C > new file mode 100644 > index 0000000..4a67516 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/debug/dwarf2/friend-4.C > @@ -0,0 +1,12 @@ > +// { dg-do compile } > +// { dg-options "-O -g -dA" } > +// { dg-final { scan-assembler-times " DW_AT_friend" 2 { xfail { powerpc-ibm-aix* } } } } > + > +struct foo { > + int f(); > +}; > +class bar { > + friend int foo::f(); > +}; > +int foo::f() {} > +bar t; > diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/friend-5.C b/gcc/testsuite/g++.dg/debug/dwarf2/friend-5.C > new file mode 100644 > index 0000000..3ccfd6d > --- /dev/null > +++ b/gcc/testsuite/g++.dg/debug/dwarf2/friend-5.C > @@ -0,0 +1,10 @@ > +// { dg-do compile } > +// { dg-options "-O -g -dA" } > +// { dg-final { scan-assembler-times " DW_AT_friend" 2 { xfail { powerpc-ibm-aix* } } } } > + > +template class foo {}; > +class bar { > + friend class foo; > +}; > +bar t; > +foo l; > diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/friend-6.C b/gcc/testsuite/g++.dg/debug/dwarf2/friend-6.C > new file mode 100644 > index 0000000..34dd458 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/debug/dwarf2/friend-6.C > @@ -0,0 +1,11 @@ > +// { dg-do compile } > +// { dg-options "-O -g -dA" } > +// { dg-final { scan-assembler-times " DW_AT_friend" 3 { xfail { powerpc-ibm-aix* } } } } > + > +template class foo {}; > +class bar { > + template friend class foo; > +}; > +bar t; > +foo l; > +foo b; > diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/friend-7.C b/gcc/testsuite/g++.dg/debug/dwarf2/friend-7.C > new file mode 100644 > index 0000000..3a6554c > --- /dev/null > +++ b/gcc/testsuite/g++.dg/debug/dwarf2/friend-7.C > @@ -0,0 +1,11 @@ > +// { dg-do compile } > +// { dg-options "-O -g -dA" } > +// { dg-final { scan-assembler-times " DW_AT_friend" 3 { xfail { powerpc-ibm-aix* } } } } > + > +template void f () {} > +class bar { > + template friend void f (); > +}; > +bar t; > +template void f (); > +template void f (); > diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/friend-8.C b/gcc/testsuite/g++.dg/debug/dwarf2/friend-8.C > new file mode 100644 > index 0000000..4ede43c > --- /dev/null > +++ b/gcc/testsuite/g++.dg/debug/dwarf2/friend-8.C > @@ -0,0 +1,13 @@ > +// { dg-do compile } > +// { dg-options "-O -g -dA" } > +// { dg-final { scan-assembler-times " DW_AT_friend" 3 { xfail { powerpc-ibm-aix* } } } } > + > +struct foo { > + template void f () {} > +}; > +class bar { > + template friend void foo::f (); > +}; > +bar t; > +template void foo::f (); > +template void foo::f (); > diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/friend-9.C b/gcc/testsuite/g++.dg/debug/dwarf2/friend-9.C > new file mode 100644 > index 0000000..fe6b0ac > --- /dev/null > +++ b/gcc/testsuite/g++.dg/debug/dwarf2/friend-9.C > @@ -0,0 +1,13 @@ > +// { dg-do compile } > +// { dg-options "-O -g -dA" } > +// { dg-final { scan-assembler-times " DW_AT_friend" 3 { xfail { powerpc-ibm-aix* } } } } > + > +template struct foo { > + void f () {} > +}; > +class bar { > + template friend void foo::f (); > +}; > +bar t; > +template void foo::f (); > +template void foo::f (); > > -- > Alexandre Oliva, freedom fighter http://FSFLA.org/~lxoliva/ > You must be the change you wish to see in the world. -- Gandhi > Be Free! -- http://FSFLA.org/ FSF Latin America board member > Free Software Evangelist|Red Hat Brasil GNU Toolchain Engineer