From 2db56bbc02cebb8fd46a62776ef209f4e945ae18 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 13 Nov 2008 22:04:32 +0100 Subject: [PATCH] re PR debug/27017 (Debug information for static local class members are not emitted) PR c++/27017 * dwarf2out.c (prune_unused_types_walk_local_classes): New function. (prune_unused_types_walk): Call it for non-perennial local classes. Set die_mark to 2 if recursing on children. If die_mark is 1 on entry, just set it to 2 and recurse on children, don't walk attributes again. * g++.dg/debug/dwarf2/localclass1.C: New test. * g++.dg/debug/dwarf2/localclass2.C: New test. From-SVN: r141829 --- gcc/ChangeLog | 9 +++ gcc/dwarf2out.c | 71 +++++++++++++++-- gcc/testsuite/ChangeLog | 6 ++ .../g++.dg/debug/dwarf2/localclass1.C | 76 +++++++++++++++++++ .../g++.dg/debug/dwarf2/localclass2.C | 76 +++++++++++++++++++ 5 files changed, 230 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/localclass1.C create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/localclass2.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9e60b2bad2b..7698bddd115 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2008-11-13 Jakub Jelinek + + PR c++/27017 + * dwarf2out.c (prune_unused_types_walk_local_classes): New function. + (prune_unused_types_walk): Call it for non-perennial local classes. + Set die_mark to 2 if recursing on children. If die_mark is 1 on + entry, just set it to 2 and recurse on children, don't walk attributes + again. + 2008-11-13 Martin Michlmayr * c-common.c (warn_about_parentheses): Add missing whitespace diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 614871ed917..337c22e119c 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -16248,6 +16248,37 @@ prune_unused_types_mark (dw_die_ref die, int dokids) } } +/* For local classes, look if any static member functions were emitted + and if so, mark them. */ + +static void +prune_unused_types_walk_local_classes (dw_die_ref die) +{ + dw_die_ref c; + + if (die->die_mark == 2) + return; + + switch (die->die_tag) + { + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + break; + + case DW_TAG_subprogram: + if (!get_AT_flag (die, DW_AT_declaration) + || die->die_definition != NULL) + prune_unused_types_mark (die, 1); + return; + + default: + return; + } + + /* Mark children. */ + FOR_EACH_CHILD (die, c, prune_unused_types_walk_local_classes (c)); +} /* Walk the tree DIE and mark types that we actually use. */ @@ -16256,12 +16287,34 @@ prune_unused_types_walk (dw_die_ref die) { dw_die_ref c; - /* Don't do anything if this node is already marked. */ - if (die->die_mark) + /* Don't do anything if this node is already marked and + children have been marked as well. */ + if (die->die_mark == 2) return; switch (die->die_tag) { + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + if (die->die_perennial_p) + break; + + for (c = die->die_parent; c; c = c->die_parent) + if (c->die_tag == DW_TAG_subprogram) + break; + + /* Finding used static member functions inside of classes + is needed just for local classes, because for other classes + static member function DIEs with DW_AT_specification + are emitted outside of the DW_TAG_*_type. If we ever change + it, we'd need to call this even for non-local classes. */ + if (c) + prune_unused_types_walk_local_classes (die); + + /* It's a type node --- don't mark it. */ + return; + case DW_TAG_const_type: case DW_TAG_packed_type: case DW_TAG_pointer_type: @@ -16269,9 +16322,6 @@ prune_unused_types_walk (dw_die_ref die) case DW_TAG_volatile_type: case DW_TAG_typedef: case DW_TAG_array_type: - case DW_TAG_structure_type: - case DW_TAG_union_type: - case DW_TAG_class_type: case DW_TAG_interface_type: case DW_TAG_friend: case DW_TAG_variant_part: @@ -16293,10 +16343,15 @@ prune_unused_types_walk (dw_die_ref die) break; } - die->die_mark = 1; + if (die->die_mark == 0) + { + die->die_mark = 1; + + /* Now, mark any dies referenced from here. */ + prune_unused_types_walk_attribs (die); + } - /* Now, mark any dies referenced from here. */ - prune_unused_types_walk_attribs (die); + die->die_mark = 2; /* Mark children. */ FOR_EACH_CHILD (die, c, prune_unused_types_walk (c)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3bf998fd7c7..6b423ed3a49 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2008-11-13 Jakub Jelinek + + PR c++/27017 + * g++.dg/debug/dwarf2/localclass1.C: New test. + * g++.dg/debug/dwarf2/localclass2.C: New test. + 2008-11-13 Uros Bizjak * gcc.dg/compat/struct-layout-1_generate.c (dg-options): Add -mno-mmx diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/localclass1.C b/gcc/testsuite/g++.dg/debug/dwarf2/localclass1.C new file mode 100644 index 00000000000..c7c55e12d43 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/localclass1.C @@ -0,0 +1,76 @@ +// PR c++/27017 +// { dg-do compile } +// { dg-options "-gdwarf-2 -dA -feliminate-unused-debug-types -fno-merge-debug-strings" } + +int +foo (int arg1) +{ + struct localstruct1 + { + static inline int staticfn1 (int arg2) + { + int var2 = arg2 << 2; + return arg2 + var2; + } + static int staticfn2 (int arg3) + { + int var3 = arg3 << 2; + return arg3 + var3; + } + static inline int staticfn3 (int arg4) + { + int var4 = arg4 << 2; + return arg4 + var4; + } + static int staticfn4 (int arg5) + { + int var5 = arg5 << 2; + return arg5 + var5; + } + int method1 (int arg6) + { + int var6 = arg6 << 2; + return arg6 + var6; + } + }; + struct localstruct2 + { + static inline int staticfn5 (int arg7) + { + int var7 = arg7 << 2; + return arg7 + var7; + } + static int staticfn6 (int arg8) + { + int var8 = arg8 << 2; + return arg8 + var8; + } + }; + return localstruct1::staticfn1 (arg1) + localstruct1::staticfn2 (arg1); +} + +int +main () +{ + return foo (1) - 10; +} + +// { dg-final { scan-assembler "main\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler "foo\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler "staticfn1\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler "staticfn2\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "staticfn3\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "staticfn4\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "staticfn5\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "staticfn6\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "method1\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler "arg1\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler "arg2\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler "arg3\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "arg4\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "arg5\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "arg6\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "arg7\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "arg8\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler "localstruct1\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "localstruct2\[^\n\r\]*DW_AT_name" } } diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/localclass2.C b/gcc/testsuite/g++.dg/debug/dwarf2/localclass2.C new file mode 100644 index 00000000000..6e9a0664f17 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/localclass2.C @@ -0,0 +1,76 @@ +// PR c++/27017 +// { dg-do compile } +// { dg-options "-gdwarf-2 -dA -O2 -feliminate-unused-debug-types -fno-merge-debug-strings" } + +int +foo (int arg1) +{ + struct localstruct1 + { + static inline int staticfn1 (int arg2) + { + int var2 = arg2 << 2; + return arg2 + var2; + } + static int staticfn2 (int arg3) + { + int var3 = arg3 << 2; + return arg3 + var3; + } + static inline int staticfn3 (int arg4) + { + int var4 = arg4 << 2; + return arg4 + var4; + } + static int staticfn4 (int arg5) + { + int var5 = arg5 << 2; + return arg5 + var5; + } + int method1 (int arg6) + { + int var6 = arg6 << 2; + return arg6 + var6; + } + }; + struct localstruct2 + { + static inline int staticfn5 (int arg7) + { + int var7 = arg7 << 2; + return arg7 + var7; + } + static int staticfn6 (int arg8) + { + int var8 = arg8 << 2; + return arg8 + var8; + } + }; + return localstruct1::staticfn1 (arg1) + localstruct1::staticfn2 (arg1); +} + +int +main () +{ + return foo (1) - 10; +} + +// { dg-final { scan-assembler "main\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler "foo\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler "staticfn1\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler "staticfn2\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "staticfn3\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "staticfn4\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "staticfn5\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "staticfn6\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "method1\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler "arg1\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler "arg2\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler "arg3\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "arg4\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "arg5\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "arg6\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "arg7\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "arg8\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler "localstruct1\[^\n\r\]*DW_AT_name" } } +// { dg-final { scan-assembler-not "localstruct2\[^\n\r\]*DW_AT_name" } } -- 2.30.2