How to interpret the types when compiling STL list

Hey all,

Given a program using the STL list, Clang emits the following type
information:

  %"class.__gnu_cxx::new_allocator" = type { i8 }
  %"class.std::_List_base" = type { %"struct.std::_List_base<int, std::allocator<int> >::_List_impl" }
  %"class.std::allocator" = type { i8 }
  %"class.std::list" = type { [16 x i8] }
  %"struct.std::_List_base<int, std::allocator<int> >::_List_impl" = type { %"struct.std::_List_node_base" }
  %"struct.std::_List_const_iterator" = type { %"struct.std::_List_node_base"* }
  %"struct.std::_List_iterator" = type { %"struct.std::_List_node_base"* }
  %"struct.std::_List_node" = type { [16 x i8], i32, [4 x i8] }
  %"struct.std::_List_node_base" = type { %"struct.std::_List_node_base"*, %"struct.std::_List_node_base"* }
  %"struct.std::__false_type" = type { i8 }

Amongst the types, %"struct.std::_List_node" and %"class.std::list"
are not nature to me. My questions are:
  - Why do the two types have no corresponding type arguments? And
    roughly how are they computed?
  - Is this unique to Clang? Can I have control on how Clang handles
    these types? E.g. something like this:

  %"struct.std::list<int,std::allocator<int> >" = type { %"struct.std::_List_base<int,std::allocator<int> >" }
  %"struct.std::_List_node<int>" = type { %"struct.std::_List_node_base", i32 }

Best,
Xiaolong

Hello,

Given a program using the STL list, Clang emits the following type
information:

  %"class.__gnu_cxx::new_allocator" = type { i8 }
  %"class.std::_List_base" = type { %"struct.std::_List_base<int, std::allocator<int> >::_List_impl" }
  %"class.std::allocator" = type { i8 }
  %"class.std::list" = type { [16 x i8] }
  %"struct.std::_List_base<int, std::allocator<int> >::_List_impl" = type { %"struct.std::_List_node_base" }
  %"struct.std::_List_const_iterator" = type { %"struct.std::_List_node_base"* }
  %"struct.std::_List_iterator" = type { %"struct.std::_List_node_base"* }
  %"struct.std::_List_node" = type { [16 x i8], i32, [4 x i8] }
  %"struct.std::_List_node_base" = type { %"struct.std::_List_node_base"*, %"struct.std::_List_node_base"* }
  %"struct.std::__false_type" = type { i8 }

Amongst the types, %"struct.std::_List_node" and %"class.std::list"
are not nature to me. My questions are:
  - Why do the two types have no corresponding type arguments? And
    roughly how are they computed?
  - Is this unique to Clang? Can I have control on how Clang handles
    these types? E.g. something like this:

  %"struct.std::list<int,std::allocator<int> >" = type { %"struct.std::_List_base<int,std::allocator<int> >" }
  %"struct.std::_List_node<int>" = type { %"struct.std::_List_node_base", i32 }

In addition to the above description on the type information in LLVM
output, I further checked the cases when the STL list is instantiated
with different types. For example, in a program I instantiated the
List class with int and a Student class. This time the type
information in the LLVM output is as below:

  %0 = type { [16 x i8], i32, [4 x i8] }
  %"class.__gnu_cxx::new_allocator" = type { i8 }
  %"class.std::_List_base" = type { %"struct.std::_List_base<int, std::allocator<int> >::_List_impl" }
  %"class.std::allocator" = type { i8 }
  %"class.std::list" = type { [16 x i8] }
  %"struct.std::_List_base<int, std::allocator<int> >::_List_impl" = type { %"struct.std::_List_node_base" }
  %"struct.std::_List_base<student, std::allocator<student> >::_List_impl" = type { %"struct.std::_List_node_base" }
  %"struct.std::_List_const_iterator" = type { %"struct.std::_List_node_base"* }
  %"struct.std::_List_iterator" = type { %"struct.std::_List_node_base"* }
  %"struct.std::_List_node" = type { [16 x i8], %struct.student }
  %"struct.std::_List_node_base" = type { %"struct.std::_List_node_base"*, %"struct.std::_List_node_base"* }
  %"struct.std::__false_type" = type { i8 }
  %struct.student = type { i32, i32, i32, i32 }

As we see, there is only one entry starting with
%"class.std::list". This indicates that the list class does not
distinguish between various type arguments. In this example, we
instantiate the List class with two distinct types, however, there is
only one instance. Another surprise to me is the type
%"struct.std::_List_node". Similarly, the _list_node class does not
distinguish between various type arguments.

So, I am wondering why the type information is so? Such type
information makes it hard to figure out the type hierarchies in some
cases.

Best,
Xiaolong

Hello

As we see, there is only one entry starting with
%"class.std::list". This indicates that the list class does not
distinguish between various type arguments.

This is correct. In LLVM world types which are structurally identical
are the same.

So, I am wondering why the type information is so?

The names are purely arbitrary. You can easily get e.g. names like "ty1",
"ty2" and so on.

Such type
information makes it hard to figure out the type hierarchies in some
cases.

You should not use (arbitrary) type names for this. Use debug information.