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
This commit is contained in:
Jakub Jelinek 2008-11-13 22:04:32 +01:00 committed by Jakub Jelinek
parent a231ffe57d
commit 2db56bbc02
5 changed files with 230 additions and 8 deletions

View File

@ -1,3 +1,12 @@
2008-11-13 Jakub Jelinek <jakub@redhat.com>
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 <tbm@cyrius.com>
* c-common.c (warn_about_parentheses): Add missing whitespace

View File

@ -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));

View File

@ -1,3 +1,9 @@
2008-11-13 Jakub Jelinek <jakub@redhat.com>
PR c++/27017
* g++.dg/debug/dwarf2/localclass1.C: New test.
* g++.dg/debug/dwarf2/localclass2.C: New test.
2008-11-13 Uros Bizjak <ubizjak@gmail.com>
* gcc.dg/compat/struct-layout-1_generate.c (dg-options): Add -mno-mmx

View File

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

View File

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