--- Begin Message ---
Hello,
This PR is an enhancement request to emit a DW_TAG_ptr_to_member_type
DIE for pointer-to-member-function types.
The patch below does add a new language hook to support this and
adapts the existing code that emits DW_TAG_ptr_to_member_type for
ponter-to-data-member types to handle pointer-to-member-function types
as well.
Tested on x86_64-unknown-linux-gnu against trunk.
I am proposing this for 4.7.
--
Dodji
>From 36d971de3a01c83f8e23c4016262ea73357f6bd6 Mon Sep 17 00:00:00 2001
From: Dodji Seketeli <do...@redhat.com>
Date: Tue, 15 Mar 2011 16:50:30 +0100
Subject: [PATCH] PR debug/28767 (Support pointer-to-member-function)
gcc/
* langhooks.h (struct lag_hooks_for_type)<is_ptr_to_member>:
Declare New language hook.
* hooks.h (hook_bool_const_tree_treeptr_false): Declare ...
hooks.c (hook_bool_const_tree_treeptr_false): ... new default
hook.
* langhooks-def.h (LANG_HOOKS_IS_PTR_TO_MEMBER): Define new hook
initializer.
(LANG_HOOKS_FOR_TYPES_INITIALIZER): Initialize the
is_ptr_to_member field to LANG_HOOKS_IS_PTR_TO_MEMBER.
* dwarf2out.c (gen_ptr_to_mbr_type_die): Handle
pointer-to-member-function in addition to pointer-to-data-member.
Both using the new language hook.
(gen_type_die_with_usage): Handle pointer-to-member-function and
pointer-to-data-member types with gen_ptr_to_mbr_type_die.
gcc/cp/
* cp-lang.c (is_ptr_to_member): New language hook implementation
for C++.
(LANG_HOOKS_IS_PTR_TO_MEMBER): Initialize this language hook for
C++.
gcc/testsuite/
* g++.dg/debug/dwarf2/ptrmem-1.C: New test.
---
gcc/cp/cp-lang.c | 39 +++++++++++++++++-
gcc/dwarf2out.c | 58 ++++++++++++++++----------
gcc/hooks.c | 7 +++
gcc/hooks.h | 1 +
gcc/langhooks-def.h | 2 +
gcc/langhooks.h | 8 ++++
gcc/testsuite/g++.dg/debug/dwarf2/ptrmem-1.C | 20 +++++++++
7 files changed, 112 insertions(+), 23 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/ptrmem-1.C
diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c
index e5c1c09..62faa1c 100644
--- a/gcc/cp/cp-lang.c
+++ b/gcc/cp/cp-lang.c
@@ -40,7 +40,7 @@ static enum classify_record cp_classify_record (tree type);
static tree cp_eh_personality (void);
static tree get_template_innermost_arguments_folded (const_tree);
static tree get_template_argument_pack_elems_folded (const_tree);
-
+static bool is_ptr_to_member (const_tree, tree*);
/* Lang hooks common to C++ and ObjC++ are declared in cp/cp-objcp-common.h;
consequently, there should be very few hooks below. */
@@ -65,6 +65,9 @@ static tree get_template_argument_pack_elems_folded
(const_tree);
#undef LANG_HOOKS_GET_ARGUMENT_PACK_ELEMS
#define LANG_HOOKS_GET_ARGUMENT_PACK_ELEMS \
get_template_argument_pack_elems_folded
+#undef LANG_HOOKS_IS_PTR_TO_MEMBER
+#define LANG_HOOKS_IS_PTR_TO_MEMBER \
+ is_ptr_to_member
#undef LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P
#define LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P \
template_template_parameter_p
@@ -238,5 +241,39 @@ get_template_argument_pack_elems_folded (const_tree t)
return fold_cplus_constants (get_template_argument_pack_elems (t));
}
+/* The C++ implementation of LANG_HOOKS_GET_PTRMEM_TYPES.
+
+ Returns TRUE if T is a pointer-to-data-member or
+ a pointer-to-member-function.
+
+ If PTRMEM_INFO is non-null and if T is a
+ pointer-to-member-function, *PTRMEM_INFO is set to a TREE_LIST
+ which TREE_PURPOSE is the METHOD_TYPE of member-function pointed
+ to. The TREE_VALUE is the class/struct type containing the member
+ function. If T is a pointer-to-member, *PTRMEM_INFO is set to a
+ TREE_LIST which TREE_PURPOSE is the type of the member, and which
+ TREE_VALUE is the class/strunct type containing the data member.
+ The TREE_TYPE is set to T. */
+
+static bool
+is_ptr_to_member (const_tree t,
+ tree *ptrmem_info)
+{
+ if (!t || !TYPE_PTR_TO_MEMBER_P (t))
+ return false;
+
+ if (ptrmem_info != NULL)
+ {
+ if (TYPE_PTRMEMFUNC_P (t))
+ *ptrmem_info = build_tree_list (TYPE_PTRMEMFUNC_FN_TYPE (t),
+ TYPE_PTRMEMFUNC_OBJECT_TYPE (t));
+ else
+ *ptrmem_info = build_tree_list (TYPE_PTRMEM_POINTED_TO_TYPE (t),
+ TYPE_PTRMEM_CLASS_TYPE (t));
+ TREE_TYPE (*ptrmem_info) = CONST_CAST_TREE (t);
+ }
+ return true;
+}
+
#include "gt-cp-cp-lang.h"
#include "gtype-cp.h"
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 733c849..949c099 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -6520,7 +6520,7 @@ static void gen_label_die (tree, dw_die_ref);
static void gen_lexical_block_die (tree, dw_die_ref, int);
static void gen_inlined_subroutine_die (tree, dw_die_ref, int);
static void gen_field_die (tree, dw_die_ref);
-static void gen_ptr_to_mbr_type_die (tree, dw_die_ref);
+static bool gen_ptr_to_mbr_type_die (tree, dw_die_ref);
static dw_die_ref gen_compile_unit_die (const char *);
static void gen_inheritance_die (tree, tree, dw_die_ref);
static void gen_member_die (tree, dw_die_ref);
@@ -20064,19 +20064,36 @@ gen_reference_type_die (tree type, dw_die_ref
context_die)
}
#endif
-/* Generate a DIE for a pointer to a member type. */
+/* Generate a DIE for a pointer to a member type. Return TRUE if the
+ DIE was actually generated, false otherwise. */
-static void
+static bool
gen_ptr_to_mbr_type_die (tree type, dw_die_ref context_die)
{
- dw_die_ref ptr_die
- = new_die (DW_TAG_ptr_to_member_type,
- scope_die_for (type, context_die), type);
+ dw_die_ref ptr_die;
+ tree ptrmem_info = NULL_TREE;
+
+ if (!lang_hooks.types.is_ptr_to_member (type, &ptrmem_info))
+ return false;
+ gcc_assert (ptrmem_info != NULL_TREE);
+
+ /* Output the description of the class type containing the
+ member pointed to. */
+ gen_type_die_with_usage (TREE_VALUE (ptrmem_info),
+ context_die, DINFO_USAGE_IND_USE);
+ /* Output the description of the type of the memeber
+ pointed to. */
+ gen_type_die_with_usage (TREE_PURPOSE (ptrmem_info),
+ context_die, DINFO_USAGE_IND_USE);
+ /* Now create the DW_TAG_ptr_to_member_type proper. */
+ ptr_die = new_die (DW_TAG_ptr_to_member_type,
+ scope_die_for (type, context_die), type);
equate_type_number_to_die (type, ptr_die);
add_AT_die_ref (ptr_die, DW_AT_containing_type,
- lookup_type_die (TYPE_OFFSET_BASETYPE (type)));
- add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
+ lookup_type_die (TREE_VALUE (ptrmem_info)));
+ add_type_attribute (ptr_die, TREE_PURPOSE (ptrmem_info), 0, 0, context_die);
+ return true;
}
/* Generate the DIE for the compilation unit. */
@@ -20603,6 +20620,14 @@ gen_type_die_with_usage (tree type, dw_die_ref
context_die,
return;
}
+ /* If this is a pointer-to-member, handle it here. */
+ if (!TREE_ASM_WRITTEN (type)
+ && gen_ptr_to_mbr_type_die (type, context_die))
+ {
+ TREE_ASM_WRITTEN (type) = 1;
+ return;
+ }
+
/* We are going to output a DIE to represent the unqualified version
of this type (i.e. without any const or volatile qualifiers) so
get the main variant (i.e. the unqualified version) of this type
@@ -20635,19 +20660,9 @@ gen_type_die_with_usage (tree type, dw_die_ref
context_die,
break;
case OFFSET_TYPE:
- /* This code is used for C++ pointer-to-data-member types.
- Output a description of the relevant class type. */
- gen_type_die_with_usage (TYPE_OFFSET_BASETYPE (type), context_die,
- DINFO_USAGE_IND_USE);
-
- /* Output a description of the type of the object pointed to. */
- gen_type_die_with_usage (TREE_TYPE (type), context_die,
- DINFO_USAGE_IND_USE);
-
- /* Now output a DIE to represent this pointer-to-data-member type
- itself. */
- gen_ptr_to_mbr_type_die (type, context_die);
- break;
+ /* This code is used for C++ pointer-to-data-member types, so
+ it should have been handled earlier. */
+ gcc_unreachable ();
case FUNCTION_TYPE:
/* Force out return type (in case it wasn't forced out already). */
@@ -21818,7 +21833,6 @@ gen_scheduled_generic_parms_dies (void)
gen_generic_params_dies (t);
}
-
/* Replace DW_AT_name for the decl with name. */
static void
diff --git a/gcc/hooks.c b/gcc/hooks.c
index f859dd9..4a2a9f2 100644
--- a/gcc/hooks.c
+++ b/gcc/hooks.c
@@ -219,6 +219,13 @@ hook_bool_const_tree_true (const_tree a ATTRIBUTE_UNUSED)
}
bool
+hook_bool_const_tree_treeptr_false (const_tree a ATTRIBUTE_UNUSED,
+ tree *b ATTRIBUTE_UNUSED)
+{
+ return false;
+}
+
+bool
hook_bool_tree_tree_false (tree a ATTRIBUTE_UNUSED, tree b ATTRIBUTE_UNUSED)
{
return false;
diff --git a/gcc/hooks.h b/gcc/hooks.h
index 7962fe8..71fe747 100644
--- a/gcc/hooks.h
+++ b/gcc/hooks.h
@@ -38,6 +38,7 @@ extern bool hook_bool_tree_false (tree);
extern bool hook_bool_const_tree_false (const_tree);
extern bool hook_bool_tree_true (tree);
extern bool hook_bool_const_tree_true (const_tree);
+extern bool hook_bool_const_tree_treeptr_false (const_tree, tree *p);
extern bool hook_bool_const_tree_hwi_hwi_const_tree_false (const_tree,
HOST_WIDE_INT,
HOST_WIDE_INT,
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index 961e929..ab077f8 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -164,6 +164,7 @@ extern tree lhd_make_node (enum tree_code);
#define LANG_HOOKS_GET_INNERMOST_GENERIC_ARGS hook_tree_const_tree_null
#define LANG_HOOKS_FUNCTION_PARAMETER_PACK_P hook_bool_const_tree_false
#define LANG_HOOKS_GET_ARGUMENT_PACK_ELEMS hook_tree_const_tree_null
+#define LANG_HOOKS_IS_PTR_TO_MEMBER hook_bool_const_tree_treeptr_false
#define LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P hook_bool_const_tree_false
#define LANG_HOOKS_FUNCTION_PARM_EXPANDED_FROM_PACK_P \
hook_bool_tree_tree_false
@@ -185,6 +186,7 @@ extern tree lhd_make_node (enum tree_code);
LANG_HOOKS_TYPE_FOR_SIZE, \
LANG_HOOKS_GENERIC_TYPE_P, \
LANG_HOOKS_GET_ARGUMENT_PACK_ELEMS, \
+ LANG_HOOKS_IS_PTR_TO_MEMBER, \
LANG_HOOKS_TYPE_PROMOTES_TO, \
LANG_HOOKS_REGISTER_BUILTIN_TYPE, \
LANG_HOOKS_INCOMPLETE_TYPE_ERROR, \
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index a994729..97758d6 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -90,6 +90,14 @@ struct lang_hooks_for_types
/* Returns the TREE_VEC of elements of a given generic argument pack. */
tree (*get_argument_pack_elems) (const_tree);
+ /* If the first parameter is a pointer-to-data-member or a
+ pointer-to-function-member, return TRUE. If the second parameter
+ is non-null, set it to a TREE_LIST. The TREE_PURPOSE is the type
+ of the member pointed to. The TREE_VALUE is the type of the
+ class containing the member. The TREE_TYPE is set to the first
+ parameter. */
+ bool (*is_ptr_to_member) (const_tree, 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
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/ptrmem-1.C
b/gcc/testsuite/g++.dg/debug/dwarf2/ptrmem-1.C
new file mode 100644
index 0000000..c232165
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/ptrmem-1.C
@@ -0,0 +1,20 @@
+// Origin PR debug/28767
+// { dg-options "-g -dA -fno-merge-debug-strings" }
+
+struct A
+{
+ int func(void);
+ char data;
+};
+
+int (A::*ptr) (void) = &A::func;
+char A::* d = &A::data;
+
+// For the code abobe we want to test that we have two sequences
+// ressembling:
+//
+// .uleb128 0x9 # (DIE (0x7f) DW_TAG_ptr_to_member_type)
+// .long 0x2d # DW_AT_containing_type
+// .long 0x88 # DW_AT_type
+//
+// { dg-final { scan-assembler-times "DIE \\(\[^\n\r\]+\\)
DW_TAG_ptr_to_member_type\\)\[\n\r\]{1,2}\[^\n\r\]+DW_AT_containing_type\[^\n\r\]*\[\n\r\]{1,2}\[^\n\r\]+DW_AT_type\[^\n\r\]*\[\n\r\]{1,2}"
2 } }
--
1.7.3.4
--- End Message ---