... 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.carl...@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.carl...@oracle.com>
PR c++/15339
* g++.dg/other/default9.C: New.
* g++.dg/other/default10.C: Likewise.
* g++.dg/other/default3.C: Remove xfail.
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) { }