@@ -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
@@ -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
@@ -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);
@@ -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
@@ -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);
@@ -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. */
@@ -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. */
new file mode 100644
@@ -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;
new file mode 100644
@@ -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;
new file mode 100644
@@ -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;
@@ -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)