Hi Jason.
After my last set of dwarf changes for locals, I found some target
library building failures which I am now fixing.
The problem at hand is that, by design, the caching code in
gen_variable_die() refuses to use a previously cached DIE if the current
context and the cached context are different:
else if (old_die->die_parent != context_die)
{
/* If the contexts differ, it means we're not talking about
the same thing. Clear things so we can get a new DIE.
This can happen when creating an inlined instance, in
which case we need to create a new DIE that will get
annotated with DW_AT_abstract_origin. */
old_die = NULL;
gcc_assert (!DECL_ABSTRACT_P (decl));
}
This is causing problems with local statics which are handled at
dwarf2out_late_global_decl, and which originally have a context of the
compilation unit (by virtue of the dwarf2out_decl call). This context
then gets changed here:
/* For local statics lookup proper context die. */
if (TREE_STATIC (decl)
&& DECL_CONTEXT (decl)
&& TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
context_die = lookup_decl_die (DECL_CONTEXT (decl));
This new context may be correct for front/middle-end purposes, but is
not the DIE context I am expecting in gen_variable_die. For example, in
the following example, the DECL_CONTEXT for the static is funky's
DW_TAG_subprogram, whereas the caching code is expecting the
DW_TAG_lexical_block:
void funky()
{
{
static const char *nested_static_const = "testing123";
}
}
My proposed way of handling it (attached) is by tightening the check in
gen_variable_die(), and special casing this scenario (assuming, there is
no other way to get a differing context). This works, and fixes all the
failures, without introducing any regressions.
Another approach would be to use whatever context is already cached with
just "context_die = lookup_decl_die (decl)", but that feels like cheating.
Are you OK with the attached approach, or do you have something else in
mind?
Thanks.
Aldy
commit 515a20666d0ea73f2380bae6d9b8ec1d5bb2f001
Author: Aldy Hernandez <al...@redhat.com>
Date: Thu Dec 11 09:26:25 2014 -0800
* dwarf2out.c (gen_subprogram_die): Handle as cached die if
dumped_early bit is set.
(dwarf2out_decl): Abstract local static check...
(local_function_static): ...into here.
(gen_variable_die): Handle different contexts in a cached die
gracefully for the non inline case.
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index e4a7973..5d55d1f 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -18511,7 +18511,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
apply; we just use the old DIE. */
expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
struct dwarf_file_data * file_index = lookup_filename (s.file);
- if (((is_cu_die (old_die->die_parent) || context_die == NULL)
+ if (((is_cu_die (old_die->die_parent)
+ || context_die == NULL
+ || dumped_early)
&& (DECL_ARTIFICIAL (decl)
|| (get_AT_file (old_die, DW_AT_decl_file) == file_index
&& (get_AT_unsigned (old_die, DW_AT_decl_line)
@@ -19132,6 +19134,17 @@ decl_will_get_specification_p (dw_die_ref old_die,
tree decl, bool declaration)
&& get_AT_flag (old_die, DW_AT_declaration) == 1);
}
+/* Return true if DECL is a local static. */
+
+static inline bool
+local_function_static (tree decl)
+{
+ gcc_assert (TREE_CODE (decl) == VAR_DECL);
+ return TREE_STATIC (decl)
+ && DECL_CONTEXT (decl)
+ && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL;
+}
+
/* Generate a DIE to represent a declared data object.
Either DECL or ORIGIN must be non-null. */
@@ -19283,13 +19296,35 @@ gen_variable_die (tree decl, tree origin, dw_die_ref
context_die)
}
else if (old_die->die_parent != context_die)
{
- /* If the contexts differ, it means we're not talking about
- the same thing. Clear things so we can get a new DIE.
- This can happen when creating an inlined instance, in
- which case we need to create a new DIE that will get
- annotated with DW_AT_abstract_origin. */
- old_die = NULL;
- gcc_assert (!DECL_ABSTRACT_P (decl));
+ /* If the contexts differ, it means we _MAY_ not be talking
+ about the same thing. */
+ if (origin)
+ {
+ /* If we will be creating an inlined instance, we need a
+ new DIE that will get annotated with
+ DW_AT_abstract_origin. Clear things so we can get a
+ new DIE. */
+ gcc_assert (!DECL_ABSTRACT_P (decl));
+ old_die = NULL;
+ }
+ else
+ {
+ /* Otherwise, the only reasonable alternate way of
+ getting here is during the final dwarf pass, when
+ being called on a local static. We can end up with
+ different contexts because the context_die is set to
+ the context of the containing function, whereas the
+ cached die (old_die) is correctly set to the
+ (possible) enclosing lexical scope
+ (DW_TAG_lexical_block). In which case, special
+ handle it (hack).
+
+ See dwarf2out_decl and its use of
+ local_function_static to see how this happened. */
+ gcc_assert (local_function_static (decl));
+ var_die = old_die;
+ goto gen_variable_die_location;
+ }
}
else
{
@@ -21563,9 +21598,7 @@ dwarf2out_decl (tree decl)
return NULL;
/* For local statics lookup proper context die. */
- if (TREE_STATIC (decl)
- && DECL_CONTEXT (decl)
- && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
+ if (local_function_static (decl))
context_die = lookup_decl_die (DECL_CONTEXT (decl));
/* If we are in terse mode, don't generate any DIEs to represent any