13. Templates#
Support for template declarations and the instantiation of classes and objects
based on templates is found principally in templates.c; templates.h
contains the associated declarations.
13.1. Overview#
Template support is almost entirely a front-end issue. By default, templates themselves are not represented in the IL, and classes and functions that are generated on the basis of templates look just like any other class or function. The exceptions to this rule are:
- Classes, functions, variables, and aliases generated from templates identify the associated template arguments, because those arguments may be needed in generating the name of the entity.
- In automatic instantiation mode additional flags are provided in the variable and routine entries so that the information provided by the flags may be represented in the resulting object file in some form.
- A template IL entry is created for each template declaration. When
PROTOTYPE_INSTANTIATIONS_IN_ILis TRUE, the entry points to a “prototype instantiation”, which is an IL entry that represents the entity declared by the template. WhenRECORD_TEMPLATE_STRINGSis TRUE, the entry contains a null-terminated string that represents the template declaration. The IL template entry is also used to represent the value of a template template argument. - The template instantiation mechanism may require support in the back end. For example, if each instantiation is placed in its own object file, the back end must recognize the data structures provided to accomplish this.
Generally speaking, when a template definition is scanned, the definition of the template is saved and then used later to generate instances of the template. There are two common techniques used by compilers to save the definition of a template: in the first technique, the template is parsed (without semantic analysis) and the parse tree is saved; in the second, some unparsed (more or less textual) representation of the template is saved. A parse tree may be a reasonable choice for a multi-pass front-end featuring a separate parser. However, in the EDG C++ front end (which uses a single pass approach in which parsing and semantic analysis are done together), a textual representation, which we call a “token cache”, is more appropriate. Correctly implemented, the two techniques are semantically equivalent.
When using exported templates (see Exported Templates) the front end reloads the translation unit(s) that define the exported templates that require instantiation so that the information from all of the translation units is available to the front end. Even though there is a great deal of special processing required to make exported templates work properly, the underlying mechanism of rescanning tokens from a token cache is still used to produce the actual instantiation.
Since the method one chooses to record the definition of the template affects the data structures used in the implementation and also influences the terminology used to describe them, it will be helpful to introduce some terms that are used in the EDG C++ front end:
- A template denotes a sequence of tokens that, along with one or more template parameters and a declarative context, is used as the basis for generating an instance of the template.A template entity may be
- a class template (e.g., class
A), - a function template (e.g., function
f), - a member function of a class template (e.g.,
A<T>::f), - a static data member of a class template (e.g.,
A<T>::t), - a nested class of a class template (e.g.,
A<T>::B), - a member class template (e.g.,
A<T>::C), - a member function template (e.g.,
A<T>::g), - a variable template (e.g.,
x<T>), - an alias template, or
- a partial specialization of a class template, member class template, or variable template.
For example,template <class T> void f(T); // function template template <class T> class A { // class template T f() { return t; } // member function of class template static T t; // static data member of class template struct B {}; // nested class of class template template <class U> void g(U); // member function template template <class U> struct C {}; // member class template template <class U> struct C<U*> {}; // partial specialization template <class U> static U vt; // member variable template }; template <class T> T x = 1; // variable template template <class T> using B = A<T*>; // alias template
- A template parameter refers to a template formal argument, and a template argument is a template actual argument.
- A template instance is a class (sometimes called a template class) generated on the basis of a class template, an alias (i.e., typedef, sometimes called a template alias) generated on the basis of an alias template, a function (sometimes called a template function) generated on the basis of a function template, or a variable (sometimes called a template variable) generated on the basis of a variable template. In addition, a member function or static data member of a template class is itself an instance of the corresponding member function or static data member of the class template. For example,
template <class T> class A { static T t; T f() { return t; } }; A<int> ai; template <class T> T g(T t) { return t; } int i = g(0);
With the declaration ofaian instance of class templateA, namely,A<int>, is generated, and in the process instancesA<int>::fandA<int>::tare also generated. Similarly, the reference tog(int)causes an instance of function templategto be generated. - In many cases instances of variable templates and static data members of template classes are treated similarly. The term “template variable” is used to refer to both cases, unless otherwise specified.
- The generation of an instance of a template is called instantiation. (Sometimes the result of instantiation, namely an instance, is also called an instantiation.)
- An instantiation may be either a partial instantiation or a full instantiation. A partial instantiation of a class template is like a declaration of an ordinary class when no body is supplied; similarly, a partial instantiation of a function template is like a declaration of a function without a function body. On the other hand, a full instantiation is the generation of a class or function definition – i.e., it includes the body. For instance,
template <class T> class A {}; A<long> *pal; A<int> ai;
In this case the declaration ofpalcauses the partial instantiation ofA<long>– that is, no body needs to be generated – whereas the declaration ofaicauses the full instantiation ofA<int>. The instantiation of an alias template is always a full instantiation. - The first time a class template is scanned – partly to record its member functions, static data members, nested classes, and friend declarations, and partly to check for errors – the result is referred to as a prototype instantiation of the class template, and the class produced is called a “nonreal” class; in general, a template class based on template arguments that include at least one template parameter is called “nonreal”. In addition, a template class based on a template that is a member of a nonreal class is also called “nonreal”. Consider this example:
template <class T, int I> struct A { template <class T2> struct X {}; }; template <class T> struct B { A<T, 0> a; typename T::X<int> x; }; B<A<int,1> > b;
In this example, when class templateAis scanned, the prototype instantiation produces nonreal classA<T,I>, and during the scanning of class templateBnonreal classesA<T,0>andT::X<int>are generated. Subsequently, whenbis declared andB<A<int,1> >is instantiated,A<int,0>, a real class, is instantiated to serve as the type for memberB<int>::a, andA<int,1>::X<int>is instantiated to serve as the type for memberB<int>::x. - A prototype instantiation is also performed for alias templates resulting in a nonreal alias. Nonreal aliases are also created for instantiations of alias templates if the template argument list depends on a template parameter. Unlike nonreal classes, nonreal aliases are actually instantiated by rescanning the tokens of the alias.
- Nested classes of class templates are not themselves referred to as templates, but their member functions and static data members are, respectively, member functions of class templates and static data members of class templates, and a member function or static data member of a class nested within a template class is handled as an instance of the corresponding member function or static data member from the class template. A class nested within a nonreal class is considered a nonreal class.
- The definition of a template instance may be supplied explicitly by the user instead of being generated based on the template. Such instances are referred to as explicit specializations of the template.
- A class template or variable template may be partially specialized. A partial specialization is an alternate version of the template that is used to generate instances whose template argument lists match a specified pattern. For example, a partial specialization could be provided that will be used to generate all instances for which a specified template argument is a pointer type.
template <class T> struct A {}; // primary template template <class T> struct A<T*> {}; // partial specialization
The template that is specialized by a partial specialization is called the primary template. - Function templates may be overloaded with normal functions and with other function templates. Overload resolution is used to select the function or template to be used for a given call. If, as a result of overload resolution, there are two or more templates that could generate equivalent functions, partial ordering rules are used to select the template to be used. Partial ordering is different from partial specialization in that there is no relationship between the function templates being ordered (i.e, one is not considered to be a specialization of the other).
- In some modes, prototype instantiations are performed for entities other than classes and aliases. When semantic analysis of nonclass templates has been requested, prototype instantiations are done for the bodies and default arguments of function templates and member functions of class templates, the initializers of template static data members, and the default values of template arguments.
- Template template parameters are class templates for which the template definition to be used for a given reference is supplied by a template template argument.
By default, prototype instantiations and entries associated with nonreal
classes and aliases do not appear in the IL. When
PROTOTYPE_INSTANTIATIONS_IN_IL is TRUE, IL entries for prototype
instantiations are generated. See Templates for more
information.
Template definitions are typically placed in header files that are included by the programs that make use of the templates. Alternatively, the definitions of template static data members and non-inline template functions may be provided using the “export” facility of the C++ language (see Exported Templates).
The major part of template support falls into several phases. The first is processing the declaration of the template, which for a class template also involves doing a prototype instantiation. The second phase is recognizing a reference to an instance of a template and producing a partial template instantiation, which can be thought of as an on-the-fly declaration of the instance. The third phase is the full instantiation of the template instance; typically, a template class is fully instantiated at the first point of reference in a given translation unit, but a template function presents special complications, since the full instantiation of a noninline template function may occur only once in a program, no matter how many translation units it may appear in.
Each of these phases of template processing will be examined in detail, but first it is necessary to describe the data structures that are built to represent templates and their instances.
13.2. Data Structures#
Each collection of tokens that is stored so that the tokens may be rescanned
later is represented by an entry of type a_template_cache. The fields of
the template cache entry are:
tokens, where the tokens are kept on which an instantiation of the template is to be based.- For classes the tokens comprise the base specifiers list as well as the body of the class.
- For functions, including member functions, they extend from the opening left brace to the closing right brace of the function body, except that for templates of constructors the ctor-initializer list, if present, is also included.
- For static data members the tokens identify the initializer, if any.
The last token in the token cache is always atok_end_of_sourcetoken.decl_info, a pointer to an entry of typea_template_decl_info, which describes the context in which the tokens stored in the token cache appeared.
The template declaration information entry (a_template_decl_info) in turn
includes the following fields:
parameters, a pointer to list of entries of typea_template_param; they record the template parameters declared in the template declaration.- For type parameters a template param entry points to an
sk_typesymbol (which in turn refers to atk_template_paramtype entry). - For nontype parameters a template param entry points to an
sk_constantsymbol (which refers to ack_template_paramconstant entry). - For template template parameters a template param entry pointed to an
sk_class_templatesymbol. The template symbol supplement for which thetemplate_template_paramfield is TRUE.
declaration_scope, identifying thesck_template_declarationscope in which the template parameter symbols were declared.enclosing_scope, a pointer to the scope containing the template declaration. This is important, for example, when a function template is defined in a friend declaration within a class, in which case the class must be reactivated when instantiations of that function template are generated.enclosing_template_decl, a pointer to the template declaration information for an enclosing template declaration. This is used for member class templates and member function templates when one needs to know, for example, not only the template parameters of the member template, but also the template parameter lists of any enclosing class templates.decl_seq, the declaration sequence number at the point of the template declaration. This is used when doing dependent name lookup to exclude names not visible at the point of the template definition.nondependent_calls, used when doing dependent name processing to record the result of overload resolution for nondependent calls that were evaluated during a prototype instantiation.
A template (of whatever flavor) is represented by the combination of a symbol
and an associated entry of type a_template_symbol_supplement (defined in
symbol_tbl.h). An instance of the template is then represented by an entry
that appears on a list pointed to from the template symbol supplement. That is
the basic pattern for representing a template and its instances – a template
symbol, a supplement, and a list of instances – but each sort of template
presents a different version of the pattern.
The template symbol supplement contains a template cache entry for the template body and also has fields that are specific to the kind of template it is associated with; these are discussed below.
In most cases the instantiation of a template creates one or more classes,
functions, and/or static data members. However, when a class template contains
members that are themselves templates (i.e, member function templates or member
class templates) the instantiation of the enclosing class template results in
the creation of entities that are templates. When this happens, it is
necessary to record the template from which the new template was generated.
The template symbol supplement field named prototype_template contains a
pointer to the symbol associated with the template from which a given member
template was generated. Similarly the prototype template contains a field
named subordinate_templates that points to a list of templates that were
generated from the prototype template.
13.2.1. Class Templates#
An sk_class_template symbol represents a class template; it contains a
pointer to a template symbol supplement. The supplement for a class template
includes the variant field instantiations, a pointer to a list of the
symbols (of kind sk_class_or_struct_tag or sk_union_tag) that represent
instances of the template. The symbol for the prototype instantiation is
pointed to by the field prototype_instantiation.
For each template class represented by a symbol on the instantiations list the class symbol supplement has several important fields:
class_templateis a pointer back to thesk_class_templatesymbol that represents the template upon which its instantiation is based. However, for a nested class of a template class theclass_templatepointer will always be NULL.corresp_prototype_symis a pointer to the template class symbol for the prototype instantiation and is present for template class instances and classes nested within template classes.is_nonreal_classis TRUE for template classes produced by prototype instantiations (and in general for template classes for which the template argument list contains at least one template parameter reference). It is also TRUE for a class that is a nested class of a nonreal template class.
A class symbol for a template class (i.e., for an instance of a class template) does not otherwise appear in the symbol table. It cannot be looked up directly but rather must be looked up via the class template symbol.
The type entry associated with a template class is like that of any other class except that it contains the following additional information about template classes:
template_arg_listpoints to the template argument used to generate the type (the template arguments are incorporated in the type so that back ends can use them to generate names for template classes).is_template_classTRUE for template class instances and classes nested within template class instances.is_nonreal_classis TRUE for nonreal instantiations and for local classes of prototype instantiations.is_prototype_instantiationis TRUE for prototype instantiations of class templates and nested classes of class templates.is_specializedis TRUE for template classes declared or defined in an explicit specialization declaration.specialized_with_old_syntaxwas specialized, but not with the “template <>” syntax that is now required by the standard.partial_spec_template_arg_listis used when a partial specialization is used to generate the definition of the template class. It points to the template argument list that is specified with respect to the partial specialization’s template parameter list.
A class template may have associated with it a set of partial specializations
that may be used instead of the primary template when generating full
instantiations of instances of the class template. The template symbol
supplement contains a field named partial_specializations that points to a
list of sk_class_template symbols for any partial specializations that may
exist. Instances created from partial specializations go on the instantiations
list of the primary template. Each partial specialization has its own
prototype instantiation, which also goes on the instantiations list of the
primary template. The class type supplement field
partial_spec_template_arg_list is used in class types generated from class
template partial specializations (including the prototype instantiation). It
contains the template argument list with respect to the partial specialization,
while the template_arg_list field contains the template argument list with
respect to the primary template. In the following example, the template
argument list with respect to the primary template is “<int*, int>”, while
the template argument list with respect to the partial specialization is
“<int>”.
template <class T1, class T2> struct A {};
template <class T> struct A<T*, int> {};
A<int*, int> a;
As mentioned previously, it is here that the type entries of real and nonreal
template classes differ – the template arguments of a nonreal template class
involve at least one tk_template_param type or ck_template_param
constant. In addition, the type entry for a nonreal class does not appear in
the IL that is passed on to the back end for further processing.
When an instance of a class template is fully instantiated, partial instantiations for all of its member functions, static data members, and nested classes are generated. Because these entities are not themselves templates, they do not have their own template argument lists. The template argument list for their enclosing class is used when a full instantiation is performed.
13.2.2. Alias Templates#
Alias templates are represented in much the same way as class templates. An
sk_class_template symbol is used to represent the alias template, however
the instantiation list and prototype instantiation fields of the template
symbol supplement point to sk_type symbols. The is_alias_template
field of the template symbol supplement is used to identify alias templates.
The typeref type created for instantiations of alias templates (with typeref
kind trk_is_template_alias) is like that of normal aliases except that it
contains additional information, including the template argument list and flags
such as is_template_alias, is_nonreal, and
is_prototype_instantiation.
13.2.3. Function Templates#
An sk_function_template symbol is used to represent a function template,
including member function templates, but not member functions of class
templates. It contains a pointer to a template symbol supplement whose variant
field instantiations points to a list of entries of type
a_template_instance: each time a partial instantiation is performed on the
function template, the resulting instance is recorded in this list.
Entries of type a_template_instance are also utilized to record instances
of member function of class templates and static data members of class
templates, but they are used somewhat differently in those cases (as described
later). When a template instance is used to record an instance of a function
template, the following use is made of its fields:
instance_sympoints to thesk_routinesymbol that represents the instance. That symbol will in turn point to the routine entry created to represent the instantiated function. A full instantiation need not have been done. The routine entry contains a pointer to the template arguments on which the instance is based.template_sympoints to thesk_function_templatesymbol that represents the template.instantiation_requiredis TRUE if the routine instance was actually called or had its address taken. It means that a full instantiation needs to be performed – i.e., that the function body needs to be generated. When this flag is set, the instance is placed on theinstantiations_requiredlist, to assure that it is checked for additional processing once the entire translation unit has been scanned.is_guiding_declis TRUE if this routine was explicitly declared by the user (whether or not a body was supplied). When this flag is set, the symbol pointed to byinstance_symwill have been added to the overload list for this name. Note that a “specific declaration” is different than an “explicit specialization”. A specifically declared function participates in overload resolution, but need not be explicitly specialized.Here’s an example:template <class T> void f(T) {} void f(int);
The second declaration assures thatf(int)is represented both in the instantiations list for function templatefand on the overload list associated with ansk_overloaded_functionsymbol with an identifierf. Such a declaration affects how the function is found during overload resolution, but it does not prevent a body from being generated for it based on the function template.explicit_instantiationis TRUE if the user has explicitly requested full instantiation by means of an explicit instantiation directive or#pragma instantiatedirective.referencing_namespacepoints to the namespace in which the use that first required the instantiation of the template was encountered, or NULL if the first reference was in the global namespace. This field is set when theinstantiation_requiredflag is set to TRUE.
In addition to the pointer to the instantiations list, the template symbol supplement for a function template makes use of some other variant fields:
routineis a pointer to a routine entry. This entry is generated when the function template declaration is scanned, but it doesn’t actually map to a real routine (and does not appear in the IL proper). Rather, it serves as a convenient place to store the routine type and other information about the function (e.g., the storage class, the special function kind, and whether inlining was specified in the original declaration).func_infois a field of typea_func_info_blockand stores information picked up during declaration processing that needs to be reused during instantiation (e.g., the names of the function parameters).def_arg_expr_listis a list of entries containing information about default arguments to be applied to the function parameters when the instantiation is done.
Whereas, as noted previously, an instance of a class template cannot be looked up independently of its template, the same is not necessarily the case for an instance of a function template. When there has been a guiding declaration, the template function’s symbol may be found during ordinary overload resolution. However, when there is no guiding declaration, the symbol can only be found via the function template symbol and its list of instantiations. Consider this example:
template <class T> T f(T t) { return t; }
char f(char); // Guiding declaration
int i = f(0); // Instantiation of f(int)
void f(int, int); // Unrelated to the template
Symbols are arrayed under the symbol header for “f” as follows:
- overloaded function symbol with overload list:
- template function symbol
f(T)with instantiation list: - instance entry pointing to routine symbol
f(char) - instance entry pointing to routine symbol
f(int) - routine symbol
f(char) - routine symbol
f(int,int)
Notice that the symbol for f(char) appears both on the overload list and on
the instantiation list (there are not two different symbols), whereas
f(int) appears only on the instantiation list. The former, consequently,
is subject to the ordinary lookup rules, whereas the latter must be looked up
using the stricter rules for template functions. Guiding declarations have
been removed from the standard language, but are still supported by the front
end depending on the command line options and configuration flags being used.
When guiding declarations are disabled, declarations such as f(char) are
simply declarations of normal functions that are unrelated to the template.
13.2.4. Member Function of Class Templates#
A member function of a class template is represented by an
sk_member_function symbol created during the prototype instantiation of the
class template. These symbols look like ordinary member function symbols,
which among other things means they do not have their own pointer to a template
symbol supplement; rather they point to a template instance entry, and it has a
pointer to a template symbol supplement.
The problem being addressed with this somewhat roundabout arrangement is that a member function of a class template is really a “quasi-template” whose partial instantiation is in fact always part of any full instantiation of the class template to which it belongs. A consequence of this approach is that the instantiations list from the associated template symbol supplement includes both
ordinary instance entries that point to ordinary member function symbols (members of real instantiations of the class template) and
one special instance entry that represents the quasi-template by pointing to a member function symbol of the nonreal prototype instantiation of the class template.
The template instance entries for member functions are similar to those for ordinary template functions:
instance_sympoints to thesk_member_functionsymbol that represents the instance.template_sympoints to thesk_member_functionsymbol that represents the template.- When
instance_symandtemplate_symare identical, thetemplate_infofield is non-NULL and points to the template symbol supplement belonging to this member function of a class template. - The flags are used as for nonmember function instances, except that
specific_declis always TRUE.
13.2.5. Variable Templates#
A variable template is represented by an sk_variable_template symbol.
Instantiations of the template result in variable entries and associated
sk_variable symbols. Variable templates declared in class scopes are, from
a language point of view, static data members, but they and their
instantiations are represented in the same way as non-member variable
templates. When a variable template is instantiated using a dependent template
argument list, the is_nonreal flag is set in the variable entry. The
variable variant of the template symbol supplement contains information
used for both variable templates and static data members of class templates
(although some fields are only used for one or the other). The
instantiations field points to a list of symbols for the real
instantiations of the variable template. Template instance entries are created
for the real instantiations of a variable template.
13.2.6. Static Data Members of Class Templates#
Static data members of class templates are represented much like member
functions of class templates. The template symbol, an
sk_static_data_member symbol from the prototype instantiation of the class
template, points to an instance entry whose template_sym field points back
to it and whose template_info field points on to a template symbol
supplement. The latter has a definitions field that points to the instance
list. The fields in the instance entries are used just like those for member
functions.
13.2.7. Template Declaration Information#
As described earlier, each token cache that is used in the template
instantiation process is associated with a pointer to an entry of type
a_template_decl_info, which contains information about the template
parameters, the scope in which the template was declared, and a pointer to an
enclosing template declaration information entry, if applicable. An enclosing
template declaration information pointer is used when a member function
template or member class template is declared within another class template. A
function template, or member function of a class template, contains a token
cache that contains the function declaration and a separate token cache
containing the function body. Each token cache has associated with it a
separate template declaration information pointer, because the two caches may
have come from different declarations with different template parameter lists,
etc.
There is one template declaration information entry for each template <...>
clause that is scanned (except for those with empty parameter lists, which are
used in explicit specializations). When there is more than one template clause
in a given declaration, the inner template clauses contain a pointer to the
enclosing template declaration clause (the one to the left of a given template
clause).
When a template is defined within another template the enclosing template declaration information pointer is NULL indicating that the template declaration information for the enclosing template should be obtained by consulting its template symbol supplement.
13.3. Template Declarations#
13.3.1. Overview#
template_directive_or_declaration is the top-level routine for handling
template directives and template declarations. It is called when the
template or export keyword is encountered during declaration
processing. This occurs for template declarations, explicit specialization
declarations, and explicit instantiation directives. For example:
template <class T> struct A {}; // template declaration
export template <class T> void f(T){} // exported template declaration
template <> class A<int> {}; // explicit specialization
template class A<int>; // explicit instantiation
When no template parameter list is present explicit_instantiation is
called. See Explicit Instantiation Directives for further information. When a
template parameter list is present, including an empty one (e.g., <>),
template_or_specialization_declaration is called.
It first calls cache_template_declaration to create a token cache
containing the entire template declaration, including both the template
parameter list(s) and the declaration that follows. The definition of the
template (e.g., the class or function body) is not included in this cache. An
initial scan of the tokens in the cache is done to determine whether the
declaration is a full specialization, and whether it is a friend declaration.
13.3.1.1. Template Parameter Clauses#
A template declaration or template specialization declaration contains one or
more “template parameter clauses”. A template parameter clause consists of the
template keyword followed by a possibly empty template parameter list. The
initial declaration of a template always has a single template parameter clause
(although a template declaration may be nested within another template
declaration). Multiple template parameter clauses are used only when a member
template of a class template is defined or specialized outside of its class.
Each template parameter list has associated with it a template “nesting depth”. The nesting depth of the parameter list and the position within the template parameter list are the attributes used when comparing two template parameters to see if they represent the same parameter. The names of the template parameters are not significant. The nesting depth and position are collectively called the template parameter’s “coordinates”.
For example:
template <class T1> struct A {
template <class T2, class T3> void f(T1, T2, T3);
};
template <class X> template <class Y, class Z> void A<X>::f(X,Y,Z){}
where
T1andXboth have a nesting depth of 1 and a position of 1T2andYboth have a nesting depth of 2 and a position of 1T3andZboth have a nesting depth of 2 and a position of 2
The nesting depth of a template parameter clause in a namespace scope is 1, a template parameter clause declared within one enclosing class template is 2, etc. When scanning a template friend declaration any enclosing class templates are ignored and the template parameter clauses are numbered beginning with 1. This is necessary so that any types declared in the friend declaration match up correctly with the template that is being made a friend. For example, to make the template in the example above a friend of another template, you would do the following:
template <class T> struct B {
template <class X>
template <class Y, class Z> friend void A<X>::f(X,Y,Z);
};
The declaration of a template template parmeter also includes a template parameter clause. The template parameters in the template parameter clause for a template template parameter have a nesting depth of zero.
For each nonempty template parameter list, the template parameters from the parameter list are scanned. This process includes the following steps:
- An
sck_template_declarationscope is pushed. This will be the declaration scope to which the template parameter names belong. scan_template_param_listis called to scan the template parameters and build a linked list of entries of typea_template_paramto represent them. Each template parameter has an associated symbol. These symbols initially point to special “prototype argument” values that, for class templates, are used during the prototype instantiation. During real instantiation these symbols are modified to point to the actual argument values to be used.- A type parameter points to an
sk_typesymbol that initially points to atk_template_paramtype. The type symbol points to the actual argument type during an instantiation. - A nontype parameter points to an
sk_constantsymbol that initially points to ack_template_paramconstant. The constant symbol points to the actual argument constant during an instantiation. - A template template parameter points to an
sk_class_templatesymbol. Unlike the type and nontype cases, the template template parameter symbol always points to the template symbol supplement for that template template parameter. Theargument_templatefield of the template symbol supplement points to the actual argument to be used during an instantiation. Template template parameters differ from other template parameters in that they have certain properties that must persist through real instantiations. For example, the default template argument values used for a template template parameter are always the ones specified in the template template parameter declaration, never those associated with the actual template template argument.
- If the template parameter has a default argument, the type or expression is scanned on the spot if possible. However, if the default argument depends on another template parameter, the default argument must be rescanned when its value is needed using the actual argument values for the template parameters on which it depends. Therefore, its tokens are cached so that they may be scanned later (see
prescan_default_arg_expr). There are a number of ways in which a default argument can depend on another template parameter:- The type of a nontype parameter may make use of another template type parameter.
- The value of a default nontype argument may depend on a template type parameter or nontype parameter.
- The type used as the default argument for a type parameter may make use of another template parameter.
For example:template <class T = int, class T2 = T, int I = 0, T J = I+1> class A {}The default type ofTand the default constant value forIcan be known when the template parameters are scanned, but the default type ofT2and the value forJare dependent upon whatever typeTtakes on, and the value ofJdepends on the value used forI.
13.3.1.2. Classifying the Template Declaration#
When processing specializations a distinction is made between a “full specialization” and a “template specialization”. A full specialization is one in which the entity being declared is a class, function, variable, or static data member, while a template specialization is one in which the entity being declared is still a template. For example:
template <class T> struct A {
void f();
template <class T2> void g(T2);
template <class T2> struct B {};
struct C {};
};
// Full specializations
template <> void A<int>::f();
template <> struct A<int>::C {};
// Template specializations
template <> template <class T2> void A<int>::g(T2);
template <> template <class T2> struct A<int>::B {};
A partial specialization of a template is treated as a normal template declaration, not as a template specialization. A template specialization is a template with one or more empty template parameter clauses.
Full specializations are handled by calling full_specialization. See
Explicit Specializations for more information. The rest of this
section describes template_declaration, which is responsible for
processing template declarations and template specializations.
Earlier, a token cache was built that contains the template parameter clauses and the declaration that follows them. We are now at the point in the token stream that marks the division between the two components. Because the declaration component must be prescanned to determine the kind of template being declared, and because the declaration may be needed later for the purpose of generating partial instantiations of functions, the existing cache is split into a template parameter cache and a template declaration cache. In certain error cases, such as the presence of a syntax error in the template parameter list, the template declaration may not have been cached correctly when the initial cache was built. When this occurs, the template declaration is recached now that the true position of the beginning of the declaration is known.
Next, is_class_template_decl is called. If the declaration is in fact of a
class template, TRUE is returned. If it is not a class template declaration,
FALSE is returned to signal that processing for other kinds of template
declarations should be done.
The template parameters are checked to ensure that they are compatible with any previous declaration of the template, and for class members, that the template parameter lists that correspond to enclosing class templates are compatible with the template parameter lists of those class templates.
13.3.2. Class Templates#
class_template_declaration is called to process class template
declarations. This includes normal class templates, partial specializations,
and template specializations. It is also called to process declarations of
nested classes of class templates that are defined outside of the class.
class_template_declaration performs the following functions:
- Looks up and verifies the template name.
- Creates the
sk_class_templatesymbol and enters it into the symbol table, if necessary. The symbols for partial specializations are not entered into the symbol table. - Calls
create_prototype_typeto create the symbol and type for the prototype instantiation, and to create the template argument list(s) for the prototype instantiation. - If a definition is provided, collects the tokens for the base class specifiers and the class body and caches them for use later.
- For partial specializations, the template parameters of the partial specialization must appear in the template argument list associated with the partial specialization in such a way that their values can be deduced. In addition, nontype arguments cannot have types that depend on other template parameters, nor may they be used in expressions. These error tests are accomplished by calling
check_partial_spec_nontype_param_usage. - If the template is a partial specialization,
check_for_prior_use_of_partial_specis called to determine whether the newly declared partial specialization would have been used to generate any existing full instantiations of the primary template, had it been declared when the full instantiation had been done. If any such full instantiations are found, an error is issued.
Then the template declaration scopes that were pushed when the template
parameter clauses were scanned are popped, and instantiate_class_template
is called to do a prototype instantiation – i.e., to scan the template
definition even though the template parameters have not yet been given “real”
values. Because declaration/expression disambiguation often cannot be done
based on dummy types, only declarative information is scanned; inline function
bodies and default argument expressions are cached and, in some modes, have
their prototype instantiations done later. Most syntax errors and some
semantic errors are detected, but some errors cannot be reported until a real
instantiation is done.
The main benefit of prototype instantiation is to record the names and types of
member functions and static data members – in effect, to create symbols to
represent member functions of class templates and static data members of class
templates. instantiate_class_template accomplishes its work in the
following steps:
- An
sck_template_instantiationscope is pushed onto the scope stack. - The token cache for the class template body is activated.
scan_class_definitionis called to process the tokens. Special provisions are made for prototype instantiations:- Diagnostics are suppressed where appropriate.
decl_member_functionanddecl_static_data_membercreate template instance entries, template symbol supplements, and whatever else is needed to make the member symbols serve as templates.delayed_scan_fixup_for_classmoves the tokens cached for member function bodies into the appropriate template symbol supplement; it also moves the entries describing default argument expressions onto a list in the appropriate template symbol supplement. The cached tokens for inline-defined friend functions are discarded – they will be picked up during real instantiation.
- The starting and ending token positions of any nested classes, member functions whose definitions were provided in the class, and member templates (functions or classes) whose definitions were provided in the class are recorded. These token positions will be used to remove the definitions from the token cache for the class template body.
- The template instantiation scope is popped.
- The bodies of nested classes, etc. are removed from the class template body token cache. Nested classes, member functions, and member templates may all be specialized. In other words, the definitions provided in the class template definition may not be the ones actually used for a given instance of the class template, so there is no sense in scanning them while instantiating the class. As with class templates and function templates, nested classes of class templates, member functions of class templates, and member class and function templates are only instantiated when needed, and may be specialized any time before the point at which they are first used in a way that requires their instantiation.
13.3.3. Alias templates#
alias_template_declaration is called to process alias template declarations
and performs the following functions:
- Verifies the template name.
- Creates the
sk_class_templatesymbol and enters it into the symbol table. - Calls
create_prototype_typeto create the symbol and type for the prototype instantiation, and to create the template argument list(s) for the prototype instantiation. - Collects the tokens for the type defined by the alias and caches them for use later.
After calling alias_template_declaration, template_declaration calls
alias_prototype_instantiation to create the prototype instantiation of the
alias.
13.3.4. Function Templates#
The above is what happens when is_class_template_decl does in fact
determine that the declaration is a class declaration. However, if it returns
FALSE, template_declaration proceeds to examine what must be a template
declaration for something other than a class template.
If the template declaration appears within the definition of a class it must be
a member function template declaration or a template friend declaration. If it
is a member function template declaration class_member_template_declaration
(in class_decl.c) is called to scan its declaration, then
complete_function_template_decl is called to create the necessary template
data structures and to scan the template body, if present.
For all other cases, scan_template_declaration is called to scan the
declaration, which it does by calling decl_specifiers and declarator.
If that produces a function type, the declaration is processed as a function
template or member function of a class template declaration; otherwise, it is
processed as a variable template or static data member of a class template
declaration or reported as an error.
function_template_declaration is called for function templates. It, in
turn, calls either decl_function_template (in decls.c) or
template_specialization.
decl_function_template does for member and nonmember template declarations
more or less what decl_routine does for ordinary function declarations.
The processing for nonmember function templates includes the following:
id_linkageis called to determine whether this is a redeclaration of a function template that is already in the symbol table and whether the name of the function template is overloaded.- If this is not a redeclaration, then:
- An
sk_function_templatesymbol is entered into the symbol table (either directly or into an overload set). - A routine entry is allocated and its fields are set to record the type, storage class, and so forth specified in the declaration. It is not added to the IL, however, because it does not designate a “real” routine.
Member functions, for which a qualified name must be present, will already have
been declared in the class template definition. Their processing includes a
call to member_function_redecl_sym, which returns the member function
symbol with a matching type signature.
decl_function_template returns to function_template_declaration an
already existing or newly created symbol that represents the function template.
Then, as with member function template declarations,
complete_function_template_decl is called.
13.3.4.1. Completing the Function Template#
The next step is to collect the tokens of the function body (including, for a constructor, the ctor-initializers) and store them in a cache in the template symbol supplement. For both member and nonmember function templates the new template declaration information (parameter list, etc.) is recorded in the associated template symbol supplement.
When doing nonclass prototype instantiations,
function_prototype_instantiation is called to perform a prototype
instantiation on the body of a function template or member function of a class
template, and default_arg_prototype_instantiation is called to perform a
prototype instantiation on the default arguments of such functions.
13.3.5. Variable Templates and Static Data Member Templates#
Variable template declarations can be either extern declarations, or are
definitions. Static data member declarations are always definitions. For
definitions, the template parameter list is recorded in the template symbol
supplement, and the tokens comprising the initializer, if any, are cached. In
some cases, some or all of the initializer may have already been cached as part
of the template declaration. In such cases, split_token_cache is used to
move the initializer tokens from the declaration cache to the initializer
cache; the remaining initializer tokens are then appended to the initializer
cache.
When doing nonclass prototype instantiations,
variable_template_prototype_instantiation is called to perform a prototype
instantiation on the initializer of the variable template or template static
data member.
13.3.6. Variadic Templates#
The C++11 standard adds “variadic templates,” which are templates that take a variable number of arguments. For example:
template<class ...T> void f(T ...args) {
int a[] = {0, args..., 5};
}
int main() {
f(1, 2, 3, 4);
}
The template f can be called with zero or more arguments. For a given
call, the parameter pack T is deduced to be a list of types, matching the
types of the arguments supplied, and args is a function parameter pack that
is a series of parameters of the types given by T.
The front end implements variadic templates by storing, along with the tokens of the template, information on the location and details of any pack references and expansions. When the template is instantiated, the cached tokens of its declaration or definition are scanned, and in places where there are pack expansions, the processing loops over a sequence of tokens, substituting a different value for the pack name on each iteration, thus producing an expanded version of the source text.
The language definition of variadic templates uses a syntax-based trick: in
contexts that allow a list of items (usually, a comma-separated list), an item
in the list can be suffixed by “...” to indicate that it is a pack
expansion. In an instantiation of the template, that pack expansion is
replaced by, in effect, a list of entities generated by the expansion of the
pack. So, in the above example, the aggregate initialization expands to the
equivalent of
int a[] = {0, 1, 2, 3, 4, 5};
with the elements of the pack expansion inserted into the surrounding list.
Such expansions are allowed in parameter lists, call argument lists, brace-enclosed aggregate initializers, base class specifiers, mem-initializers, template argument lists, exception specifications, attributes, and capture lists.
The front end uses its own trick to expand these patterns. In each of those contexts, the code that handles the normal, non-variadic, case is enclosed in a loop with the following general structure:
a_pack_expansion_stack_entry_ptr pesep;
a_boolean any_more;
any_more = begin_potential_pack_expansion_context(&pesep);
while (any_more) {
a_pack_expansion_descr_ptr pedep;
/* Normal processing for one item is done here. */
...
pedep = end_potential_pack_expansion_context(pesep,
/*is_declarator=*/FALSE);
if (pedep != NULL) {
/* Mark the IL created as being for a pack expansion. */
} /* if */
any_more = advance_to_next_pack_element(pesep);
} /* while */
When no pack expansions are present, the “begin...” call returns TRUE, the
“end...” call returns NULL, and the “advance...” call returns FALSE, so
the loop goes around exactly once and handles one item on the list.
When a pack expansion is present, in the prototype instantiation the
“begin...” call returns TRUE, the “end...” call swallows the “...”
indicating the pack expansion and returns a pointer to a structure that
describes the pack expansion, and the “advance...” call returns FALSE.
Again, the loop goes around exactly once, but information about the pack
expansion is recorded in the IL and in data structures attached to the
template.
In a real instantiation, the loop goes around as many times as the pack being
expanded has values. Each time through, the source token position is reset to
the start of the expansion, the pack identifier is given an appropriate value
for that iteration, and the tokens are scanned again. After the right number
of iterations, the “advance...” call returns FALSE and the loop exits. If
the pack has zero elements, the “begin...” call advances the source token
position to after the “...” at the end of the expansion, and returns FALSE,
and the loop goes around zero times, thus producing no items on the list for
the pack expansion.
The pattern above appears in every place where a pack expansion could occur.
In a call argument list, for example, it must be done around the scanning of
every argument, which means in a lot of places. (Or, at least, in a lot of
places when inside a template that has variadic parameters.) Almost all the
time, the variadic processing notes a starting position and starts a potential
expansion context, but then finds out later that there is no trailing “...”
and therefore no pack expansion, and discards the information saved. This has
to be done, however, so that we can recall the starting position of a pack
expansion in the cases where one does occur.
The information saved for a pack expansion in the prototype scope (and,
incidentally, prototype instantiations are forced for variadic templates, so
that such information can be recorded) includes the starting position of the
pack expansion, so that, in a real instantiation, the “begin...” call can
look up the current token position and see whether a pack expansion starts at
the current token, and what the details of the expansion are. The saved
information includes the list of pack names that were referenced and are to be
iterated over in the loop. With that information, the “begin...” routine
can set up the proper looping over the proper sequence of tokens.
There are variant versions of these variadic-loop-management routines that are used for expression rescan contexts (no source tokens are consumed; pack identifiers are updated and the right number of iterations of the loop are done) and prescan and disambiguation contexts (where we don’t know yet the context of the code, and therefore can’t be certain about what pack expansions mean, so we don’t want to record anything permanent).
Template argument lists need to contain some extra information when variadic templates are used. For example, for a case like
template<class U, class ...T> void f(U p, T ...args) {
}
int main() {
f(1, 2.0, 3.0f);
}
the complete deduced template argument list for f has int for U,
and then a list of double and float for T. In diagnostics, this is
displayed as <int, <double, float>>. Internally, it requires a way to
indicate that part of the list is a pack expansion. That’s the function of the
tak_start_of_pack_expansion kind of template argument: it marks the start
of a sequence of template arguments associated with a pack expansion (and each
member of that sequence is marked with the is_pack_element flag).
That causes problems for lots of code in the front end that traverses template
argument lists. In most cases, that code does not want to worry about
start-of-pack-expansion entries. It just wants the “real” entries on the list.
That’s what the traversal routines begin_template_arg_list_traversal,
advance_to_next_template_arg, and the “..._simple” versions of those
routines do. They allow easy set up of a traversal of a template argument list
that ignores the start-of-pack-expansion entries. They should be used in
general to process template argument lists, to avoid problems.
Deduction does special processing to handle parameter packs, matching up template parameters with multiple types, or nontype values, or template template parameters. Zero-length packs are a particular problem, in that they are deduced from an absense of information (e.g., no arguments corresponding to that parameter pack).
Overload resolution does special processing for parameter packs, and in particular has to be careful because the normal one-to-one correspondence between arguments and parameters does not always hold.
Initializer processing deals with pack expansions by using expresison caches. The initializer routines call to fetch one expression. If the expression scanned is a pack expansion, the first expresison of the expansion is returned, and the rest are pushed into an expression cache. They are then returned on subsequent calls at the same or a higher or lower level. If the pack expansion produces zero expressions, another expression is scanned, unless we hit the end of the initializer (e.g., a closing brace). In some cases an expression is prescanned so we can decide whether the expression-list is over before going down a path in the code that will expects to be able to fetch an expression.
Partial ordering and partial specialization processing also deal specially with variadic templates.
13.4. Templates in the IL#
An entry of type a_template is created for each template declaration (see
make_il_template_entry). By default, no information about the template
itself is preserved in the IL. There are two different optional mechanisms
that can be used to record information about templates:
- If
PROTOTYPE_INSTANTIATIONS_IN_ILis TRUE, any prototype instantiation is recorded in the IL. If nonclass prototype instantiations have been requested, prototype instantiations will be generated for each template entity declared; otherwise, prototype instantiations will be recorded only for class templates. A prototype instantiation is an IL entry whose kind corresponds to the kind of entry being declared, but that represents the template itself and not any particular instantiation thereof. In other words, it still contains references to the template parameters. A type entry is used to represent a class template, a routine entry is used to represent a function template, and a variable entry is used to represent a variable template or template static data member. - If
RECORD_TEMPLATE_STRINGSto TRUE, the IL template entry will point to a null-terminated string that reproduces the text (minus comments, after preprocessing) of the template declaration in the source program (seemake_template_string). If a template has more than one declaration (e.g., a nondefining declaration followed by a definition), an IL template entry is produced for each declaration.
Both of these mechanisms can be used at the same time. Note that while all
templates can be represented as template strings, only those templates that
make use of the standard-mandated typename and template keywords
can have prototype instantiation IL entries generated (because without such
keywords it is not possible to parse the template definitions in the
absence of a set of actual template argument values). See
Templates for more information.
13.5. Partial Instantiation#
Partial instantiation occurs automatically for nested classes, member functions, and static data members when the class of which they are members is instantiated. That is to say, the full instantiation of a class necessarily entails the implicit declaration of all its members: symbols are introduced into the symbol table, type entries are created as required, IL entries are created and added to the IL, and so forth. The partial instantiation of class templates and function templates, on the other hand, is triggered by a reference.
13.5.1. Class Templates#
When a class template reference – class-template-name<template-arg-list> – is encountered, a call is made to
coalesce_template_class_reference to scan the template argument list and
look up the reference. Having verified that types in the template argument
list correspond to type template parameters and constants correspond to nontype
template parameters, it builds a linked-list representation of the template
arguments. If there are more template parameters than template arguments and
if the template parameters have default values, entries are supplied for the
default values as well, whether from a saved constant value or after rescanning
the cached tokens comprising the default argument expression.
The template argument list is then passed to find_template_class, which
searches among the instantiations that already exist for the class template,
calling equiv_template_arg_lists to compare the template arguments scanned
for the current reference against the template arguments associated with
existing instantiations. If an instance with matching template arguments is
located, the symbol for it is returned. If no match is found, a new symbol is
created (see make_template_class_sym in symbol_tbl.c) and added to the
instantiations list for the class template. A new class type is also created,
but, since this is a partial instantiation, no body is generated for it yet.
A reference to an instance of a class template always causes a partial instantiation, but not all references cause full instantiation. Partial instantiation occurs during the lexical scan of a template class reference, whereas the decision whether to do full instantiation occurs during semantic processing. Partial and full instantiation are always separate steps in template processing.
Note that a partial instantiation can be generated on the basis of an incomplete class template. For example:
template <class T> class A;
A<int> *x;
Even though no body has been supplied for class template A, a partial
instantiation of A<int> can be produced. On the other hand, A<int> is
an incomplete (and incompletable) type, and so an error would be issued if it
were used in a context that required a complete type. Similarly, partial
specializations are not relevant when a partial instantiation is generated.
They are only considered when a full instantiation is done.
13.5.2. Function Templates#
A function template may be referenced in several different ways:
- as a function call,
- by taking the address of a function,
- and by declaring a function in an explicit specialization, explicit instantiation, or friend instance declaration.
In each case, determining which function template is to be used, and which instance of the template is being referenced, requires the evaluation of an explicitly specified template argument list, deducing template arguments from the function template’s parameters, or some combination of the two. This process involves the following steps for each of the candidate function templates:
- If an explicit template argument list was specified,
substitute_template_argumentsis called. Note that an explicit template argument list is completely scanned beforesubstitute_template_argumentsis called. When it is scanned, the number of parameters, and their types are not known. Consequently, the template argument list needs to be converted into one that matches the template parameter list of the candidate template. This is done by callingcreate_initial_template_arg_list. If the specified template arguments cannot be converted to the types of the corresponding parameters, or if there are more template arguments than template parameters, no template argument list is created and the candidate template is disqualified. Note that an error is not issued because there may be another candidate template that is actually the one intended to be used. - Once an appropriate template argument list has been produced,
substitute_template_argumentscallscopy_type_with_substitutionto create a function type that represents the function type of the candidate template with the template parameters that correspond to the explicitly specified template arguments replaced with the specified template argument values. If the substitution process would result in an invalid type (e.g., a pointer to a reference type, or an array of void) the candidate template is disqualified. - Template argument deduction is done using the substituted function type created above in an attempt to deduce the template arguments that were not explicitly specified. Template argument deduction is done by calling
matches_template_type, which is described below. - If template argument deduction succeeds,
wrapup_function_template_argument_deductionis called to verify that values have been deduced for all of the template parameters, and that the types of any deduced nontype parameters match the types of the corresponding template parameters.copy_type_with_substitutionis called once again to create a new function type in which all of the template parameters have been replaced with the corresponding template argument values.
When the reference is from a function call, the routines described above are
called from the overload resolution routines. When the reference is from the
address of a function or from a declaration, these routines are called by
is_match_for_function_template, which in turn is called from either
matching_template_function or has_matching_template_function.
There are several routines in templates.c that directly and indirectly
support the process described above:
matches_template_typeis designed to be called successively to build a template argument list while checking for a match between a type from the function template routine type and a type from a new routine type; it also calls itself recursively to apply the processing to type trees. When a template parameter type is found, the “real” type with which it is paired is recorded in the corresponding template argument entry – unless it already has some other type, in which case an inconsistency has been found. As long as there are no inconsistencies or type incongruities, this process of augmenting the template argument list continues; otherwise,matches_template_typereturns FALSE to halt further processing and invalidate the template argument list built thus far.Aftermatches_template_typehas indicated that each of the arguments match the template,verify_template_nontype_argsmust be called to verify that nontype parameters whose types depend on a template parameter are consistent with the deduced types. It also supplies types for nontype parameters that are deduced entirely from array bounds.compare_function_templatesis used to determine whether one function template is more specialized than another based on the partial ordering rules for function templates. It is called by the overload resolution routines to compare two function templates that are otherwise identical from the point of view of overload resolution.add_to_partial_order_candidates_listis used in contexts other than overload resolution in which a function template must be selected from a set of function templates using the partial ordering rules. This is done when taking the address of a function that is determined to be an instance of a function template, and when the lookup of a conversion operator name results in the partial instantiation of a template (e.g., whenoperator int*is a reference to an instance of a function template such asoperator T*). After this routine has been called for each candidate template,select_best_partial_order_candidateis called to return the best matching template.find_template_functionis passed a function template symbol and a template argument list. After checking for the use of a local type among the template arguments (an error), it goes through the instances that already exist for the template, callingequiv_template_arg_listsuntil a match is found. If none of the existing instances match the new template argument list, it creates a new instance by callingmake_template_function, to which the new template argument list is passed.is_match_for_function_templateis passed a function template symbol and a new routine type. It returns TRUE if the type fits the type signature of the template and FALSE if not. First, obvious mismatches are detected, such as mismatches in the number of function parameters. Next, if an explicit template argument list was specified, the template arguments are compared with the corresponding template parameters. Type arguments must be associated with type parameters, nontype arguments must be associated with nontype parametersm, and the specific nontype value specified must match the type of the nontype parameter or must be capable of being converted to the type of the nontype parameter. It then tries to find among the instances of the template one whose type signature exactly matches the new routine type. If it finds such an instance, it returns TRUE, along with the symbol it found. Otherwise, it makes successive calls tomatches_template_typein an attempt to construct a template argument list based on any explicitly specified template arguments, the template parameter types, the template routine type, and the new routine type; if this is successful, it returns TRUE, along with the new template argument list, but otherwise it returns FALSE.matching_template_functionis passed a function template symbol and a routine type. It callsis_match_for_function_templatewhich checks for a match between the routine type and the template. If there is a match but no instance already exists, it creates a new instance by callingmake_template_function, to which the routine type is passed.has_matching_template_functionis similar tomatching_template_functionin that it determines whether a given routine type matches a potential instance of the specified template, but it does not create an instance of the template. It is primarily used when issuing diagnostics, to choose the most appropriate of several possible messages. In the following example, the error “specializing overloaded function"A::f"requirestemplate <>syntax” is used because the function type matches the template declared in the class.struct A { template <class T> void f(T); }; void A::f(int) {}
make_template_functionis the routine that actually does the partial instantiation. When it is passed a non-NULL routine type, it simply uses that type; otherwise, it activates the declaration token cache (see thedecl_token_cachefield in the template symbol supplement) and calls eitherscan_member_declarationorscan_template_declaration, for member and nonmember function templates, respectively, to assure that template arguments are correctly substituted for template parameters in the new routine type; and then, if there are default arguments, it callsdelayed_scan_for_function_template_default_args. In addition, it creates thesk_member_funciontorsk_routinesymbol entry, the routine entry, and the template instance, setting all their pointers and other fields appropriately. The symbol is not entered directly into the symbol table – it is accessible to lookup via the instantiation list only.
13.5.3. Variable Templates#
A reference to a variable template results in a full instantiation of the instance if a definition is available. The only exception is when the variable template is used in a declarative context (i.e., to declare an explicit specialization of the variable template). In a partial instantiation the initializer is not scanned.
13.6. Full Instantiation#
Full instantiation of a template means providing an instance of the template with a defining body (or, in the case of a static data member, a definition with an implicit or explicit initializer). Typically, this occurs automatically, on the basis of the template provided. However, it can also occur when the user provides an explicit specialization definition. Both cases are discussed in this section.
13.6.1. Explicit Specializations#
Two forms of explicit specialization are supported by the front end: the new
explicit specialization syntax (e.g., template <> ...), and the old form
that used the normal declaration syntax. The new form is accepted in all
modes, while acceptance of the old form is controlled by a command line option.
Member function templates and member class templates may only be explicitly
specialized using the new syntax.
For example:
template <class T> void f(T);
template <class T> class A {};
template <> class A<int>; // new specialization declaration
template <> class A<int> {}; // new specialization definition
class A<char>; // old specialization declaration
class A<short> {}; // old specialization definition
template <> void f(int); // new specialization declaration
template <> void f(int){} // new specialization definition
void f(char); // guiding declaration
void f(double){} // old specialization
Explicit specializations that use the new syntax begin with one or more template parameter clauses in which the parameter list is empty. An explicit specialization can be a declaration or a definition. The language requires that an explicit specialization be declared before its first use in a translation unit.
When using the old syntax, only classes can be declared as specializations. For all other kinds of entities, specializations can only be supplied as definitions. A function declaration that looks like an old-style specialization declaration is actually what is known as a “guiding declaration”, whose only purpose is to cause a template instance to be treated like a normal function for overload resolution purposes. There are no member guiding declarations.
Old-style explicit specializations look like normal class, function, and static data member declarations and are handled by the same routines that handle normal declarations.
full_specialization processes new-style explicit specializations and is
called after the template parameter clauses have been scanned.
decl_specifiers and declarator are called to scan the declaration that
follows the template parameter clauses. If the entity being specialized is a
class, the call to declarator is bypassed. full_specialization then
identifies the template instance that is being specialized.
13.6.1.1. Class Templates#
An explicit specialization of a class template occurs when the explicit specialization syntax is used, or when old specializations are enabled, when an ordinary class definition is provided in which the class name is a template class reference, for example:
template <class T> class A {};
template <> class A<short> {};
class A<int> {};
A<char> x;
In this example the bodies for A<int> and A<short> are the ones
provided by the user’s explicit definitions. The bodies for all other
instances of template class A, such as A<char>, are based on the
template definition.
The processing of class template explicit specializations is done within
class_specifier, even when the new specialization syntax is used. This is
necessary because only when class_specifier is called is it possible to
determine whether the class is being specialized or whether the class specifier
is part of an elaborated type specifier in some other kind of declaration.
When the template class reference is encountered as a tag name (see
scan_tag_name), a partial instantiation is done automatically and the
symbol is entered on the instantiations list of the class template. Then
class_specifier marks the class as being explicitly specialized by setting
the is_specialized flag in the type entry, and adds the definition, if one
has been supplied. Because the is_specialized flag is set, no subsequent
automatic instantiation will be attempted.
The same processing applies to both class templates and member class templates. The processing for nested classes of class templates is basically the same except that, as with other members of class templates, the partial instantiation of the nested class is done when the enclosing class is instantiated.
13.6.1.2. Function Templates and Member Functions of Class Templates#
An instance of a function template may be explicitly specialized using the explicit specialization syntax, or when old specializations are enabled, by providing a function definition that happens to match the type signature of a function template. For example:
template <class T> void f(T) {}
template <> void f(char); // explicit specialization
void f(int) {} // old explicit specialization
void f(int,int} {} // Unrelated to the template
In both the old and new style specializations, the is_specialized flag in
the routine entry is set, which suppresses the full instantiation of the
template. The old-style specialization of a function also acts as a guiding
declaration for overload resolution purposes.
When the new specialization syntax is used, find_matching_template_instance
is called to find the template instance that matches the routine type returned
by declarator. This is done not only for instances of function templates
and member function templates, but also for member functions of class
templates.
Processing for old-style explicit specializations follows the track for
ordinary function definitions. The primary difference appears in
find_linked_symbol (called from decl_routine via id_linkage), which
searches for previous declarations of the entity being declared. If the
ordinary search fails to turn up a matching function but does find a function
template with the given name, a call is made to matching_template_function,
which extends the search to instances of the template function and, as
described above, creates a new one when appropriate. In other words, this
search in id_linkage may have the effect of doing a partial instantiation
of a new template function. Once the instance symbol has been found (or
created by means of a partial instantiation), attaching the function definition
to the routine involves no special processing.
It can happen that an old-style explicit specialization of a function template precedes the declaration of the template itself. For example:
void f(int) {} // Specific definition
template <class T> void f(T) {}
When the function template declaration is encountered,
decl_function_template goes back through existing functions of the same
name and calls record_predeclared_template_function for each – if the
function turns out to match the new template, it is retroactively entered as an
instance.
Old-style explicit specializations of member functions or static data members of instances of a class templates involve little special handling beyond what is normally done for definitions of member functions and static data members of nontemplate classes. Here’s an example:
template <class T> class A {
void f(T);
static T s;
};
void A<int>::f(int) {}
int A<int>::s = 0;
The reason no special processing is required is that the full instantiation of
A<int> entails the partial instantiation of its members f(int) and
s. After that it’s just a matter of marking the symbols as defined and
adding the function body or initializer.
13.6.1.3. Variable Templates#
The use of a variable template in an expression context results in a full instantiation if a definition is available. If a definition is not available, the normal instantiation processing is done as for template functions and static data members of template classes (e.g., an instantiation could be done later in the translation unit if a definition was provided, depending on the instantiation mode). Even though a full instantiation may be done, an external definition of the instance may or may not be emitted depending on the instantiation mode.
13.6.2. Automatically Generated Definitions#
13.6.2.1. Class Templates#
The full instantiation of a template class occurs at the first point in the translation unit where a reference to the instance requires it to be a complete type. In other words, it is done as soon as necessary, but no sooner. For example:
template <class T> class A {};
A<int> *p; // Partial instantiation of A<int>
A<int> a; // Full instantiation of A<int>
The first declaration involving A<int> does not require that it be a
complete type, but the second one does, and so that is the point at which the
full instantiation occurs. At points in the front end where a complete type is
required, the macro complete_class_type_is_needed is invoked, resulting, if
appropriate, in a call to instantiate_template_class to generate the full
instantiation.
13.6.2.1.1. Partial Specializations#
A class or variable template may be partially specialized. A partial specialization is a version of the template that should be used for certain instantiations. The template to be used is selected based on the template argument list on which the instantiation is to be based.
When a full instantiation is required, check_partial_specializations is
called to match the template argument list of the class being instantiated with
each of the partial specializations that have been declared for the template.
matches_partial_specialization is called to perform the actual matching.
The matching is done using the same process and routines that are used to do
function template argument deduction (see matches_template_type above). If
the template parameters for a given partial specialization can be deduced from
the actual template arguments, then the template class matches the partial
specialization. For example:
template <class T1, class T2> struct A {}; // #1
template <class U1, class U2> struct A<U1*, U2> {}; // #2
template <class V1> struct A<V1, V1> {}; // #3
template <class X1> struct A<X1*, short> {}; // #4
A<int, char> a1; // uses primary template (#1)
A<int*, int> a2; // uses #2
A<int, int> a3; // uses #3
The declaration of a1 does not match any of the partial specializations, so
the primary template is used. The declaration of a2 matches the partial
specialization labeled #2 because U1 and U2 can be deduced from
<int*, int> (as int and int, respectively). Partial specialization
#3 is used when the two template arguments are the same, as in the declaration
of a3.
Each partial specialization that matches the argument list is added to a list
of candidate partial specializations using the routine
add_to_partial_order_candidates_list, which compares the new entry with any
entries already on the candidates list. The comparison is done by
is_more_specialized, which determines whether a given partial
specialization is “more specialized” than another. If the entry being added is
not as specialized as an entry already on the list, the new entry is not added.
If the new entry is more specialized than an entry already on the list, that
entry is removed from the list. After all of the partial specializations have
been evaluated, the candidates list contains a set of partial specializations
that match the template argument list of the class being instantiated and which
are unordered relative to one another. If there are no entries on the list,
the primary template is used to generate the class. If there is exactly one
entry on the list, that partial specialization is used to generate the class or
variable. If there is more than one entry on the list, the instantiation is
ambiguous and an error is issued.
A<int*, int*> a4; // ambiguous - could be #2 or #3
A<int*, short> a5; // uses #4
The declaration of a5 uses partial specialization #4, even though both #2
and #4 match. #4 is preferred because it is “more specialized” than #2.
Whether a given partial specialization is more specialized than another is
determined in much the same way in which a partial specialization is determined
to match a given actual template argument list, i.e., though use of the
argument deduction routines. In the example above, if the argument list of #4
was considered to be the actual argument list and the argument list of #2 was
considered to be the parameter list, the parameters of #2 could be deduced as
U1=X1 and U2=short. If the roles of the two partial specializations
are reversed, making #2 the actual argument list and #4 the formal parameter
list, the type deduction fails. Therefore, #4 is considered more specialized
than #2.
13.6.2.1.2. Generating the Template Class#
Once the appropriate template has been selected (i.e., either the primary template or a partial specialization), the body of the template class is generated. These are the steps:
- The
pending_instantiationsvalue in the template symbol supplement for the class template is incremented. This allows the compiler to catch and report “runaway recursive instantiation,” as the following example would produce:template <int I> class A { A<I+1> a; }; A<0> x;
Once the pending instantiations counter reachesmax_pending_instantiation(a global variable that can be set by a command-line option, and whose default is defined inlang_feat.h), an error is issued and the recursion is halted. push_template_instantiation_scopeis called to push a template instantiation scope onto the scope stack and to do some special processing for template instantiations:- Pointers to the template symbol, the instance symbol, and the template argument list are recorded in the scope stack entry.
depth_innermost_instantiation_scopeis updated with the current scope stack depth.update_template_param_symbolsis called to bind the symbols for template parameters to the values in the corresponding template arguments. For example:template <class T, int I> class A {}; A<int,0> x;
By default thesk_typesymbol for template parameterTrefers to atk_template_paramtype entry and thesk_constantsymbol forIrefers to ack_template_paramconstant. But during the instantiation ofA<int,0>– that is, while the template instantiation scope is active – any reference toTorIshould be translated into a reference to the value of the corresponding template argument, namely, tointor0, respectively. This is done by modifying the pointers in the symbols; the default pointers are restored when the template instantiation scope is popped.- The cache containing the tokens for class template definition is activated.
scan_class_definitionis called. In most respects processing is identical to the processing for any class definition. The differences have mainly to do with recording member functions and static data members as instances:find_corresp_prototype_tag_symis called to find the symbol for the prototype instantiation of the class. (When a nested class within a template class is scanned, the symbol returned is the corresponding nested class of the prototype instantiation.) That symbol is required for calling the two routines described next.find_member_function_templateis called for member functions of the new template class. It locates the template symbol (i.e., the symbol for the corresponding member function in prototype instantiation), creates a template instance entry for the new member function, and adds it to the instantiation list of the template. The template argument list for the new template class serves for the instance, too.find_variable_member_templateis called for variable templates and static data members of the new template class. The processing is similar to what is done for member functions.find_function_template_memberis called for member function templates of the new template class. The processing is similar to what is done for member functions.find_class_template_memberis called for member class templates of the new template class. The processing is similar to what is done for member functions.set_nested_template_class_symbol_infois called for nested classes of the new template class. This call is made byclass_specifierwhen the nested class is first encountered. The processing is otherwise similar to what is done for member function.delayed_scan_fixup_for_class, called at the end of scanning the class definition, provides somewhat special handling for template classes. For inline-defined member functions the function bodies are not scanned at this time; such functions are only instantiated if they are called, so that errors are not issued on functions that are not actually used. Also,delayed_scan_for_function_template_default_argsis called to process the default arguments on the function parameters: the token cache to be used is accessed through the template symbol supplement.
set_instantiation_required_for_template_class_membersis invoked; for each member function and static data member, both of the template class and of any classes nested within the template class, it callsupdate_instantiation_required_flag.pop_template_instantiation_scopeis called to pop the template instantiation scope. The template parameter symbols anddepth_innermost_instantiation_scopeare restored to the values they had before the scope was pushed. (Note that the possibility of recursive instantiation prohibits restoring these values to default values.)- The
pending_instantiationsvalue in the template symbol supplement for the class template is decremented.
13.6.2.2. Alias Templates#
When an instance of an alias template is referenced, find_template_class is
called to look for a previously created template alias or instantiate a new
alias if no previously created instance exists. Template aliases are
instantiated by instantiate_template_alias. Note that unlike class
templates, there are no partial instantiations of alias templates
13.6.2.3. Function Templates#
The timing for the instantiation of member and nonmember template functions is partly controlled by the user (as discussed in the next section). A function may end up being instantiated
- at the point of first reference in a given translation unit (e.g., functions declared
inline); - at the end of the translation unit; or
- externally to the current translation unit.
Wherever it occurs, it is instantiate_template_function that is called to
generate a function body based on a template. These are the steps in the
process:
- The function’s storage class and name linkage are set, along with its
is_inlineflag if required. - The
pending_instantiationsvalue in the template symbol supplement is incremented. As for class templates, this field is used to catch runaway recursive instantiation. push_template_instantiation_scopeis called to push a template instantiation scope onto the scope stack.- The token cache is activated.
push_scopeis called again to push a function scope onto the scope stack.- On the basis of the
param_idlist saved in the template symbol supplement the function parameters are entered into the symbol table (in the function scope) bydecl_parameter. - For constructors a call is made to
ctor_initializerto process the ctor-initializer list, if any, as well as to do default processing, and for destructors a call is made todtor_initializer. - In case a function is being instantiated “on the fly” in the midst of executable code, the structured statement stack is suspended and a new one begun by a call to
new_struct_stmt_stack. compound_statementis called to process the tokens comprising the function body. The IL produced is recorded in the function scope.- If appropriate,
restore_struct_stmt_stackis called. pop_scopeis called for the function scope.pop_template_instantiation_scopeis called for the template instantiation scope.- The
pending_instantiationsvalue in the template symbol supplement for the class template is decremented.
13.6.2.4. Variable Templates and Static Data Members of Class Templates#
instantiate_template_variable is invoked to handle full instantiation of
static data members and for partial and full instantiations of variable
templates. It performs the following:
- Static data members are marked as defined. Variable templates are marked as defined if the declaration is a definition.
- If an explicit initializer was specified in the static data member template declaration, then:
push_template_instantiation_scopeis called to push a template instantiation scope onto the scope stack.- The token cache is activated.
- The type is scanned to determine the type of a template variable, or to make sure the type agrees with the declaration in the class for static data members.
- For a full instantiation, if a definition is available,
initializeris called to process the tokens comprising the initializer. pop_template_instantiation_scopeis called for the template instantiation scope.
- If no initializer was specified for a defined variable template or static data member,
def_initializeris called.
13.7. Constrained Templates#
C++20 introduces the notion of “constrained templates”, which is often referred to as “concepts” (although concepts are just one feature in support of constrained templates). For example:
template<typename T> requires(sizeof(T)<4*sizeof(int*))
int hash(T *p);
Constraints are boolean predicates. In the example above, it’s just a normal
expression. Whenever template instance is considered (e.g., for overload
resolution or for a partial instantiation), its constraint predicates are
substituted and evaluated: If the predicates evaluates to false, the
template is discarded. For functions and partial specializations, that may not
be an error (assuming other candidates satisfy their constraint or are
unconstrained), but other cases will then elicit an error that will indicate
which constraint failed to be satisfied.
13.7.1. Concepts#
A constraint expression can be abstracted through a concept template. For example:
template<typename T> concept SmallHashable = sizeof(T)<4*sizeof(int*);
After that definition, the declaration of hash above can instead be rewritten as:
template<typename T> requires SmallHashable(T)
int hash(T *p);
or
template<typename T>
int hash(T *p) requires SmallHashable(T);
or
template<SmallHashable T> int hash(T *p);
or even
int hash(SmallHashable auto *p);
Although concept template are a kind of template, they are not (partially or fully) instantiated. Instead, they are “substituted” somewhat like function templates are substituted during the deduction process.
Concept templates are represented in the IL using a_template entries of
templk_concept kind, and in the symbol table using sk_concept_template
symbols (that point to a_template_symbol_supplement entries with no variant
fields). A templk_concept template points to the predicate, which is
represented as an ordinary expression tree (an_expr_node structure).
Concept templates can also be “invoked” directly to produce a boolean value. For example:
auto cond = SmallHashable<X>;
Such expressions are represented using enk_concept_id nodes: They point to
a templk_concepta_template entry and, optionally, to a list of
template arguments.
13.7.2. Representation of constraints#
As hinted above, there are four possible syntactic locations for constraints:
- A concept name used to introduce a template type parameter. Such constraints – called type constraints – are represented as
enk_concept_idnodes pointed to by thea_template_param_type_supplementassociated with the constrained template parameter. The first template argument for suchenk_concept_idnodes are implied (it’s the template parameter being constrained) and that is indicated by theis_type_constraintflag in theenk_concept_idnode. - A requires clause following a
template<...>header, as in our original example. Such constrains are represented usinga_requires_clauseentries pointed to froma_template_decl, itself pointed to froma_template.a_requires_clauseis itself mostly a structure pointing to an expression tree. - An implicit template type parameter introduces by a so-called “abbreviated function template declaration”, as in the example
int hash(SmallHashable auto *p);above. This case is represented very much as the first case (concept name used to introduce a template type parameter): By having the associateda_template_param_type_supplemententry point to anenk_concept_idnode representing the constraint. However, in this case, thea_param_typeentry corresponding to the parameter that introduced the constrained also has the flagis_auto_paramset to TRUE. - A trailing requires clause following the function declaration itself, as we showed in the second variation of our example:
template<typename T> int hash(T *p) requires SmallHashable(T);
This is represented by having thea_routineentry for the prototype instantiation of the function template point to an entry of typea_requires_clause. It’s worth noting that this variation of a constraint can also be applied to ordinary member functions of class templates (hence the need to point to it from ana_routineentry rather than a template-specific entry).To ease the description of constraints, C++20 also introduces requires-expressions (not to be confused with requires-clauses, which were described above). For example:
template<typename T> void f() {
bool b = requires { typename T::node; };
}
Such expressions are represented by an enk_requires node, which points to a
list of expression nodes: Entries on that list that are of kind
enk_type_operand, enk_compound_req, and enk_nested_req are of
special significance. See il_def.h and expr.c for details.
13.7.3. Important Constrained-Template Functions#
The following are some functions that are central to the handling of constrained templates:
scan_requires_clauseandscan_concept_expression(both inexpr.c). These are the functions that parse constraint expressions, which requires special treatment of the logical operators (&&and||).scan_requires_expr(expr.c), which parses requires-expressions.check_template_constraints(templates.c), which determines if a given template’s constraints are satisfied by a given set of template arguments.requires_clause_satisfied(exprutil.c). This function performs substitution of constraint expression, which is subject to various subtle rules. It leans heavily on the expression rescanning facilities (see Rescanning Expressions).compare_constraints(exprutil.c). When determining the partial order of function templates or partial specializations, constraint can play a special role. This function, is the main function for comparing the constraints on templates (to determine whether a template is more or less constrained than another, or maybe neither is more constrained than the other). The algorithm for this comparison is relatively complex and described in great detail inexprutil.c.
13.8. Managing Instantiation of Functions, Variables, and Static Data Members#
As noted previously, the full instantiation of template classes occurs as soon as necessary, but no sooner. The timing for the automatic instantiation of template functions, variables and members of template classes is more complicated.
For example, if a member function of a template class is not referenced,
there is no reason to instantiate it. But even if it is referenced, its
instantiation may occur elsewhere. The EDG C++ front end supports several
methods whereby the user can manage the instantiation of templates:
automatic instantiation, instantiation modes that are specified on the
command line, and explicit instantiation directives included in the source
code of the program. Explicit instantiation directives are supported in
both the form specified by the C++ standard and as #pragma directives.
For a detailed description of how the instantiation modes and pragmas are
used, see Template Instantiation.
The instantiation_required flag in template instance entries is set to
indicate that a function, variable, or static data member has been referenced
in such a way as to require its definition (i.e., full instantiation) somewhere
in the program, even if not in the current translation unit. For example,
calling a template function causes the flag to be set.
update_instantiation_required_flag is called to set the flag and to place
the instance on a linked list (see add_to_instantiations_required_list) so
that it can be readily found later, when the actual instantiation is done.
Sometimes the routine to do full instantiation is called immediately, however
(e.g., for calls to template functions that are declared as inline or when
in the midst of instantiation wrapup processing); in such cases the instance is
not placed on the list.
It is do_any_needed_instantiations, called by
template_and_inline_function_wrapup, as part of the fe_wrapup process,
that goes through the instantiations_required list. It determines for each
instance whether full instantiation is actually required in the current
translation unit as a result of the instantiation mode being used, explicit
instantiation and #pragma directives found in the program (see
should_be_instantiated, which checks instantiation modes and directives),
and whether the instantiation has been assigned to the current translation unit
by the automatic instantiation mechanism. It then will call
instantiate_entity, if appropriate.
Instantiations are normally generated as part of the object file of the translation unit in which the instantiations are performed. But when “one instantiation per object” mode is specified, each instantiation is placed in its own object file, and the names of those object files are written to the template information file (which is described below). One instantiation per object mode is useful when generating libraries that need to include copies of the instances referenced from the library. If each instance is not placed in its own object file it may be impossible to link the library with another library containing some of the same instances. Without this feature it is necessary to create each individual instantiation object file using the manual instantiation mechanism.
13.8.1. Automatic Instantiation#
The EDG C++ front end provides a complete prototype implementation of an
automatic instantiation mechanism. The EDG automatic instantiation mechanism
is a “linker feedback” mechanism. It works by providing additional information
in the object file that is used by a “prelinker” to determine which template
entities require instantiation so that the program can be linked successfully.
Unlike most aspects of the front end the automatic instantiation mechanism is,
by its nature, dependent on certain operating system and object file format
properties. In particular the prelinker is a separate program that makes use
of the UNIX nm command to access information about the symbols defined in
object files. Furthermore it relies on features implemented in the eccp
driver script. Consequently, this code should be viewed as a sample
implementation that may need adaptation to work on other systems.
This section describes the steps involved in automatic instantiation. The steps are described in the sequence in which they would occur while compiling and linking an application and not necessarily the sequence in which they occur in a given execution of the front end. While one might expect the two sequences to be the same the automatic instantiation mechanism may, in fact, compile a given file a number of times while determining the set of instantiations that are needed to link the application.
13.8.1.1. Initial Compilation#
When a program is compiled, the front end generates a set of flags that are provided to the back end and are ultimately either output as a separate file by the front end or are encoded in some form in the generated object file. The flags are stored in the IL variable and routine entries.
- The
can_be_instantiatedflag indicates that this translation unit is capable of generating an instantiation for a given function, variable, or static data member (hereafter referred to as a “template entity”). This is used by the prelinker to determine which source files are possible instantiation sites for the template entity. This flag is set even if the translation unit provides an instantiation of the template entity. - The
instance_requiredflag indicates that a definition of the template entity must be supplied by some translation unit (but not necessarily this one). Both theinstance_requiredand thecan_instantiateflags indicate that the entity is one that can potentially be defined by a generated template instantiation. This information allows the prelinker to distinguish between an unresolved template reference and a plain undefined symbol. These flags are also used by the prelinker to distinguish class specializations, whose members cannot be defined by generated instantiations, from regular template classes whose members may be defined by generated instantiations. - The
do_not_instantiateflag indicates that instantiation of the template entity has been explicitly prohibited by use of thedo_not_instantiate#pragmadirective. When automatic instantiation is used, thedo_not_instantiatepragma prohibits instantiation not only in the file in which the pragma was included but anywhere within the application with which the resulting object file is being linked.
In the default configuration, these flags are written to the template
information file, which is descibed below. In earlier versions of the front
end these flags were translated by IL lowering into tentative definitions of
specially named symbols. The old behavior can be selected using the
INSTANTIATION_FLAGS_IN_TEMPLATE_INFO_FILE configuration flag. The flags
were removed from the object file because the amount of space consumed by the
names of the flags could be excessive, because the mangled names of template
entities can be very long. When the flags are generated as part of the object
file, the symbol names include a code that indicates the flag kind and also
includes the name of the symbol being described. The special symbol includes a
prefix of __CBI__ (can be instantiated), __TIR__ (template instance
required), or __DNI__ (do not instantiate) followed by the mangled name of
the entity. For example, a template function of type void f(int) could
have the following flags generated.
__CBI__f__fi__TIR__f__fi__DNI__f__fi``
Because they are generated as tentative definitions, they may each appear in any or all of the object files being linked into an application while only appearing once in the generated executable file
When a template class contains noninline virtual functions, the instantiation mechanism must ensure that the virtual function table is defined. IL lowering does this by generating a “template instance required” flag for the first noninline virtual function of any template class, because it’s the presence or absence of a definition for that function that controls whether or not IL lowering puts out a definition for the virtual function table. By requiring the first noninline virtual function to be defined we ensure that the virtual function table will also be defined
13.8.1.2. The Template Information and Instantiation Request Files#
Information is exchanged between the front end and prelinker using the
“template information” and “instantiation request” files. These files are also
known respectively as the .ti and .ii files [1]. The template
information file is used for infomation produced by the front end for use by
the prelinker. The instantiation request file is produced by the prelinker for
use by the front end. The template information file was added in version 2.37
of the front end to support features such as one-instantiation-per-object mode,
and generation of instantiation flags in a separate file instead of the object
file. The front end can be configured to not use a template information file
in order to be compatible with earlier versions of the front end, but this
requires that the features that use the template information file be disabled.
The template information file provides several diferent kinds of information to the prelinker. Each line of the file contains a type code followed by a string. The type code indicates the type of information being provided. The following types of lines are generated by either the front end or driver:
cmd:command line (supplied by the driver)dir:compilation directory (supplied by the driver)fnm:compilation file name (supplied by the driver)idn:instantiation directory (in one-instantiation-per-object mode, supplied by the driver)flg:instantiation flags (when not encoded in the object file)ifn:instantiation file names (in one-instantiation-per-object mode)stu:secondary translation units (supplied by the driver)tnm:export templates defined in this filedep:dependency information when exported instantiations have been generated
The order in which these are specified is not, in general, significant except that the prelinker currently requires that the instantiation directory entry precede any instantiation file name entries.
The template information and instantiation request files have the same base
name as the source file, but use special suffixes specified by configuration
parameters in host_envir.h, with the default values indicated above.
At the end of each compilation the front end determines whether any template entities were referenced in the translation unit. If so a template information file is created (or an instantiation request file, if template information files are not being used). If no template entities were referenced in the translation unit the file will not be created and any existing file will be removed. When template information files are being used, the instantiation request file is also removed if the template information file is removed.
After invoking the front end the driver checks for the existence of either the template information or instantiation request file, depending on the configuration. If one exists, the driver updates it with the command line used to compile the source file, the name of the current directory when the compilation was done, and the name of the file that was compiled. This information is used later if the prelinker needs to recompile the file.
13.8.1.3. Prelinker#
Once a complete set of object files has been generated, including the appropriate flags, the prelinker is invoked to determine whether any new instantiations are required or if any existing instantiations are no longer required. The command line arguments to the prelinker include a list of input files to be analyzed. The input files are the object files and libraries that constitute the application. The prelinker begins by looking for template information files for each of the object files (or instantiation request files, if template information files are not being used). If no template information (or instantiation request) files are present, the prelinker concludes that no further action is required.
If there are template information (or instantiation request) files, the
prelinker reads the template information file and the current instantiation
list from the instantiation request file. The instantiation list is the list
of instantiations assigned to a given source file by a previous invocation of
the prelinker. The prelinker uses the UNIX nm command to produce a list of
the global symbols that are referenced or defined by each of the input files.
The prelinker then simulates a link operation to determine which symbols must
be defined for the application to link successfully.
When the link simulation has been completed, the prelinker processes each input file to determine whether any new instantiations should be assigned to the input file or if any existing instantiations should be removed. The prelinker goes through the current instantiation list from the instantiation request file to determine whether any of the existing instantiations are no longer needed. An instantiation may be no longer needed because the template entity is no longer referenced by the program or because a user supplied specialization has been provided. If the instantiation is no longer needed, it is removed from the list (internally; the file will be updated later) and the file is flagged as requiring recompilation.
The prelinker then examines any symbols referenced by the input file. The responsibility for generating an instantiation of a given entity that has not already been defined is assigned to the first file that is capable of generating that instantiation.
If a given file contains instantiations of exported templates, the template information file contains dependency information. If a source file that is part of an exported template translation unit changes, the dependency information is used to detect such a change so that the prelinker can recompile the file and regenerate the instantiations of the exported templates.
13.8.1.4. Recompilation#
Once all of the assignments have been updated, the prelinker once again goes through the list of object files. For each, if the corresponding instantiation request file must be updated, the new file is written. Only source files whose corresponding instantiation request file has been modified will be recompiled.
At this point the combination of the template information and instantiation request files contains the information needed to recompile the source file, and a list of instantiations assigned to the source file (in the form of mangled function, variable and static data member names).
Then, during recompilation the front end reads the entries from the
instantiation request file produced by the prelinker and checks them against
entries on its own “instantiations required” list. Whenever a match is found,
based on comparing the mangled name from the instantiation request file and the
name returned by either get_mangled_function_name or
get_mangled_variable_name (in lower_il.c), the
automatically_instantiated flag is set in the template instance entry.
When the prelinker invokes the front end, it provides a “definition list file”,
which contains a list of all the external definitions found in the object files
and libraries specified on the prelinker command line. The front end reads the
definition list file and determines whether each of the entries on its
instantiations required list has already been defined elsewhere. If an entity
is found that is not defined elsewhere, its automatically_instantiated flag
is set.
Later, in instantiation_wrapup, instantiations will be generated for all
instances for which the automatically_instantiated flag is set, whether as
a result of being included in the instantiation request file or “adopted” by
the front end when it was determined that the instance was not defined
elsewhere. A list of the entities adopted by the front end is written to the
definition list file. This list is used by the prelinker to add the adopted
entities to the adopting translation unit’s instantiation request file.
The definition list file permits the front end to perform instantiations that have become necessary as a result of other instantiations that were assigned by the prelinker, without requiring that the prelinker invoke the front end an additional time to perform those instantiations. This reduces the number of iterations of the prelinker and front end that are required to generate a complete set of instantiations for a program.
If an error occurs during a recompilation, the prelinker exits without updating the remaining information files and without attempting any additional compilations.
13.8.1.5. Iteration and Termination#
If all recompilations complete without error, the prelink process is repeated, since an instantiation can produce the demand for another instantiation. This prelink cycle (finding uninstantiated templates, updating the appropriate instantiation request files, and dispatching recompilations) continues until no further recompilations are required. [2]
When the prelinker is finished, the linker is invoked. Note that simply because the prelinker completes successfully does not assure that the linker will not detect errors. Unresolvable template references and other linker errors will not be diagnosed by the prelinker.
In many cases, once the application has been successfully linked, the recompilation overhead will have become a one-time-only expense, because the next time the source file is compiled, the instantiation request file will provide precisely the right list of instantiations to be done. Recompilation will be required again only if the instantiation request file is invalidated, that is:
- if additional instantiations come to be needed (in this or another file);
- if existing instantiations are not longer referenced;
- if a different set of command-line options is used to compile the file; or
- if the instantiation request file is deleted.
Except in such cases, once the complete set of instantiation request files has been generated, the prelinker should not need to force recompilation for any source files in the application.
13.8.1.6. Implementing Alternative Automatic Instantiation Mechanisms#
The default automatic instantiation implementation uses the instantiation
request file as described above. The routines in templates.c are designed
to permit an alternative mechanism to be used (e.g., querying a database) to
determine whether a given entity should be instantiated. This may be done by
modifying the following routines:
init_auto_instantiation_informationis called at the beginning of the automatic instantiation processing. The default version callsread_auto_instantiation_information, which opens the instantiation request file and reads its contents.check_if_entity_should_be_automatically_instantiatedis called for each instantiatable entity (external function, variable, or static data member). It sets theautomatically_instantiatedflag if the entity is to be instantiated in this translation unit, and theadd_to_request_fileflag if the instantiation was “adopted” by this translation unit and must be added to the instantiation request file by the prelinker. The default version callscheck_if_present_in_request_fileto determine whether the specified entity was named in the instantiation request file and/or the definition list file.wrapup_auto_instantiation_informationis called byfe_wrapup. The default version callscreate_or_remove_instantiation_information_fileandclose_or_remove_template_infofile.
13.8.2. Instantiation Modes#
The instantiation mode is specified by a command line option and determines
whether the compiler should automatically generate instances of template
entities (function templates, variable templates, member function of template
classes, and static data members of template classes.) The command line option
is used to set the global variable instantiation_mode to one of the
following values:
tim_none |
Do not automatically create instantiations of any template entities.
This is the default.
|
tim_used |
Instantiate those template entities that were used in the compilation.
This will include all static data members for which there are template
definitions.
|
tim_all |
Instantiate all template entities declared or referenced in the
compilation unit. For each fully instantiated template class, all of
its member functions and static data members will be instantiated
whether or not they were used. Nonmember template functions will be
instantiated even if the only reference was a declaration.
|
tim_local |
Similar to
tim_used except that the functions are given internal
linkage. This is intended to provide a very simple mechanism for
those getting started with templates. The compiler will instantiate
the functions, variables and static data members used in the
compilation as local (static) functions and local (static) variables. |
Inline functions are usually instantiated when they are first referenced, and
so unreferenced inline functions are usually not instantiated. However, in
tim_all mode they are always instantiated – either during
instantiation_wrapup or, for member functions for which the body is
supplied in the class template definition, when the class is instantiated.
13.8.3. #pragma Directives#
There are three instantiation pragmas, instantiate, which causes the
specified entity to be instantiated, do_not_instantiate, which causes
instantiation of the specified entity to be suppressed, and
can_instantiate, which indicates that the specified entity can be
instantiated by an automatic instantiation mechanism, but need not be. [3]
The do_not_instantiate pragma is typically used with the manual
instantiation mechanisms when a specific definition will be supplied elsewhere.
The argument to the instantiation pragmas may be a template class name, a member function name, a variable name, a static data member name, a member function declaration, a function declaration, an elaborated type specifier for a class, or a static data member declaration. When a class name or elaborated type specifier is specified, the directive is applied to all member functions and static data members of the class.
Processing the pragmas results in setting some flags in the template instance.
They are later checked by should_be_instantiated (called from
instantiation_wrapup) to determine whether the entity requires full
instantiation. The instantiate pragma sets the instantiation_required
and explicit_instantiation flags and records the current source position
(for reporting errors later). The do_not_instantiate pragma clears
instantiation_required and sets specific_def to block instantiation
based on the instantiation mode.
Explicit instantiations are processed by instantiation_wrapup in much the
same way as instantiations that may be generated depending on the instantiation
mode. The only difference is that certain conditions that are ignored for
nonexplicit instantiations cause errors to be issued for explicit
instantiation. If no template definition has been supplied from which to
generate an instantiation, an error is issued for explicit instantiation
requests. Likewise, if a specific definition has been supplied and an explicit
instantiation was requested, an error is also issued.
13.8.4. Explicit Instantiation Directives#
Explicit instantiation directives are processed in nearly the same way as instantiation pragmas. The differences between the handling of the instantiation pragma and an explicit instantiation directive are as follows:
- Inline functions may be specified in explicit instantiation directives, even though doing so is meaningless.
- An entity may not appear in more than one explicit instantiation directive.
- Explicit instantiation directives require that a declaration follow the
templatekeyword, while the instantiation pragmas permit a simple name to be specified.
13.8.5. Implicit Inclusion#
In the cfront model of programming with templates the template
declarations are placed in a header (e.g., “.h”) file while the
definitions of noninline functions and static data members are placed in a
source (e.g., “.c”) file. To support this style of programming the
front end provides an optional “implicit inclusion” feature. When this
feature is enabled, the front end will implicitly include a source file
when needed to provide definitions of template entities declared in a given
header file.
When a header file is included, information about the kind of include statement
used is stored in the IL source file structure. This specifies whether the
include statement was a “normal” include (e.g., #include "file.h") or a
system include (e.g., #include <file.h>).
At the end of compilation, during instantiation wrapup processing, the source file associated with a given header file will be included if needed. A file is “needed” if an instantiation of an entity is required as a result of a command line option, pragma directive, or instantiation list file. In automatic instantiation mode implicit inclusions of template definition files will essentially always be done so that accurate “can be instantiated” flags may be generated.
The implicit inclusion is done by searching through each of the directories in
the appropriate search path list (based on the kind of include statement used
to include the header file). A configuration parameter specifies a list of
file suffixes to be used during the search for a file to be implicitly
included. In each directory on the search path each of the possible suffixes
will be tried in sequence. If no matching file is found, the next directory in
the list is used. If no matching file is found in any directory, no error is
reported (unless the instantiation was explicitly requested using an
instantiate pragma in which case an error will be issued indicating that no
template definition was supplied).
13.8.6. Instantiating Non-Template Inline Functions#
The front end provides two implementations of C++``extern inline`` functions,
referred to as “lower extern inline” and “instantiate extern inline”. The
“lower” version is the default, and causes extern inline functions to be
translated into static functions with special care taken to ensure that
entities such as local static variables have the proper semantics. (See the
comments on the definition of INSTANTIATE_EXTERN_INLINE in targ_def.h
for the advantages and disadvantages of each implementation.)
The “instantiate” version, which is enabled by setting the
INSTANTIATE_EXTERN_INLINE configuration flag, ensures that only a single
external out-of-line copy of the inline function is generated, and then only if
one is required by the program. The automatic template instantiation mechanism
is used to implement this mechanism.
When an inline function is defined, add_to_inline_function_list is called
to add the function to a list of all of the inline functions in the translation
unit. During the wrapup processing at the end of the compilation,
inline_function_wrapup uses the inline function list to determine which
inline functions should have their bodies emitted as part of this compilation.
The suppress_inline_body flag in the routine entry is cleared if a back end
should emit an out-of-line body of an inline function.
update_inline_function_flags emits instantiation flags as is done for
template entities. The prelinker will then assign the “instantiation” of
inline functions for which out-of-line bodies are required.
13.9. Exported Templates#
The C++ standard specifies that the definition of certain templates (static
data members and non-inline functions) can be separately compiled. This
feature is generally referred to as “export” as such templates are declared
using the export keyword. The definition of an exported template is
provided in a single translation unit. Other translation units that use the
template require only a declaration of the template.
Exported templates require special processing not needed for normal (non-exported) templates:
- When the definition of an exported template is encountered, a record of the translation unit containing the exported template must be made so that the definition can be found later when an instantiation is needed.
- When an instantiation of an exported template is generated, the front end must be able to search for a definition of the template.
- Generating an instantiation of an exported template requires that the front end have access to information about the translation unit containing the template definition and the translation unit containing the reference. One exported template may call another, which may call another, and so on. As a result, the front end must be able to simultaneously process an arbitrary number of translation units at the same time (see Multiple Translation Units).
- Whenever a partial or full instantiation of an entity must be done, the front end must update its context information so that the translation unit containing the template is the current translation unit (see Initialization, Termination, and Keeping Translation Units Separate).
When an exported template is defined, information about the definition must be
recorded. add_to_exported_templates_list is called when an exported
definition is encountered. This information is used at the end of the
compilation to create a file that provides a list of the exported templates
defined in the translation unit. This file is known as the “exported template”
file and, by default, has a suffix of .et. The following is an example of
an exported template file:
fnm:t.c
tnm:f__tm__4_Z1Z__FZ1Z_v
tnm:f2__tm__4_Z1Z__FZ1Z_v
mid:t_c_ee131b0b
def:XXX=3
und:YYY
end:
The following types of lines appear in such a file:
fnm:The name of the primary source file to be used when reloading the translation unit.tnm:The mangled name of a template defined in the translation unit.mid:The module ID to be used when instantiating templates from the file.def:A command-line macro definition to be used when reloading the translation unit.und:A command-line macro un-definition to be used when reloading the translation unit.end:The end of the entries associated with the previousfnm:entry.
The information for a given file always begins with “fnm:” and ends with
“end:”. This makes it possible to concatenate a group of exported template
files together, which is useful when creating a library that defines exported
templates.
When the front end compiles a file that makes use of exported templates, a
search path of exported template directories is used to locate the file that
defines a given exported template. The entries on the search path are
specified with the --template_directory command-line option. The front end
searches each of the directories in the search path to find any exported
template files that exist there. Each of the exported template files is read
to determine which exported templates are defined, and the name of the file
that defines each template. An exported template directory can also contain a
file named export_info, which provides information used when reloading
exported template translation units. The export info file contains the include
search path to be used when reloading a translation unit. If no export info
file is present, the include search path associated with the primary
translation unit is used.
A translation unit may contain entities that must be given unique names (e.g., unnamed namespace members). A “module ID” is used as part of the name in such cases to ensure that the name is unique. The instantiation of an exported template must be able to refer to, and generate additional, entities with appropriate unique names. To accomplish this, the module ID is saved in the exported template file and that module ID is re-used when the translation unit containing the exported template definitions is reloaded.
When an exported template translation unit is reloaded, it undergoes what is basically the normal compilation process, except that none of the external entities defined in the translation unit are emitted. Only the instantiations of exported templates, and other templates or inline functions referenced as a result of such instantiations (directly or indirectly) are emitted. The entities that are emitted are copied into the IL of the primary file being compiled (see Copying from Secondary Translation Units). The command-line options used when the exported template translation unit is loaded are the same options used to compile the primary translation unit. The only exceptions are command-line macro definitions/undefinitions, and the include search path to be used. The command-line macro definitions/undefinitions are saved in the exported template file, and those values are used when the exported template translation unit is loaded (include search path handling is described above).
A mangled name is generated for each exported template. It is this mangled
name that is used to match a reference to an exported template with the
definition found elsewhere. A hash table of exported template definitions is
built as the exported template files are read. When an instantiation is
needed, the mangled name is looked up in the hash table to see if a definition
is available. If a definition is available, process_translation_unit is
called to load the translation unit that defines the exported template.
A template instance entry is created for each function, variable, or static data member instance that is partially or fully instantiated. If a given instance is declared in more than one translation unit, there will be multiple template instance entries created. In addition, a “master instance” entry is created to represent the information that is shared among translation units. For template instances in the primary translation unit, the master instance is created when the template instance is added to the instantiation required list. For template instances in secondary translation units, the correspondence information is used to find a master instance entry that may have been already created for an earlier translation unit. Because the correspondence information is not set until a translation unit has been completely scanned, the master instance information cannot be established until after scanning has completed. The master instance entry points to the template instance entry associated with the canonical copy of the instance (see Canonical Entries). Each template instance contains a pointer to the associated master instance.
Instantiations of exported templates are generated during the “instantiation
wrapup” process, which is performed by template_and_inline_function_wrapup.
The instantiations required list for each translation unit is examined, and
instantiations are generated if appropriate. An instantiation in one
translation unit may result in the need for an instantiation in another
translation unit. Because the other translation unit may already have been
processed, the wrapup process must iterate over the set of translation units
until no additional instantiations are added for during an iteration.
The instantiation of a function, variable, or static data member is initiated
by calling instantiate_entity with the template instance entry of the
instance to be generated. For exported templates defined in other translation
units, the translation unit is loaded and find_corresponding_instance is
called to find or create the template instance entry in the exported template
translation unit that corresponds to the one for which the instantiation is
being generated. The corresponding instance is then used for the remainder of
the instantiation process.
A “translation unit stack” is maintained when instantiating an entities defined in other translation units. This stack serves two purposes: it provides a sequence of lookup contexts for resolving dependent function names during the instantiation process, and it provides a record of the translation unit switches that have taken place so that the prior translation unit state can be restored when an instantiation has completed.
13.10. C++/CLI Generics#
C++/CLI generics are sort of like templates, and sort of not. They have arguments, but the arguments are more constrained than for templates, being effectively only managed class types or handles to them, value classes, fundamental types, or scoped enum types. (And types only: No nontype arguments, no template template arguments.) In addition, generics can have user-written constraint clauses that further restrict the valid argument values to certain kinds of class types. Generic classes do get instantiated for each set of template arguments, much like template classes, but generic functions effectively have just one instantiation, which corresponds to a single routine body that can operate on all types. That’s possible because the function can only perform those operations that are valid based on the declared constraints. That allows the instantiation of generic functions to be delayed until runtime and for most references to share a single instantiation (for example, all instantiations based on handles to ref classes share a single instantiation at runtime). That in turn forces some restrictions on the code that can be written in generic functions.
Generics are represented as templates marked with the is_generic_definition
flag in the class type or routine entry. If they have constraints, those are
represented by entries of type a_generic_constraint and
a_generic_constraint_clause.
Generic classes and generic functions don’t get the standard prototype instantiations. Instead, they undergo a process similar to prototype instantiation (and kicked off by the same routine that does prototype instantiations) using invented types based on the constraints. The result is marked as a “generic definition” instead of a prototype instantiation. The same process applies to static data members as well.
During the generic definition instantiation, a “constraint type” is created for
each generic parameter. It is a class type that reflects the constraints,
e.g., if the generic parameter is required to be derived from a class X, the
constraint type has X as a base class. The constraint type is a real type (not
a nonreal type), and lookups can be done in it. Such lookups in fact
significantly define what can be done with an object of that generic parameter
type, in the sense, for example, that a “+” operation can be done only if a
lookup finds an appropriate “operator+” function in the constraint type.
The actual type that is used for a given generic parameter type during the generic defintition instantiation is known as the “generic definition argument type.” It is a handle to the constraint type except in cases when the generic parameter is constrained to be a value class type, in which case it is the same as the constraint type.
During the generic definition instantiation, the template parameter symbols for
the generic are set to the generic definition argument type. That makes a lot
of processing, in declarations and expressions, work out fine without special
handling: uses of the template parameter name produce the generic definition
argument type, and for the most part that that can be processed without
difficulty. In particular, the generic definition argument type is not a
dependent type, and therefore real types can be built (instead of unknown
template parameter types), real results of overload resolution can be
determined, etc. However, there are also cases where one wants to think of the
type as being the generic parameter type. There’s a duality here: the template
parameter type and the generic definition argument type are really equivalent
types, and sometimes we want one and sometimes the other. We chose to make the
default value be the generic definition argument type, because that seemed to
work out better in terms of requiring less special-case code, but whichever way
we had decided that there would be cases that wanted to look at the type the
other way. Fortunately, because the types point to each other, it’s easy to
flip to the other representation if one has the wrong one. See, for example,
generic_param_if_generic_definition_argument.
Because the rules for valid generic template arguments are different than those
for normal template arguments, a special routine is used to scan generic
template argument lists: scan_generic_argument_list. It calls
is_valid_generic_argument to check that each argument is valid for any
kind of generic. Later, when one has a full set of generic type arguments
(whether from an explicit list or through type deduction),
verify_generic_arg_list_satisfies_constraints is called to check that the
arguments satisfy their constraints.
Generic classes can overload on arity, meaning that there can be multiple generic classes with the same name, but differing numbers of type arguments, declared in the same scope. That is not valid in source code, but it does come up in libraries written in other languages and imported via metadata. When such overloading occurs, the first generic that is declared is what is entered into the symbol table and what is returned by lookup. The template symbol supplement for that symbol has a pointer to a list of any other generic classes with the same name and different arities in the same scope. If there is also a non-generic class in the same scope, it is pointed to by another pointer there. With this information, references to the name can be resolved to the proper instance of the generic or to the non-generic.
Template deduction for generics is done in the usual way; there are no special tricks to speak of.