[cfe-commits] r89872 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.param/p9.cpp

Douglas Gregor dgregor at apple.com
Wed Nov 25 09:50:39 PST 2009


Author: dgregor
Date: Wed Nov 25 11:50:39 2009
New Revision: 89872

URL: http://llvm.org/viewvc/llvm-project?rev=89872&view=rev
Log:
Diagnose ill-formed uses of default template arguments in
function templates (in C++98), friend function templates, and
out-of-line definitions of members of class templates.

Also handles merging of default template arguments from previous
declarations of function templates, for C++0x. However, we don't yet
make use of those default template arguments.

Added:
    cfe/trunk/test/CXX/temp/temp.param/p9.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=89872&r1=89871&r2=89872&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Nov 25 11:50:39 2009
@@ -919,7 +919,15 @@
   "previous default template argument defined here">;
 def err_template_param_default_arg_missing : Error<
   "template parameter missing a default argument">;
-  
+def err_template_parameter_default_in_function_template : Error<
+  "a template parameter of a function template cannot have a default argument "
+  "in C++98">;
+def err_template_parameter_default_template_member : Error<
+  "cannot add a default template argument to the definition of a member of a "
+  "class template">;
+def err_template_parameter_default_friend_template : Error<
+  "default template argument not permitted on a friend template">;
+
 def err_template_variable : Error<"variable %0 declared as a template">;
 def err_template_variable_noparams : Error<
   "extraneous 'template<>' in declaration of variable %0">;

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=89872&r1=89871&r2=89872&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Nov 25 11:50:39 2009
@@ -2256,8 +2256,19 @@
                              SourceLocation LAngleLoc,
                              DeclPtrTy *Params, unsigned NumParams,
                              SourceLocation RAngleLoc);
+
+  /// \brief The context in which we are checking a template parameter
+  /// list.
+  enum TemplateParamListContext {
+    TPC_ClassTemplate,
+    TPC_FunctionTemplate,
+    TPC_ClassTemplateMember,
+    TPC_FriendFunctionTemplate
+  };
+
   bool CheckTemplateParameterList(TemplateParameterList *NewParams,
-                                  TemplateParameterList *OldParams);
+                                  TemplateParameterList *OldParams,
+                                  TemplateParamListContext TPC);
   TemplateParameterList *
   MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
                                           const CXXScopeSpec &SS,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=89872&r1=89871&r2=89872&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Nov 25 11:50:39 2009
@@ -3025,6 +3025,16 @@
           Previous.getResultKind() != LookupResult::FoundOverloaded) &&
          "previous declaration set still overloaded");
 
+  // If we have a function template, check the template parameter
+  // list. This will check and merge default template arguments.
+  if (FunctionTemplate) {
+    FunctionTemplateDecl *PrevTemplate = FunctionTemplate->getPreviousDeclaration();
+    CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(),
+                      PrevTemplate? PrevTemplate->getTemplateParameters() : 0,
+             D.getDeclSpec().isFriendSpecified()? TPC_FriendFunctionTemplate
+                                                : TPC_FunctionTemplate);
+  }
+
   if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
     // An out-of-line member function declaration must also be a
     // definition (C++ [dcl.meaning]p1).

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=89872&r1=89871&r2=89872&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Nov 25 11:50:39 2009
@@ -354,9 +354,8 @@
 
   if (CheckEquivalentExceptionSpec(
           Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
-          New->getType()->getAs<FunctionProtoType>(), New->getLocation())) {
+          New->getType()->getAs<FunctionProtoType>(), New->getLocation()))
     Invalid = true;
-  }
 
   return Invalid;
 }

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=89872&r1=89871&r2=89872&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Nov 25 11:50:39 2009
@@ -925,7 +925,8 @@
   // merging in the template parameter list from the previous class
   // template declaration.
   if (CheckTemplateParameterList(TemplateParams,
-            PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0))
+            PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0,
+                                 TPC_ClassTemplate))
     Invalid = true;
 
   // FIXME: If we had a scope specifier, we better have a previous template
@@ -1006,6 +1007,55 @@
   return DeclPtrTy::make(NewTemplate);
 }
 
+/// \brief Diagnose the presence of a default template argument on a
+/// template parameter, which is ill-formed in certain contexts.
+///
+/// \returns true if the default template argument should be dropped.
+static bool DiagnoseDefaultTemplateArgument(Sema &S, 
+                                            Sema::TemplateParamListContext TPC,
+                                            SourceLocation ParamLoc,
+                                            SourceRange DefArgRange) {
+  switch (TPC) {
+  case Sema::TPC_ClassTemplate:
+    return false;
+
+  case Sema::TPC_FunctionTemplate:
+    // 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 (!S.getLangOptions().CPlusPlus0x)
+      S.Diag(ParamLoc, 
+             diag::err_template_parameter_default_in_function_template)
+        << DefArgRange;
+    return false;
+
+  case Sema::TPC_ClassTemplateMember:
+    // C++0x [temp.param]p9:
+    //   A default template-argument shall not be specified in the
+    //   template-parameter-lists of the definition of a member of a
+    //   class template that appears outside of the member's class.
+    S.Diag(ParamLoc, diag::err_template_parameter_default_template_member)
+      << DefArgRange;
+    return true;
+
+  case Sema::TPC_FriendFunctionTemplate:
+    // C++ [temp.param]p9:
+    //   A default template-argument shall not be specified in a
+    //   friend template declaration.
+    S.Diag(ParamLoc, diag::err_template_parameter_default_friend_template)
+      << DefArgRange;
+    return true;
+
+    // FIXME: C++0x [temp.param]p9 allows default template-arguments
+    // for friend function templates if there is only a single
+    // declaration (and it is a definition). Strange!
+  }
+
+  return false;
+}
+
 /// \brief Checks the validity of a template parameter list, possibly
 /// considering the template parameter list from a previous
 /// declaration.
@@ -1024,9 +1074,13 @@
 /// arguments will be merged from the old template parameter list to
 /// the new template parameter list.
 ///
+/// \param TPC Describes the context in which we are checking the given
+/// template parameter list.
+///
 /// \returns true if an error occurred, false otherwise.
 bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
-                                      TemplateParameterList *OldParams) {
+                                      TemplateParameterList *OldParams,
+                                      TemplateParamListContext TPC) {
   bool Invalid = false;
 
   // C++ [temp.param]p10:
@@ -1066,9 +1120,17 @@
       Invalid = true;
     }
 
-    // Merge default arguments for template type parameters.
     if (TemplateTypeParmDecl *NewTypeParm
           = dyn_cast<TemplateTypeParmDecl>(*NewParam)) {
+      // Check the presence of a default argument here.
+      if (NewTypeParm->hasDefaultArgument() && 
+          DiagnoseDefaultTemplateArgument(*this, TPC, 
+                                          NewTypeParm->getLocation(), 
+               NewTypeParm->getDefaultArgumentInfo()->getTypeLoc()
+                                                       .getFullSourceRange()))
+        NewTypeParm->removeDefaultArgument();
+
+      // Merge default arguments for template type parameters.
       TemplateTypeParmDecl *OldTypeParm
           = OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0;
 
@@ -1098,6 +1160,15 @@
         MissingDefaultArg = true;
     } else if (NonTypeTemplateParmDecl *NewNonTypeParm
                = dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
+      // Check the presence of a default argument here.
+      if (NewNonTypeParm->hasDefaultArgument() && 
+          DiagnoseDefaultTemplateArgument(*this, TPC, 
+                                          NewNonTypeParm->getLocation(), 
+                    NewNonTypeParm->getDefaultArgument()->getSourceRange())) {
+        NewNonTypeParm->getDefaultArgument()->Destroy(Context);
+        NewNonTypeParm->setDefaultArgument(0);
+      }
+
       // Merge default arguments for non-type template parameters
       NonTypeTemplateParmDecl *OldNonTypeParm
         = OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : 0;
@@ -1124,9 +1195,16 @@
       } else if (SawDefaultArgument)
         MissingDefaultArg = true;
     } else {
-    // Merge default arguments for template template parameters
+      // Check the presence of a default argument here.
       TemplateTemplateParmDecl *NewTemplateParm
         = cast<TemplateTemplateParmDecl>(*NewParam);
+      if (NewTemplateParm->hasDefaultArgument() && 
+          DiagnoseDefaultTemplateArgument(*this, TPC, 
+                                          NewTemplateParm->getLocation(), 
+                     NewTemplateParm->getDefaultArgument().getSourceRange()))
+        NewTemplateParm->setDefaultArgument(TemplateArgumentLoc());
+
+      // Merge default arguments for template template parameters
       TemplateTemplateParmDecl *OldTemplateParm
         = OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0;
       if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
@@ -1299,6 +1377,8 @@
                                          ExpectedTemplateParams,
                                          true, TPL_TemplateMatch);
       }
+
+      CheckTemplateParameterList(ParamLists[Idx], 0, TPC_ClassTemplateMember);
     } else if (ParamLists[Idx]->size() > 0)
       Diag(ParamLists[Idx]->getTemplateLoc(),
            diag::err_template_param_list_matches_nontemplate)

Added: cfe/trunk/test/CXX/temp/temp.param/p9.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.param/p9.cpp?rev=89872&view=auto

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.param/p9.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.param/p9.cpp Wed Nov 25 11:50:39 2009
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -std=c++98 -verify %s
+
+// A default template-argument shall not be specified in a function
+// template declaration or a function template definition
+template<typename T = int> // expected-error{{cannot have a default argument}}
+  void foo0(T); 
+template<typename T = int> // expected-error{{cannot have a default argument}} 
+  void foo1(T) { } 
+
+// [...] nor in the template-parameter-list of the definition of a
+// member of a class template.
+template<int N>
+struct X0 {
+  void f();
+};
+
+template<int N = 0> // expected-error{{cannot add a default template argument}}
+void X0<N>::f() { } 
+
+class X1 {
+  template<template<int> class TT = X0> // expected-error{{not permitted on a friend template}}
+  friend void f2();
+};

Propchange: cfe/trunk/test/CXX/temp/temp.param/p9.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CXX/temp/temp.param/p9.cpp

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CXX/temp/temp.param/p9.cpp

------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list