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

Reply via email to