]> granicus.if.org Git - clang/commitdiff
Implement template instantiation for template names, including both
authorDouglas Gregor <dgregor@apple.com>
Tue, 31 Mar 2009 18:38:02 +0000 (18:38 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 31 Mar 2009 18:38:02 +0000 (18:38 +0000)
template template parameters and dependent template names. For
example, the oft-mentioned

  typename MetaFun::template apply<T1, T2>::type

can now be instantiated, with the appropriate name lookup for "apply".

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68128 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/TemplateName.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/TemplateName.cpp
lib/Sema/Sema.h
lib/Sema/SemaTemplateInstantiate.cpp
test/SemaTemplate/instantiate-template-template-parm.cpp [new file with mode: 0644]
test/SemaTemplate/metafun-apply.cpp

index 3107a35841937688af352cd8ce625fef1776991c..09e81be091d115cdbd04633dcd2f4f65c8653f98 100644 (file)
@@ -99,6 +99,10 @@ public:
   /// \brief Print the template name.
   void Print(llvm::raw_ostream &OS) const;
 
+  /// \brief Debugging aid that dumps the template name to standard
+  /// error.
+  void Dump() const;
+
   void Profile(llvm::FoldingSetNodeID &ID) {
     ID.AddPointer(Storage.getOpaqueValue());
   }
index b16e15ea0b4659aeea10ea687212154e5daf5348..74a13478c162c4ed05d6e218ad6abd5392e2fa91 100644 (file)
@@ -701,6 +701,8 @@ def note_typename_refers_here : Note<
 
 def err_template_kw_refers_to_non_template : Error<
     "%0 following the 'template' keyword does not refer to a template">;
+def err_template_kw_refers_to_function_template : Error<
+    "%0 following the 'template' keyword refers to a function template">;
 
 def err_unexpected_typedef : Error<
   "unexpected type name %0: expected expression">;
index 4e54fe495596920762cba440ada7773379ee3a50..3659e2350de61042fccb0da7039916812cc4f5c3 100644 (file)
@@ -14,6 +14,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/NestedNameSpecifier.h"
 #include "llvm/Support/raw_ostream.h"
+#include <stdio.h>
 
 using namespace clang;
 
@@ -52,3 +53,12 @@ void TemplateName::Print(llvm::raw_ostream &OS) const {
     OS << DTN->getName()->getName();
   }
 }
+
+void TemplateName::Dump() const {
+  std::string Result;
+  {
+    llvm::raw_string_ostream OS(Result);
+    Print(OS);
+  }
+  fprintf(stderr, "%s", Result.c_str());
+}
index 634c90a36e209ecffabd0af29f0525a38b5075e9..3a18f9676b032ef41cb7786100a36ac8fcc719f1 100644 (file)
@@ -1981,6 +1981,11 @@ public:
                                  const TemplateArgument *TemplateArgs,
                                  unsigned NumTemplateArgs);
 
+  TemplateName
+  InstantiateTemplateName(TemplateName Name, SourceLocation Loc,
+                          const TemplateArgument *TemplateArgs,
+                          unsigned NumTemplateArgs);
+
   // Simple function for cloning expressions.
   template<typename T> 
   OwningExprResult Clone(T *E) {
index 2eb874597e4a9003d0a4e89beafdf6b08133ab16..c9f0d4fd799c8f758aeabebc848c5bc4a50b22cb 100644 (file)
@@ -472,10 +472,13 @@ InstantiateTemplateSpecializationType(
 
   // FIXME: We're missing the locations of the template name, '<', and
   // '>'.
-  // FIXME: Need to instantiate into the template name.
-  return SemaRef.CheckTemplateIdType(T->getTemplateName(),
-                                     Loc,
-                                    SourceLocation(),
+
+  TemplateName Name = SemaRef.InstantiateTemplateName(T->getTemplateName(),
+                                                      Loc, 
+                                                      TemplateArgs,
+                                                      NumTemplateArgs);
+
+  return SemaRef.CheckTemplateIdType(Name, Loc, SourceLocation(),
                                      &InstantiatedTemplateArgs[0],
                                      InstantiatedTemplateArgs.size(),
                                      SourceLocation());
@@ -839,3 +842,72 @@ Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
   // Required to silence a GCC warning
   return 0;
 }
+
+TemplateName
+Sema::InstantiateTemplateName(TemplateName Name, SourceLocation Loc,
+                              const TemplateArgument *TemplateArgs,
+                              unsigned NumTemplateArgs) {
+  if (TemplateTemplateParmDecl *TTP 
+        = dyn_cast_or_null<TemplateTemplateParmDecl>(
+                                                 Name.getAsTemplateDecl())) {
+    assert(TTP->getDepth() == 0 && 
+           "Cannot reduce depth of a template template parameter");
+    assert(TTP->getPosition() < NumTemplateArgs && "Wrong # of template args");
+    assert(dyn_cast_or_null<ClassTemplateDecl>(
+                          TemplateArgs[TTP->getPosition()].getAsDecl()) &&
+           "Wrong kind of template template argument");
+    ClassTemplateDecl *ClassTemplate 
+      = dyn_cast<ClassTemplateDecl>(
+                               TemplateArgs[TTP->getPosition()].getAsDecl());
+
+    if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
+      NestedNameSpecifier *NNS 
+        = InstantiateNestedNameSpecifier(QTN->getQualifier(),
+                                         /*FIXME=*/SourceRange(Loc),
+                                         TemplateArgs, NumTemplateArgs);
+      if (NNS)
+        return Context.getQualifiedTemplateName(NNS, 
+                                                QTN->hasTemplateKeyword(),
+                                                ClassTemplate);
+    }
+
+    return TemplateName(ClassTemplate);
+  } else if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
+    NestedNameSpecifier *NNS 
+      = InstantiateNestedNameSpecifier(DTN->getQualifier(),
+                                       /*FIXME=*/SourceRange(Loc),
+                                       TemplateArgs, NumTemplateArgs);
+    
+    if (!NNS) // FIXME: Not the best recovery strategy.
+      return Name;
+    
+    if (NNS->isDependent())
+      return Context.getDependentTemplateName(NNS, DTN->getName());
+
+    // Somewhat redundant with ActOnDependentTemplateName.
+    CXXScopeSpec SS;
+    SS.setRange(SourceRange(Loc));
+    SS.setScopeRep(NNS);
+    TemplateTy Template;
+    TemplateNameKind TNK = isTemplateName(*DTN->getName(), 0, Template, &SS);
+    if (TNK == TNK_Non_template) {
+      Diag(Loc, diag::err_template_kw_refers_to_non_template)
+        << DTN->getName();
+      return Name;
+    } else if (TNK == TNK_Function_template) {
+      Diag(Loc, diag::err_template_kw_refers_to_non_template)
+        << DTN->getName();
+      return Name;
+    }
+    
+    return Template.getAsVal<TemplateName>();
+  }
+
+  
+
+  // FIXME: Even if we're referring to a Decl that isn't a template
+  // template parameter, we may need to instantiate the outer contexts
+  // of that Decl. However, this won't be needed until we implement
+  // member templates.
+  return Name;
+}
diff --git a/test/SemaTemplate/instantiate-template-template-parm.cpp b/test/SemaTemplate/instantiate-template-template-parm.cpp
new file mode 100644 (file)
index 0000000..b158251
--- /dev/null
@@ -0,0 +1,21 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<template<typename T> class MetaFun, typename Value>
+struct apply {
+  typedef typename MetaFun<Value>::type type;
+};
+
+template<class T>
+struct add_pointer {
+  typedef T* type;
+};
+
+template<class T>
+struct add_reference {
+  typedef T& type;
+};
+
+int i;
+apply<add_pointer, int>::type ip = &i;
+apply<add_reference, int>::type ir = i;
+apply<add_reference, float>::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a value of type 'int'}}
index 22be5ab34f768dbea4c022a340a4e7c0f0b34b7e..e81d1421ebe89a9673521a8b8e532cdde48dd4ab 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only %s
+// RUN: clang-cc -fsyntax-only -verify %s
 
 struct add_pointer {
   template<typename T>
@@ -10,20 +10,21 @@ struct add_pointer {
 struct add_reference {
   template<typename T>
   struct apply {
-    typedef T& type;
+    typedef T& type; // expected-error{{cannot form a reference to 'void'}}
   };
 };
 
 template<typename MetaFun, typename T>
 struct apply1 {
-  typedef typename MetaFun::template apply<T>::type type;
+  typedef typename MetaFun::template apply<T>::type type; // expected-note{{in instantiation of template class 'struct add_reference::apply<void>' requested here}}
 };
 
-#if 0
-// FIXME: The code below requires template instantiation for dependent
-// template-names that occur within nested-name-specifiers.
 int i;
-
 apply1<add_pointer, int>::type ip = &i;
 apply1<add_reference, int>::type ir = i;
-#endif
+apply1<add_reference, float>::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a value of type 'int'}}
+
+void test() {
+  apply1<add_reference, void>::type t; // expected-note{{in instantiation of template class 'struct apply1<struct add_reference, void>' requested here}} \
+  // FIXME: expected-error{{unexpected type name 'type': expected expression}}
+}