From e83a4a2e4040d52b9c0ef052b8f49b5afbed60ac Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Sat, 2 Aug 2014 19:41:32 +0000 Subject: [PATCH] re PR c++/15339 ([DR217] Adding default arguments to function templates in redeclarations should be forbidden) /cp 2014-08-02 Paolo Carlini 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-02 Paolo Carlini PR c++/15339 * g++.dg/other/default9.C: New. * g++.dg/other/default10.C: Likewise. * g++.dg/other/default3.C: Remove xfail. From-SVN: r213519 --- gcc/cp/ChangeLog | 7 +++ gcc/cp/decl.c | 62 +++++++++++++++++--------- gcc/testsuite/ChangeLog | 9 +++- gcc/testsuite/g++.dg/other/default10.C | 4 ++ gcc/testsuite/g++.dg/other/default3.C | 2 +- gcc/testsuite/g++.dg/other/default9.C | 18 ++++++++ 6 files changed, 80 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/g++.dg/other/default10.C create mode 100644 gcc/testsuite/g++.dg/other/default9.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 193a9c2d848..9fdd4c7906b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2014-08-02 Paolo Carlini + + PR c++/15339 + * decl.c (check_redeclaration_no_default_args): New. + (duplicate_decls): Use it, handle default arguments + in redeclarations of function templates. + 2014-08-02 Trevor Saunders * optimize.c, semantics.c: Use hash_map instead of pointer_map. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 88152f0daf2..d4dde6129aa 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1236,6 +1236,27 @@ validate_constexpr_redeclaration (tree old_decl, tree new_decl) 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 newdecl_is_friend) ; 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 newdecl_is_friend) 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)) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index aab609706f9..68c4cf67759 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,4 +1,11 @@ -2014-08-01 Jan Hubicka +2014-08-02 Paolo Carlini + + PR c++/15339 + * g++.dg/other/default9.C: New. + * g++.dg/other/default10.C: Likewise. + * g++.dg/other/default3.C: Remove xfail. + +2014-08-02 Jan Hubicka * g++.dg/warn/Wsuggest-final.C: New testcase. * g++.dg/ipa/devirt-34.C: Fix. diff --git a/gcc/testsuite/g++.dg/other/default10.C b/gcc/testsuite/g++.dg/other/default10.C new file mode 100644 index 00000000000..1c9731e2fa7 --- /dev/null +++ b/gcc/testsuite/g++.dg/other/default10.C @@ -0,0 +1,4 @@ +// PR c++/15339 + +template void g3(int, int); +template void g3(int = 0, int) { } // { dg-error "may not have default arguments|default argument missing" } diff --git a/gcc/testsuite/g++.dg/other/default3.C b/gcc/testsuite/g++.dg/other/default3.C index 42c1fe48922..025d2c1b461 100644 --- a/gcc/testsuite/g++.dg/other/default3.C +++ b/gcc/testsuite/g++.dg/other/default3.C @@ -25,7 +25,7 @@ template void g3(int, int); template void g3(int = 0, int); // { dg-error "default" } template void g4(int, int); -template void g4(int = 0, int) {} // { dg-error "default" "" { xfail *-*-* } } +template void g4(int = 0, int) {} // { dg-error "default" } template void g5(); template void g5(int = 0, int); // { dg-error "default" } diff --git a/gcc/testsuite/g++.dg/other/default9.C b/gcc/testsuite/g++.dg/other/default9.C new file mode 100644 index 00000000000..62f0a791527 --- /dev/null +++ b/gcc/testsuite/g++.dg/other/default9.C @@ -0,0 +1,18 @@ +// PR c++/15339 + +template void fun(int); +template void fun(int = 0); // { dg-error "default arguments" } + +class A +{ + template void fun(int); +}; + +template void A::fun(int = 0) { } // { dg-error "default arguments" } + +class B +{ + void fun(int); +}; + +void B::fun(int = 0) { }