[lldb-dev] Supporting class templates in the expression parser

Douglas Gregor dgregor at apple.com
Tue Nov 30 18:36:19 PST 2010


I've just committed support for class templates into Clang's ASTImporter, which is a necessary step toward teaching LLDB's expression parser to properly handle C++ class templates. In particular, it should make it possible for the expression parser to handle code like

	((vector<int> *)ptr)->push_back(17)

where we're naming a class template specialization. This can work assuming that vector<int> and vector<int>::push_back were instantiated in some translation unit and we have DWARF describing them.

Here are some notes on how class templates are represented within Clang and how LLDB will need to represent class templates and their specializations/instantiations to make expression parsing work. As our example, let's take:

  template<typename T>
  struct vector {
   void push_back(const T&);
  };

  void func_to_debug(vector<int> &v) {
     v.push_back(17);
  }

Here, the 'vector' class template is represented as a ClassTemplateDecl node, which encodes the template parameter list containing a single type parameter. That ClassTemplateDecl also stores a "templated" declaration, which contains the definition of the class that will be created if the class template is instantiated. In this case, it's a CXXRecordDecl describing a class named "vector", which  has a push_back member.

vector<int> is a class template specialization, which is represented by a ClassTemplateSpecializationDecl. A ClassTemplateSpecializationDecl is a special kind of CXXRecordDecl that has information describing how it specializes a ClassTemplateDecl, i.e., the set of template arguments that was used in the specialization. In this case, the ClassTemplateSpecializationDecl for vector<int> refers to the ClassTemplateDecl for 'vector' and has a set of template arguments containing just 'int'. Other than that, however, a ClassTemplateSpecializationDecl is like any other CXXRecordDecl, with bases, members, etc.

It's important to note that class template specializations are never found by name lookup. Rather, name lookup finds the ClassTemplateDecl ('vector'), and then looks up the appropriate specialization based on the template arguments. So, both the class template and its specializations need to be extracted from DWARF for expression parsing. Specifically, LLDB will have to go through the following steps when a class template specialization is encountered:

	1) If it doesn't already exist, create a ClassTemplateDecl to represent the template. Using DW_TAG_template_type_parameter and DW_TAG_template_value_parameter, it should be possible to reconstruct the template parameter list. That, along with the name, context, and kind of class template (class/struct/union) is enough to build a forward declaration of the ClassTemplateDecl, which is enough for expression parsing to work [*].

	2) Determine the template arguments used to generate the  template instantiation/specialization based on the DW_AT_type/DW_AT_const_value/etc. tags. At this point, we've identified the core components of the class template instantiation/specialization.

	3) Use the ClassTemplateDecl's findSpecialization() method to find the specialization; if it isn't there already, create a ClassTemplateSpecializationDecl and add it with AddSpecialization. The definition of the ClassTemplateSpecializationDecl can be read in the same way as any other CXXRecordDecl.

I suspect we'll have to add another callback to ExternalASTSource that lets LLDB look for specializations when one is requested, e.g., when Clang parses "vector<int>", LLDB needs to get the chance to look for that specialization in the DWARF entries. 

	- Doug

[*] DWARF doesn't have enough information to actually recreate the template definition, so template *instantiation* won't be possible. However, being able to use specializations/instantiations that were written out to DWARF would be very helpful.



More information about the lldb-dev mailing list