Difference between revisions of "C++0x: Variadic templates"

From Dwarf Wiki
Jump to: navigation, search
 
(10 intermediate revisions by one user not shown)
Line 5: Line 5:
 
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2080.pdf
 
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2080.pdf
  
 +
== README ==
 +
 +
In the June 2 DWARF meeting, four proposals were presented for voting:
 +
 +
# <tt>DW_TAG_template_parameter_pack</tt>/<tt>DW_TAG_formal_parameter_pack</tt> is used as marker.
 +
# Make <tt>DW_TAG_template_type_parameter</tt> DIEs children of <tt>DW_TAG_template_parameter_pack</tt>. And make <tt>DW_TAG_formal_parameter</tt> DIEs children of <tt>DW_TAG_formal_parameter_pack</tt>.
 +
# Create new children DIEs under <tt>DW_TAG_template_parameter_pack</tt>/<tt>DW_TAG_formal_parameter_pack</tt> DIE and add references to <tt>DW_TAG_template_type_parameter</tt>/<tt>DW_TAG_formal_parameter</tt> respectively.
 +
# Reject Variadic templates proposal.
 +
 +
The consensus is to reject the proposal and wait for a vendor to produce the information first.  We can revisit the vendor implementation at a later time and re-evaluate the proposal then.
  
 
== Overview ==
 
== Overview ==
Line 52: Line 62:
 
* DECL
 
* DECL
 
* DW_AT_name
 
* DW_AT_name
* DW_AT_type
 
 
* DW_AT_sibling
 
* DW_AT_sibling
  
 
'''New DWARF attribute'''
 
  
 
{| border="1"
 
{| border="1"
|DW_AT_parameter_pack
+
|DW_TAG_formal_parameter_pack
|0x6A
+
|0x44
|flag
+
|function parameters pack  
|an argument within function parameters pack  
+
 
|}
 
|}
 +
 +
Allowable attributes:
 +
* DECL
 +
* DW_AT_name
 +
* DW_AT_sibling
  
  
 
'''3.3.7: Function Template Instantiations'''
 
'''3.3.7: Function Template Instantiations'''
  
Each template parameter pack declaration appearing in the template definition is represented by a debugging information entry with the tag <tt>DW_TAG_template_parameter_pack</tt>. Each such entry may have a <tt>DW_AT_name</tt> attribute, whose value is a null-terminated string containing the name of the template parameter pack as it appears in the source program.
+
4. Each template parameter pack declaration appearing in the template definition is represented by a debugging information entry with the tag <tt>DW_TAG_template_parameter_pack</tt>. Each such entry may have a <tt>DW_AT_name</tt> attribute, whose value is a null-terminated string containing the name of the template parameter pack as it appears in the source program.
 +
 
 +
5. Each argument within the template parameter pack is represented by a debugging information entry with the tag <tt>DW_TAG_template_type_parameter</tt>.  These entries are children of the debugging information entry with the tag <tt>DW_TAG_template_parameter_pack</tt>. Each such entry does not have a <tt>DW_AT_name</tt> attribute. Each such entry has a <tt>DW_AT_type</tt> attribute describing the actual type by which the formal is replaced for this instantiation.
 +
 
 +
6. Each function parameter pack declaration appearing in the template definition is represented by a debugging information entry with the tag <tt>DW_TAG_formal_parameter_pack</tt>. Each such entry may have a <tt>DW_AT_name</tt> attribute, whose value is a null-terminated string containing the name of the template parameter pack as it appears in the source program.
  
Template parameter pack entries can have zero or more child entries. Each entry correspond to exactly one argument within the template parameter pack. This child entry must have the tag <tt>DW_TAG_template_type_parameter</tt>, and will have same form as other template type parameter entries.
+
7. Each argument within the function parameter pack is represented by a debugging information entry with the tag <tt>DW_TAG_formal_parameter</tt>. These entries are children of the debugging information entry with the tag <tt>DW_TAG_formal_parameter_pack</tt>. Each such entry does not have a <tt>DW_AT_name</tt> attribute. Each such entry has a <tt>DW_AT_type</tt> attribute describing the actual type by which the formal is replaced for this instantiation.
  
  
Line 79: Line 94:
 
If the template parameter pack entry represent a template value parameter pack, it may contain a <tt>DW_AT_type</tt> attribute to denote the type of the arguments within the template value parameter pack.
 
If the template parameter pack entry represent a template value parameter pack, it may contain a <tt>DW_AT_type</tt> attribute to denote the type of the arguments within the template value parameter pack.
  
Template parameter pack entries can have zero or more child entries. Each entry correspond to exactly one argument within the template parameter pack. This child entry can have one of the tags <tt>DW_TAG_template_type_parameter</tt> or <tt>DW_TAG_template_value_parameter</tt>, and will have same form as other template parameter entries.
+
Each argument within the template parameter pack can have one of the tags <tt>DW_TAG_template_type_parameter</tt> or <tt>DW_TAG_template_value_parameter</tt>, and will have same form as other template parameter entries.  These entries are children of the debugging information entry with the tag <tt>DW_TAG_template_parameter_pack</tt>. Each such entry does not have a <tt>DW_AT_name</tt> attribute. Each such entry has a <tt>DW_AT_type</tt> attribute describing the actual type by which the formal is replaced for this instantiation.
  
  
'''4.1: Data Object Entries'''
+
== APPENDIX ==
  
If a formal parameter is an argument within the function parameter pack, the formal parameter entry has a <tt>DW_AT_parameter_pack</tt> attribute, whose value is a flag.  If a formal parameter is the first argument within the function parameter pack, the formal parameter entry has a <tt>DW_AT_name</tt> attribute, whose value is a null-terminated string containing the name of the function parameter pack.  All other formal parameters within the function parameter pack does not have a <tt>DW_AT_name</tt> attribute.
+
'''D.8 Variadic Templates Examples'''
  
 
+
'''D.8.1 Function Template Instantiations'''
== Example ==
+
  
 
<pre>
 
<pre>
Line 93: Line 107:
 
void printf(const char* s) {
 
void printf(const char* s) {
 
   while (*s) {
 
   while (*s) {
     std::out << *s++;
+
     std::cout << *s++;
 
   }
 
   }
 
}
 
}
template<typename T, typename... Args>
+
template<typename T, typename... PackTypes>
void printf(const char* s, T value, Args... args) {
+
void printf(const char* s, T value, PackTypes... args) {
 
   while (*s) {
 
   while (*s) {
 
     if (*s == '%' && *++s != '%') {
 
     if (*s == '%' && *++s != '%') {
Line 103: Line 117:
 
       return printf (++s, args...);
 
       return printf (++s, args...);
 
     }
 
     }
     std::out << *s++;
+
     std::cout << *s++;
 
   }
 
   }
 
}
 
}
Line 111: Line 125:
 
</pre>
 
</pre>
  
Compiler may instantiate these 4 functions as a result:
+
The base case for printf is not a template instantiation:
 +
 
 +
<pre>
 +
printf (const char* s);
 +
1$:  DW_TAG_subprogram
 +
          DW_AT_name("printf")
 +
2$:      DW_TAG_formal_parameter
 +
              DW_AT_name("s")
 +
              DW_AT_type(reference to type "const char*")
 +
<pre>
 +
 
 +
Compiler may instantiate these 3 functions:
  
 
# printf<int,char,int> (const char* s, int value, char, int);  // args => char, int
 
# printf<int,char,int> (const char* s, int value, char, int);  // args => char, int
 
# printf<char,int>    (const char* s, char value, int);      // args => int
 
# printf<char,int>    (const char* s, char value, int);      // args => int
 
# printf<int>          (const char* s, int value);            // args => (empty)
 
# printf<int>          (const char* s, int value);            // args => (empty)
# printf              (const char* s);
 
  
 
<pre>
 
<pre>
 
1) printf<int,char,int> (const char* s, int value, char, int);  // args => char, int
 
1) printf<int,char,int> (const char* s, int value, char, int);  // args => char, int
<1>< ###>      DW_TAG_subprogram
+
10$: DW_TAG_subprogram
                DW_AT_name                 printf
+
          DW_AT_name("printf")
<2><  ###>     DW_TAG_template_type_parameter
+
11$:     DW_TAG_template_type_parameter
                DW_AT_name                 T
+
              DW_AT_name("T")
                DW_AT_type                 <xxx>  // int
+
              DW_AT_type(reference to base type "int")
<2><  ###>     DW_TAG_template_parameter_pack
+
12$:     DW_TAG_template_parameter_pack
                DW_AT_name                 Args
+
              DW_AT_name("PackTypes")
<3><  ###>      DW_TAG_template_type_parameter
+
13$:          DW_TAG_template_type_parameter
                DW_AT_type                 <yyy>  // char
+
                  ! no DW_AT_name attribute
<3><  ###>      DW_TAG_template_type_parameter
+
                  DW_AT_type(reference to base type "char")
                DW_AT_type                 <xxx>  // int
+
14$:          DW_TAG_template_type_parameter
<2><  ###>     DW_TAG_formal_parameter
+
                  ! no DW_AT_name attribute
                DW_AT_name                 s
+
                  DW_AT_type(reference to base type "int")
                DW_AT_type                 <zzz>  // const char*
+
15$:     DW_TAG_formal_parameter
<2><  ###>     DW_TAG_formal_parameter
+
              DW_AT_name("s")
                DW_AT_name                 value
+
              DW_AT_type(reference to type "const char*")
                DW_AT_type                 <xxx>  // int
+
16$:     DW_TAG_formal_parameter
<2><  ###>     DW_TAG_formal_parameter
+
              DW_AT_name("value")
                DW_AT_name                 args
+
              DW_AT_type(reference to 11$)
                DW_AT_parameter_pack        yes
+
17$:     DW_TAG_formal_parameter_pack
                DW_AT_type                 <yyy>  // char
+
              DW_AT_name("args")
<2><  ###>      DW_TAG_formal_parameter
+
18$:          DW_TAG_formal_parameter
                DW_AT_parameter_pack        yes
+
                  ! no DW_AT_name attribute
                DW_AT_type                 <xxx>  // int
+
                  DW_AT_type(reference to 13$)
 +
19$:          DW_TAG_formal_parameter
 +
                  ! no DW_AT_name attribute
 +
                  DW_AT_type(reference to 14$)
  
 
2) printf<char,int>    (const char* s, char value, int);      // args => int
 
2) printf<char,int>    (const char* s, char value, int);      // args => int
<1>< ###>      DW_TAG_subprogram
+
20$: DW_TAG_subprogram
                DW_AT_name                 printf
+
          DW_AT_name("printf")
<2><  ###>     DW_TAG_template_type_parameter
+
21$:     DW_TAG_template_type_parameter
                DW_AT_name                 T
+
              DW_AT_name("T")
                DW_AT_type                 <yyy>  // char
+
              DW_AT_type(reference to base type "int")
<2><  ###>     DW_TAG_template_parameter_pack
+
22$:     DW_TAG_template_parameter_pack
                DW_AT_name                 Args
+
              DW_AT_name("PackTypes")
<3><  ###>      DW_TAG_template_type_parameter
+
23$:          DW_TAG_template_type_parameter
                DW_AT_type                 <xxx>  // int
+
                  ! no DW_AT_name attribute
<2><  ###>     DW_TAG_formal_parameter
+
                  DW_AT_type(reference to base type "int")
                DW_AT_name                 s
+
24$:     DW_TAG_formal_parameter
                DW_AT_type                 <zzz>  // const char*
+
              DW_AT_name("s")
<2><  ###>     DW_TAG_formal_parameter
+
              DW_AT_type(reference to type "const char*")
                DW_AT_name                 value
+
25$:     DW_TAG_formal_parameter
                DW_AT_type                 <yyy>  // char
+
              DW_AT_name("value")
<2><  ###>     DW_TAG_formal_parameter
+
              DW_AT_type(reference to 21$)
                DW_AT_name                 args
+
26$:     DW_TAG_formal_parameter_pack
                DW_AT_parameter_pack        yes
+
              DW_AT_name("args")
                DW_AT_type                 <xxx>  // int
+
27$:          DW_TAG_formal_parameter
 +
                  ! no DW_AT_name attribute
 +
                  DW_AT_type(reference to 23$)
  
 
3) printf<int>          (const char* s, int value);            // args => (empty)
 
3) printf<int>          (const char* s, int value);            // args => (empty)
<1>< ###>      DW_TAG_subprogram
+
30$: DW_TAG_subprogram
                DW_AT_name                 printf
+
          DW_AT_name("printf")
<2><  ###>     DW_TAG_template_type_parameter
+
31$:     DW_TAG_template_type_parameter
                DW_AT_name                 T
+
              DW_AT_name("T")
                DW_AT_type                 <xxx>  // int
+
              DW_AT_type(reference to base type "int")
<2><  ###>     DW_TAG_template_parameter_pack
+
32$:     DW_TAG_template_parameter_pack
                DW_AT_name                 Args
+
              DW_AT_name("PackTypes")
<2><  ###>     DW_TAG_formal_parameter
+
33$:     DW_TAG_formal_parameter
                DW_AT_name                 s
+
              DW_AT_name("s")
                DW_AT_type                 <zzz>  // const char*
+
              DW_AT_type(reference to type "const char*")
<2><  ###>     DW_TAG_formal_parameter
+
34$:     DW_TAG_formal_parameter
                DW_AT_name                 value
+
              DW_AT_name("value")
                DW_AT_type                 <xxx> // int
+
              DW_AT_type(reference to 31$)
 +
35$:      DW_TAG_formal_parameter_pack
 +
              DW_AT_name("args")
 +
</pre>
 +
 
 +
 
 +
'''D.8.2 Class Template Instantiations'''
 +
 
 +
<pre>
 +
/* Template definition for counting number of template type arguments */
 +
template<typename... PackTypes> struct count;
 +
 
 +
/* Full specialization for zero argument */
 +
template <>
 +
struct count<> {
 +
  static const int value = 0;
 +
};
 +
 
 +
/* Partial specialization for peeling off the first argument */
 +
template<typename T, typename... PackTypes>
 +
struct count<T, PackTypes...> {
 +
  static const int value = 1 + count<PackTypes...>::value;
 +
};
  
4) printf (const char* s);
+
/* Template instantiation */
<1>< ###>      DW_TAG_subprogram
+
count<char, short, int> a;
                DW_AT_name                 printf
+
</pre>
<2><  ###>      DW_TAG_formal_parameter
+
 
                DW_AT_name                 s
+
The base case template:
                DW_AT_type                 <zzz// const char*
+
 
 +
<pre>
 +
1$:  DW_TAG_structure_type
 +
          DW_AT_name("count")
 +
2$:      DW_TAG_member
 +
              DW_AT_name("value")
 +
              DW_AT_declaration(yes)
 +
              DW_AT_type(reference to type "const int")
 +
3$:  DW_TAG_variable
 +
          DW_AT_specification(reference to 2$)
 +
          DW_AT_location(...)
 +
</pre>
 +
 
 +
Compiler may instantiate these 3 types:
 +
 
 +
<pre>
 +
 
 +
1) count<char, short, int>      // PackTypes => short, int
 +
11$:  DW_TAG_structure_type
 +
          DW_AT_name("count")
 +
12$:      DW_TAG_template_type_parameter
 +
              DW_AT_name("T")
 +
              DW_AT_type(reference to base type "char")
 +
13$:      DW_TAG_template_parameter_pack
 +
              DW_AT_name("PackTypes")
 +
14$:          DW_TAG_template_type_parameter
 +
                  DW_AT_type(reference to base type "short")
 +
15$:          DW_TAG_template_type_parameter
 +
                  DW_AT_type(reference to base type "int")
 +
16$:      DW_TAG_member
 +
              DW_AT_name("value")
 +
              DW_AT_declaration(yes)
 +
              DW_AT_type(reference to type "const int")
 +
17$:  DW_TAG_variable
 +
          DW_AT_specification(reference to 16$)
 +
          DW_AT_location(...)
 +
 
 +
2) count<short, int>            // PackTypes => int
 +
21$:  DW_TAG_structure_type
 +
          DW_AT_name("count")
 +
22$:      DW_TAG_template_type_parameter
 +
              DW_AT_name("T")
 +
              DW_AT_type(reference to base type "short")
 +
23$:      DW_TAG_template_parameter_pack
 +
              DW_AT_name("PackTypes")
 +
24$:          DW_TAG_template_type_parameter
 +
                  DW_AT_type(reference to base type "int")
 +
25$:      DW_TAG_member
 +
              DW_AT_name("value")
 +
              DW_AT_declaration(yes)
 +
              DW_AT_type(reference to type "const int")
 +
26$:  DW_TAG_variable
 +
          DW_AT_specification(reference to 25$)
 +
          DW_AT_location(...)
 +
 
 +
3) count<int>                  // PackTypes => (empty)
 +
31$:  DW_TAG_structure_type
 +
          DW_AT_name("count")
 +
32$:      DW_TAG_template_type_parameter
 +
              DW_AT_name("T")
 +
              DW_AT_type(reference to base type "int")
 +
33$:      DW_TAG_template_parameter_pack
 +
              DW_AT_name("PackTypes")
 +
34$:      DW_TAG_member
 +
              DW_AT_name("value")
 +
              DW_AT_declaration(yes)
 +
              DW_AT_type(reference to type "const int")
 +
35$:  DW_TAG_variable
 +
          DW_AT_specification(reference to 34$)
 +
          DW_AT_location(...)
 +
 
 +
4) count<char, short, int> a;
 +
41$:  DW_TAG_variable
 +
          DW_AT_name("a")
 +
          DW_AT_type(reference to 11$)
 +
          DW_AT_location(...)
 +
</pre>
 +
 
 +
'''D.8.3 Multiple template packs in template definition'''
 +
 
 +
<pre>
 +
template <class X,int I>
 +
struct pair {
 +
  void showself () {
 +
    std::cout << I << std::endl;
 +
    X local;
 +
    local.showself();
 +
  }
 +
};
 +
 
 +
struct a1 { void showself () { std::cout << "a1" << std::endl; }};
 +
struct a2 { void showself () { std::cout << "a2" << std::endl; }};
 +
 
 +
template <class headX, int headI, class... restX, int... restI>
 +
void showself (pair<headX, headI> headArg, pair<restX, restI>... restArg) {
 +
  headArg.showself();
 +
  showself (restArg...);
 +
}
 +
 
 +
/* Instantiations */
 +
pair<a1,1> t1;
 +
pair<a2,2> t2;
 +
showself(t1,t2);
 +
</pre>
 +
 
 +
First the simple structures:
 +
 
 +
<pre>
 +
struct a1 { void showself () { std::cout << "a1" << std::endl; }};
 +
 
 +
11$:  DW_TAG_structure_type
 +
          DW_AT_name("a1")
 +
12$:     DW_TAG_subprogram
 +
              DW_AT_name("showself")
 +
              DW_AT_type(reference to type "void")
 +
 
 +
struct a2 { void showself () { std::cout << "a2" << std::endl; }};
 +
 
 +
21$:  DW_TAG_structure_type
 +
          DW_AT_name("a2")
 +
22$:      DW_TAG_subprogram
 +
              DW_AT_name("showself")
 +
              DW_AT_type(reference to type "void")
 +
</pre>
 +
 
 +
DWARF for 'pair' structures:
 +
 
 +
<pre>
 +
pair<a1,1> t1;
 +
 
 +
31$:  DW_TAG_structure_type
 +
          DW_AT_name("pair")
 +
32$:      DW_TAG_template_type_parameter
 +
              DW_AT_name("X")
 +
              DW_AT_type(reference to 11$)
 +
33$:      DW_TAG_template_value_parameter
 +
              DW_AT_name("I")
 +
              DW_AT_type(reference to base type "int")
 +
              DW_AT_const_value(1)
 +
33$:      DW_TAG_subprogram
 +
              DW_AT_name("showself")
 +
              DW_AT_type(reference to type "void")
 +
34$: DW_TAG_variable
 +
          DW_AT_name("t1")
 +
          DW_AT_type(reference to 31$)
 +
          DW_AT_location(...)
 +
 
 +
pair<a2,2> t2;
 +
 
 +
41$:  DW_TAG_structure_type
 +
          DW_AT_name("pair")
 +
42$:      DW_TAG_template_type_parameter
 +
              DW_AT_name("X")
 +
              DW_AT_type(reference to 21$)
 +
43$:      DW_TAG_template_value_parameter
 +
              DW_AT_name("I")
 +
              DW_AT_type(reference to base type "int")
 +
              DW_AT_const_value(2)
 +
43$:      DW_TAG_subprogram
 +
              DW_AT_name("showself")
 +
              DW_AT_type(reference to type "void")
 +
44$:  DW_TAG_variable
 +
          DW_AT_name("t2")
 +
          DW_AT_type(reference to 41$)
 +
          DW_AT_location(...)
 +
</pre>
 +
 
 +
The variadic template function showself():
 +
 
 +
<pre>
 +
template <class headX, int headI, class... restX, int... restI>
 +
void showself (pair<headX, headI> headArg, pair<restX, restI>... restArg) {
 +
  headArg.showself();
 +
  showself (restArg...);
 +
}
 +
 
 +
showself (pair<struct a1,1>, pair<struct a2,2>):
 +
 
 +
51$:  DW_TAG_subprogram
 +
          DW_AT_name("showself")
 +
52$:      DW_TAG_template_type_parameter
 +
              DW_AT_name("headX")
 +
              DW_AT_type(reference to 11$)
 +
53$:      DW_TAG_template_value_parameter
 +
              DW_AT_name("headI")
 +
              DW_AT_type(reference to base type "int")
 +
              DW_AT_const_value(1)
 +
54$:      DW_TAG_template_parameter_pack
 +
              DW_AT_name("restX")
 +
55$:          DW_TAG_template_type_parameter
 +
                  DW_AT_type(reference to 21$)
 +
56$:      DW_TAG_template_parameter_pack
 +
              DW_AT_name("restI")
 +
              DW_AT_type(reference to base type "int")
 +
57$:          DW_TAG_template_value_parameter
 +
                  DW_AT_const_value(2)
 +
58$:     DW_TAG_formal_parameter
 +
              DW_AT_name("headArg")
 +
              DW_AT_type(reference to 31$)
 +
59$:      DW_TAG_formal_parameter_pack
 +
              DW_AT_name("restArg")
 +
60$:          DW_TAG_formal_parameter
 +
                  ! no DW_AT_name attribute
 +
                  DW_AT_type(reference to 41$)
 +
 
 +
showself (pair<struct a2,2>):
 +
 
 +
71$: DW_TAG_subprogram
 +
          DW_AT_name("showself")
 +
72$:      DW_TAG_template_type_parameter
 +
              DW_AT_name("headX")
 +
              DW_AT_type(reference to 21$)
 +
73$:      DW_TAG_template_value_parameter
 +
              DW_AT_name("headI")
 +
              DW_AT_type(reference to base type "int")
 +
              DW_AT_const_value(2)
 +
74$:      DW_TAG_template_parameter_pack
 +
              DW_AT_name("restX")
 +
75$:      DW_TAG_template_parameter_pack
 +
              DW_AT_name("restI")
 +
76$:      DW_TAG_formal_parameter
 +
              DW_AT_name("headArg")
 +
              DW_AT_type(reference to 41$)
 +
77$:      DW_TAG_formal_parameter_pack
 +
              DW_AT_name("restArg")
 
</pre>
 
</pre>
  
Line 195: Line 470:
 
* Add <tt>DW_AT_parameter_pack</tt> to indicate that a parameter is a part of template parameter pack.
 
* Add <tt>DW_AT_parameter_pack</tt> to indicate that a parameter is a part of template parameter pack.
 
* Add naming convention for parameters which are part of template parameter pack.
 
* Add naming convention for parameters which are part of template parameter pack.
 +
 +
April 13, 2009.
 +
* Place Example section in Appendix D
 +
* Re-format DWARF description in Example section to match current documentation.
 +
* Remove <tt>DW_AT_parameter_pack</tt> attribute
 +
* Add example of class template instantiation with template parameter pack.
 +
 +
May 5, 2009.
 +
* Add <tt>DW_TAG_formal_parameter_pack</tt> to indicate the name of the function parameter pack.
 +
* <tt>DW_TAG_template_type_parameter</tt> are not longer children of <tt>DW_TAG_template_parameter_pack</tt>.  This is made so that consumer don't need to understand the new TAG, and still be able to process the other information.
 +
* Add debug information representation for variable 'a' in D.8.2.
 +
 +
June 2, 2009.
 +
* Add example for multiple template parameter pack in template definition.
 +
 +
September 11, 2009.
 +
* Dodji Seketeli points out that function parameter packs does not have to be located at the end of a parameter-declaration-list:<br/>http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2939.html#US45<br/>This provides the argument that <tt>DW_TAG_formal_parameter_pack</tt> can not be used as marker.  And for consistency, <tt>DW_TAG_template_parameter_pack</tt> can follow the same behavior as <tt>DW_TAG_formal_parameter_pack</tt>
 +
* Adjust examples to make <tt>DW_TAG_template_type_parameter</tt> and <tt>DW_TAG_formal_parameter</tt> children of <tt>DW_TAG_template_parameter_pack</tt> and <tt>DW_TAG_formal_parameter_pack</tt> respectively.

Latest revision as of 08:05, 14 September 2009

For detail description of the feature, please refer to:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2087.pdf

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2080.pdf

README

In the June 2 DWARF meeting, four proposals were presented for voting:

  1. DW_TAG_template_parameter_pack/DW_TAG_formal_parameter_pack is used as marker.
  2. Make DW_TAG_template_type_parameter DIEs children of DW_TAG_template_parameter_pack. And make DW_TAG_formal_parameter DIEs children of DW_TAG_formal_parameter_pack.
  3. Create new children DIEs under DW_TAG_template_parameter_pack/DW_TAG_formal_parameter_pack DIE and add references to DW_TAG_template_type_parameter/DW_TAG_formal_parameter respectively.
  4. Reject Variadic templates proposal.

The consensus is to reject the proposal and wait for a vendor to produce the information first. We can revisit the vendor implementation at a later time and re-evaluate the proposal then.

Overview

C++0x will allow function and class templates to take an arbitrary number of arguments. The motivation behind this language extension is to allow TR1 facilities such as tuple to accept variable number of parameters.

template<typename... Elements> class tuple;
tuple<int, long> tuple_int_long;  // Elements is a template type parameter pack 
                                  // containing 2 arguments, int and long type
tuple<float> tuple_float;         // Elements is a template type parameter pack
                                     containing 1 argument: float type

template<typename T, unsigned PrimaryDimension, unsigned... Dimensions> class array;
array<double, 3, 3> t1;           // Dimensions is a template value parameter pack
                                  // containing a single argument: unsigned int 3.
array<double, 3, 3, 4, 5> t2;     // Dimensions is a template value parameter pack
                                  // containing three arguments: unsigned int 3, 4 and 5.

template<typename... Args> void eat(Args... args);
// The eat() function is a variadic template with template parameter pack Args.
// The ellipsis to the left of the identifier args indicates that args is a 
//   function parameter pack.

Proposed change to DWARF

Purpose

  • DWARF does not represent the generic template definition, but does represent each template instantiation.
  • Template type parameter pack contains only template type parameters
  • Template value parameter pack contains only template value parameters
  • Debug information should show where the template parameter pack is used within the template definition.
  • If possible, debug information should also show the arguments within the template parameter pack.


New DWARF tag

DW_TAG_template_parameter_pack 0x43 template parameters pack

Allowable attributes:

  • DECL
  • DW_AT_name
  • DW_AT_sibling


DW_TAG_formal_parameter_pack 0x44 function parameters pack

Allowable attributes:

  • DECL
  • DW_AT_name
  • DW_AT_sibling


3.3.7: Function Template Instantiations

4. Each template parameter pack declaration appearing in the template definition is represented by a debugging information entry with the tag DW_TAG_template_parameter_pack. Each such entry may have a DW_AT_name attribute, whose value is a null-terminated string containing the name of the template parameter pack as it appears in the source program.

5. Each argument within the template parameter pack is represented by a debugging information entry with the tag DW_TAG_template_type_parameter. These entries are children of the debugging information entry with the tag DW_TAG_template_parameter_pack. Each such entry does not have a DW_AT_name attribute. Each such entry has a DW_AT_type attribute describing the actual type by which the formal is replaced for this instantiation.

6. Each function parameter pack declaration appearing in the template definition is represented by a debugging information entry with the tag DW_TAG_formal_parameter_pack. Each such entry may have a DW_AT_name attribute, whose value is a null-terminated string containing the name of the template parameter pack as it appears in the source program.

7. Each argument within the function parameter pack is represented by a debugging information entry with the tag DW_TAG_formal_parameter. These entries are children of the debugging information entry with the tag DW_TAG_formal_parameter_pack. Each such entry does not have a DW_AT_name attribute. Each such entry has a DW_AT_type attribute describing the actual type by which the formal is replaced for this instantiation.


5.6.8: Class Template Instantiations

Each template parameter pack declaration appearing in the template definition is represented by a debugging information entry with the tag DW_TAG_template_parameter_pack. Each such entry may have a DW_AT_name attribute, whose value is a null-terminated string containing the name of the template parameter pack as it appears in the source program.

If the template parameter pack entry represent a template value parameter pack, it may contain a DW_AT_type attribute to denote the type of the arguments within the template value parameter pack.

Each argument within the template parameter pack can have one of the tags DW_TAG_template_type_parameter or DW_TAG_template_value_parameter, and will have same form as other template parameter entries. These entries are children of the debugging information entry with the tag DW_TAG_template_parameter_pack. Each such entry does not have a DW_AT_name attribute. Each such entry has a DW_AT_type attribute describing the actual type by which the formal is replaced for this instantiation.


APPENDIX

D.8 Variadic Templates Examples

D.8.1 Function Template Instantiations

/* Base case for printf */
void printf(const char* s) {
  while (*s) {
    std::cout << *s++;
  }
}
template<typename T, typename... PackTypes>
void printf(const char* s, T value, PackTypes... args) {
  while (*s) {
    if (*s == '%' && *++s != '%') {
      std::cout << value;
      return printf (++s, args...);
    }
    std::cout << *s++;
  }
}

int x;
printf<int, char, int> ("%c %d", x, 'x', 3);

The base case for printf is not a template instantiation:

printf (const char* s);
1$:   DW_TAG_subprogram
          DW_AT_name("printf")
2$:       DW_TAG_formal_parameter
              DW_AT_name("s")
              DW_AT_type(reference to type "const char*")
<pre>

Compiler may instantiate these 3 functions:

# printf<int,char,int> (const char* s, int value, char, int);  // args => char, int
# printf<char,int>     (const char* s, char value, int);       // args => int
# printf<int>          (const char* s, int value);             // args => (empty)

<pre>
1) printf<int,char,int> (const char* s, int value, char, int);  // args => char, int
10$:  DW_TAG_subprogram
          DW_AT_name("printf")
11$:      DW_TAG_template_type_parameter
              DW_AT_name("T")
              DW_AT_type(reference to base type "int")
12$:      DW_TAG_template_parameter_pack
              DW_AT_name("PackTypes")
13$:          DW_TAG_template_type_parameter
                  ! no DW_AT_name attribute
                  DW_AT_type(reference to base type "char")
14$:          DW_TAG_template_type_parameter
                  ! no DW_AT_name attribute
                  DW_AT_type(reference to base type "int")
15$:      DW_TAG_formal_parameter
              DW_AT_name("s")
              DW_AT_type(reference to type "const char*")
16$:      DW_TAG_formal_parameter
              DW_AT_name("value")
              DW_AT_type(reference to 11$)
17$:      DW_TAG_formal_parameter_pack
              DW_AT_name("args")
18$:          DW_TAG_formal_parameter
                  ! no DW_AT_name attribute
                  DW_AT_type(reference to 13$)
19$:          DW_TAG_formal_parameter
                  ! no DW_AT_name attribute
                  DW_AT_type(reference to 14$)

2) printf<char,int>     (const char* s, char value, int);       // args => int
20$:  DW_TAG_subprogram
          DW_AT_name("printf")
21$:      DW_TAG_template_type_parameter
              DW_AT_name("T")
              DW_AT_type(reference to base type "int")
22$:      DW_TAG_template_parameter_pack
              DW_AT_name("PackTypes")
23$:          DW_TAG_template_type_parameter
                  ! no DW_AT_name attribute
                  DW_AT_type(reference to base type "int")
24$:      DW_TAG_formal_parameter
              DW_AT_name("s")
              DW_AT_type(reference to type "const char*")
25$:      DW_TAG_formal_parameter
              DW_AT_name("value")
              DW_AT_type(reference to 21$)
26$:      DW_TAG_formal_parameter_pack
              DW_AT_name("args")
27$:          DW_TAG_formal_parameter
                  ! no DW_AT_name attribute
                  DW_AT_type(reference to 23$)

3) printf<int>          (const char* s, int value);             // args => (empty)
30$:  DW_TAG_subprogram
          DW_AT_name("printf")
31$:      DW_TAG_template_type_parameter
              DW_AT_name("T")
              DW_AT_type(reference to base type "int")
32$:      DW_TAG_template_parameter_pack
              DW_AT_name("PackTypes")
33$:      DW_TAG_formal_parameter
              DW_AT_name("s")
              DW_AT_type(reference to type "const char*")
34$:      DW_TAG_formal_parameter
              DW_AT_name("value")
              DW_AT_type(reference to 31$)
35$:      DW_TAG_formal_parameter_pack
              DW_AT_name("args")


D.8.2 Class Template Instantiations

/* Template definition for counting number of template type arguments */
template<typename... PackTypes> struct count;

/* Full specialization for zero argument */
template <>
struct count<> {
  static const int value = 0;
};

/* Partial specialization for peeling off the first argument */
template<typename T, typename... PackTypes>
struct count<T, PackTypes...> {
  static const int value = 1 + count<PackTypes...>::value;
};

/* Template instantiation */
count<char, short, int> a;

The base case template:

1$:   DW_TAG_structure_type
          DW_AT_name("count")
2$:       DW_TAG_member
              DW_AT_name("value")
              DW_AT_declaration(yes)
              DW_AT_type(reference to type "const int")
3$:   DW_TAG_variable
          DW_AT_specification(reference to 2$)
          DW_AT_location(...)

Compiler may instantiate these 3 types:


1) count<char, short, int>      // PackTypes => short, int
11$:  DW_TAG_structure_type
          DW_AT_name("count")
12$:      DW_TAG_template_type_parameter
              DW_AT_name("T")
              DW_AT_type(reference to base type "char")
13$:      DW_TAG_template_parameter_pack
              DW_AT_name("PackTypes")
14$:          DW_TAG_template_type_parameter
                  DW_AT_type(reference to base type "short")
15$:          DW_TAG_template_type_parameter
                  DW_AT_type(reference to base type "int")
16$:      DW_TAG_member
              DW_AT_name("value")
              DW_AT_declaration(yes)
              DW_AT_type(reference to type "const int")
17$:  DW_TAG_variable
          DW_AT_specification(reference to 16$)
          DW_AT_location(...)

2) count<short, int>            // PackTypes => int
21$:  DW_TAG_structure_type
          DW_AT_name("count")
22$:      DW_TAG_template_type_parameter
              DW_AT_name("T")
              DW_AT_type(reference to base type "short")
23$:      DW_TAG_template_parameter_pack
              DW_AT_name("PackTypes")
24$:          DW_TAG_template_type_parameter
                  DW_AT_type(reference to base type "int")
25$:      DW_TAG_member
              DW_AT_name("value")
              DW_AT_declaration(yes)
              DW_AT_type(reference to type "const int")
26$:  DW_TAG_variable
          DW_AT_specification(reference to 25$)
          DW_AT_location(...)

3) count<int>                   // PackTypes => (empty)
31$:  DW_TAG_structure_type
          DW_AT_name("count")
32$:      DW_TAG_template_type_parameter
              DW_AT_name("T")
              DW_AT_type(reference to base type "int")
33$:      DW_TAG_template_parameter_pack
              DW_AT_name("PackTypes")
34$:      DW_TAG_member
              DW_AT_name("value")
              DW_AT_declaration(yes)
              DW_AT_type(reference to type "const int")
35$:  DW_TAG_variable
          DW_AT_specification(reference to 34$)
          DW_AT_location(...)

4) count<char, short, int> a;
41$:  DW_TAG_variable
          DW_AT_name("a")
          DW_AT_type(reference to 11$)
          DW_AT_location(...)

D.8.3 Multiple template packs in template definition

template <class X,int I>
struct pair {
  void showself () {
    std::cout << I << std::endl;
    X local;
    local.showself();
  }
};

struct a1 { void showself () { std::cout << "a1" << std::endl; }};
struct a2 { void showself () { std::cout << "a2" << std::endl; }};

template <class headX, int headI, class... restX, int... restI> 
void showself (pair<headX, headI> headArg, pair<restX, restI>... restArg) {
  headArg.showself();
  showself (restArg...);
}

/* Instantiations */
pair<a1,1> t1;
pair<a2,2> t2;
showself(t1,t2);

First the simple structures:

struct a1 { void showself () { std::cout << "a1" << std::endl; }};

11$:   DW_TAG_structure_type
          DW_AT_name("a1")
12$:      DW_TAG_subprogram
              DW_AT_name("showself")
              DW_AT_type(reference to type "void")

struct a2 { void showself () { std::cout << "a2" << std::endl; }};

21$:   DW_TAG_structure_type
          DW_AT_name("a2")
22$:      DW_TAG_subprogram
              DW_AT_name("showself")
              DW_AT_type(reference to type "void")

DWARF for 'pair' structures:

pair<a1,1> t1;

31$:   DW_TAG_structure_type
          DW_AT_name("pair")
32$:      DW_TAG_template_type_parameter
              DW_AT_name("X")
              DW_AT_type(reference to 11$)
33$:      DW_TAG_template_value_parameter
              DW_AT_name("I")
              DW_AT_type(reference to base type "int")
              DW_AT_const_value(1)
33$:      DW_TAG_subprogram
              DW_AT_name("showself")
              DW_AT_type(reference to type "void")
34$:  DW_TAG_variable
          DW_AT_name("t1")
          DW_AT_type(reference to 31$)
          DW_AT_location(...)

pair<a2,2> t2;

41$:   DW_TAG_structure_type
          DW_AT_name("pair")
42$:      DW_TAG_template_type_parameter
              DW_AT_name("X")
              DW_AT_type(reference to 21$)
43$:      DW_TAG_template_value_parameter
              DW_AT_name("I")
              DW_AT_type(reference to base type "int")
              DW_AT_const_value(2)
43$:      DW_TAG_subprogram
              DW_AT_name("showself")
              DW_AT_type(reference to type "void")
44$:  DW_TAG_variable
          DW_AT_name("t2")
          DW_AT_type(reference to 41$)
          DW_AT_location(...)

The variadic template function showself():

template <class headX, int headI, class... restX, int... restI> 
void showself (pair<headX, headI> headArg, pair<restX, restI>... restArg) {
  headArg.showself();
  showself (restArg...);
}

showself (pair<struct a1,1>, pair<struct a2,2>):

51$:  DW_TAG_subprogram
          DW_AT_name("showself")
52$:      DW_TAG_template_type_parameter
              DW_AT_name("headX")
              DW_AT_type(reference to 11$)
53$:      DW_TAG_template_value_parameter
              DW_AT_name("headI")
              DW_AT_type(reference to base type "int")
              DW_AT_const_value(1)
54$:      DW_TAG_template_parameter_pack
              DW_AT_name("restX")
55$:          DW_TAG_template_type_parameter
                  DW_AT_type(reference to 21$)
56$:      DW_TAG_template_parameter_pack
              DW_AT_name("restI")
              DW_AT_type(reference to base type "int")
57$:          DW_TAG_template_value_parameter
                  DW_AT_const_value(2)
58$:      DW_TAG_formal_parameter
              DW_AT_name("headArg")
              DW_AT_type(reference to 31$)
59$:      DW_TAG_formal_parameter_pack
              DW_AT_name("restArg")
60$:          DW_TAG_formal_parameter
                  ! no DW_AT_name attribute
                  DW_AT_type(reference to 41$)

showself (pair<struct a2,2>):

71$:  DW_TAG_subprogram
          DW_AT_name("showself")
72$:      DW_TAG_template_type_parameter
              DW_AT_name("headX")
              DW_AT_type(reference to 21$)
73$:      DW_TAG_template_value_parameter
              DW_AT_name("headI")
              DW_AT_type(reference to base type "int")
              DW_AT_const_value(2)
74$:      DW_TAG_template_parameter_pack
              DW_AT_name("restX")
75$:      DW_TAG_template_parameter_pack
              DW_AT_name("restI")
76$:      DW_TAG_formal_parameter
              DW_AT_name("headArg")
              DW_AT_type(reference to 41$)
77$:      DW_TAG_formal_parameter_pack
              DW_AT_name("restArg")


Change History

March 17, 2009.

  • Define template parameter pack and function parameter pack.
  • Add DW_AT_parameter_pack to indicate that a parameter is a part of template parameter pack.
  • Add naming convention for parameters which are part of template parameter pack.

April 13, 2009.

  • Place Example section in Appendix D
  • Re-format DWARF description in Example section to match current documentation.
  • Remove DW_AT_parameter_pack attribute
  • Add example of class template instantiation with template parameter pack.

May 5, 2009.

  • Add DW_TAG_formal_parameter_pack to indicate the name of the function parameter pack.
  • DW_TAG_template_type_parameter are not longer children of DW_TAG_template_parameter_pack. This is made so that consumer don't need to understand the new TAG, and still be able to process the other information.
  • Add debug information representation for variable 'a' in D.8.2.

June 2, 2009.

  • Add example for multiple template parameter pack in template definition.

September 11, 2009.

  • Dodji Seketeli points out that function parameter packs does not have to be located at the end of a parameter-declaration-list:
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2939.html#US45
    This provides the argument that DW_TAG_formal_parameter_pack can not be used as marker. And for consistency, DW_TAG_template_parameter_pack can follow the same behavior as DW_TAG_formal_parameter_pack
  • Adjust examples to make DW_TAG_template_type_parameter and DW_TAG_formal_parameter children of DW_TAG_template_parameter_pack and DW_TAG_formal_parameter_pack respectively.