diff mbox

[PR56974] output DWARF-5 markers for ref_qualifiers

Message ID orpopef6or.fsf@livre.home
State New
Headers show

Commit Message

Alexandre Oliva Aug. 12, 2016, 1:38 p.m. UTC
When a method or a method or function type has a ref-qualifier, output
DW_AT_reference or DW_AT_rvalue_reference in the subprogram or
subroutine_type tag, as specified in DWARF version 5 drafts, see
<http://dwarfstd.org/ShowIssue.php?issue=131105.1>.

Output pointer to member function types as DW_TAG_ptr_to_member_type,
as required by DWARF since version 2.

Output DW_TAG_use_location for pointers to data member types, as
specified in DWARF since version 2.

DW_TAG_use_location is allowed for pointers to member function types as
well, but the specification doesn't make much sense for them, so I'm
leaving it out until it is clarified.

Regstrapped on x86_64-linux-gnu and i686-linux-gnu.  Ok to install?


for  include/ChangeLog

	PR debug/56974
	* dwarf2.def (DW_AT_reference, DW_AT_rvalue_reference): New.

for  gcc/ChangeLog

	PR debug/56974
	* dwarf2out.c (gen_subprogram_die): Add DW_AT_reference or
	DW_AT_rvalue_reference to methods.
	(gen_subroutine_type_die): Likewise to method types.
	(gen_ptr_to_mbr_type_die): Take enclosing and member types.
	Output DW_AT_use_location for pointers to data members.
	(gen_type_die_with_usage): Don't drop rquals of METHOD_TYPEs.
	Adjust OFFSET_TYPE handling.  Introduce RECORD_TYPE handling
	of pointers to member functions.
	* hooks.c (hook_tree_const_tree_int_null): New.
	* hooks.h (hook_tree_const_tree_int_null): Declare.
	* langhooks-def.h (LANG_HOOKS_GET_REF_QUALIFIER): Define.
	(LANG_HOOKS_GET_PTRMEMFN_TYPE): Define.
	(LANG_HOOKS_FOR_TYPES_INITIALIZER): Add them.
	* langhooks.h (struct lang_hooks_for_types): Add
	get_ref_qualifier and get_ptrmemfn_type.

for  gcc/cp/ChangeLog

	PR debug/56974
	* cp-objcp-common.c (cp_get_ref_qualifier): New.
	(cp_get_ptrmemfn_type): New.
	* cp-objcp-common.h: Declared them.
	(LANG_HOOKS_GET_REF_QUALIFIER): Override.
	(LANG_HOOKS_GET_PTRMEMFN_TYPE): Likewise.

for  gcc/testsuite/ChangeLog

	PR debug/56974
	* g++.dg/debug/dwarf2/refqual-1.C: New.
	* g++.dg/debug/dwarf2/refqual-2.C: New.
	* g++.dg/debug/dwarf2/ptrdmem-1.C: New.
---
 gcc/cp/cp-objcp-common.c                      |   37 +++++++++++
 gcc/cp/cp-objcp-common.h                      |    9 ++-
 gcc/dwarf2out.c                               |   87 ++++++++++++++++++++++---
 gcc/hooks.c                                   |    8 ++
 gcc/hooks.h                                   |    1 
 gcc/langhooks-def.h                           |    6 +-
 gcc/langhooks.h                               |   10 +++
 gcc/testsuite/g++.dg/debug/dwarf2/ptrdmem-1.C |    9 +++
 gcc/testsuite/g++.dg/debug/dwarf2/refqual-1.C |   17 +++++
 gcc/testsuite/g++.dg/debug/dwarf2/refqual-2.C |   17 +++++
 include/dwarf2.def                            |    2 +
 11 files changed, 191 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/ptrdmem-1.C
 create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/refqual-1.C
 create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/refqual-2.C

Comments

Alexandre Oliva Sept. 24, 2016, 12:19 a.m. UTC | #1
On Aug 12, 2016, Alexandre Oliva <aoliva@redhat.com> wrote:

> When a method or a method or function type has a ref-qualifier, output
> DW_AT_reference or DW_AT_rvalue_reference in the subprogram or
> subroutine_type tag, as specified in DWARF version 5 drafts, see
> <http://dwarfstd.org/ShowIssue.php?issue=131105.1>.

> Output pointer to member function types as DW_TAG_ptr_to_member_type,
> as required by DWARF since version 2.

> Output DW_TAG_use_location for pointers to data member types, as
> specified in DWARF since version 2.

> DW_TAG_use_location is allowed for pointers to member function types as
> well, but the specification doesn't make much sense for them, so I'm
> leaving it out until it is clarified.

> Regstrapped on x86_64-linux-gnu and i686-linux-gnu.  Ok to install?

Ping?

https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01022.html
diff mbox

Patch

diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index 9cb9dd7..e9f9a63 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -130,6 +130,43 @@  cxx_types_compatible_p (tree x, tree y)
   return same_type_ignoring_top_level_qualifiers_p (x, y);
 }
 
+/* Return 0 if TYPE is NOT a C++ method or function type with a
+   ref-qualifier, 1 if the ref-qualifier is '&', and 2 if it is
+   '&&'.  */
+
+int
+cp_get_ref_qualifier (const_tree type)
+{
+  if ((TREE_CODE (type) == METHOD_TYPE || TREE_CODE (type) == FUNCTION_TYPE)
+      && FUNCTION_REF_QUALIFIED (type))
+    return FUNCTION_RVALUE_QUALIFIED (type) ? 2 : 1;
+  else
+    return 0;
+}
+
+/* Return NULL if TYPE is NOT a C++ pointer to member function type.
+   Otherwise, return the class type when the selector is 0, or the
+   member function type when the selector is 1.  */
+
+tree
+cp_get_ptrmemfn_type (const_tree type, int selector)
+{
+  if (!TYPE_PTRMEMFUNC_P (type))
+    return NULL_TREE;
+
+  switch (selector)
+    {
+    case 0:
+      return TYPE_PTRMEMFUNC_OBJECT_TYPE (type);
+
+    case 1:
+      return TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type));
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* 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 3ad3eb6..00780c7 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -21,7 +21,10 @@  along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_CP_OBJCP_COMMON
 #define GCC_CP_OBJCP_COMMON
 
-/* In cp/cp-lang.c and objcp/objcp-lang.c.  */
+/* In cp/objcp-common.c, cp/cp-lang.c and objcp/objcp-lang.c.  */
+
+extern int cp_get_ref_qualifier (const_tree);
+extern tree cp_get_ptrmemfn_type (const_tree, int);
 
 extern tree objcp_tsubst_copy_and_build (tree, tree, tsubst_flags_t,
 					 tree, bool);
@@ -127,6 +130,10 @@  extern void cp_common_init_ts (void);
 #define LANG_HOOKS_REGISTER_BUILTIN_TYPE c_register_builtin_type
 #undef LANG_HOOKS_RECONSTRUCT_COMPLEX_TYPE
 #define LANG_HOOKS_RECONSTRUCT_COMPLEX_TYPE cp_reconstruct_complex_type
+#undef LANG_HOOKS_GET_REF_QUALIFIER
+#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_TO_TARGET_CHARSET
 #define LANG_HOOKS_TO_TARGET_CHARSET c_common_to_target_charset
 #undef LANG_HOOKS_GIMPLIFY_EXPR
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 3b25358..f40f759 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -3383,7 +3383,7 @@  static void gen_label_die (tree, dw_die_ref);
 static void gen_lexical_block_die (tree, dw_die_ref);
 static void gen_inlined_subroutine_die (tree, dw_die_ref);
 static void gen_field_die (tree, struct vlr_context *, dw_die_ref);
-static void gen_ptr_to_mbr_type_die (tree, dw_die_ref);
+static void gen_ptr_to_mbr_type_die (tree, dw_die_ref, tree, tree);
 static dw_die_ref gen_compile_unit_die (const char *);
 static void gen_inheritance_die (tree, tree, tree, dw_die_ref);
 static void gen_member_die (tree, dw_die_ref);
@@ -20535,6 +20535,24 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
 	{
 	  add_AT_flag (subr_die, DW_AT_declaration, 1);
 
+	  /* If this is a method with a ref-qualifier, generate the
+	     corresponding attribute.  */
+	  int rqual = lang_hooks.types.get_ref_qualifier (TREE_TYPE (decl));
+	  if (rqual && (dwarf_version >= 5 || !dwarf_strict))
+	    switch (rqual)
+	      {
+	      case 1:
+		add_AT_flag (subr_die, DW_AT_reference, 1);
+		break;
+
+	      case 2:
+		add_AT_flag (subr_die, DW_AT_rvalue_reference, 1);
+		break;
+
+	      default:
+		gcc_unreachable ();
+	      }
+
 	  /* If this is an explicit function declaration then generate
 	     a DW_AT_explicit attribute.  */
 	  if (lang_hooks.decls.function_decl_explicit_p (decl)
@@ -21742,10 +21760,13 @@  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.  TYPE can be an
+   OFFSET_TYPE, for a pointer to data member, or a RECORD_TYPE, for a
+   pointer to member function.  */
 
 static void
-gen_ptr_to_mbr_type_die (tree type, dw_die_ref context_die)
+gen_ptr_to_mbr_type_die (tree type, dw_die_ref context_die,
+			 tree class_type, tree member_type)
 {
   dw_die_ref ptr_die
     = new_die (DW_TAG_ptr_to_member_type,
@@ -21753,9 +21774,15 @@  gen_ptr_to_mbr_type_die (tree type, dw_die_ref context_die)
 
   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), TYPE_UNQUALIFIED, false,
+		  lookup_type_die (class_type));
+  add_type_attribute (ptr_die, member_type, TYPE_UNQUALIFIED, false,
 		      context_die);
+
+  if (TREE_CODE (type) == OFFSET_TYPE)
+    {
+      dw_loc_descr_ref op = new_loc_descr (DW_OP_plus, 0, 0);
+      add_AT_loc (ptr_die, DW_AT_use_location, op);
+    }
 }
 
 static char *producer_string;
@@ -22663,6 +22690,25 @@  gen_subroutine_type_die (tree type, dw_die_ref context_die)
 
   if (get_AT (subr_die, DW_AT_name))
     add_pubtype (type, subr_die);
+
+  /* If this is a C++ method or function type with a ref-qualifier,
+     generate the corresponding attribute.  */
+  int rqual = lang_hooks.types.get_ref_qualifier (type);
+
+  if (rqual && (dwarf_version >= 5 || !dwarf_strict))
+    switch (rqual)
+      {
+      case 1:
+	add_AT_flag (subr_die, DW_AT_reference, 1);
+	break;
+
+      case 2:
+	add_AT_flag (subr_die, DW_AT_rvalue_reference, 1);
+	break;
+
+      default:
+	gcc_unreachable ();
+      }
 }
 
 /* Generate a DIE for a type definition.  */
@@ -22887,10 +22933,13 @@  gen_type_die_with_usage (tree type, dw_die_ref context_die,
   /* 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
-     now.  (Vectors and arrays are special because the debugging info is in the
-     cloned type itself).  */
+     now.  (Vectors and arrays are special because the debugging info
+     is in the cloned type itself; method types are special because
+     they are never cv-qualified, but they can be ref-qualified, and
+     we don't want to drop these qualifiers from the method type).  */
   if (TREE_CODE (type) != VECTOR_TYPE
-      && TREE_CODE (type) != ARRAY_TYPE)
+      && TREE_CODE (type) != ARRAY_TYPE
+      && TREE_CODE (type) != METHOD_TYPE)
     type = type_main_variant (type);
 
   /* If this is an array type with hidden descriptor, handle it first.  */
@@ -22956,7 +23005,8 @@  gen_type_die_with_usage (tree type, dw_die_ref context_die,
 
       /* Now output a DIE to represent this pointer-to-data-member type
 	 itself.  */
-      gen_ptr_to_mbr_type_die (type, context_die);
+      gen_ptr_to_mbr_type_die (type, context_die,
+			       TYPE_OFFSET_BASETYPE (type), TREE_TYPE (type));
       break;
 
     case FUNCTION_TYPE:
@@ -22978,8 +23028,25 @@  gen_type_die_with_usage (tree type, dw_die_ref context_die,
       gen_array_type_die (type, context_die);
       break;
 
-    case ENUMERAL_TYPE:
     case RECORD_TYPE:
+      {
+	tree class_type = lang_hooks.types.get_ptrmemfn_type (type, 0);
+	if (class_type != NULL_TREE)
+	  {
+	    gen_type_die_with_usage (class_type, context_die,
+				     DINFO_USAGE_IND_USE);
+
+	    tree memfn_type = lang_hooks.types.get_ptrmemfn_type (type, 1);
+	    gen_type_die_with_usage (memfn_type, context_die,
+				     DINFO_USAGE_IND_USE);
+
+	    gen_ptr_to_mbr_type_die (type, context_die,
+				     class_type, memfn_type);
+	    return;
+	  }
+      }
+      /* Fall through.  */
+    case ENUMERAL_TYPE:
     case UNION_TYPE:
     case QUAL_UNION_TYPE:
       gen_tagged_type_die (type, context_die, usage);
diff --git a/gcc/hooks.c b/gcc/hooks.c
index 99ec401..5a09103 100644
--- a/gcc/hooks.c
+++ b/gcc/hooks.c
@@ -458,6 +458,14 @@  hook_tree_const_tree_null (const_tree t ATTRIBUTE_UNUSED)
   return NULL;
 }
 
+/* Generic hook that takes a const_tree and an int, and returns NULL_TREE.  */
+tree
+hook_tree_const_tree_int_null (const_tree t ATTRIBUTE_UNUSED,
+			       int i ATTRIBUTE_UNUSED)
+{
+  return NULL;
+}
+
 /* Generic hook that takes a rtx_insn * and an int and returns a bool.  */
 
 bool
diff --git a/gcc/hooks.h b/gcc/hooks.h
index 2dc59ba..723be57 100644
--- a/gcc/hooks.h
+++ b/gcc/hooks.h
@@ -88,6 +88,7 @@  extern int hook_int_rtx_mode_as_bool_0 (rtx, machine_mode, addr_space_t,
 					bool);
 
 extern tree hook_tree_const_tree_null (const_tree);
+extern tree hook_tree_const_tree_int_null (const_tree, int);
 
 extern tree hook_tree_tree_tree_null (tree, tree);
 extern tree hook_tree_tree_tree_tree_null (tree, tree, tree);
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index 10d910c..5961c42 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -180,6 +180,8 @@  extern tree lhd_make_node (enum tree_code);
 #define LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE lhd_enum_underlying_base_type
 #define LANG_HOOKS_GET_DEBUG_TYPE	NULL
 #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_FOR_TYPES_INITIALIZER { \
   LANG_HOOKS_MAKE_TYPE, \
@@ -202,7 +204,9 @@  extern tree lhd_make_node (enum tree_code);
   LANG_HOOKS_RECONSTRUCT_COMPLEX_TYPE, \
   LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE, \
   LANG_HOOKS_GET_DEBUG_TYPE, \
-  LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO \
+  LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO, \
+  LANG_HOOKS_GET_REF_QUALIFIER, \
+  LANG_HOOKS_GET_PTRMEMFN_TYPE \
 }
 
 /* Declaration hooks.  */
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index 44c258e..cf8b550 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -160,6 +160,16 @@  struct lang_hooks_for_types
      for the debugger about scale factor, etc.  */
   bool (*get_fixed_point_type_info) (const_tree,
 				     struct fixed_point_type_info *);
+
+  /* Return 0 if TYPE is NOT a C++ method or function type with a
+     ref-qualifier, 1 if the ref-qualifier is '&', and 2 if it is
+     '&&'.  */
+  int (*get_ref_qualifier) (const_tree);
+
+  /* Return NULL if TYPE is NOT a C++ pointer to member function type.
+     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);
 };
 
 /* Language hooks related to decls and the symbol table.  */
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/ptrdmem-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/ptrdmem-1.C
new file mode 100644
index 0000000..5d65196
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/ptrdmem-1.C
@@ -0,0 +1,9 @@ 
+// { dg-do compile }
+// { dg-options "-O -std=c++11 -g -dA -gno-strict-dwarf" }
+// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_ptr_to_member_type" 1 { xfail { powerpc-ibm-aix* } } } }
+// { dg-final { scan-assembler-times " DW_AT_use_location" 1 { xfail { powerpc-ibm-aix* } } } }
+// { dg-final { scan-assembler-not " DW_AT_reference" { xfail { powerpc-ibm-aix* } } } }
+
+struct S;
+typedef int S::*pdm;
+pdm pmf = 0;
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/refqual-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/refqual-1.C
new file mode 100644
index 0000000..221008e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/refqual-1.C
@@ -0,0 +1,17 @@ 
+// { dg-do compile }
+// { dg-options "-O -std=c++11 -g -dA -gno-strict-dwarf" }
+// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_ptr_to_member_type" 1 { xfail { powerpc-ibm-aix* } } } }
+// { dg-final { scan-assembler-times " DW_AT_reference" 2 { xfail { powerpc-ibm-aix* } } } }
+// { dg-final { scan-assembler-not " DW_AT_use_location" { xfail { powerpc-ibm-aix* } } } }
+/* It is not clear what if anything we should output for
+   DW_AT_use_location in a pointer to member function, so we don't
+   output it for now.  */
+
+struct S {
+  void mf(void) &;
+};
+
+void S::mf() & {}
+
+typedef void (S::*pmft)(void) &;
+pmft pmf = &S::mf;
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/refqual-2.C b/gcc/testsuite/g++.dg/debug/dwarf2/refqual-2.C
new file mode 100644
index 0000000..ddf33c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/refqual-2.C
@@ -0,0 +1,17 @@ 
+// { dg-do compile }
+// { dg-options "-O -std=c++11 -g -dA -gno-strict-dwarf" }
+// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_ptr_to_member_type" 1 { xfail { powerpc-ibm-aix* } } } }
+// { dg-final { scan-assembler-times " DW_AT_rvalue_reference" 2 { xfail { powerpc-ibm-aix* } } } }
+// { dg-final { scan-assembler-not " DW_AT_use_location" { xfail { powerpc-ibm-aix* } } } }
+/* It is not clear what if anything we should output for
+   DW_AT_use_location in a pointer to member function, so we don't
+   output it for now.  */
+
+struct S {
+  void mf(void) &&;
+};
+
+void S::mf() && {}
+
+typedef void (S::*pmft)(void) &&;
+pmft pmf = &S::mf;
diff --git a/include/dwarf2.def b/include/dwarf2.def
index 67b2a5b..8546f7e 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -309,6 +309,8 @@  DW_AT (DW_AT_const_expr, 0x6c)
 DW_AT (DW_AT_enum_class, 0x6d)
 DW_AT (DW_AT_linkage_name, 0x6e)
 /* DWARF 5.  */
+DW_AT (DW_AT_reference, 0x77)
+DW_AT (DW_AT_rvalue_reference, 0x78)
 DW_AT (DW_AT_noreturn, 0x87)
 DW_AT (DW_AT_deleted, 0x8a)
 DW_AT (DW_AT_defaulted, 0x8b)