]> granicus.if.org Git - clang/commitdiff
Tighten up the semantics of default template arguments, per C++0x
authorDouglas Gregor <dgregor@apple.com>
Fri, 4 Feb 2011 04:20:44 +0000 (04:20 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 4 Feb 2011 04:20:44 +0000 (04:20 +0000)
[temp.param]p9 and C++ DR226. Fixes PR8747.

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

include/clang/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.param/p9-0x.cpp

index 4777bca4b86d44166e96b2aed9a398c8b61e11e6..026930dabfe45bce509836dce6e9781f51e72571 100644 (file)
@@ -2914,7 +2914,8 @@ public:
     TPC_ClassTemplate,
     TPC_FunctionTemplate,
     TPC_ClassTemplateMember,
-    TPC_FriendFunctionTemplate
+    TPC_FriendFunctionTemplate,
+    TPC_FriendFunctionTemplateDefinition
   };
 
   bool CheckTemplateParameterList(TemplateParameterList *NewParams,
index 9c4fdc99f27d8e3326bab601ac06efebfddbb92e..88c3a770c272237b1de41c3ea2d6d3e2f5375ce3 100644 (file)
@@ -3967,8 +3967,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
       FunctionTemplateDecl *PrevTemplate = FunctionTemplate->getPreviousDeclaration();
       CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(),
                                  PrevTemplate? PrevTemplate->getTemplateParameters() : 0,
-                                 D.getDeclSpec().isFriendSpecified()? TPC_FriendFunctionTemplate
-                                                  : TPC_FunctionTemplate);
+                            D.getDeclSpec().isFriendSpecified()
+                              ? (IsFunctionDefinition 
+                                   ? TPC_FriendFunctionTemplateDefinition
+                                   : TPC_FriendFunctionTemplate)
+                              : (D.getCXXScopeSpec().isSet() && 
+                                 DC && DC->isRecord())
+                                  ? TPC_ClassTemplateMember
+                                  : TPC_FunctionTemplate);
     }
 
     if (NewFD->isInvalidDecl()) {
index f7060f03a3b886881dd22cb3915e8ae63a6d35da..e867354273fc44e181519149944d4c656232f08e 100644 (file)
@@ -946,7 +946,10 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
   // template declaration.
   if (CheckTemplateParameterList(TemplateParams,
             PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0,
-                                 TPC_ClassTemplate))
+                                 (SS.isSet() && SemanticContext &&
+                                  SemanticContext->isRecord())
+                                   ? TPC_ClassTemplateMember
+                                   : TPC_ClassTemplate))
     Invalid = true;
 
   if (SS.isSet()) {
@@ -1045,11 +1048,15 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
     return false;
 
   case Sema::TPC_FunctionTemplate:
+  case Sema::TPC_FriendFunctionTemplateDefinition:
     // C++ [temp.param]p9:
     //   A default template-argument shall not be specified in a
     //   function template declaration or a function template
     //   definition [...]
-    // (This sentence is not in C++0x, per DR226).
+    //   If a friend function template declaration specifies a default 
+    //   template-argument, that declaration shall be a definition and shall be
+    //   the only declaration of the function template in the translation unit.
+    // (C++98/03 doesn't have this wording; see DR226).
     if (!S.getLangOptions().CPlusPlus0x)
       S.Diag(ParamLoc,
              diag::ext_template_parameter_default_in_function_template)
index 1980bc6eaa1af087111ff2bc716695d89b7d1be8..c9d5bfb0173640cf8baf8025a5ab97238ed731b7 100644 (file)
@@ -12,3 +12,41 @@ template<typename T> struct vector;
 
 template<template<class> class ...Templates = vector> // expected-error{{template parameter pack cannot have a default argument}}
 struct X2; 
+
+struct X3 {
+  template<typename T = int> // expected-error{{default template argument not permitted on a friend template}}
+  friend void f0(X3);
+
+  template<typename T = int>
+  friend void f1(X3) {
+  }
+};
+
+namespace PR8747 {
+  // Testcase 1
+  struct A0 { template<typename U> struct B; }; 
+  template<typename U = int> struct A0::B { }; // expected-error{{cannot add a default template argument to the definition of a member of a class template}}
+  
+  // Testcase 2
+  template<typename T> struct A1 { template<typename U> struct B; }; 
+  template<typename T> template<typename U = int> struct A1<T>::B { }; // expected-error{{cannot add a default template argument to the definition of a member of a class template}}
+
+  // Testcase 3
+  template<typename T>
+  struct X2 {
+    void f0();
+    template<typename U> void f1();
+  };
+  
+  template<typename T = int> void X2<T>::f0() { } // expected-error{{cannot add a default template argument to the definition of a member of a class template}} 
+  template<typename T> template<typename U = int> void X2<T>::f1() { } // expected-error{{cannot add a default template argument to the definition of a member of a class template}}
+
+  namespace Inner {
+    template<typename T> struct X3;
+    template<typename T> void f2();
+  }
+
+  // Okay; not class members.
+  template<typename T = int> struct Inner::X3 { };
+  template<typename T = int> void Inner::f2() {}
+}