From: Douglas Gregor Date: Wed, 11 Feb 2009 18:16:40 +0000 (+0000) Subject: Allow the use of default template arguments when forming a class X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=62cb18dd11472965e03374d40bc27d650bc331b6;p=clang Allow the use of default template arguments when forming a class template specialization (e.g., std::vector 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 --- diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index ccbe1288f8..334a03a439 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -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); + } }; //===----------------------------------------------------------------------===// diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index 4fed9443d0..25fe8254bb 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -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, diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index b297dd25cb..dccb8df075 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -44,6 +44,26 @@ TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc, NumParams, RAngleLoc); } +unsigned TemplateParameterList::getMinRequiredArguments() const { + unsigned NumRequiredArgs = size(); + iterator Param = const_cast(this)->end(), + ParamBegin = const_cast(this)->begin(); + while (Param != ParamBegin) { + --Param; + if (!(isa(*Param) && + cast(*Param)->hasDefaultArgument()) && + !(isa(*Param) && + cast(*Param)->hasDefaultArgument()) && + !(isa(*Param) && + cast(*Param)->hasDefaultArgument())) + break; + + --NumRequiredArgs; + } + + return NumRequiredArgs; +} + //===----------------------------------------------------------------------===// // TemplateDecl Implementation //===----------------------------------------------------------------------===// diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 86f1e2017f..b4436a2c3c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -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(Template)? 1 : isa(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 index 0000000000..94976e9735 --- /dev/null +++ b/test/SemaTemplate/default-arguments.cpp @@ -0,0 +1,13 @@ +// RUN: clang -fsyntax-only -verify %s + +template struct X; // expected-note{{template is declared here}} + +X *x1; +X *x2; + +X<> *x3; // expected-error{{too few template arguments for class template 'X'}} \ + // FIXME: expected-error{{expected unqualified-id}} + +template struct X; + +X<> *x4; diff --git a/test/SemaTemplate/temp_arg.cpp b/test/SemaTemplate/temp_arg.cpp index 0f69b5f4b1..b8bb279caf 100644 --- a/test/SemaTemplate/temp_arg.cpp +++ b/test/SemaTemplate/temp_arg.cpp @@ -2,7 +2,7 @@ template class TT> - class A; + class A; // expected-note 2 {{template is declared here}} template class X;