0% found this document useful (0 votes)
131 views14 pages

Template Ion and Concepts in Clang

The document analyzes template instantiation and concepts in the CLANG compiler. It discusses how CLANG performs semantic checks on template definitions and instantiations separately. It also evaluates CLANG's current support for C++ concepts and describes potential code changes needed to fully implement concepts.

Uploaded by

Angelus Mortis
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
131 views14 pages

Template Ion and Concepts in Clang

The document analyzes template instantiation and concepts in the CLANG compiler. It discusses how CLANG performs semantic checks on template definitions and instantiations separately. It also evaluates CLANG's current support for C++ concepts and describes potential code changes needed to fully implement concepts.

Uploaded by

Angelus Mortis
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

Seminar Program Analysis and Transformation HSR, University of Applied Sciences Rapperswil

C++ Template Instantiation and Concepts in CLANG


Yves Thrier, ythrier(at)hsr.ch June 3, 2011

Abstract In modern C++ development, templates are essential to achieve maintainable and reusable code. On compilation of the source code, the compilers have to perform semantic checks of the template denition and instantiation, to satisfy the rules of the C++ standard and to make sure, the code related to the templates is correct. This task can be accomplished in dierent ways. In this paper, the process of the semantic verication of C++ tenmplates in CLANG is analyzed. The mechanism of checking the template denition and instantiation is explored separately by examining selected functions from the CLANG source code. Beside this, statements about the code quality and implementation are given. In addition, an analysis of the capability of CLANG to support Concepts, a type-system for template parameters, originally proposed for the C++0x standard is included in this paper. Based on the ndings of the template denition and instantiation semantics, necessary changes to the code of CLANG are described as well as possible problems that can appear.

Motivation

The template mechanism is an important part of the C++ programming language. Templates are widely spread over the Standard Template Library [4] as in std::vector or std::map, used in libraries such as boost [5] and applied in application code. Templates increase reusability of code written by a software engineer by using generic template parameter types instead of an explicit type. Thus code with common logic only have to be written once, increasing the quality of software and make applications more reliable [1]. In this paper, we will analyze the semantic analysis code responsible for template denition and instantation mechanism in CLANG [2], a C language family compiler frontend for LLVM [3]. Our goal is to review the quality and understandability of the code itself, since no higher level documentation for these features exists.

In the second part of this paper, we evaluate the capability of CLANG to support concepts, a type-system for templates originally proposed as a language feature for C++ templates [8]. We will describe necessary changes to the code to support concepts, as it may be reintroduced in future standard releases, or to use it as a compiler level type checking facility. The layout of this paper is as follows: We start with an overview of CLANG and LLVM, an introduction to template instantiation and concepts in section 2. In section 3 we analyze the template denition and instantation mechanism based on the semantic analysis code of CLANG. In section 4 we evaluate the capability of CLANG to support concepts including a small overview of necessary code adjustments. We nish with a discussion in section 5 and the conclusion in section 6.

Introduction

To understand the main sections of this paper, a short overview of LLVM/CLANG, template instantiation and concepts is given in this section. This should allow our readers to easier understand the further content of this paper.
2.1 CLANG and LLVM

Using a template denition includes the template instantiation. For example, the call-side of listing 1 may look the following way:
1

2 #include 3 4 5 6 7

// Main . cpp A. h

LLVM is the abbreviation for Low Level Virtual Machine. It is a collection of modular and reusable compiler and toolchain technologies [3] The project was thought to be an alternative for the GNU Compiler Collection [18]. Due to the nature of GCC, it is hard to add or change functionality. LLVM aims to have an easier base to start new projects. CLANG is a C language family frontend for LLVM. The development of such a frontend was started out of a need - a need for a compiler that allows better diagnostics, better integration with IDEs, a license that is compatible with commercial products, and a nimble compiler that is easy to develop and maintain. All of these were motivations for starting work on a new front-end that could meet these needs [2].
2.2 Template Instantiation Mechanism

8 9 10

i n t main ( ) { // . . . i n t x = min ( 5 , 7 ) ; // i n s t a n t i a t i o n // . . . return 0 ; }

Listing 2: Template Instantiation On compilation of listing 1 and 2 the compiler rst checks the template denition and in a second step the template instantiation. The template denition must be valid considering all non-dependent names. A non-dependent name is, as its name says, not depending on one of the template parameter. Thus checking whether the template denition is correct is based only on the non-dependent names because the absence of an instantiation does not allow to check depedent names. The example of listing 1 contains only dependent names, since only the parameters a and b are used with the generic type T. If the non-dependent names of the template denition are correct, the depedent names are checked. Dependent names depend on the template parameter (for example in listing 1, the less-than (<) operator is a dependent name, because the type of a and b is not known). Since the dependent names depend on the template parameter, they can only be checked at instantation time (as in listing 2). This mechanism of using dependent and non-dependent names is referre
1

The compile-time life cycle of a template in C++ can be divided into two parts: 1. Template denition 2. Template instantiation Template denition refers to writing the template code without having code calling the template. An example of a template denition is presented in listing 1.
1 2 3 4 5 6

// A. h template<typename T> const T& min ( const T& a , const T& b ) { return a < b ? a : b ; }

2 3 4

auto c o n c e p t LessThanComparable<typename T> { bool operator <(const T&, const T&) ; };

Listing 3: LessThanComparable Concept d to as two-phase name lookup [6].

Listing 1: Template Denition

2.3

C++ Concepts

Concepts is a C++ language feature proposed for the C++0x standard [7]. Unfortunately, concepts were removed from the standard since they were considered to be not ready for C++0x [9]. Concepts introduce a type-system for C++ templates. In the current denition of C++, a complete template denition is itself the only expression of a templates assumptions about its parameters [10]. Thus, concepts allow to decouple the checking of the template denition and the checking of the template parameter types. As an example, remember the template denition of listing 1. According to the template denition, the typename template parameter T must comply to the following constraint: A less-than (<) operator must be present for arguments (const T&, const T&) with a return type convertible to bool. This assumption about the typename template parameter T s capabilities is called the concept of the template parameter. According to the standard drafts for concepts in C++ [8], this concept can be expressed with the following code:
5 6 7 8 1 2 3 4 5 6 7 8 9 10

Listing 5: Template Denition with Concept The compiler is now able to check the template denition and the type used in an instantiation separately. In addition, concepts introduced a mechanism called concept-maps. This technique allows to map parts of a concept to a dierent implementation. In our example of listing 3, we specify that the template parameter must have a lessthan operator. Instead of explicitly dening such an operator, it would be possible to map an existing greater-than operator to this lessthan operator. This is easy, since we only have to change the position of the arguments passed to the operator.
concept map LessThanComparable<MyType> { bool operator <(const MyType& a , const MyType& b ) { // Mapping > t o < return b > a ; } };

Listing 6: Concept Map Example


3 Template Instantiation in CLANG

auto c o n c e p t LessThanComparable<typename T> { bool operator <(const T&, const T&) ; };

Listing 4: LessThanComparable Concept Note that an operator with a return type convertible to bool will match this concept as well, due to the fact that this conversion is implicit. An implementation of such an operator as a member-function is allowed as well, although the signature of the operator is dierent. To use this concept of our example in listing 1, we replace the keyword typename with our concept LessThanComparable:
1 2 3 4 5 6

To understand the template instantiation in CLANG, we only have the possibility to look at the code and the source le documentation. Unfortunately, no other documentation is available. Therefore we will analyze the two main source les related to template instantiation semantics and inspect the code. The source les to begin with are located in lib/Sema/ : lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiate.cpp Of course, there are other source les which participate in the template instantiation process. Although we mention them during the code analysis, we will not have a look at them

// A. h template<LessThanComparable T> const T& min ( const T& a , const T& b ) { return a < b ? a : b ; }

in depth.
1 2 3

3.1

Overview of the Template Semantics

4 5

The semantic analysis of template denitions is available in the source code le lib/Sema/SemaTemplate.cpp. The include dependencies are not surprising. There are references to nodes of the abstract syntax tree specifying template related functionality, diagnostic mechanisms and template deduction (see [11] for a full overview of the dependencies).

6 7

// P a r s e r . h class Parser : public CodeCompletionHandler { // . . . Sema &A c t i o n s ; // . . . }

Listing 7: Semantic reference in Parser.h Having a look at this source le, we can easily identify other template related parsing options, e.g. ParseTemplateDeclarationOrSpecialization(..). The builders (Build... functions) are used by the declarator semantics and by the template instantiation process to build expression results by evaluating the passed arguments. We will not have a deeper look at them since they do not add valuable information to understand the semantic analysis of templates. The checkers (Check... functions) perform the semantic analysis of the template denitions. To understand the semantic analysis, we will have a deeper look at them in the following sections.

3.1.1

Basic Semantic

Figure 1: Subset of SemaTemplate.cpp includes The functionality of the template semantics is divided into three main sections: 1. Actor 2. Builder 3. Checker The actors (ActOn... functions) are used by the parser to act on the occurrence of a template declarator and dierent template parameter types. To build the abstract syntax tree (AST) the CLANG parser uses these functions to generate the correct AST nodes. The implementation of the parsing mechanisms related to templates is available in lib/Parse/ParseTemplate.cpp [14] which uses a reference (dened in include/clang/Parse/Parser.h [15]) to the semantic classes of CLANG.

To gain insight into the semantic tests, we will analyze the checks performed for class templates in the function CheckClassTemplate(..) of SemaTemplate.cpp. These tests can be applied to function templates as well with slight dierences in default values for template parameters (which is not possible for functions in the current C++ standard). The same applies to template parameter deduction, due to the fact that in a template function, all template parameter types may be calculated from the function arguments. It is important to interpret the return type of the CheckClassTemplate(..) function correctly when analyzing the function body. The function returns an instance of DeclResult which is a typedef for a ActionResult<Decl*>.
1 2

// Ownership . h typedef A c t i o n R e s u l t <Decl> D e c l R e s u l t ;

Listing 8: DeclResult Typedef in Ownership.h This is nothing special. However, a DeclResult has a constructor for a boolean. Thus, in the function CheckClassTemplate(..) a boolean can be returned as well, since an implicit conversion from boolean to DeclResult takes place. Unfortunately, returning true is likely to be interpreted as a success indicator. Though, the DeclResult uses this boolean as ag to show that the result is invalid. This can generate confusion.
1 2 3 4 5 6 7 1 2 3 4 5 6 7 8 9

fact that a template declaration only can appear in namespace or class scope declarations [17]:
// A. h template<typename T> void f o o (T t ) {} // v a l i d void bar ( ) { template<typename T> c l a s s f o o b a r { } ; // i n v a l i d . }

Listing 11: Template Scope This test is performed using CheckTemplateDeclScope(..) in SemaTemplate.cpp. Testing the type of the underlying declaration of the template makes sure that the template is not an enumeration type, which is invalid.

// Ownership . h class ActionResult { // C o n s t r u c t o r w i t h i n v a l i d f l a g A c t i o n R e s u l t ( bool I n v a l i d=f a l s e ) : Val ( PtrTy ( ) ) , I n v a l i d ( I n v a l i d ) {} // . . . }

Listing 9: Ownership.h

ActionResult

Denition

in

3.1.2

Scope Semantic

At the beginning of the CheckClassTemplate(..) function, there are four basic semantic tests: Template parameter Template usage Template scope Template type The template parameter check veries that at least one template parameter exists:
1 1 2 3 4

After the basic tests, the template declaration is searched inside the specied scope generated by the parser. In case the scope is valid, it can either be namespace or a class scope, since these are the only scopes valid to declare or dene a template in (validated by the template scope test in section 3.1.1). Invalid scopes will evaluate to an invalid semantic analysis result. If the scope is valid, a pointer to the declaration context of this scope is looked up. A declaration context contains all declaration in a given scope. For example, assume the following code:
2 3 4 5 6 7 8 9 10 11 12

// SemaTemplate . cpp a s s e r t ( TemplateParams && TemplateParams>s i z e ( ) > 0 && No t e m p l a t e p a r a m e t e r s ) ;

Listing 10: Template Parameter Size If the template parameter size is not a least one, the template declaration contains an extraneous template keyword, which is invalid. The template usage validates that the template keyword is used correctly according to the underlying declaration (i.e. dening a template on a declaration of a pointer is invalid). Testing the scope of the template veries the

template<typename T> void f o o b a r (T t ) ; namespace A { template<typename T> void f o o (T t ) ; namespace B { template<typename T> void bar (T t ) ; } }

Listing 12: Declaration Context Example In listing 12, there are three declaration contexts:

1. Global declaration context containing declaration of foobar 2. Namespace A declaration context containing declaration of foo 3. Namespace B declaration context containing declaration of bar If the lookup for the declaration context of the scope fails, the class template is invalid. It is not possible to have a template declaration with a scope specier, but without having a declaration context for this scope or an empty declaration context, because at least the template declaration must be contained in the declaration context for the given scope.
SCOPE <name>

plate declaration. This also includes a comparison of the template parameter list when dealing with redeclaration and specialization. Although this is a large part of the semantic analysis implemented in this function, it only deals with rules dened in the C++ standard ([17] section 14 and subsections).
Parser.h SemaTemplate.cpp

ActOnClassTemplateSpecialization() CheckClassTemplate()

CheckTemplateParameterSize() CheckTemplateParameterUsage() CheckTemplateScope() CheckTemplateTypes()

template_declaration_1
FindDeclarationContext()

other_declarations...
IsCompleteEnought()

lookup declaration context for scope

DECLARATION_CONTEXT <name>

Must contain template declaration as well

template_declaration_1

Figure 3: Sequence Diagram for Template Denition Check (Note that for gure 3, the methods invoked in the CheckClassTemplate(..) function do not exists, they are just displayed to describe the logical sequence of operations).
3.2 Overview of the Template Instantiation Semantics

Figure 2: Scope with Declaration Context The semantic analysis of CLANG is missing a diagnostic at this place to give a reasonable output to a user if this situation occurs. However, the developers are aware of this issue as the code comments implies. If a declaration context for this scope exists, a test whether the template declaration is complete enough for a name lookup is performed. This is the case, if all names of the template declaration are either dependent names (they are always considered complete, because they have to be checked during template instantiation), or, for all other names, a denition is present. The remaining semantic analysis of the CheckClassTemplate(..) function deals with redeclaration, specialization, injected names and name lookup for declarations of a friend tem-

The semantic analysis of template instantiations is available in the source code le lib/Sema/SemaTemplateInstantiate.cpp [12] and lib/Sema/SemaTemplateInstantiateDecl.cpp [13]. Similar to the template denition semantics, the functionality of the template instantiation can be divided into three main sections: 1. Instantiation 2. Substitution

3. Instantiator The instantiation (InstantiateXXX functions) deals with class template instantiation. Interestingly, instantiation of function templates is not available in this sourcele, but can be found in lib/Sema/SemaTemplateInstantiateDecl.cpp [13]. We did not nd any reason for why this separation was made. The instantiation does also manage the point of instantiation (see [6] and [17]). The substitution (SubstXXX functions) performs the replacement of types, names, expressions and similar. The substitution mechanism is used by the instantiaton and the instantiators (either the class TemplateInstantiator which deals with class templates, or the class TemplateDeclInstantiator which deals with function templates). The instantiator (class TemplateInstantiator in [12] and TemplateDeclInstantiator in [13]) transforms (instantiates) dierent entities of a template class or function. To understand the template instantiation in CLANG, we will look at the InstantiateClass(..) function in lib/Sema/SemaTemplateInstantiate.cpp [12], which performs a template instantiation for a class template and analyzes the semantic tests.

3.2.2

Attribute Classes

Instantiation

and

Base

In the next step of the process, the attributes of the class denition are instantiated. The attribute instantiation uses the substitution described in section 3.2 to replace the generic template types with the type of the template parameter found at the call-side of the template class. These step is completed with the attribute instantiation in the inheritance hierarchy, if there are any template base classes. Although we would think that the members are instantiated here as well, this happens after traversing the inheritance hierarchy. Actually, this have something to do with the lexical and semantical scope of class template members. For example, in listing 13 the class B has the lexical scope of the template class, though semantically it is introduced in the global namespace (see [12]):
1 2 3 4 5

template<i n t i > class A { class B g ; };

Listing 13: Member Instantiation Scope To nish the instantiation, it is checked whether the eld instantiation is valid.
3.2.3 Partial Specialization

3.2.1

Denition Lookup Semantic

A class template instantiation requires a valid denition of a template. However, it is possible that the InstantiateClass(..) function receives a class template declaration to instantiate. Therefore, the rst step is to successfully retrieve the denition of such a declaration. If this is not possible, an instantiation process can not take place and the according diagnostics are performed to give a valuable feedback to a user. When retrieving a template denition was successful, the point of instantiation for the template is recorded in the instantiation context.

Before nishing the instantiation of the class template, a test is performed whether any partial specializations for the current class template are available. If there are partial specializations available for the class template, each one is instantiated by using the nonpartial specialized class template instantiation (i.e. the template instantiation we have instantiated before). This is done by reusing the nonpartial specialized template instantiation and substituting the types known from the partial specialization. For example, assume the following template denition and partial specialization:
1 2

// Template D e f i n i t i o n template<typename T, typename U>

3 4 5 6 7 8 9 10 11 12 13

struct something { // do s o m e t h i n g }; // Template P a r t i a l S p e c i a l i z a t i o n template<typename T> struct something<T, int> { // do s o m e t h i n g s p e c i a l w i t h i n t s };

Concepts in CLANG

In the previous section, we described the semantic analysis of template denition and instantiation in CLANG using chosen functions from the source les. Having concepts as a language feature would change this process. We will analyze and describe changes that are necessary to support concepts by CLANG in the following sections.
4.1 Grammar and Parser Changes

Listing 14: Template Denition with Partial Specialization The template denition from listing 14 is reused by the template partial specialization, substituting an int for the second template parameter. The rst template parameter does not have to be substituted, because this is already done in the original template instantiation. The responsible code for this task is available in listing 15.
1

3 4 5 6

for ( TemplateDeclInstantiator : : delayed partial spec iterator P = Instantiator . d e l a y e d p a r t i a l s p e c b e g i n ( ) , PEnd = Instantiator . d e l a y e d p a r t i a l s p e c e n d ( ) ; P != PEnd ; ++P) { i f ( ! I n s t a n t i a t o r . InstClsTempPartSpec (P >f i r s t , P>s e c o n d ) ) { I n v a l i d = true ; break ; } }

Apparently, extending the grammar and the parser is inevitable for having concepts as a language feature. This includes adding new keywords such as concept, concept map and the alternative syntax of applying a concept to a template by using the keyword with. These changes must include extensions to the abstract syntax tree as well. However, We will not further investigate on how to apply these changes to CLANG, since our focus lays on template instantiation.
4.2 Internal Representation Changes

Listing 15: Instantiation Specializations in CLANG

of

Partial
1 2 3

The current C++ standard [17] allows the usage of class or typename when denining a template parameter in a template declaration (assuming we do not use types explicitly and no partial specialization). In CLANG, this difference is represented by a ag whether class (ag is false) or typename (ag is true) was used [16].
c l a s s TemplateTypeParmDecl : public TypeDecl { bool Typename : 1 ; // . . . };

(The original name of the instantiation method is Instantiator.InstantiateClassTemplatePartialSpecialization(..). We have shortened the name for simplicity). The instantiation of partial specializations will induce further semantic checks on the newly substituted types from the partial specialization. This includes checking whether the type substitution was valid, or in case of an invalid substitution, to stop the instantiation with a diagnostic returning an error message to a user.

4 5 6

Listing 16: Typename or Class This internal representation has to be changed to point to the appropriate concept(-map) definition or declaration, if one is given. This could be done by adding a pointer to a concept denition or declaration:
1

c l a s s TemplateTypeParmDecl :

2 3 4 5 6 7 8 9 10 11 12

public TypeDecl { ConceptDecl Concept ; // . . . public : bool hasConcept ( ) const { return Concept ; } // . . . };

12 13 14 15 16 17 18 19 20 21 22

void f o o b a r 2 (T t , U u ) { // . . . } // Case 3 : No C o n s t r a i n t s template<typename T, typename U> void f o o b a r 3 (T t , U u ) { // . . . }

Listing 17: Possible Implementation of a Template Parameter with Concept In case the template parameter is unconstrained, a Null-Concept using the Null-Object design pattern could be used [21]. However, this could increase the compile-time memoryusage in cases where most of the templates in the source code are unconstrained (i.e. have no associated concept - specied by typename or class).
4.3 Template Denition Semantic Changes

Listing 18: Concepts in Template Denition The third case does not require any further concept related processing. It is an original template denition as it already exists in the currenct C++ standard [17]. The rst and second case do require additional processing. The dierence between the rst and the second case is that in case 1, all template parameters have an associated concept. But in case 2, an associated concept exists only for the rst template parameter T. For any template parameter where an associated concept exists, the denition of this concept, or at least the declaration of the concept has to be found. It may make more sense to only search for the concept declaration, since the process of checking a template parameter against a concept takes place in the template instantiation mechanism. If a template denition with template parameters having associated concepts is never instantiated, the lookup for the denition is not necessary. Therefore, having only the declaration of the concept available at template denition time is sucient. This also implies, that a concept can be considered as a dependent-name, according to the two-phase name lookup [6]. In addition, the separation of concept declarations at template denition and concept denitions at template instantiation in the lookup can increase compile-time eciency in time and memory-space due to the delayed lookup mechanism.
4.4 Template Changes Instantiation Semantic

During the semantic check of a template denition, the template denition has to be checked whether concepts are dened for a template parameter. It is possible to distinguish between three cases: 1. All template parameter have an associated concept 2. A subset of all template parameter have an associated concept 3. None of the template parameters have an associated concept To illustrate these cases, assume the following example:
1 2 3 4 5 6 7 8 9 10 11

// Case 1 : Complete C o n s t r a i n t s template<LessThanComparable T, I n c r e m e n t a b l e U> void f o o b a r 1 (T t , U u ) { // . . . } // Case 2 : P a r t i a l C o n s t r a i n t s template<LessThanComparable T, typename U>

The instantiation process requires the largest amount of extensions or changes to achieve

concepts support. In template instantiation, the substitution types of the template parameters have to be checked against the associated concepts. There are two dierent possibilities: 1. An associated concept exists for the template parameter 2. An associated concept does not exist for the template parameter (or a NullConcept [21]) Case 2 is equivalent to the existing template situation in the current C++ standard [17]. The template parameter was dened with typename or class and no explicit constraints are dened for the template parameter. However, the substitution still has to be checked for validity, since a non-existing concept does not imply that the substitution type does automatically comply to the usage of the type in the template. It is up to CLANG to generate accurate diagnostics indicating missing requirements on a substitution type, decoupled from the concept validation diagnostics. In the rst case where an associated concept exists, there are several steps necessary to check the template parameters against the concepts. Depending on whether the denition or declaration of the concept was retrieved during template denition, the denition of the associated concept has to be found. A missing concept denition should yield an error to the user, because a concept declaration is not sucient to validate a substitution type for a template parameter. The concept denition is subsequently used to validate the substitution type of the template parameter. This allows to check the type independent of the template denition. This has the advantage, that the type-checking is decoupled from the template denition. The same process has to be applied for concept maps, although checking the concept against the substitution types is dierent. For concept maps, the mappings (e.g. less-than operator to greater-than operator) must be validated as well. The benet of applying the concept mechanism as described, is that nearly all diagnostics related to tem-

plate parameter checking during instantiation can be placed together into the code representation of concepts. Having a Null-Concept (Null-Object) [21] would assist this clean encapsulation. However, it is not sucient to just check the template parameter against the associated concept. Even an existing concept does not imply that the substitution type does automatically comply to the usage of the type in the template. The diagnostics of concept-checking should also be aware of the inheritance hierarchy during the instantiation process. Thus making sure that the Liskov Substitution Principle (LSP) [22] is not violated. In the example of listing 19, the class B overrides the member function foobar(..), but the template parameter is more constrained compared to the base class A. This violates LSP. However, checking for this violation may not be appropriate, or should only yield a warning, because a software engineer may not be fully aware of this paradigm in the given context. In addition, such a check could break framework code where it is likely to unintentionally violate the principle, but still having valid behaviour.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

// Concept LessThanComparable auto c o n c e p t LessThanComparable<typename T> { bool operator <(const T&, const T&) ; }; // Concept LessThanEqualComparable auto c o n c e p t LessThanEqualComparable<typename T> { r e q u i r e s LessThanComparable<T>; bool operator==(const T&, const T&) ; bool operator !=( const T&, const T&) ; }; // For b r e v i t y , i g n o r e t h e p o s s i b l e // mapping f o r e q u a l t o un e q ua l , v . v . // A. h template<LessThanComparable T> struct A { v i r t u a l void f o o b a r (T t ) { // . . . } };

10

27 28 29 30 31 32 33 34 35 36

template<LessThanEqualComparable T> struct B : A<T> { // LSP V i o l a t i o n : T o f B has more // c o n s t r a i n t s than T o f A v i r t u a l void f o o b a r (T t ) { // . . . } };

Listing 19: Example of LSP Violation with Concepts We have to note that LSP violations are possible whether we have concepts or not. However, it may be valuable to have a validation option in case concepts are used, since the necessary informations are present.
5 Discussion

style guide for hacking on CLANG. However, it seems that sometimes this guide is not enforced (e.g. variable names in loops). This also includes mixing return results where sometimes a DeclResult is used, and sometimes only bool s using the implicit constructor conversion of DeclResult, but the decision to return the type directly or using a conversion appears to be random and not by following specic rules (e.g. in CheckClassTemplate(..) of lib/sema/SemaTemplate.cpp). In documentation work of CLANG, we would recommend to write sequence diagrams and explanations to the template instantiation process (and maybe to other parts of the code as well, e.g. similar to gure 3). This makes it easier for beginners to understand the project, component collaboration and may lower the barrier for a user interested in improving CLANG to start collaborating in the project. The CLANG project homepage [2] states as one of its main feature and goal to be A realworld, production quality compiler. The results generated by the compiler can be considered production quality. However, the source code analyzed when writing this paper is in our opinion not production quality. A simple task search for FIXME and TODO in SemaTemplate.cpp and SemaTemplateInstantiate.cpp using Eclipse, yields 53 entries, where parts of the FIXME notes do not have an entry in the bug tracker platform of CLANG (if we include other template related semantic sourceles, there are about 101 entries). Although this may be internal rules of the developer team, we would recommend to track this outside of the source code as well, as this makes things more reliable and comprehensible. The separation of template denition semantic checks and template instantation semantic checks is made on a le basis: SemaTemplate.cpp deals with template denition where SemaTemplateInstantiate.cpp implements template instantiation. However, some of the functionality is mixed between

In our opinion, CLANG does the job of template instantiation very well. Especially the generated diagnostic messages to indicate the type of error and the position are impressive compared to the compiler errors generated by the GNU Compiler Collection (GCC/g++) [18]. The reason that CLANG has become a serious competitor forced the GCC developers to improve their diagnostics as well over the last years. However, we still think that the diagnostics of CLANG are more clear and accurate compared to the GCC diagnostics. A good indicator for this is the usage of CLANG as the compiler frontend in the Xcode IDE since version 4 of Apple. LLVM was thought to be an easier to use compiler infrastructure compared to the GNU Compiler Collection. CLANG does follow this rule as well, but getting into the project and understand the source code is barely easier compared to GCC. The lack of more expressive documentation than only source code comments and the source code itself made it hard to understand the process and draw reasonable conclusions about it. In addition, we encountered dierent programming styles mixed. We do not question that there is a

11

these les. There are code parts responsible for template instantiation which is called from the template denition code (using the ActOn...(..) functions). In our opinion, this should be invoked from the parser, not from the template denition to achieve a better separation. However, this may be more complex, because going from denition to instantiation is more natural and the necessary informations already exists in the instantiation context, since CLANG starts at the denition. Adding concept support to CLANG is possible, but includes changing several working parts of the current code. The most interesting question of a concept implementation would be whether the diagnostics become better, worse or stay at the same level. The performance of concepts in CLANG is a second important part of such an implementation. There is a GCC based version of a compiler supporting concepts [20], but the performance was very bad. ConceptGCC could be a good point to look at when implementing concepts, since they propably already solve several problems that can occur when implementing concepts.

Future Work

Even if concepts are no longer in the C++0x standard, compiler based concept checking could increase the reliability and quality of C++ code. It seems that a CLANG based concept compiler was started in mai 2011 [23]. However, this is in an early stage, therefore not much information is available.
8 Acknowledgement

I would like to thank Peter Sommerlad for the support and corrections while writing this paper. In addition, I would like to thank Sebastian Hunkeler for his help in reviewing the paper and for his correction-proposals. This paper is a term paper at the university of applied sciences (HSR) in Rapperswil, Switzerland.
References

[1] Yves Thrier (2011), CloneWar Refactoring/Transformation in CDT: Extract Template Parameter, Master Semester-Thesis, University of Applied Sciences, Rapperswil (HSR) [2] CLANG Project (2011), CLANG: A C Language Family Frontend for LLVM, http://clang.llvm.org/, Timestamp: 2011/03/26 [3] LLVM Project (2011), The LLVM Compiler Infrastructure, http://llvm.org/, Timestamp: 2011/03/26 [4] Standard Template Library, STL: Ocial Guide, http://www.sgi.com/tech/stl/, Timestamp: 2011/03/26 [5] Boost C++ Libraries (2011), Boost: C++ Library Projects, http://www.boost.org/, Timestamp: 2011/03/26

Conclusion

CLANG has the capability to become one of the best and widely-spread compilers for the C language family. The template instantiation process of CLANG is implemented very well and can, once you understand the internals, be easy extendend. The performance of the instantiation is as good as the performance of GCC, or sometimes even better [19]. The diagnostics of CLANG are not always perfect, but far better compared to GCC, which in our opinion, is one of the most important features for end users. Therefore, we are condent that the CLANG project will displace GCC or at least be the best alternative.

12

[6] David Vandevoorde, Nicolai M. Josuttis (2003), C++ Templates - The Complete Guide, 3rd Printing, Addison-Wesley [7] ISO/IEC Programming Language C++, Draft (2011), Standard for Programming Language C++, http://www.openstd.org/JTC1/SC22/WG21/docs/papers/ 2010/n3126.pdf Timestamp: 2011/03/26 [8] ISO/IEC C++ Standard Draft (2009), Programming Languages - C++, http://www.openstd.org/jtc1/sc22/wg21/docs/papers/ 2009/n2914.pdf Timestamp:2011/05/18 [9] ACCU Overload Journal #92 (2009), Bjarne Stroustrup, No Concepts in C++0x, http://accu.org/index.php/journals/1576 Timestamp: 2011/03/26 [10] Bjarne Stroustrup, Gabriel Dos Reis (2005), Specifying C++ Concepts, http://www.openstd.org/jtc1/sc22/wg21/docs/papers/ 2005/n1886.pdf Timestamp: 2011/03/26 [11] CLANG Sourcele SemaTemplate.cpp, lib/Sema/SemaTemplate.cpp, http://clang.llvm.org/doxygen/Sema Template 8cpp.html Timestamp: 2011/04/29 [12] CLANG Sourcele SemaTemplateInstantiate.cpp, lib/Sema/SemaTemplateInstantiate.cpp, http://clang.llvm.org/doxygen/Sema TemplateInstantiate 8cpp.html Timestamp: 2011/04/29 [13] CLANG Sourcele SemaTemplateInstantiateDecl.cpp, lib/Sema/SemaTemplateInstantiateDecl.cpp, http://clang.llvm.org/doxygen/Sema TemplateInstantiateDecl 8cpp.html Timestamp: 2011/04/29

[14] CLANG Sourcele ParseTemplate.cpp, lib/Parse/ParseTemplate.cpp, http://clang.llvm.org/doxygen/Parse Template 8cpp.html Timestamp: 2011/04/29 [15] CLANG Sourcele Parser.h, lib/Parse/Parser.h, http://clang.llvm.org/doxygen/ Parser 8h.html Timestamp: 2011/04/29 [16] CLANG Sourcele DeclTemplate.h, include/clang/AST/DeclTemplate.h, http://clang.llvm.org/doxygen/Decl Template 8h.html [17] ISO/IEC C++ Standard (1998), Programming Languages - C++, http://wwwd0.fnal.gov/ dladams/cxx standard.pdf Timestamp: 2011/04/29 [18] GNU Compiler Collection (2011), The GNU Compiler Collection, http://gcc.gnu.org/ Timestamp: 2011/05/01 [19] Template Instantiation Performance (2010), Bugzilla Entry for CLANG Template Instantiation Performance, http://llvm.org/bugs/show bug.cgi? id=6998 Timestamp: 2011/05/01 [20] Concept GCC, GCC Concepts Branch, http://www.genericprogramming.org/software/ConceptGCC/ Timestamp: 2011/06/02 [21] Henney, Kevlin (2003), Null Object Something for Nothing, www.twosdg.demon.co.uk/curbralan/papers/ europlop/NullObject.pdf Timestamp: 2011/05/25 [22] Liskov, Barbara (1987), Data Abstraction and Hierarchy, http://portal.acm.org/citation.cfm?id=62141 Timestamp: 2011/05/26

13

[23] Concept CLANG, CLANG based Concepts for C++, http://www.generic-

programming.org/software/ConceptClang/ Timestamp: 2011/06/02

14

You might also like