diff mbox

[C++] PR 15339

Message ID 53DC3ADA.9080909@oracle.com
State New
Headers show

Commit Message

Paolo Carlini Aug. 2, 2014, 1:11 a.m. UTC
... the below seems better to me:
1- FUNCTION_DECLs and TEMPLATE_DECLs are handled in their own places.
2- When I tweaked default3.C I didn't notice at first the real reason 
for the existing xfail: in such case we didn't give the 
check_default_args diagnostics. Restored in the below.
3- By handling TEMPLATE_DECLs separately, we can give the 
check_redeclaration_no_default_args permerror and the check_default_args 
error in a consistent order, that is the former before the latter, which 
makes most sense to me (also matches the clang order).

Thanks!
Paolo.

//////////////////////
/cp
2014-08-01  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/15339
	* decl.c (check_redeclaration_no_default_args): New.
	(duplicate_decls): Use it, handle default arguments
	in redeclarations of function templates.

/testsuite
2014-08-01  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/15339
	* g++.dg/other/default9.C: New.
	* g++.dg/other/default10.C: Likewise.
	* g++.dg/other/default3.C: Remove xfail.

Comments

Jason Merrill Aug. 2, 2014, 3:38 p.m. UTC | #1
OK.

Jason
diff mbox

Patch

Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 213505)
+++ cp/decl.c	(working copy)
@@ -1236,6 +1236,27 @@  validate_constexpr_redeclaration (tree old_decl, t
   return true;
 }
 
+/* DECL is a redeclaration of a function or function template.  If
+   it does have default arguments issue a diagnostic.  Note: this
+   function is used to enforce the requirements in C++11 8.3.6 about
+   no default arguments in redeclarations.  */
+
+static void
+check_redeclaration_no_default_args (tree decl)
+{
+  gcc_assert (DECL_DECLARES_FUNCTION_P (decl));
+
+  for (tree t = FUNCTION_FIRST_USER_PARMTYPE (decl);
+       t && t != void_list_node; t = TREE_CHAIN (t))
+    if (TREE_PURPOSE (t))
+      {
+	permerror (input_location,
+		   "redeclaration of %q#D may not have default "
+		   "arguments", decl);
+	return;
+      }
+}
+
 #define GNU_INLINE_P(fn) (DECL_DECLARED_INLINE_P (fn)			\
 			  && lookup_attribute ("gnu_inline",		\
 					       DECL_ATTRIBUTES (fn)))
@@ -1706,28 +1727,23 @@  duplicate_decls (tree newdecl, tree olddecl, bool
 	;
       else if (TREE_CODE (olddecl) == FUNCTION_DECL)
 	{
-	  tree t1 = FUNCTION_FIRST_USER_PARMTYPE (olddecl);
-	  tree t2 = FUNCTION_FIRST_USER_PARMTYPE (newdecl);
-	  int i = 1;
-
-	  if (DECL_FUNCTION_MEMBER_P (newdecl)
-	      && CLASSTYPE_TEMPLATE_INFO (CP_DECL_CONTEXT (newdecl)))
-	    {
-	      /* C++11 8.3.6/6.
-		 Default arguments for a member function of a class template
-		 shall be specified on the initial declaration of the member
-		 function within the class template.  */
-	      for (; t2 && t2 != void_list_node; t2 = TREE_CHAIN (t2))
-		if (TREE_PURPOSE (t2))
-		  {
-		    permerror (input_location,
-			       "redeclaration of %q#D may not have default "
-			       "arguments", newdecl);
-		    break;
-		  }
-	    }
+	  /* Note: free functions, as TEMPLATE_DECLs, are handled below.  */
+	  if (DECL_FUNCTION_MEMBER_P (olddecl)
+	      && (/* grokfndecl passes member function templates too
+		     as FUNCTION_DECLs.  */
+		  DECL_TEMPLATE_INFO (olddecl)
+		  /* C++11 8.3.6/6.
+		     Default arguments for a member function of a class
+		     template shall be specified on the initial declaration
+		     of the member function within the class template.  */
+		  || CLASSTYPE_TEMPLATE_INFO (CP_DECL_CONTEXT (olddecl))))
+	    check_redeclaration_no_default_args (newdecl);
 	  else
 	    {
+	      tree t1 = FUNCTION_FIRST_USER_PARMTYPE (olddecl);
+	      tree t2 = FUNCTION_FIRST_USER_PARMTYPE (newdecl);
+	      int i = 1;
+
 	      for (; t1 && t1 != void_list_node;
 		   t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2), i++)
 		if (TREE_PURPOSE (t1) && TREE_PURPOSE (t2))
@@ -1864,6 +1880,12 @@  duplicate_decls (tree newdecl, tree olddecl, bool
 
       if (DECL_FUNCTION_TEMPLATE_P (newdecl))
 	{
+	  /* Per C++11 8.3.6/4, default arguments cannot be added in later
+	     declarations of a function template.  */
+	  check_redeclaration_no_default_args (newdecl);
+
+	  check_default_args (newdecl);
+
 	  if (GNU_INLINE_P (old_result) != GNU_INLINE_P (new_result)
 	      && DECL_INITIAL (new_result))
 	    {
Index: testsuite/g++.dg/other/default10.C
===================================================================
--- testsuite/g++.dg/other/default10.C	(revision 0)
+++ testsuite/g++.dg/other/default10.C	(working copy)
@@ -0,0 +1,4 @@ 
+// PR c++/15339
+
+template<typename> void g3(int, int);
+template<typename> void g3(int = 0, int) { }  // { dg-error "may not have default arguments|default argument missing" }
Index: testsuite/g++.dg/other/default3.C
===================================================================
--- testsuite/g++.dg/other/default3.C	(revision 213504)
+++ testsuite/g++.dg/other/default3.C	(working copy)
@@ -25,7 +25,7 @@  template<typename> void g3(int, int);
 template<typename> void g3(int = 0, int);    // { dg-error "default" }
 
 template<typename> void g4(int, int);
-template<typename> void g4(int = 0, int) {}  // { dg-error "default" "" { xfail *-*-* } }
+template<typename> void g4(int = 0, int) {}  // { dg-error "default" }
 
 template<typename> void g5();
 template<typename> void g5(int = 0, int);    // { dg-error "default" }
Index: testsuite/g++.dg/other/default9.C
===================================================================
--- testsuite/g++.dg/other/default9.C	(revision 0)
+++ testsuite/g++.dg/other/default9.C	(working copy)
@@ -0,0 +1,18 @@ 
+// PR c++/15339
+
+template<typename> void fun(int); 
+template<typename> void fun(int = 0);  // { dg-error "default arguments" }
+
+class A
+{
+  template<typename> void fun(int);
+};
+
+template<typename> void A::fun(int = 0) { } // { dg-error "default arguments" }
+
+class B
+{
+  void fun(int);
+};
+
+void B::fun(int = 0) { }