diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-11-25 18:55:14 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-11-25 18:55:14 +0000 |
commit | 5c80a27ba26431c9f88d80edbbe61c562c5f9950 (patch) | |
tree | ce2ca684e8296e670efbce658f337fb7513372d4 | |
parent | 4cd30817d3739207cca1ef07e4048b122280081a (diff) | |
download | bcm5719-llvm-5c80a27ba26431c9f88d80edbbe61c562c5f9950.tar.gz bcm5719-llvm-5c80a27ba26431c9f88d80edbbe61c562c5f9950.zip |
Implement support for default template arguments of function templates.
llvm-svn: 89874
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 61 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 56 | ||||
-rw-r--r-- | clang/test/Parser/cxx-template-decl.cpp | 2 | ||||
-rw-r--r-- | clang/test/SemaTemplate/default-arguments-cxx0x.cpp | 26 |
6 files changed, 136 insertions, 18 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index cf13b68a15f..fed2cffc0db 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -882,7 +882,7 @@ def err_addr_ovl_ambiguous : Error< def err_template_param_shadow : Error< "declaration of %0 shadows template parameter">; def note_template_param_here : Note<"template parameter is declared here">; -def note_template_export_unsupported : Note< +def warn_template_export_unsupported : Warning< "exported templates are unsupported">; def err_template_outside_namespace_or_class_scope : Error< "templates can only be declared in namespace or class scope">; diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 8528560555c..084f720d4dd 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2384,6 +2384,13 @@ public: SourceLocation TemplateLoc, Declarator &D); + TemplateArgumentLoc + SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation RAngleLoc, + Decl *Param, + TemplateArgumentListBuilder &Converted); + bool CheckTemplateArgument(NamedDecl *Param, const TemplateArgumentLoc &Arg, TemplateDecl *Template, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 621362d2efb..4efecea9351 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -764,7 +764,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth, DeclPtrTy *Params, unsigned NumParams, SourceLocation RAngleLoc) { if (ExportLoc.isValid()) - Diag(ExportLoc, diag::note_template_export_unsupported); + Diag(ExportLoc, diag::warn_template_export_unsupported); return TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc, (NamedDecl**)Params, NumParams, @@ -1869,6 +1869,65 @@ SubstDefaultTemplateArgument(Sema &SemaRef, AllTemplateArgs); } +/// \brief If the given template parameter has a default template +/// argument, substitute into that default template argument and +/// return the corresponding template argument. +TemplateArgumentLoc +Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation RAngleLoc, + Decl *Param, + TemplateArgumentListBuilder &Converted) { + if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) { + if (!TypeParm->hasDefaultArgument()) + return TemplateArgumentLoc(); + + DeclaratorInfo *DI = SubstDefaultTemplateArgument(*this, Template, + TemplateLoc, + RAngleLoc, + TypeParm, + Converted); + if (DI) + return TemplateArgumentLoc(TemplateArgument(DI->getType()), DI); + + return TemplateArgumentLoc(); + } + + if (NonTypeTemplateParmDecl *NonTypeParm + = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + if (!NonTypeParm->hasDefaultArgument()) + return TemplateArgumentLoc(); + + OwningExprResult Arg = SubstDefaultTemplateArgument(*this, Template, + TemplateLoc, + RAngleLoc, + NonTypeParm, + Converted); + if (Arg.isInvalid()) + return TemplateArgumentLoc(); + + Expr *ArgE = Arg.takeAs<Expr>(); + return TemplateArgumentLoc(TemplateArgument(ArgE), ArgE); + } + + TemplateTemplateParmDecl *TempTempParm + = cast<TemplateTemplateParmDecl>(Param); + if (!TempTempParm->hasDefaultArgument()) + return TemplateArgumentLoc(); + + TemplateName TName = SubstDefaultTemplateArgument(*this, Template, + TemplateLoc, + RAngleLoc, + TempTempParm, + Converted); + if (TName.isNull()) + return TemplateArgumentLoc(); + + return TemplateArgumentLoc(TemplateArgument(TName), + TempTempParm->getDefaultArgument().getTemplateQualifierRange(), + TempTempParm->getDefaultArgument().getTemplateNameLoc()); +} + /// \brief Check that the given template argument corresponds to the given /// template parameter. bool Sema::CheckTemplateArgument(NamedDecl *Param, diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index c5571d16436..06b2dec590b 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1272,18 +1272,56 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); + // Template argument deduction for function templates in a SFINAE context. + // Trap any errors that might occur. + SFINAETrap Trap(*this); + + // Enter a new template instantiation context while we instantiate the + // actual function declaration. + InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), + FunctionTemplate, Deduced.data(), Deduced.size(), + ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); + if (Inst) + return TDK_InstantiationDepth; + // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size()); for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { - if (Deduced[I].isNull()) { + if (!Deduced[I].isNull()) { + Builder.Append(Deduced[I]); + continue; + } + + // Substitute into the default template argument, if available. + NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I); + TemplateArgumentLoc DefArg + = SubstDefaultTemplateArgumentIfAvailable(FunctionTemplate, + FunctionTemplate->getLocation(), + FunctionTemplate->getSourceRange().getEnd(), + Param, + Builder); + + // If there was no default argument, deduction is incomplete. + if (DefArg.getArgument().isNull()) { Info.Param = makeTemplateParameter( - const_cast<NamedDecl *>(TemplateParams->getParam(I))); + const_cast<NamedDecl *>(TemplateParams->getParam(I))); return TDK_Incomplete; } + + // Check whether we can actually use the default argument. + if (CheckTemplateArgument(Param, DefArg, + FunctionTemplate, + FunctionTemplate->getLocation(), + FunctionTemplate->getSourceRange().getEnd(), + Builder)) { + Info.Param = makeTemplateParameter( + const_cast<NamedDecl *>(TemplateParams->getParam(I))); + return TDK_SubstitutionFailure; + } - Builder.Append(Deduced[I]); + // If we get here, we successfully used the default template argument. } // Form the template argument list from the deduced template arguments. @@ -1291,18 +1329,6 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); Info.reset(DeducedArgumentList); - // Template argument deduction for function templates in a SFINAE context. - // Trap any errors that might occur. - SFINAETrap Trap(*this); - - // Enter a new template instantiation context while we instantiate the - // actual function declaration. - InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), - FunctionTemplate, Deduced.data(), Deduced.size(), - ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); - if (Inst) - return TDK_InstantiationDepth; - // Substitute the deduced template arguments into the function template // declaration to produce the function template specialization. Specialization = cast_or_null<FunctionDecl>( diff --git a/clang/test/Parser/cxx-template-decl.cpp b/clang/test/Parser/cxx-template-decl.cpp index 2b2d3de5049..e6cc462504d 100644 --- a/clang/test/Parser/cxx-template-decl.cpp +++ b/clang/test/Parser/cxx-template-decl.cpp @@ -5,7 +5,7 @@ export class foo { }; // expected-error {{expected template}} template x; // expected-error {{C++ requires a type specifier for all declarations}} \ // expected-error {{does not refer}} export template x; // expected-error {{expected '<' after 'template'}} -export template<class T> class x0; // expected-note {{exported templates are unsupported}} +export template<class T> class x0; // expected-warning {{exported templates are unsupported}} template < ; // expected-error {{parse error}} expected-error {{declaration does not declare anything}} template <template X> struct Err1; // expected-error {{expected '<' after 'template'}} \ // expected-error{{extraneous}} diff --git a/clang/test/SemaTemplate/default-arguments-cxx0x.cpp b/clang/test/SemaTemplate/default-arguments-cxx0x.cpp new file mode 100644 index 00000000000..8d8833c6702 --- /dev/null +++ b/clang/test/SemaTemplate/default-arguments-cxx0x.cpp @@ -0,0 +1,26 @@ +// RUN: clang-cc -fsyntax-only -std=c++0x -verify %s + +// Test default template arguments for function templates. +template<typename T = int> +void f0(); + +template<typename T> +void f0(); + +void g0() { + f0(); // okay! +} + +template<typename T, int N = T::value> +int &f1(T); + +float &f1(...); + +struct HasValue { + static const int value = 17; +}; + +void g1() { + float &fr = f1(15); + int &ir = f1(HasValue()); +} |