Bug 41172 - C frontend botches type.name for typedef chains
Summary: C frontend botches type.name for typedef chains
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.5.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-08-26 02:08 UTC by Dan Witte
Modified: 2012-03-13 23:54 UTC (History)
3 users (show)

See Also:
Host: i686-pc-linux-gnu
Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu
Known to work:
Known to fail:
Last reconfirmed:


Attachments
testcase (82 bytes, text/plain)
2009-08-26 02:09 UTC, Dan Witte
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Dan Witte 2009-08-26 02:08:03 UTC
gcc version 4.5.0 20090825 (experimental) (GCC)

I found this bug while working on static analysis tools for Mozilla (using the plugin framework), where we access |tree| structures in the cfg. (For reference, this is also filed as https://bugzilla.mozilla.org/show_bug.cgi?id=511261.)

Consider testcase.c:

typedef struct  { int i; } foo_t;
typedef const foo_t bar_t;
bar_t func() { bar_t b; return b; }

Invoked via:
cc1 testcase.c

Then the |bar_t| return type of |func()| will have a null TYPE_NAME(). I proved this by introducing a syntax error in the body of |func()| and breaking in lhd_print_error_function() in gcc/langhooks.c:

Breakpoint 3, lhd_print_error_function (context=0x8ac2760, 
    file=0xbffff542 "/home/dwitte/builds/gcc-dehydra/dehydra/test/test_c_typedef_bug.c", diagnostic=0xbfffeee4)
    at ../../src/gcc/langhooks.c:349
349	{
(gdb) p current_function_decl->common.type->base.code
$21 = FUNCTION_TYPE
(gdb) p current_function_decl->common.type->common.type->base.code
$22 = RECORD_TYPE
(gdb) p current_function_decl->common.type->common.type->type.name
$23 = (tree) 0x0

If the |const| is removed from the definition of bar_t, things work fine:
(gdb) p current_function_decl->common.type->common.type->type.name->decl_minimal.name.identifier.id.str
$25 = (const unsigned char *) 0xb7d6bc00 "bar_t"

If the return type of |func()| is instead |foo_t|, things also work:
(gdb) p current_function_decl->common.type->common.type->type.name->decl_minimal.name.identifier.id.str
$26 = (const unsigned char *) 0xb7d6bbf8 "foo_t"

In addition, it's worth noting that the variant chain of the return type (in the testcase as written) does include |bar_t|, as well as |foo_t| (twice), but interspersed with null-named trees. This may or may not be relevant.

(gdb) p $rt = current_function_decl->common.type->common.type
$47 = (tree) 0xb7d7d7e0
(gdb) p $variant = $rt->type.main_variant
$48 = (tree) 0xb7d7d5b0
(gdb) p $variant->type.name
$49 = (tree) 0x0
(gdb) p $variant = $variant->type.next_variant
$50 = (tree) 0xb7d7d8c0
(gdb) p $variant->type.name
$51 = (tree) 0xb7d7d850
(gdb) p $variant->type.name->decl_minimal.name.identifier.id.str
$52 = (const unsigned char *) 0xb7d6bc00 "bar_t"
(gdb) p $variant = $variant->type.next_variant
$53 = (tree) 0xb7d7d7e0
(gdb) p $variant->type.name
$54 = (tree) 0x0
(gdb) p $variant = $variant->type.next_variant
$55 = (tree) 0xb7d7d770
(gdb) p $variant->type.name
$56 = (tree) 0xb7d7d690
(gdb) p $variant->type.name->decl_minimal.name.identifier.id.str
$57 = (const unsigned char *) 0xb7d6bbf8 "foo_t"
(gdb) p $variant = $variant->type.next_variant
$58 = (tree) 0xb7d7d700
(gdb) p $variant->type.name
$59 = (tree) 0xb7d7d690
(gdb) p $variant->type.name->decl_minimal.name.identifier.id.str
$60 = (const unsigned char *) 0xb7d6bbf8 "foo_t"
(gdb) p $variant = $variant->type.next_variant
$61 = (tree) 0x0

Note that the C++ FE gets this right. I'm guessing that there's something wrong with variant type creation involving qualifiers.

gcc -v:
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: ../src/configure --without-libstdcxx --prefix=/home/dwitte/builds/gcc-trunk/obj/../installed --enable-languages=c,c++
Thread model: posix
gcc version 4.5.0 20090825 (experimental) (GCC)
Comment 1 Dan Witte 2009-08-26 02:09:49 UTC
Created attachment 18425 [details]
testcase
Comment 2 Dan Witte 2009-08-26 02:13:41 UTC
Also, this bug applies to ENUMERAL_TYPEs and UNION_TYPEs in addition to RECORD_TYPEs.
Comment 3 Andrew Pinski 2009-08-26 03:18:20 UTC
Unlike C++, C does not inject foo_t if used as struct foo_t.

So I think this is correct behavior and really does not matter.
Comment 4 Dan Witte 2009-08-26 04:25:15 UTC
Then how does the compiler determine type equality? By looking at the variant chain? By determining the originating type somehow? If you can point me to the procedure it uses to do this, perhaps we can duplicate it in our plugin code.
Comment 5 Andrew Pinski 2009-08-26 04:28:07 UTC
(In reply to comment #4)
> Then how does the compiler determine type equality? By looking at the variant
> chain? 

Easy  pointer equality on TYPE_MAIN_VARIANT :)
Comment 6 Dan Witte 2009-08-26 05:52:51 UTC
Well, if it's comparing two existing types, sure. :)

How does it work in the case where the parser is dealing with the declaration |bar_t func()|, and it wants to determine if it's seen the declaration of |bar_t| before?

Wait, don't tell me. The parser keeps a separate mapping of names->trees?
Comment 7 Tom Tromey 2009-08-26 14:28:12 UTC
Typedefs are found using lookup_name.
There is not really a separate mapping; instead the
trees are held directly in the identifier node.
These are reset as typedefs (or whatever) go out of scope,
though.
Comment 8 Andrew Pinski 2012-03-13 23:54:48 UTC
As mentioned the C front-end is working correctly.