[PATCH] DW_TAG_typedef and DW_TAG_structure_type not emitted when typedef is used

David Blaikie dblaikie at gmail.com
Tue Sep 16 23:40:30 PDT 2014


>>! In D2498#10, @jyoti.yalamanchili wrote:
> Hi David,
> 
>>>! In D2498#9, @dblaikie wrote:
>>>>! In D2498#4, @jyoti.yalamanchili wrote:
>>> This bug appears only when typedef is used.
>> 
>> Doesn't look like it.
> This was my previous analysis which was incorrect. This issue occurs whenever explicit casting occurs. The type to which we are explicitly casting is not emitted in debug info.
>> 
>> Changing the code to cast to (S*) instead of (T) still demonstrates the bug and is still present even with this patch applied.
>> 
> As you mentioned, I verified this for the following code snippet where i am replacing T with struct S* and the result was that DW_TAG_structure_type & DW_TAG_member were emitted but not DW_TAG_typedef because T was not used. I thought this is expected behaviour. Please correct me if i am wrong.

Looks like I was confused (perhaps by the old title of this code review which still mentions typedefs - and perhaps by Phab showing me the newer diff, or maybe I was looking in the wrong place somehow and saw the old code which still special-cased for typedefs). Now that I apply your latest patch properly I see the behavior you describe - this fixes the issue regardless of whether a typedef is used.

> 
> typedef struct S {
>   int i;
> } *T;
> #define M(p) (**(struct S*)**(p))
> 
> void foo(void *p) { M(p)->i++; }
> 
> 
>> The problem is more general than typedefs and casts - arguably we should get this (C++11) case too:
>> 
>>   struct S { int i; };
>>   void func(S);
>>   void func() {
>>     func(S{42});
>>   }
>> 
>> but GCC doesn't get this either, so I'm less concerned.
>> 
>> GCC does get the cast case - with or without a typedef. So perhaps we can just deal with casts for now... 
>> 
> Okay. 
> 
>> The only other thing I can think of is far more invasive/more work - to get this all right, what we really need is a tree of "completeness" - keeping track of any time a type is required to be complete (not just a single bit that says "this has been required to be complete") & then emitting any type for which it was requried to be complete during a function we codegen'd.
>> 
> Sorry, could you please explain this with an example ?

  struct foo { };
  inline void func() { foo f; } // this makes 'f' required to be complete, which means we emit a definition of 'f' if we ever need any reference to 'f'
  foo *f; // this causes us to emit 'f'

Without the second line, we just emit a declaration (in the default -fno-standalone-debug mode). 

> I could mention this in the testcase as a TODO note if you want so we don't loose track of this improvement scope.

That's OK - it's pretty much outside the scope of your change. It wouldn't really belong in this test file.

> 
>> This infrastructure would also allow us to do a better job minimizing debug info for the limited debug info optimization where we currently fail:
>> 
>>   struct foo { ... };
>>   inline void unused() { foo f; } // 'f' is required to be complete here, but the function is never called
>>   foo *f; // but that required completeness is never relied upon for this TU - a declaration would've sufficed
>> 
>> This hurts us in, for example, Clang's own Sema.h - the giant Sema class has a single non-member inline function right after it that has dereferences a Sema pointer, thus requiring Sema to be complete. From then on, if anything else in the TU including Sema.h requires Sema (evern just a pointer to it it) the debug info for the entire class will be emitted.
> 
> If i understand this correctly, point of worry here is about the increase in debug info size, am i right? 

The -fno-standalone-debug default option is an attempt to minimize debug info size, yes. The issue is that it uses /some/ part of the powers necessary to make our general debug info strategy more reliable and to fix this bug you're addressing and possible others in a more general manner. Though I can't site any particular examples similar to yours (places where a type is used, but no named instance or reference to the type is ever needed)... actually I can:

 struct S { };
 void *v = new S;

Clang doesn't emit debug info describing 'S' (but then again, neither does GCC). I imagine maybe there's a few other pieces of syntax that allow one to reference a type without ever naming a variable of that type.

> But, we certainly need the debug info of any referenced variables isn't ?

Sure - in this case there was no variable, but it's still reasonable to describe the type. The rough heuristic is: Any expression written in executing code (global intializers, functions that are actually codegen'd, etc) should be able to be written and executed in a sufficiently advanced debugger given the information Clang produces. 

Any cases where the information is fundamentally not there - are bugs.

================
Comment at: llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp:279
@@ +278,3 @@
+    CGDebugInfo *DI = CGF.getDebugInfo();
+    if (DI &&
+        CGF.CGM.getCodeGenOpts().getDebugInfo() >=
----------------
Roll the DI variable into the if condition and sink the LimitedDebugInfo check into the DI function (at least I think that's how we are/should be doing this - keeping as much of the implementation details down in CGDebugInfo rather than up in the CodeGen callsites)

================
Comment at: llvm/tools/clang/test/CodeGen/Debug-info-explicitcast.c:4
@@ +3,3 @@
+typedef struct S { int i; } *T;
+#define M(p) ((T)(p))
+
----------------
Could you drop the macro usage and the typedef as they're not needed to demonstrate the fundamental bug here?

http://reviews.llvm.org/D2498






More information about the cfe-commits mailing list