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)
Created attachment 18425 [details] testcase
Also, this bug applies to ENUMERAL_TYPEs and UNION_TYPEs in addition to RECORD_TYPEs.
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.
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.
(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 :)
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?
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.
As mentioned the C front-end is working correctly.