]> granicus.if.org Git - clang/commitdiff
Implement support for default template arguments of function templates.
authorDouglas Gregor <dgregor@apple.com>
Wed, 25 Nov 2009 18:55:14 +0000 (18:55 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 25 Nov 2009 18:55:14 +0000 (18:55 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89874 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.h
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateDeduction.cpp
test/Parser/cxx-template-decl.cpp
test/SemaTemplate/default-arguments-cxx0x.cpp [new file with mode: 0644]

index cf13b68a15feb1b6440112928216ec6d1e61ece1..fed2cffc0dbe675fe1ead8f3069a2f1f75ae2c1b 100644 (file)
@@ -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">;
index 8528560555c3b9ce3c4b1fe9092a340f94067027..084f720d4ddc202fe464dec130aece0a20a945c7 100644 (file)
@@ -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,
index 621362d2efb944da417c11310d433a8644febd84..4efecea935123875089ee74a11922ae9fa1293cf 100644 (file)
@@ -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,
index c5571d16436292abc0fd2141eaa7fc92352d3520..06b2dec590b2297f52b5d862d8266ccf76ee85cb 100644 (file)
@@ -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>(
index 2b2d3de50497c9aff5cb95c916f1296bd988e542..e6cc462504d1639af9769e1cbe4cfca2f40750c3 100644 (file)
@@ -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/test/SemaTemplate/default-arguments-cxx0x.cpp b/test/SemaTemplate/default-arguments-cxx0x.cpp
new file mode 100644 (file)
index 0000000..8d8833c
--- /dev/null
@@ -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());
+}