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 } }
