Issue 090107.2: Support C++0x Variadic templates

Author: Kendrick Wong
Champion: Kendrick Wong
Date submitted: 2009-01-07
Date revised:
Date closed:
Type: Enhancement
Status: Rejected
DWARF Version: 4
Background
----------
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 

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_type
    * 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 follow immediately after the debugging information entry 
   with the tag DW_TAG_template_parameter_pack, and are owned by the same 
   parent entry. 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 follow immediately after the debugging information entry with 
   the tag DW_TAG_formal_parameter_pack, and are owned by the same parent 
   entry. 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 follow 
immediately after the debugging information entry with the tag 
DW_TAG_template_parameter_pack, and are owned by the same parent entry. 
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*")

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)

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(...)

 
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. 


-----------

Rejected:  Recommend that this be re-submitted when there is
a working implementation using vendor extensions.