https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110439
Bug ID: 110439 Summary: Missing DW_TAG_typedef for variable with attribute of typedef'd type Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: debug Assignee: unassigned at gcc dot gnu.org Reporter: david.faust at oracle dot com Target Milestone: --- $ cat typedef-skip-1.c typedef int foo; foo __attribute__((may_alias)) attr_foo; foo plain_foo; DW_AT_type in the variable DIE for 'attr_foo' refers to the base int type, while for 'plain_foo' it refers to the typedef DIE I would expect: $ gcc -g -c typedef-skip-1.c $ readelf -wi typedef-skip-1.o <0><c>: Abbrev Number: 2 (DW_TAG_compile_unit) <d> DW_AT_producer : (indirect string, offset: 0): GNU C17 12.2.0 -mtune=generic -march=x86-64 -g -fasynchronous-unwind-tables <11> DW_AT_language : 29 (C11) <12> DW_AT_name : (indirect line string, offset: 0): typedef-skip-1.c <16> DW_AT_comp_dir : (indirect line string, offset: 0x11): /home/dfaust/playpen <1a> DW_AT_stmt_list : 0 <1><1e>: Abbrev Number: 3 (DW_TAG_typedef) <1f> DW_AT_name : foo <23> DW_AT_decl_file : 1 <24> DW_AT_decl_line : 1 <25> DW_AT_decl_column : 13 <26> DW_AT_type : <0x2a> <1><2a>: Abbrev Number: 4 (DW_TAG_base_type) <2b> DW_AT_byte_size : 4 <2c> DW_AT_encoding : 5 (signed) <2d> DW_AT_name : int <1><31>: Abbrev Number: 1 (DW_TAG_variable) <32> DW_AT_name : (indirect string, offset: 0x4c): attr_foo <36> DW_AT_decl_file : 1 <36> DW_AT_decl_line : 2 <37> DW_AT_decl_column : 32 <38> DW_AT_type : <0x2a> <3c> DW_AT_external : 1 <3c> DW_AT_location : 9 byte block: 3 0 0 0 0 0 0 0 0 (DW_OP_addr: 0) <1><46>: Abbrev Number: 1 (DW_TAG_variable) <47> DW_AT_name : (indirect string, offset: 0x55): plain_foo <4b> DW_AT_decl_file : 1 <4b> DW_AT_decl_line : 3 <4c> DW_AT_decl_column : 5 <4d> DW_AT_type : <0x1e> <51> DW_AT_external : 1 <51> DW_AT_location : 9 byte block: 3 4 0 0 0 0 0 0 0 (DW_OP_addr: 4) <1><5b>: Abbrev Number: 0 DWARF output by clang has the DW_TAG_typedef DIE in DW_AT_type for both variables: $ clang -c -g typedef-skip-1.c -o typedef-skip-1.o.clang $ readelf -wi typedef-skip-1.o.clang <1><1e>: Abbrev Number: 2 (DW_TAG_variable) <1f> DW_AT_name : (indexed string: 0x3): attr_foo <20> DW_AT_type : <0x29> <24> DW_AT_external : 1 <24> DW_AT_decl_file : 0 <25> DW_AT_decl_line : 2 <26> DW_AT_location : (DW_OP_addrx <0>) <1><29>: Abbrev Number: 3 (DW_TAG_typedef) <2a> DW_AT_type : <0x31> <2e> DW_AT_name : (indexed string: 0x5): foo <2f> DW_AT_decl_file : 0 <30> DW_AT_decl_line : 1 <1><31>: Abbrev Number: 4 (DW_TAG_base_type) <32> DW_AT_name : (indexed string: 0x4): int <33> DW_AT_encoding : 5 (signed) <34> DW_AT_byte_size : 4 <1><35>: Abbrev Number: 2 (DW_TAG_variable) <36> DW_AT_name : (indexed string: 0x6): plain_foo <37> DW_AT_type : <0x29> <3b> DW_AT_external : 1 <3b> DW_AT_decl_file : 0 <3c> DW_AT_decl_line : 3 <3d> DW_AT_location : (DW_OP_addrx <0x1>) <1><40>: Abbrev Number: 0 Note this isn't strictly related to 'may_alias', I just found it to be a reliable reproducer. I tripped on this while working on a patch to support a BPF feature, the btf_type_tag attribute. I think this happens because this lookup in modified_type_die: /* If we do, then we can just use its DIE, if it exists. */ if (qualified_type) { mod_type_die = lookup_type_die (qualified_type); finds the typedef DIE for the un-__attribute__-ed use 'foo', but returns NULL for the __attribute__-ed use of 'foo': Breakpoint 6, modified_type_die (type=<integer_type 0x7ffff77adf18 foo>, cv_quals=0, reverse=false, context_die=<dw_die_ref 0x7ffff762d190 DW_TAG_compile_unit>) at ../../../gcc/gcc/dwarf2out.cc:13631 (gdb) pt type <integer_type 0x7ffff77ad690 foo asm_written SI size <integer_cst 0x7ffff7602fd8 type <integer_type 0x7ffff76210a8 bitsizetype> constant 32> unit-size <integer_cst 0x7ffff7625000 type <integer_type 0x7ffff7621000 sizetype> constant 4> align:32 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7ffff76215e8 attributes <tree_list 0x7ffff77ae348 purpose <identifier_node 0x7ffff77c0e10 may_alias>> precision:32 min <integer_cst 0x7ffff7602f90 -2147483648> max <integer_cst 0x7ffff7602fa8 2147483647>> ... 13699 if (qualified_type) (gdb) 13701 mod_type_die = lookup_type_die (qualified_type); (gdb) 13706 if (mod_type_die (gdb) p mod_type_die $1 = <dw_die_ref 0x0> Then recurses with return modified_type_die (DECL_ORIGINAL_TYPE (name), cv_quals, reverse, context_die); Where DECL_ORIGINAL_TYPE (name) is a plain integer type: <integer_type 0x7ffff76215e8 int public SI size <integer_cst 0x7ffff7602fd8 type <integer_type 0x7ffff76210a8 bitsizetype> constant 32> unit-size <integer_cst 0x7ffff7625000 type <integer_type 0x7ffff7621000 sizetype> constant 4> align:32 warn_if_not_align:0 symtab:-142864960 alias-set -1 canonical-type 0x7ffff76215e8 precision:32 min <integer_cst 0x7ffff7602f90 -2147483648> max <integer_cst 0x7ffff7602fa8 2147483647> pointer_to_this <pointer_type 0x7ffff7629b28>> I am not 100% sure whether the GCC output is "strictly incorrect" DWARF, but at the least it is an inconsistency between clang and GCC. Observed with gcc (Debian 12.2.0-14) 12.2.0 and git master (GCC) 14.0.0 20230627 (experimental) on x86_64