Discussion:
[PATCH 1/2] PR debug/63239 Add DWARF representation for C++11 deleted member function.
Mark Wielaard
2014-10-03 13:12:01 UTC
Permalink
Currently we output a declaration of the explicitly deleted function
in DWARF. That seems wrong. An alternative to adding an attribute would
be to just not output the declaration. But that is also confusing since
then it looks precisely the same as an class that has that special
function implicitly defined, since we don't output a declaration for
such implicitly defined special functions either. So this implementation
defines a new attribute DW_AT_GNU_deleted that gets added to the
declaration.

include/ChangeLog

* dwarf2.def (DW_AT_GNU_deleted): New attribute.

gcc/ChangeLog

* dwarf2out.c (gen_subprogram_die): When a member function is
explicitly deleted then add a DW_AT_GNU_deleted attribute.
* langhooks.h (struct lang_hooks_for_decls): Add
function_decl_deleted_p langhook.
* langhooks-def.h (LANG_HOOKS_FUNCTION_DECL_DELETED_P): Define.
(LANG_HOOKS_DECLS): Add LANG_HOOKS_FUNCTION_DECL_DELETED_P.

gcc/cp/ChangeLog

* cp-objcp-common.h (LANG_HOOKS_FUNCTION_DECL_DELETED_P): Define.
(cp_function_decl_deleted_p): New prototype.
* cp-objcp-common.c (cp_function_deleted_p): New function.

gcc/testsuite/ChangeLog

* g++.dg/debug/dwarf2/deleted-member-function.C: New testcase.
---
gcc/ChangeLog | 10 ++++++++++
gcc/cp/ChangeLog | 7 +++++++
gcc/cp/cp-objcp-common.c | 10 ++++++++++
gcc/cp/cp-objcp-common.h | 3 +++
gcc/dwarf2out.c | 6 ++++++
gcc/langhooks-def.h | 2 ++
gcc/langhooks.h | 3 +++
gcc/testsuite/ChangeLog | 5 +++++
.../g++.dg/debug/dwarf2/deleted-member-function.C | 17 +++++++++++++++++
include/ChangeLog | 5 +++++
include/dwarf2.def | 2 ++
11 files changed, 70 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/deleted-member-function.C

diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index 0c50f40..0d144ef 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -168,6 +168,16 @@ cp_function_decl_explicit_p (tree decl)
&& DECL_NONCONVERTING_P (decl));
}

+/* Return true if DECL is deleted special member function. */
+
+bool
+cp_function_decl_deleted_p (tree decl)
+{
+ return (decl
+ && DECL_LANG_SPECIFIC (STRIP_TEMPLATE (decl))
+ && DECL_DELETED_FN (decl));
+}
+
/* Stubs to keep c-opts.c happy. */
void
push_file_scope (void)
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index 246800e..c289774 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -27,6 +27,7 @@ extern tree objcp_tsubst_copy_and_build (tree, tree, tsubst_flags_t,
tree, bool);

extern bool cp_function_decl_explicit_p (tree decl);
+extern bool cp_function_decl_deleted_p (tree decl);
extern void cp_common_init_ts (void);

/* Lang hooks that are shared between C++ and ObjC++ are defined here. Hooks
@@ -131,6 +132,8 @@ extern void cp_common_init_ts (void);
#define LANG_HOOKS_GIMPLIFY_EXPR cp_gimplify_expr
#undef LANG_HOOKS_FUNCTION_DECL_EXPLICIT_P
#define LANG_HOOKS_FUNCTION_DECL_EXPLICIT_P cp_function_decl_explicit_p
+#undef LANG_HOOKS_FUNCTION_DECL_DELETED_P
+#define LANG_HOOKS_FUNCTION_DECL_DELETED_P cp_function_decl_deleted_p
#undef LANG_HOOKS_OMP_PREDETERMINED_SHARING
#define LANG_HOOKS_OMP_PREDETERMINED_SHARING cxx_omp_predetermined_sharing
#undef LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index b5fcfa4..11544d8 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -18299,6 +18299,12 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
&& (dwarf_version >= 3 || !dwarf_strict))
add_AT_flag (subr_die, DW_AT_explicit, 1);

+ /* If this is a C++11 deleted special function member then generate
+ a DW_AT_GNU_deleted attribute. */
+ if (lang_hooks.decls.function_decl_deleted_p (decl)
+ && (! dwarf_strict))
+ add_AT_flag (subr_die, DW_AT_GNU_deleted, 1);
+
/* The first time we see a member function, it is in the context of
the class to which it belongs. We make sure of this by emitting
the class first. The next time is the definition, which is
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index e77d2d9..e5ae3e3 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -203,6 +203,7 @@ extern tree lhd_make_node (enum tree_code);
#define LANG_HOOKS_PUSHDECL pushdecl
#define LANG_HOOKS_GETDECLS getdecls
#define LANG_HOOKS_FUNCTION_DECL_EXPLICIT_P hook_bool_tree_false
+#define LANG_HOOKS_FUNCTION_DECL_DELETED_P hook_bool_tree_false
#define LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL lhd_warn_unused_global_decl
#define LANG_HOOKS_WRITE_GLOBALS write_global_declarations
#define LANG_HOOKS_DECL_OK_FOR_SIBCALL lhd_decl_ok_for_sibcall
@@ -224,6 +225,7 @@ extern tree lhd_make_node (enum tree_code);
LANG_HOOKS_PUSHDECL, \
LANG_HOOKS_GETDECLS, \
LANG_HOOKS_FUNCTION_DECL_EXPLICIT_P, \
+ LANG_HOOKS_FUNCTION_DECL_DELETED_P, \
LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P, \
LANG_HOOKS_FUNCTION_PARM_EXPANDED_FROM_PACK_P, \
LANG_HOOKS_GET_GENERIC_FUNCTION_DECL, \
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index 72fa85e..32e76f9 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -166,6 +166,9 @@ struct lang_hooks_for_decls
/* Returns true if DECL is explicit member function. */
bool (*function_decl_explicit_p) (tree);

+ /* Returns true if DECL is C++11 deleted special member function. */
+ bool (*function_decl_deleted_p) (tree);
+
/* Returns True if the parameter is a generic parameter decl
of a generic type, e.g a template template parameter for the C++ FE. */
bool (*generic_generic_parameter_decl_p) (const_tree);
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/deleted-member-function.C b/gcc/testsuite/g++.dg/debug/dwarf2/deleted-member-function.C
new file mode 100644
index 0000000..4cc77e6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/deleted-member-function.C
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-O -std=c++11 -g -dA" }
+// { dg-final { scan-assembler-times "# DW_AT_GNU_deleted" 2 } }
+
+struct Foo
+{
+ Foo () {}
+ // Make non-copyable
+ Foo (const Foo&) = delete;
+ Foo & operator=(const Foo&) = delete;
+};
+
+void
+bar ()
+{
+ Foo foo;
+}
diff --git a/include/dwarf2.def b/include/dwarf2.def
index 71a37b3..42a8d4b 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -383,6 +383,8 @@ DW_AT (DW_AT_GNU_all_call_sites, 0x2117)
DW_AT (DW_AT_GNU_all_source_call_sites, 0x2118)
/* Section offset into .debug_macro section. */
DW_AT (DW_AT_GNU_macros, 0x2119)
+/* Attribute for C++ deleted special member functions (= delete;). */
+DW_AT (DW_AT_GNU_deleted, 0x211a)
/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */
DW_AT (DW_AT_GNU_dwo_name, 0x2130)
DW_AT (DW_AT_GNU_dwo_id, 0x2131)
--
1.8.3.1
Mark Wielaard
2014-10-03 13:12:02 UTC
Permalink
A debugger not knowing whether a special member function was explicitly
defaulted, implicitly declared or explicitly defined seems less confusion
than not knowing whether it was deleted. But there are some subtle cases
where knowing whether a constructor was user defined or explicitly
defaulted do matter for whether the default constructor might have been
implicitly generated. So like the deleted case this patch introduces
a new attribute DW_AT_GNU_defaulted that gets attached to the function
declaration. Note that since this is for declarations we explicitly
test for DECL_DEFAULTED_IN_CLASS_P and ignore any implementation
definitions that use = default; outside the class body.

gcc/ChangeLog

* dwarf2out.c (gen_subprogram_die): When a member function is
declared default then add a DW_AT_GNU_defaulted attribute.
* langhooks.h (struct lang_hooks_for_decls): Add
function_decl_defaulted_p langhook.
* langhooks-def.h (LANG_HOOKS_FUNCTION_DECL_DEFAULTED_P): Define.
(LANG_HOOKS_DECLS): Add LANG_HOOKS_FUNCTION_DECL_DEFAULTED_P.

gcc/cp/ChangeLog

* cp-objcp-common.h (LANG_HOOKS_FUNCTION_DECL_DEFAULTED_P): Define.
(cp_function_decl_defaulted_p): New prototype.
* cp-objcp-common.c (cp_function_defaulted_p): New function.

gcc/testsuite/ChangeLog

* g++.dg/debug/dwarf2/defaulted-member-function.C: New testcase.

include/ChangeLog

* dwarf2.def (DW_AT_GNU_defaulted): New attribute.
---
gcc/ChangeLog | 10 ++++++++++
gcc/cp/ChangeLog | 7 +++++++
gcc/cp/cp-objcp-common.c | 10 ++++++++++
gcc/cp/cp-objcp-common.h | 3 +++
gcc/dwarf2out.c | 6 ++++++
gcc/langhooks-def.h | 2 ++
gcc/langhooks.h | 3 +++
gcc/testsuite/ChangeLog | 5 +++++
.../g++.dg/debug/dwarf2/defaulted-member-function.C | 17 +++++++++++++++++
include/ChangeLog | 5 +++++
include/dwarf2.def | 2 ++
11 files changed, 70 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/defaulted-member-function.C

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index dc3287b..255b1b6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2014-10-03 Mark Wielaard <***@redhat.com>
+
+ PR debug/63240
+ * dwarf2out.c (gen_subprogram_die): When a member function is
+ declared default then add a DW_AT_GNU_defaulted attribute.
+ * langhooks.h (struct lang_hooks_for_decls): Add
+ function_decl_defaulted_p langhook.
+ * langhooks-def.h (LANG_HOOKS_FUNCTION_DECL_DEFAULTED_P): Define.
+ (LANG_HOOKS_DECLS): Add LANG_HOOKS_FUNCTION_DECL_DEFAULTED_P.
+
2014-10-02 Mark Wielaard <***@redhat.com>

PR debug/63239
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 921f95c..d88bcd8 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,10 @@
+2014-10-03 Mark Wielaard <***@redhat.com>
+
+ PR debug/63240
+ * cp-objcp-common.h (LANG_HOOKS_FUNCTION_DECL_DEFAULTED_P): Define.
+ (cp_function_decl_defaulted_p): New prototype.
+ * cp-objcp-common.c (cp_function_defaulted_p): New function.
+
2014-10-02 Mark Wielaard <***@redhat.com>

PR debug/63239
diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index 0d144ef..5516671 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -178,6 +178,16 @@ cp_function_decl_deleted_p (tree decl)
&& DECL_DELETED_FN (decl));
}

+/* Return true if DECL is defaulted in the class body. */
+
+bool
+cp_function_decl_defaulted_p (tree decl)
+{
+ return (decl
+ && DECL_LANG_SPECIFIC (STRIP_TEMPLATE (decl))
+ && DECL_DEFAULTED_IN_CLASS_P (decl));
+}
+
/* Stubs to keep c-opts.c happy. */
void
push_file_scope (void)
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index c289774..348874f 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -28,6 +28,7 @@ extern tree objcp_tsubst_copy_and_build (tree, tree, tsubst_flags_t,

extern bool cp_function_decl_explicit_p (tree decl);
extern bool cp_function_decl_deleted_p (tree decl);
+extern bool cp_function_decl_defaulted_p (tree decl);
extern void cp_common_init_ts (void);

/* Lang hooks that are shared between C++ and ObjC++ are defined here. Hooks
@@ -134,6 +135,8 @@ extern void cp_common_init_ts (void);
#define LANG_HOOKS_FUNCTION_DECL_EXPLICIT_P cp_function_decl_explicit_p
#undef LANG_HOOKS_FUNCTION_DECL_DELETED_P
#define LANG_HOOKS_FUNCTION_DECL_DELETED_P cp_function_decl_deleted_p
+#undef LANG_HOOKS_FUNCTION_DECL_DEFAULTED_P
+#define LANG_HOOKS_FUNCTION_DECL_DEFAULTED_P cp_function_decl_defaulted_p
#undef LANG_HOOKS_OMP_PREDETERMINED_SHARING
#define LANG_HOOKS_OMP_PREDETERMINED_SHARING cxx_omp_predetermined_sharing
#undef LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 11544d8..9ff4d77 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -18305,6 +18305,12 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
&& (! dwarf_strict))
add_AT_flag (subr_die, DW_AT_GNU_deleted, 1);

+ /* If this is a C++11 defaulted function member in the class body
+ then generate a DW_AT_GNU_defaulted attribute. */
+ if (lang_hooks.decls.function_decl_defaulted_p (decl)
+ && (! dwarf_strict))
+ add_AT_flag (subr_die, DW_AT_GNU_defaulted, 1);
+
/* The first time we see a member function, it is in the context of
the class to which it belongs. We make sure of this by emitting
the class first. The next time is the definition, which is
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index e5ae3e3..190a803 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -204,6 +204,7 @@ extern tree lhd_make_node (enum tree_code);
#define LANG_HOOKS_GETDECLS getdecls
#define LANG_HOOKS_FUNCTION_DECL_EXPLICIT_P hook_bool_tree_false
#define LANG_HOOKS_FUNCTION_DECL_DELETED_P hook_bool_tree_false
+#define LANG_HOOKS_FUNCTION_DECL_DEFAULTED_P hook_bool_tree_false
#define LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL lhd_warn_unused_global_decl
#define LANG_HOOKS_WRITE_GLOBALS write_global_declarations
#define LANG_HOOKS_DECL_OK_FOR_SIBCALL lhd_decl_ok_for_sibcall
@@ -226,6 +227,7 @@ extern tree lhd_make_node (enum tree_code);
LANG_HOOKS_GETDECLS, \
LANG_HOOKS_FUNCTION_DECL_EXPLICIT_P, \
LANG_HOOKS_FUNCTION_DECL_DELETED_P, \
+ LANG_HOOKS_FUNCTION_DECL_DEFAULTED_P, \
LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P, \
LANG_HOOKS_FUNCTION_PARM_EXPANDED_FROM_PACK_P, \
LANG_HOOKS_GET_GENERIC_FUNCTION_DECL, \
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index 32e76f9..9ffc39a 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -169,6 +169,9 @@ struct lang_hooks_for_decls
/* Returns true if DECL is C++11 deleted special member function. */
bool (*function_decl_deleted_p) (tree);

+ /* Returns true if DECL is C++11 defaulted function in the class body. */
+ bool (*function_decl_defaulted_p) (tree);
+
/* Returns True if the parameter is a generic parameter decl
of a generic type, e.g a template template parameter for the C++ FE. */
bool (*generic_generic_parameter_decl_p) (const_tree);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 2a6fe3f..353a90e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2014-10-03 Mark Wielaard <***@redhat.com>
+
+ PR debug/63240
+ * g++.dg/debug/dwarf2/defaulted-member-function.C: New testcase.
+
2014-10-02 Mark Wielaard <***@redhat.com>

PR debug/63239
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/defaulted-member-function.C b/gcc/testsuite/g++.dg/debug/dwarf2/defaulted-member-function.C
new file mode 100644
index 0000000..635e5ba
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/defaulted-member-function.C
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-O -std=c++11 -g -dA" }
+// { dg-final { scan-assembler-times "# DW_AT_GNU_defaulted" 2 } }
+
+struct Foo
+{
+ Foo () {}
+ // Make copyable
+ Foo (const Foo&) = default;
+ Foo & operator=(const Foo&) = default;
+};
+
+void
+bar ()
+{
+ Foo foo;
+}
diff --git a/include/ChangeLog b/include/ChangeLog
index fd6274f..e9a3a02 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,8 @@
+2013-10-03 Mark Wielaard <***@redhat.com>
+
+ PR debug/63240
+ * dwarf2.def (DW_AT_GNU_defaulted): New attribute.
+
2013-10-02 Mark Wielaard <***@redhat.com>

PR debug/63239
diff --git a/include/dwarf2.def b/include/dwarf2.def
index 42a8d4b..067454c 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -385,6 +385,8 @@ DW_AT (DW_AT_GNU_all_source_call_sites, 0x2118)
DW_AT (DW_AT_GNU_macros, 0x2119)
/* Attribute for C++ deleted special member functions (= delete;). */
DW_AT (DW_AT_GNU_deleted, 0x211a)
+/* Attribute for C++ defaulted function in class body (= default;). */
+DW_AT (DW_AT_GNU_defaulted, 0x211b)
/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */
DW_AT (DW_AT_GNU_dwo_name, 0x2130)
DW_AT (DW_AT_GNU_dwo_id, 0x2131)
--
1.8.3.1
Jason Merrill
2014-10-03 14:17:46 UTC
Permalink
Post by Mark Wielaard
A debugger not knowing whether a special member function was explicitly
defaulted, implicitly declared or explicitly defined seems less confusion
than not knowing whether it was deleted. But there are some subtle cases
where knowing whether a constructor was user defined or explicitly
defaulted do matter for whether the default constructor might have been
implicitly generated.
Can you elaborate?
Post by Mark Wielaard
So like the deleted case this patch introduces
a new attribute DW_AT_GNU_defaulted that gets attached to the function
declaration. Note that since this is for declarations we explicitly
test for DECL_DEFAULTED_IN_CLASS_P and ignore any implementation
definitions that use = default; outside the class body.
Hmm, I'm dubious about this choice. How do you expect a consumer to use
this information?

Jason
Mark Wielaard
2014-10-03 14:35:43 UTC
Permalink
Post by Jason Merrill
Post by Mark Wielaard
A debugger not knowing whether a special member function was explicitly
defaulted, implicitly declared or explicitly defined seems less confusion
than not knowing whether it was deleted. But there are some subtle cases
where knowing whether a constructor was user defined or explicitly
defaulted do matter for whether the default constructor might have been
implicitly generated.
Can you elaborate?
Say you have a user defined copy constructor. The DWARF consumer will
see the declaration and can assume the class won't have a default
constructor (unless that one is explicitly declared too). But currently
the DWARF consumer cannot know whether that move constructor was really
a user defined. If it was declared with = default; then it will see the
move constructor and erroneously conclude that it was user defined and
so the class won't have a default constructor generated for it. Having
the defaulted attribute on the declaration makes clear that the special
function member wasn't in fact user defined. This is because gcc doesn't
output implicit special member function declarations.
Post by Jason Merrill
Post by Mark Wielaard
So like the deleted case this patch introduces
a new attribute DW_AT_GNU_defaulted that gets attached to the function
declaration. Note that since this is for declarations we explicitly
test for DECL_DEFAULTED_IN_CLASS_P and ignore any implementation
definitions that use = default; outside the class body.
Hmm, I'm dubious about this choice. How do you expect a consumer to use
this information?
In two ways. First simply to let the debugger more accurately show the
declaration of the class. Just like one uses = default; in their source
code to be explicit about the fact that the special member function was
really desired. It would be nice if the debugger could provide the same
source information.

Secondly, as described above. There is a difference between = default;
on the declaration and on the implementation definition. If the out of
class definition of a special member function has an = default; then the
in class declaration cannot have it. That means that a = default; on the
out of class definition actually means that the function is user defined
(it just happens to be defined by the default implementation). While a =
default; on the in class declaration means it explicitly isn't user
defined. The consumer can use this information to deduce which implicit
member functions are available.

Cheers,

Mark
Jason Merrill
2014-10-03 14:54:13 UTC
Permalink
Post by Mark Wielaard
Say you have a user defined copy constructor. The DWARF consumer will
see the declaration and can assume the class won't have a default
constructor (unless that one is explicitly declared too). But currently
the DWARF consumer cannot know whether that move constructor was really
a user defined. If it was declared with = default; then it will see the
move constructor and erroneously conclude that it was user defined and
so the class won't have a default constructor generated for it.
That's not erroneous, a declaration with =default still suppresses the
default constructor. "If there is no user-declared constructor for
class X, a constructor having no parameters is implicitly declared as
defaulted."

"user-declared" includes declarations that are defaulted in the class
body. "user-provided" is the category that does not include such
declarations.

Jason
Mark Wielaard
2014-10-03 17:32:05 UTC
Permalink
Post by Jason Merrill
"user-declared" includes declarations that are defaulted in the class
body. "user-provided" is the category that does not include such
declarations.
O. Then I was indeed wrong and defaulted does not impact ABI at all.
At least that is one worry less for the abi checkers :)

In that case I think we should indeed not distinguish between
DECL_DEFAULTED_IN_CLASS_P and DECL_DEFAULTED_OUTSIDE_CLASS_P and just
use DECL_DEFAULTED_FN. Then the information provided is just that the
source indicates that the special member function has the default
implementation. Which still is useful to know for a consumer. If only to
show the debug users what the intention of the original source code was.

The following variant of the patch does that (and removes any mention of
"out of class" definitions).

Thanks,

Mark
Cary Coutant
2014-10-03 18:41:28 UTC
Permalink
Post by Mark Wielaard
O. Then I was indeed wrong and defaulted does not impact ABI at all.
At least that is one worry less for the abi checkers :)
As Siva mentioned, it does in fact impact the ABI. A class with a
non-trivial destructor is not a POD, and affects the calling
convention, so the debugger needs to know the difference. C++ ABI
reference here:

http://mentorembedded.github.io/cxx-abi/abi.html#return-value

I've submitted a DWARF proposal to document the use of the
DW_AT_artificial attribute on a default copy constructor or
destructor.

-cary
Mark Wielaard
2014-10-03 19:00:58 UTC
Permalink
Post by Cary Coutant
Post by Mark Wielaard
O. Then I was indeed wrong and defaulted does not impact ABI at all.
At least that is one worry less for the abi checkers :)
As Siva mentioned, it does in fact impact the ABI. A class with a
non-trivial destructor is not a POD, and affects the calling
convention, so the debugger needs to know the difference. C++ ABI
http://mentorembedded.github.io/cxx-abi/abi.html#return-value
I've submitted a DWARF proposal to document the use of the
DW_AT_artificial attribute on a default copy constructor or
destructor.
Thanks for that reference. I was just stepping through gdb's
gdbarch_return_in_first_hidden_param_p to understand why Siva's example
did indeed seem to go wrong under GDB. That code is a little hairy with
all the arch specific indirections, so I am happy I can stop now :)

I can adjust my patch so that it does mark the declaration with
DW_AT_artificial if it is DECL_COPY_CONSTRUCTOR_P or DECL_DESTRUCTOR_P.
But maybe that is probably better done as a separate patch.

Or does it make sense to mark all defaulted special function members as
artificial instead of having a separate attribute for it? The (small)
advantage of having a separate attribute is that the consumer knows
whether it was explicitly defaulted.

Thanks,

Mark
Siva Chandra
2014-10-03 21:31:46 UTC
Permalink
Post by Mark Wielaard
Thanks for that reference. I was just stepping through gdb's
gdbarch_return_in_first_hidden_param_p to understand why Siva's example
did indeed seem to go wrong under GDB. That code is a little hairy with
all the arch specific indirections, so I am happy I can stop now :)
I agree that GDB's code here is a spaghetti. The function
gdbarch_return_in_first_hidden_param_p seems like an arch related
function, but on most arch's it defaults to the language specific
function language_pass_by_reference via
default_return_in_first_hidden_param_p.
Post by Mark Wielaard
I can adjust my patch so that it does mark the declaration with
DW_AT_artificial if it is DECL_COPY_CONSTRUCTOR_P or DECL_DESTRUCTOR_P.
But maybe that is probably better done as a separate patch.
I have been meaning to send a patch to mark members declared default
with DW_AT_artificial. I have attached what I had in mind with this
mail. If you think it is reasonable, I can send it formally in a
different thread.
Post by Mark Wielaard
Or does it make sense to mark all defaulted special function members as
artificial instead of having a separate attribute for it? The (small)
advantage of having a separate attribute is that the consumer knows
whether it was explicitly defaulted.
It might still be of value, may be to answer questions like "why is
the member marked as artificial?".

gcc/cp/ChangeLog:

2014-10-03 Siva Chandra Reddy <***@google.com>

* decl2.c (grokfield): Mark special methods declared as default
to be artificial.

gcc/testsuite/ChangeLog:

2014-10-03 Siva Chandra Reddy <***@google.com>

* g++.dg/dwarf2/default-ctor-dtor.C: New test.
Jason Merrill
2014-10-04 18:13:22 UTC
Permalink
Post by Siva Chandra
* decl2.c (grokfield): Mark special methods declared as default
to be artificial.
No, defaulted methods are still user-declared, not artificial.

Jason
Jason Merrill
2014-10-03 19:45:38 UTC
Permalink
Post by Cary Coutant
Post by Mark Wielaard
O. Then I was indeed wrong and defaulted does not impact ABI at all.
At least that is one worry less for the abi checkers :)
As Siva mentioned, it does in fact impact the ABI. A class with a
non-trivial destructor is not a POD, and affects the calling
convention, so the debugger needs to know the difference.
Yes, but defaulted does not imply trivial (though the converse is true),
so knowing whether a declaration is defaulted is neither necessary nor
sufficient to determine the parameter passing ABI. It would be good to
represent trivial_fn_p in the DWARF.

Jason
Siva Chandra
2014-10-03 21:41:46 UTC
Permalink
Post by Cary Coutant
Post by Mark Wielaard
O. Then I was indeed wrong and defaulted does not impact ABI at all.
At least that is one worry less for the abi checkers :)
As Siva mentioned, it does in fact impact the ABI. A class with a
non-trivial destructor is not a POD, and affects the calling
convention, so the debugger needs to know the difference.
Yes, but defaulted does not imply trivial (though the converse is true), so
knowing whether a declaration is defaulted is neither necessary nor
sufficient to determine the parameter passing ABI.
I understand that knowing whether a copy-ctor or a d-tor has been
explicitly defaulted is not sufficient to determine the parameter
passing ABI. However, why is it not necessary? I could be wrong, but
doesn't the example I have given show that it is necessary?

Thanks,
Siva Chandra
Jason Merrill
2014-10-04 18:14:05 UTC
Permalink
Post by Siva Chandra
I understand that knowing whether a copy-ctor or a d-tor has been
explicitly defaulted is not sufficient to determine the parameter
passing ABI. However, why is it not necessary? I could be wrong, but
doesn't the example I have given show that it is necessary?
An implicitly declared 'tor can also be trivial.

Jason
Siva Chandra
2014-10-07 00:50:23 UTC
Permalink
Post by Jason Merrill
Post by Siva Chandra
I understand that knowing whether a copy-ctor or a d-tor has been
explicitly defaulted is not sufficient to determine the parameter
passing ABI. However, why is it not necessary? I could be wrong, but
doesn't the example I have given show that it is necessary?
An implicitly declared 'tor can also be trivial.
But, the question is whether it is required to determine the parameter
passing ABI. If there is no special marker to indicate that the user
declared 'tor is explicitly defaulted, then GDB could (in the absence
of other properties which make the 'tor non-trivial) incorrectly
conclude that the the 'tor is user defined, and hence not-trivial.
Jason Merrill
2014-10-07 00:55:41 UTC
Permalink
Post by Siva Chandra
Post by Jason Merrill
Post by Siva Chandra
I understand that knowing whether a copy-ctor or a d-tor has been
explicitly defaulted is not sufficient to determine the parameter
passing ABI. However, why is it not necessary? I could be wrong, but
doesn't the example I have given show that it is necessary?
An implicitly declared 'tor can also be trivial.
But, the question is whether it is required to determine the parameter
passing ABI. If there is no special marker to indicate that the user
declared 'tor is explicitly defaulted, then GDB could (in the absence
of other properties which make the 'tor non-trivial) incorrectly
conclude that the the 'tor is user defined, and hence not-trivial.
I've been thinking that we should just mark the 'tor as trivial or not
directly rather than hint at it. Does GDB have enough information to
determine triviality if we just add defaulted info?

Jason
Dodji Seketeli
2014-10-07 07:24:45 UTC
Permalink
Post by Jason Merrill
Post by Siva Chandra
Post by Jason Merrill
Post by Siva Chandra
I understand that knowing whether a copy-ctor or a d-tor has been
explicitly defaulted is not sufficient to determine the parameter
passing ABI. However, why is it not necessary? I could be wrong, but
doesn't the example I have given show that it is necessary?
An implicitly declared 'tor can also be trivial.
But, the question is whether it is required to determine the parameter
passing ABI. If there is no special marker to indicate that the user
declared 'tor is explicitly defaulted, then GDB could (in the absence
of other properties which make the 'tor non-trivial) incorrectly
conclude that the the 'tor is user defined, and hence not-trivial.
I've been thinking that we should just mark the 'tor as trivial or not
directly rather than hint at it.
FWIW, this would be my inclination too. I think it would make the job
of the debug info consumer a lot easier.

Thanks.
--
Dodji
Mark Wielaard
2014-10-07 11:05:40 UTC
Permalink
Post by Jason Merrill
Post by Siva Chandra
Post by Jason Merrill
Post by Siva Chandra
I understand that knowing whether a copy-ctor or a d-tor has been
explicitly defaulted is not sufficient to determine the parameter
passing ABI. However, why is it not necessary? I could be wrong, but
doesn't the example I have given show that it is necessary?
An implicitly declared 'tor can also be trivial.
But, the question is whether it is required to determine the parameter
passing ABI. If there is no special marker to indicate that the user
declared 'tor is explicitly defaulted, then GDB could (in the absence
of other properties which make the 'tor non-trivial) incorrectly
conclude that the the 'tor is user defined, and hence not-trivial.
I've been thinking that we should just mark the 'tor as trivial or not
directly rather than hint at it. Does GDB have enough information to
determine triviality if we just add defaulted info?
To be honest my original patches for a deleted/defaulted markers on
special member functions was really just meant to give the consumer a
way to know why GCC produced a declaration in the first place. Which I
still think is useful information for the consumer to have, but
certainly not enough to solve the abi problem with inferior function
calls Siva was seeing. Maybe GDB has enough information/smarts, but I
don't think other consumers have. So an explicit "trivial/non-trivial"
marker on special member functions seems like a good idea.

But looking at the definition of trivial copy constructor and trivial
destructor they do look more like class concepts instead of individual
constructor/destructor concepts (since they rely on properties of other
members and the base class). Currently GCC doesn't output declarations
unless the user declares them. So an implicit copy constructor or
destructor doesn't get a DWARF class member declaration. But I don't
think a consumer can conclude just from that fact that the copy
constructor or destructor is trivial. Nor can it asssume they are
non-trivial just because they are are respresented in DWARF. So should
we always output them and add a flag value to indicate
(non-trivialness). Or should we add attributes on the class itself?

Taking a step back and looking at the actual function that is causing
the trouble because abi/calling convention seems unclear. Which makes me
wonder if the issue isn't actually with the DWARF declaration of the
function that has special calling conventions. I am slightly surprised
the special return value passed in rule isn't expressed in the mangling
of the function name (or is it?). So the calling convention needs to be
interpreted from the DWARF representation. We already add a synthetic
formal parameter for "this" if necessary to be passed in. Why don't we
just add a similar synthetic "return" formal parameter if that is how
the function is really being invoked? That seems like a more direct way
to solve the inferior function call issue.

Cheers,

Mark
Siva Chandra
2014-10-07 14:13:31 UTC
Permalink
Post by Mark Wielaard
To be honest my original patches for a deleted/defaulted markers on
special member functions was really just meant to give the consumer a
way to know why GCC produced a declaration in the first place. Which I
still think is useful information for the consumer to have, but
certainly not enough to solve the abi problem with inferior function
calls Siva was seeing. Maybe GDB has enough information/smarts, but I
don't think other consumers have. So an explicit "trivial/non-trivial"
marker on special member functions seems like a good idea.
But looking at the definition of trivial copy constructor and trivial
destructor they do look more like class concepts instead of individual
constructor/destructor concepts (since they rely on properties of other
members and the base class). Currently GCC doesn't output declarations
unless the user declares them. So an implicit copy constructor or
destructor doesn't get a DWARF class member declaration. But I don't
think a consumer can conclude just from that fact that the copy
constructor or destructor is trivial. Nor can it asssume they are
non-trivial just because they are are respresented in DWARF. So should
we always output them and add a flag value to indicate
(non-trivialness). Or should we add attributes on the class itself?
I also feel that triviality of special methods is more like a class
concept. Also, this concept is specified by the language.
Post by Mark Wielaard
Taking a step back and looking at the actual function that is causing
the trouble because abi/calling convention seems unclear. Which makes me
wonder if the issue isn't actually with the DWARF declaration of the
function that has special calling conventions. I am slightly surprised
the special return value passed in rule isn't expressed in the mangling
of the function name (or is it?). So the calling convention needs to be
interpreted from the DWARF representation. We already add a synthetic
formal parameter for "this" if necessary to be passed in. Why don't we
just add a similar synthetic "return" formal parameter if that is how
the function is really being invoked? That seems like a more direct way
to solve the inferior function call issue.
Triviality (or not) is specified by the language. Similarly, the
'this' pointer is specified by the language. However, function calling
convention is specified by the ABI. ISTR that DWARF cannot/should not
describe the ABI. May be I am wrong, but if it is indeed possible to
specify the ABI in DWARF, then I agree that it probably is the best
solution for function call issue.

Thanks,
Siva Chandra
Siva Chandra
2014-10-07 13:36:31 UTC
Permalink
Post by Jason Merrill
Post by Siva Chandra
But, the question is whether it is required to determine the parameter
passing ABI. If there is no special marker to indicate that the user
declared 'tor is explicitly defaulted, then GDB could (in the absence
of other properties which make the 'tor non-trivial) incorrectly
conclude that the the 'tor is user defined, and hence not-trivial.
I've been thinking that we should just mark the 'tor as trivial or not
directly rather than hint at it. Does GDB have enough information to
determine triviality if we just add defaulted info?
Barring some incompleteness, for which patches are very close to
getting committed, I believe GDB has the rest of the information.
After those patches are committed, the algorithm used by GDB to
determine whether a value is returned in a hidden param or not is as
follows:

1. If the value is of a dynamic class (as in, has virtual bases or
virtual functions), return in hidden param.
2. Else, go over all methods that are found in the DWARF:
----2a. If a method is marked artificial, ignore it.
----2b. If the method is a copy-constructor or a destructor, conclude
that a pointer to the value is to be returned in the hidden first
param.
-------- This is because, presence of a copy-ctor or dtor which are
nor artificial indicates that they were user declared and not
implicit.
3. If a decision was not made in 2, do 1 and 2 for base class
subobjects and non-static members.
4. If a decision was not made in 3, then conclude that it should not
be passed in a hidden param.

If an explicitly defaulted copy-ctor or dtor is not marked as such,
step 2 is broken.
Jason Merrill
2014-10-08 12:56:43 UTC
Permalink
Post by Siva Chandra
Barring some incompleteness, for which patches are very close to
getting committed, I believe GDB has the rest of the information.
Interesting. It is still the case that defaulting in the class is
different from defaulting outside the class, though; a function
defaulted outside the class is user-provided, and therefore not trivial.
But rather than encode "defaulted in the class body" (as Mark's
initial patch) I'd prefer to just encode "trivial".

DW_AT_artificial is for things not actually declared in the source, so
using it for explicitly declared functions is incorrect.

Jason

Siva Chandra
2014-10-03 17:13:44 UTC
Permalink
Post by Jason Merrill
Post by Mark Wielaard
A debugger not knowing whether a special member function was explicitly
defaulted, implicitly declared or explicitly defined seems less confusion
than not knowing whether it was deleted. But there are some subtle cases
where knowing whether a constructor was user defined or explicitly
defaulted do matter for whether the default constructor might have been
implicitly generated.
Can you elaborate?
Post by Mark Wielaard
So like the deleted case this patch introduces
a new attribute DW_AT_GNU_defaulted that gets attached to the function
declaration. Note that since this is for declarations we explicitly
test for DECL_DEFAULTED_IN_CLASS_P and ignore any implementation
definitions that use = default; outside the class body.
Hmm, I'm dubious about this choice. How do you expect a consumer to use
this information?
I apologize for gate crashing here...

Currently, there is no special attribute to indicate that a special
member function is declared = default. So, if you have a class
definition like this:

class A
{
public:
A () {}
~A () = default;
int a;
};

then, GDB sees the declaration of the destructor with no special
attributes (like DW_AT_artificial or similar) and thinks that the copy
constructor is user defined. Consequently, if there is a function
defined as:

A
make_a (int i)
{
A a;
a.a = i;

return a;
}

Then, if a user invokes make_a at the GDB prompt, then GDB will
wrongly pass the pointer to the return value as a hidden first
parameter.

Question: Should special member functions declared = default be marked
DW_AT_artificial?

Thanks,
Siva Chandra
Siva Chandra
2014-10-03 17:15:32 UTC
Permalink
Post by Siva Chandra
Post by Jason Merrill
Post by Mark Wielaard
A debugger not knowing whether a special member function was explicitly
defaulted, implicitly declared or explicitly defined seems less confusion
than not knowing whether it was deleted. But there are some subtle cases
where knowing whether a constructor was user defined or explicitly
defaulted do matter for whether the default constructor might have been
implicitly generated.
Can you elaborate?
Post by Mark Wielaard
So like the deleted case this patch introduces
a new attribute DW_AT_GNU_defaulted that gets attached to the function
declaration. Note that since this is for declarations we explicitly
test for DECL_DEFAULTED_IN_CLASS_P and ignore any implementation
definitions that use = default; outside the class body.
Hmm, I'm dubious about this choice. How do you expect a consumer to use
this information?
I apologize for gate crashing here...
Currently, there is no special attribute to indicate that a special
member function is declared = default. So, if you have a class
class A
{
A () {}
~A () = default;
int a;
};
then, GDB sees the declaration of the destructor with no special
attributes (like DW_AT_artificial or similar) and thinks that the copy
constructor is user defined.
Aww, sorry. I should have said destructor instead of copy constructor.
Jason Merrill
2014-10-03 14:15:31 UTC
Permalink
OK.

Jason
Andreas Schwab
2014-10-06 07:38:35 UTC
Permalink
Post by Mark Wielaard
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/deleted-member-function.C b/gcc/testsuite/g++.dg/debug/dwarf2/deleted-member-function.C
new file mode 100644
index 0000000..4cc77e6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/deleted-member-function.C
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-O -std=c++11 -g -dA" }
+// { dg-final { scan-assembler-times "# DW_AT_GNU_deleted" 2 } }
$ grep DW_AT_GNU_deleted deleted-member-function.s
// DW_AT_GNU_deleted
// DW_AT_GNU_deleted
.uleb128 0x211a // (DW_AT_GNU_deleted)
.uleb128 0x211a // (DW_AT_GNU_deleted)

Andreas.
--
Andreas Schwab, SUSE Labs, ***@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE 1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."
Mark Wielaard
2014-10-06 07:54:44 UTC
Permalink
Post by Andreas Schwab
Post by Mark Wielaard
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/deleted-member-function.C b/gcc/testsuite/g++.dg/debug/dwarf2/deleted-member-function.C
new file mode 100644
index 0000000..4cc77e6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/deleted-member-function.C
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-O -std=c++11 -g -dA" }
+// { dg-final { scan-assembler-times "# DW_AT_GNU_deleted" 2 } }
$ grep DW_AT_GNU_deleted deleted-member-function.s
// DW_AT_GNU_deleted
// DW_AT_GNU_deleted
.uleb128 0x211a // (DW_AT_GNU_deleted)
.uleb128 0x211a // (DW_AT_GNU_deleted)
With gcc master this testcase gives:

$ grep DW_AT_GNU_deleted deleted-member-function.s
# DW_AT_GNU_deleted
# DW_AT_GNU_deleted
.uleb128 0x211a # (DW_AT_GNU_deleted)
.uleb128 0x211a # (DW_AT_GNU_deleted)

Somehow in your version the # comment turned into // ?

Just removing the # prefix (but keeping the space) from
scan-assembler-times should work for both our cases. I just don't know
why our .s outputs look different. If it is something that can be fixed
through setting a dg-options that would be preferable I think.

Cheers,

Mark
Steven Bosscher
2014-10-06 08:03:53 UTC
Permalink
Post by Mark Wielaard
Just removing the # prefix (but keeping the space) from
scan-assembler-times should work for both our cases. I just don't know
why our .s outputs look different.
Wild guess: different comment marker in the target's assembly language?

Ciao!
Steven
Rainer Orth
2014-10-08 08:56:13 UTC
Permalink
Post by Steven Bosscher
Post by Mark Wielaard
Just removing the # prefix (but keeping the space) from
scan-assembler-times should work for both our cases. I just don't know
why our .s outputs look different.
Wild guess: different comment marker in the target's assembly language?
True: on Solaris/x86 with /bin/as, I have

/ DW_AT_GNU_deleted

on Solaris/SPARC with /bin/as, it's

.byte 0x1 ! DW_AT_GNU_deleted

instead, and probably even more others on different platforms.

Rainer
--
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University
Mark Wielaard
2014-10-08 10:27:22 UTC
Permalink
Post by Rainer Orth
Post by Steven Bosscher
Post by Mark Wielaard
Just removing the # prefix (but keeping the space) from
scan-assembler-times should work for both our cases. I just don't know
why our .s outputs look different.
Wild guess: different comment marker in the target's assembly language?
True: on Solaris/x86 with /bin/as, I have
/ DW_AT_GNU_deleted
on Solaris/SPARC with /bin/as, it's
.byte 0x1 ! DW_AT_GNU_deleted
instead, and probably even more others on different platforms.
Thanks for checking this was the cause of the failure Andreas was
seeing. I pushed the following as obvious to fix it. Please yell and
scream if it wasn't obvious or if it doesn't solve the failure.

Cheers,

Mark

diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 723412c..21b2c26 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2014-10-08 Mark Wielaard <***@redhat.com>
+
+ * g++.dg/debug/dwarf2/deleted-member-function.C: Remove comment marker
+ prefix from scan-assembler-times.
+
2014-10-07 Marek Polacek <***@redhat.com>

* lib/target-supports.exp (check_effective_target_fd_truncate):
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/deleted-member-function.C b/gcc/testsuite/g++.dg/debug/dwarf2/deleted-member-function.C
index 4cc77e6..50a8451 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/deleted-member-function.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/deleted-member-function.C
@@ -1,6 +1,6 @@
// { dg-do compile }
// { dg-options "-O -std=c++11 -g -dA" }
-// { dg-final { scan-assembler-times "# DW_AT_GNU_deleted" 2 } }
+// { dg-final { scan-assembler-times " DW_AT_GNU_deleted" 2 } }

struct Foo
{
Loading...