]> granicus.if.org Git - clang/commitdiff
Allow the use of default template arguments when forming a class
authorDouglas Gregor <dgregor@apple.com>
Wed, 11 Feb 2009 18:16:40 +0000 (18:16 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 11 Feb 2009 18:16:40 +0000 (18:16 +0000)
template specialization (e.g., std::vector<int> would now be
well-formed, since it relies on a default argument for the Allocator
template parameter).

This is much less interesting than one might expect, since (1) we're
not actually using the default arguments for anything important, such
as naming an actual Decl, and (2) we'll often need to instantiate the
default arguments to check their well-formedness. The real fun will
come later.

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

include/clang/AST/DeclTemplate.h
include/clang/Basic/DiagnosticSemaKinds.def
lib/AST/DeclTemplate.cpp
lib/Sema/SemaTemplate.cpp
test/SemaTemplate/default-arguments.cpp [new file with mode: 0644]
test/SemaTemplate/temp_arg.cpp

index ccbe1288f84af4ce7bc3b1319f6e28551a00ef1c..334a03a439db3051f38660d8b9b58e806014c1e7 100644 (file)
@@ -66,9 +66,19 @@ public:
 
   unsigned size() const { return NumParams; }
 
+  /// \btief Returns the minimum number of arguments needed to form a
+  /// template specialization. This may be fewer than the number of
+  /// template parameters, if some of the parameters have default
+  /// arguments.
+  unsigned getMinRequiredArguments() const;
+
   SourceLocation getTemplateLoc() const { return TemplateLoc; }
   SourceLocation getLAngleLoc() const { return LAngleLoc; }
   SourceLocation getRAngleLoc() const { return RAngleLoc; }
+
+  SourceRange getSourceRange() const {
+    return SourceRange(TemplateLoc, RAngleLoc);
+  }
 };
 
 //===----------------------------------------------------------------------===//
index 4fed9443d0233332ddc9d8ec8b1270d0b1e8ab1d..25fe8254bbcf17be8ea3578b706cf14917c5d7a1 100644 (file)
@@ -505,6 +505,8 @@ DIAG(err_template_param_default_arg_missing, ERROR,
 // C++ Template Argument Lists
 DIAG(err_template_arg_list_different_arity, ERROR,
      "%select{too few|too many}0 template arguments for %select{class template|function template|template template parameter|template}1 %2")
+DIAG(note_template_decl_here, NOTE,
+     "template is declared here")
 DIAG(err_template_arg_must_be_type, ERROR,
      "template argument for template type parameter must be a type")
 DIAG(err_template_arg_must_be_expr, ERROR,
index b297dd25cbe42c5dcd841b8435d4bd1d54a3ad2f..dccb8df0757fcd77331fe75fe07e7ffac347eac4 100644 (file)
@@ -44,6 +44,26 @@ TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc,
                                          NumParams, RAngleLoc);
 }
 
+unsigned TemplateParameterList::getMinRequiredArguments() const {
+  unsigned NumRequiredArgs = size();
+  iterator Param = const_cast<TemplateParameterList *>(this)->end(), 
+      ParamBegin = const_cast<TemplateParameterList *>(this)->begin();
+  while (Param != ParamBegin) {
+    --Param;
+    if (!(isa<TemplateTypeParmDecl>(*Param) && 
+          cast<TemplateTypeParmDecl>(*Param)->hasDefaultArgument()) &&
+        !(isa<NonTypeTemplateParmDecl>(*Param) &&
+          cast<NonTypeTemplateParmDecl>(*Param)->hasDefaultArgument()) &&
+        !(isa<TemplateTemplateParmDecl>(*Param) &&
+          cast<TemplateTemplateParmDecl>(*Param)->hasDefaultArgument()))
+      break;
+        
+    --NumRequiredArgs;
+  }
+
+  return NumRequiredArgs;
+}
+
 //===----------------------------------------------------------------------===//
 // TemplateDecl Implementation
 //===----------------------------------------------------------------------===//
index 86f1e2017f19e662b0d035c41e49bdca307d0c7a..b4436a2c3c1127907277dd8eda8666f2d3af72f2 100644 (file)
@@ -685,7 +685,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
   bool Invalid = false;
 
   if (NumArgs > NumParams ||
-      NumArgs < NumParams /*FIXME: default arguments! */) {
+      NumArgs < Params->getMinRequiredArguments()) {
     // FIXME: point at either the first arg beyond what we can handle,
     // or the '>', depending on whether we have too many or too few
     // arguments.
@@ -698,7 +698,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
           isa<FunctionTemplateDecl>(Template)? 1 :
           isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
       << Template << Range;
-
+    Diag(Template->getLocation(), diag::note_template_decl_here)
+      << Params->getSourceRange();
     Invalid = true;
   }
   
diff --git a/test/SemaTemplate/default-arguments.cpp b/test/SemaTemplate/default-arguments.cpp
new file mode 100644 (file)
index 0000000..94976e9
--- /dev/null
@@ -0,0 +1,13 @@
+// RUN: clang -fsyntax-only -verify %s
+
+template<typename T, int N = 2> struct X; // expected-note{{template is declared here}}
+
+X<int, 1> *x1;
+X<int> *x2;
+
+X<> *x3; // expected-error{{too few template arguments for class template 'X'}} \
+        // FIXME: expected-error{{expected unqualified-id}}
+
+template<typename U = float, int M> struct X;
+
+X<> *x4;
index 0f69b5f4b1aa6cb784ef887a4ef946549ed71228..b8bb279caf2dcab6e4f1b3041cfee1905441327f 100644 (file)
@@ -2,7 +2,7 @@
 template<typename T, 
          int I, 
          template<typename> class TT>
-  class A;
+  class A; // expected-note 2 {{template is declared here}}
 
 template<typename> class X;