[cfe-dev] AST template definition VS. template instantiations

Benoit Belley Benoit.Belley at autodesk.com
Wed Aug 25 13:21:00 PDT 2010


Hi Everyone,

While traversing the Clang AST in a custom static analyzer check (using the RecursiveASTVisitor), I need to determine whether the given function is a template definition because it is part of a template class, template function or a partial specialization of a class template. The reason I need to know this is that template definitions are not fully semantically checked, while template instantiations are. For example, the operator new() referenced by a CXXNewExpr is unresolved in a template definition.

Things are not so clear cut because classes and functions can be nested, and therefore one has to look at all of the enclosing scopes to determine if a given FunctionDecl is actually part of a template.

I have come out with the following function to perform such a check and I am wondering if there is an easier way to achieve this:

// Recursively examines the parent contexts to determine if any of them
// represents either a function or a class template.
static bool isTemplatedContext(DeclContext* ctx) 
{
  if ( !ctx ) {
    return false;
  }

  switch ( ctx->getDeclKind() ) {
    case Decl::TranslationUnit:
    case Decl::Namespace: 
    case Decl::LinkageSpec:
    case Decl::ClassTemplateSpecialization: {
      // Ignored.
    } break;

    case Decl::CXXRecord: {
      CXXRecordDecl* decl = static_cast<CXXRecordDecl*>(ctx);
      if ( decl->getDescribedClassTemplate() != 0 ) {
        return true;
      }
    } break;

    case Decl::ClassTemplatePartialSpecialization: {
          return true;
    } break;
        
    case Decl::Function: 
    case Decl::CXXMethod: 
    case Decl::CXXConstructor: 
    case Decl::CXXDestructor:
    case Decl::CXXConversion: {
      FunctionDecl* decl = static_cast<FunctionDecl*>(ctx);
      if ( decl->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate ) {
        return true;
      }
    } break;

      default: {
        llvm::errs() << "Unexpected context kind in isTemplatedContext() :" << ctx->getDeclKindName() << "\n";
        assert(false && "Unexpected context kind in isTemplatedContext.\n");
      } break;
  }

  return isTemplatedContext( ctx->getParent() );
}


At first, I thought that it would be simpler to prune the RecursiveASTVisitor to skip any template class definition, but it did not work since members of template classes can be defined outside of the class definition. For example, given:

template <typename T> struct A {
   struct B {
      void foo();
   }
};

template <typename T> void A<T>::B::foo() {}

the DeclContext of the TranslationUnitDecl contains a direct reference to the CXXMethodDecl for foo(). We then have to look at the nested classes to determine that foo() is actually templated.
 
Thanks for your help,
Benoit
 
 
Benoit Belley
Sr Principal Developer
M&E-Product Development Group    
 
Autodesk Canada Inc. 
10 Rue Duke
Montreal, Quebec  H3C 2L7 
Canada
 
Direct 514 954-7154
 
 

-------------- next part --------------
A non-text attachment was scrubbed...
Name: image002.gif
Type: image/gif
Size: 651 bytes
Desc: image002.gif
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20100825/0e1e7f1f/attachment.gif>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: ATT00001..txt
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20100825/0e1e7f1f/attachment.txt>


More information about the cfe-dev mailing list