decl.c (redeclaration_error_message): Complain when redeclaring a friend function...
authorDouglas Gregor <doug.gregor@gmail.com>
Wed, 28 Mar 2007 14:05:29 +0000 (14:05 +0000)
committerDoug Gregor <dgregor@gcc.gnu.org>
Wed, 28 Mar 2007 14:05:29 +0000 (14:05 +0000)
2007-03-28  Douglas Gregor  <doug.gregor@gmail.com>

* decl.c (redeclaration_error_message): Complain when redeclaring
a friend function with default template arguments (C++0x mode only).
* cp-tree.h (check_default_tmpl_args): Declare.
* pt.c (check_default_tmpl_args): In C++0x mode, permit default
template arguments in function templates. Add support for checking
the default template arguments of friend templates.
(push_template_decl_real): Fix call to check_default_tmpl_args.
(type_unification_real): If a template parameter has not been
deduced but provides a default template argument, substitute into
that default template argument.
* parser.c (cp_parser_init_declarator): When declaring (but not
defining!) a function template in C++0x mode, check for default
template arguments.

2007-03-28  Douglas Gregor  <doug.gregor@gmail.com>

* g++.dg/cpp0x/temp_default1.C: New.
* g++.dg/cpp0x/temp_default3.C: New.
* g++.dg/cpp0x/temp_default2.C: New.
* g++.dg/cpp0x/temp_default4.C: New.

From-SVN: r123300

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/temp_default1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/temp_default2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/temp_default3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/temp_default4.C [new file with mode: 0644]

index 7541770c57959be6a3bb75ccb27363613e13d51a..2a636294a68ccf4bf40a00dc119ca323cbc968c5 100644 (file)
@@ -1,3 +1,19 @@
+2007-03-28  Douglas Gregor  <doug.gregor@gmail.com>
+
+       * decl.c (redeclaration_error_message): Complain when redeclaring
+       a friend function with default template arguments (C++0x mode only).
+       * cp-tree.h (check_default_tmpl_args): Declare.
+       * pt.c (check_default_tmpl_args): In C++0x mode, permit default
+       template arguments in function templates. Add support for checking
+       the default template arguments of friend templates.
+       (push_template_decl_real): Fix call to check_default_tmpl_args.
+       (type_unification_real): If a template parameter has not been
+       deduced but provides a default template argument, substitute into
+       that default template argument.
+       * parser.c (cp_parser_init_declarator): When declaring (but not
+       defining!) a function template in C++0x mode, check for default
+       template arguments.
+
 2007-03-28 Douglas Gregor <doug.gregor@gmail.com>
 
        PR c++/29993
index 18f2cfbc639be9c9a5f6f0b8c634072e41b09b90..95945b33837dd7acbf522fc617b6f0e532cfa837 100644 (file)
@@ -4300,6 +4300,7 @@ extern tree check_explicit_specialization (tree, tree, int, int);
 extern tree process_template_parm              (tree, tree, bool, bool);
 extern tree end_template_parm_list             (tree);
 extern void end_template_decl                  (void);
+extern bool check_default_tmpl_args             (tree, tree, int, int, int);
 extern tree push_template_decl                 (tree);
 extern tree push_template_decl_real            (tree, bool);
 extern bool redeclare_class_template           (tree, tree);
index f107bee73ebd4cb156a97c2578f4a780e8942ab8..ce1c54f10cdc007a9e71e43d90d3a9c3cf91e1cb 100644 (file)
@@ -2148,6 +2148,19 @@ redeclaration_error_message (tree newdecl, tree olddecl)
       if (DECL_INITIAL (nt) && DECL_INITIAL (ot))
        return "redefinition of %q#D";
 
+      /* Core issue #226 (C++0x): 
+           
+           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.  */
+      if (flag_cpp0x 
+          && TREE_CODE (ot) == FUNCTION_DECL && DECL_FRIEND_P (ot)
+          && !check_default_tmpl_args (nt, DECL_TEMPLATE_PARMS (newdecl), 
+                                       /*is_primary=*/1, /*is_partial=*/0,
+                                       /*is_friend_decl=*/2))
+        return "redeclaration of friend %q#D may not have default template arguments";
+
       return NULL;
     }
   else if (TREE_CODE (newdecl) == VAR_DECL
index ec907264623731a10c0522f2901b211f4a19f7ea..da573cb91f75618bae32893a7b0afe0258257c94 100644 (file)
@@ -11721,6 +11721,13 @@ cp_parser_init_declarator (cp_parser* parser,
                      ((is_parenthesized_init || !is_initialized)
                     ? 0 : LOOKUP_ONLYCONVERTING));
     }
+  else if (flag_cpp0x && friend_p && decl && TREE_CODE (decl) == FUNCTION_DECL)
+    /* Core issue #226 (C++0x only): A default template-argument
+       shall not be specified in a friend class template
+       declaration. */
+    check_default_tmpl_args (decl, current_template_parms, /*is_primary=*/1, 
+                             /*is_partial=*/0, /*is_friend_decl=*/1);
+
   if (!friend_p && pushed_scope)
     pop_scope (pushed_scope);
 
index da3cd23a9443ac6b2c3fed05dde5d2b6edbd54e2..1e6c04408e22416f5bec7cbb2c262a027059b32d 100644 (file)
@@ -152,7 +152,6 @@ static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
 static bool check_specialization_scope (void);
 static tree process_partial_specialization (tree);
 static void set_current_access_from_decl (tree);
-static void check_default_tmpl_args (tree, tree, int, int);
 static tree get_template_base (tree, tree, tree, tree);
 static tree try_class_unification (tree, tree, tree, tree);
 static int coerce_template_template_parms (tree, tree, tsubst_flags_t,
@@ -3377,14 +3376,24 @@ process_partial_specialization (tree decl)
 /* Check that a template declaration's use of default arguments is not
    invalid.  Here, PARMS are the template parameters.  IS_PRIMARY is
    nonzero if DECL is the thing declared by a primary template.
-   IS_PARTIAL is nonzero if DECL is a partial specialization.  */
+   IS_PARTIAL is nonzero if DECL is a partial specialization.
+   
 
-static void
-check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
+   IS_FRIEND_DECL is nonzero if DECL is a friend function template
+   declaration (but not a definition); 1 indicates a declaration, 2
+   indicates a redeclaration. When IS_FRIEND_DECL=2, no errors are
+   emitted for extraneous default arguments.
+
+   Returns TRUE if there were no errors found, FALSE otherwise. */
+
+bool
+check_default_tmpl_args (tree decl, tree parms, int is_primary, 
+                         int is_partial, int is_friend_decl)
 {
   const char *msg;
   int last_level_to_check;
   tree parm_level;
+  bool no_errors = true;
 
   /* [temp.param]
 
@@ -3397,7 +3406,7 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
     /* You can't have a function template declaration in a local
        scope, nor you can you define a member of a class template in a
        local scope.  */
-    return;
+    return true;
 
   if (current_class_type
       && !TYPE_BEING_DEFINED (current_class_type)
@@ -3417,40 +3426,49 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
        declared, so there's no need to do it again now.  This function
        was defined in class scope, but we're processing it's body now
        that the class is complete.  */
-    return;
-
-  /* [temp.param]
+    return true;
 
-     If a template-parameter has a default template-argument, all
-     subsequent template-parameters shall have a default
-     template-argument supplied.  */
-  for (parm_level = parms; parm_level; parm_level = TREE_CHAIN (parm_level))
+  /* Core issue 226 (C++0x only): the following only applies to class
+     templates.  */
+  if (!flag_cpp0x || TREE_CODE (decl) != FUNCTION_DECL)
     {
-      tree inner_parms = TREE_VALUE (parm_level);
-      int ntparms = TREE_VEC_LENGTH (inner_parms);
-      int seen_def_arg_p = 0;
-      int i;
+      /* [temp.param]
 
-      for (i = 0; i < ntparms; ++i)
-       {
-         tree parm = TREE_VEC_ELT (inner_parms, i);
+         If a template-parameter has a default template-argument, all
+         subsequent template-parameters shall have a default
+         template-argument supplied.  */
+      for (parm_level = parms; parm_level; parm_level = TREE_CHAIN (parm_level))
+        {
+          tree inner_parms = TREE_VALUE (parm_level);
+          int ntparms = TREE_VEC_LENGTH (inner_parms);
+          int seen_def_arg_p = 0;
+          int i;
 
-          if (parm == error_mark_node)
-            continue;
+          for (i = 0; i < ntparms; ++i)
+            {
+              tree parm = TREE_VEC_ELT (inner_parms, i);
 
-         if (TREE_PURPOSE (parm))
-           seen_def_arg_p = 1;
-         else if (seen_def_arg_p)
-           {
-             error ("no default argument for %qD", TREE_VALUE (parm));
-             /* For better subsequent error-recovery, we indicate that
-                there should have been a default argument.  */
-             TREE_PURPOSE (parm) = error_mark_node;
-           }
-       }
+              if (parm == error_mark_node)
+                continue;
+
+              if (TREE_PURPOSE (parm))
+                seen_def_arg_p = 1;
+              else if (seen_def_arg_p)
+                {
+                  error ("no default argument for %qD", TREE_VALUE (parm));
+                  /* For better subsequent error-recovery, we indicate that
+                     there should have been a default argument.  */
+                  TREE_PURPOSE (parm) = error_mark_node;
+                  no_errors = false;
+                }
+            }
+        }
     }
 
-  if (TREE_CODE (decl) != TYPE_DECL || is_partial || !is_primary)
+  if ((!flag_cpp0x && TREE_CODE (decl) != TYPE_DECL)
+      || is_partial 
+      || !is_primary
+      || is_friend_decl)
     /* For an ordinary class template, default template arguments are
        allowed at the innermost level, e.g.:
         template <class T = int>
@@ -3461,8 +3479,8 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
         The template parameter list of a specialization shall not
         contain default template argument values.
 
-       So, for a partial specialization, or for a function template,
-       we look at all of them.  */
+       So, for a partial specialization, or for a function template
+       (in C++98/C++03), we look at all of them.  */
     ;
   else
     /* But, for a primary class template that is not a partial
@@ -3471,7 +3489,11 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
     parms = TREE_CHAIN (parms);
 
   /* Figure out what error message to issue.  */
-  if (TREE_CODE (decl) == FUNCTION_DECL)
+  if (is_friend_decl == 2)
+    msg = "default template arguments may not be used in function template friend re-declaration";
+  else if (is_friend_decl)
+    msg = "default template arguments may not be used in function template friend declarations";
+  else if (TREE_CODE (decl) == FUNCTION_DECL && !flag_cpp0x)
     msg = "default template arguments may not be used in function templates";
   else if (is_partial)
     msg = "default template arguments may not be used in partial specializations";
@@ -3510,6 +3532,10 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
            {
              if (msg)
                {
+                  no_errors = false;
+                  if (is_friend_decl == 2)
+                    return no_errors;
+
                  error (msg, decl);
                  msg = 0;
                }
@@ -3525,6 +3551,8 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
       if (msg)
        msg = "default argument for template parameter for class enclosing %qD";
     }
+
+  return no_errors;
 }
 
 /* Worker for push_template_decl_real, called via
@@ -3652,7 +3680,7 @@ push_template_decl_real (tree decl, bool is_friend)
   /* Check to see that the rules regarding the use of default
      arguments are not being violated.  */
   check_default_tmpl_args (decl, current_template_parms,
-                          primary, is_partial);
+                          primary, is_partial, /*is_friend_decl=*/0);
 
   /* Ensure that there are no parameter packs in the type of this
      declaration that have not been expanded.  */
@@ -11346,6 +11374,27 @@ type_unification_real (tree tparms,
              && !saw_undeduced++)
            goto again;
 
+          /* Core issue #226 (C++0x) [temp.deduct]:
+
+               If a template argument has not been deduced, its
+               default template argument, if any, is used. 
+
+             When we are not in C++0x mode (i.e., !flag_cpp0x),
+             TREE_PURPOSE will either be NULL_TREE or ERROR_MARK_NODE,
+             so we do not need to explicitly check flag_cpp0x here.  */
+          if (TREE_PURPOSE (TREE_VEC_ELT (tparms, i)))
+            {
+              tree arg = tsubst (TREE_PURPOSE (TREE_VEC_ELT (tparms, i)), 
+                                 targs, tf_none, NULL_TREE);
+              if (arg == error_mark_node)
+                return 1;
+              else
+                {
+                  TREE_VEC_ELT (targs, i) = arg;
+                  continue;
+                }
+            }
+
          return 2;
        }
 
index 442ea61e1c1413f64e9d992c3f8f2ba267b56544..b59cc0a009bb24085ba4814c8c54209b37811c00 100644 (file)
@@ -1,5 +1,11 @@
 2007-03-28  Douglas Gregor  <doug.gregor@gmail.com>
 
+       * g++.dg/cpp0x/temp_default1.C: New.
+       * g++.dg/cpp0x/temp_default3.C: New.
+       * g++.dg/cpp0x/temp_default2.C: New.
+       * g++.dg/cpp0x/temp_default4.C: New.
+
+2007-03-28  Douglas Gregor  <doug.gregor@gmail.com>
 
        PR c++/29993
        * g++.dg/other/cv_func2.C: New.
diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default1.C b/gcc/testsuite/g++.dg/cpp0x/temp_default1.C
new file mode 100644 (file)
index 0000000..dfa2cfb
--- /dev/null
@@ -0,0 +1,32 @@
+// { dg-options "-std=c++0x" }
+
+template<typename T, typename U>
+struct is_same
+{
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T> {
+  static const bool value = true;
+};
+
+template<typename T = int> void f()
+{
+  static_assert(is_same<T, int>::value, 
+                "T can only be instantiated with an int");
+}
+
+template<typename T = int, typename U>
+void f(U)
+{
+  static_assert(is_same<T, int>::value, 
+                "T can only be instantiated with an int");
+}
+
+void g()
+{
+  float pi = 3.14159;
+  f();
+  f(pi);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default2.C b/gcc/testsuite/g++.dg/cpp0x/temp_default2.C
new file mode 100644 (file)
index 0000000..f7f2228
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-options "-std=c++0x" }
+
+template <class T, class U = double> 
+void f(T t = 0, U u = 0); 
+
+void g() 
+{ 
+  f(1, 'c'); // f<int,char>(1,'c') 
+  f(1); // f<int,double>(1,0) 
+  f(); // { dg-error "no matching function" }
+  f<int>(); // f<int,double>(0,0) 
+  f<int,char>(); // f<int,char>(0,0) 
+} 
diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default3.C b/gcc/testsuite/g++.dg/cpp0x/temp_default3.C
new file mode 100644 (file)
index 0000000..f71fe0f
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-options "-std=c++0x" }
+
+template<typename T, typename U = typename T::value_type>
+void f(T);
+
+void f(...);
+
+struct X {
+  typedef int value_type;
+};
+
+void g()
+{
+  f(X()); // okay
+  f(17); // okay?
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default4.C b/gcc/testsuite/g++.dg/cpp0x/temp_default4.C
new file mode 100644 (file)
index 0000000..f1e254c
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-options "-std=c++0x" }
+
+class X {
+  template<typename T = int> friend void f(X) { }
+  template<typename T> friend void g(X); // { dg-error "previously declared here" }
+  template<typename T = int> friend void h(X); // { dg-error "function template friend" }
+};
+
+template<typename T = int> void g(X) // { dg-error "default template argument" }
+{
+}