[patch] Fix PR c++/16829: Diagnose missing default parameters

Volker Reichelt reichelt@igpm.rwth-aachen.de
Thu Jan 5 17:28:00 GMT 2006


When a function parameter has a default value, all subsequent
parameters must have one, too. Unfortunately, we failed to diagnose
violations of this rule in several circumstances (mostly in templates).

In some cases we even crashed (see first testcase below).

Some missing diagnostics are fixed by moving the calls to
check_default_args in start_preparsed_function and
pushdecl_maybe_friend to places where the call happens
unconditionally. The remaining ones are fixed by adding a call
to check_default_args in cp_parser_late_parsing_default_args.

The crash is avoided by replacing the missing arguments with
error_mark_nodes after diagnosis in check_default_args, so that
no missing arguments can confuse template instantiation etc.
This also prevents duplicate error messages, since arguments
aren't missing anymore after the first diagnosis.

The first testcase checks for the crash.
The second testcase checks several combinations of redeclarations,
definitions, partial specializations, templates and non-templates,
member functions and non-member functions. We used to diagnose only
about 10 of the 35 cases correctly without the patch.

Bootstrapped and regtested on x86_64-unknown-linux-gnu.
Ok for mainline?

Most of the missing diagnostics (though not all) are regressions
from gcc 3.3.6.
Ok for the branch 4.1, 4.0, and 3.4, too?

Regards,
Volker


:ADDPATCH C++:


2006-01-05  Volker Reichelt  <reichelt@igpm.rwth-aachen.de>

	PR c++/16829
	* decl.c (start_preparsed_function): Check default arguments
	unconditionally.
	* name-lookup.c (pushdecl_maybe_friend): Check default arguments
	of all functions and function templates.
	* parser.c (cp_parser_late_parsing_default_args): Check default
	arguments.
	* decl2.c (check_default_args): Set missing default arguments to
	error_mark_node.

======================================================================
--- gcc/gcc/cp/decl.c       2005-12-03 02:02:33 +0100
+++ gcc/gcc/cp/decl.c       2006-01-05 02:34:19 +0100
@@ -10216,6 +10216,8 @@ start_preparsed_function (tree decl1, tr
      you declare a function, these types can be incomplete, but they
      must be complete when you define the function.  */
   check_function_type (decl1, current_function_parms);
+  /* Make sure no default arg is missing.  */
+  check_default_args (decl1);
 
   /* Build the return declaration for the function.  */
   restype = TREE_TYPE (fntype);
@@ -10282,8 +10284,6 @@ start_preparsed_function (tree decl1, tr
 	  /* We need to set the DECL_CONTEXT.  */
 	  if (!DECL_CONTEXT (decl1) && DECL_TEMPLATE_INFO (decl1))
 	    DECL_CONTEXT (decl1) = DECL_CONTEXT (DECL_TI_TEMPLATE (decl1));
-	  /* And make sure we have enough default args.  */
-	  check_default_args (decl1);
 	}
       fntype = TREE_TYPE (decl1);
     }
======================================================================
--- gcc/gcc/cp/name-lookup.c        2005-11-25 13:49:19 +0100
+++ gcc/gcc/cp/name-lookup.c        2006-01-05 02:40:46 +0100
@@ -597,6 +597,9 @@ pushdecl_maybe_friend (tree x, bool is_f
 	DECL_LOCAL_FUNCTION_P (x) = 1;
     }
 
+  if (TREE_CODE (x) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (x))
+    check_default_args (x);
+
   name = DECL_NAME (x);
   if (name)
     {
@@ -710,8 +713,6 @@ pushdecl_maybe_friend (tree x, bool is_f
 		{
 		  if (TREE_CODE (t) == TYPE_DECL)
 		    SET_IDENTIFIER_TYPE_VALUE (name, TREE_TYPE (t));
-		  else if (TREE_CODE (t) == FUNCTION_DECL)
-		    check_default_args (t);
 
 		  POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
 		}
======================================================================
--- gcc/gcc/cp/parser.c     2005-12-02 13:37:15 +0100
+++ gcc/gcc/cp/parser.c     2006-01-05 02:32:20 +0100
@@ -15831,6 +15831,9 @@ cp_parser_late_parsing_default_args (cp_
       cp_parser_pop_lexer (parser);
     }
 
+  /* Make sure no default arg is missing.  */
+  check_default_args (fn);
+
   /* Restore the state of local_variables_forbidden_p.  */
   parser->local_variables_forbidden_p = saved_local_variables_forbidden_p;
 
======================================================================
--- gcc/gcc/cp/decl2.c      2005-12-02 12:21:28 +0100
+++ gcc/gcc/cp/decl2.c      2006-01-04 22:52:26 +0100
@@ -3228,7 +3228,7 @@ check_default_args (tree x)
       else if (saw_def)
 	{
 	  error ("default argument missing for parameter %P of %q+#D", i, x);
-	  break;
+	  TREE_PURPOSE (arg) = error_mark_node;
 	}
     }
 }
======================================================================


2006-01-05  Volker Reichelt  <reichelt@igpm.rwth-aachen.de>

	PR c++/16829
	* g++.dg/other/default2.C: New test.
	* g++.dg/other/default3.C: New test.

======================================================================
--- gcc/gcc/testsuite/g++.dg/other/default2.C	2005-08-29 00:25:44 +0200
+++ gcc/gcc/testsuite/g++.dg/other/default2.C	2006-01-05 14:27:00 +0100
@@ -0,0 +1,9 @@
+// PR c++/16829
+// { dg-do "compile" }
+
+template<typename T> void foo(T, int = 0, int) {}  // { dg-error "default" }
+
+void bar()
+{
+  foo(0);
+}
======================================================================
--- gcc/gcc/testsuite/g++.dg/other/default3.C	2005-08-29 00:25:44 +0200
+++ gcc/gcc/testsuite/g++.dg/other/default3.C	2006-01-05 13:27:44 +0100
@@ -0,0 +1,109 @@
+// PR c++/16829
+// { dg-do "compile" }
+
+void f1(int = 0, int);                       // { dg-error "default" }
+
+void f2(int = 0, int) {}                     // { dg-error "default" }
+
+void f3(int, int);
+void f3(int = 0, int);                       // { dg-error "default" }
+
+void f4(int, int);
+void f4(int = 0, int) {}                     // { dg-error "default" }
+
+void f5();
+void f5(int = 0, int);                       // { dg-error "default" }
+
+void f6();
+void f6(int = 0, int) {}                     // { dg-error "default" }
+
+template<typename> void g1(int = 0, int);    // { dg-error "default" }
+
+template<typename> void g2(int = 0, int) {}  // { dg-error "default" }
+
+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" }
+
+template<typename> void g5();
+template<typename> void g5(int = 0, int);    // { dg-error "default" }
+
+template<typename> void g6();
+template<typename> void g6(int = 0, int) {}  // { dg-error "default" }
+
+template<typename T> void g7(T, T)   {}
+template<typename T> void g7(T* = 0, T*) {}  // { dg-error "default" }
+
+
+struct A
+{
+  void F1(int = 0, int);                       // { dg-error "default" }
+
+  void F2(int = 0, int) {}                     // { dg-error "default" }
+
+  void F3(int, int);
+
+  void F4();
+  void F4(int = 0, int);                       // { dg-error "default" }
+
+  void F5();
+  void F5(int = 0, int) {}                     // { dg-error "default" }
+
+  template<typename> void G1(int = 0, int);    // { dg-error "default" }
+
+  template<typename> void G2(int = 0, int) {}  // { dg-error "default" }
+
+  template<typename> void G3(int, int);
+
+  template<typename> void G4();
+  template<typename> void G4(int = 0, int);    // { dg-error "default" }
+
+  template<typename> void G5();
+  template<typename> void G5(int = 0, int) {}  // { dg-error "default" }
+
+  template<typename T> void G6(T, T)   {}
+  template<typename T> void G6(T* = 0, T*) {}  // { dg-error "default" }
+};
+
+void A::F3(int = 0, int) {}                     // { dg-error "default" }
+
+template<typename> void A::G3(int = 0, int) {}  // { dg-error "default" }
+
+
+template<typename> struct B
+{
+  void F1(int = 0, int);                       // { dg-error "default" }
+
+  void F2(int = 0, int) {}                     // { dg-error "default" }
+
+  void F3(int, int);
+
+  void F4();
+  void F4(int = 0, int);                       // { dg-error "default" }
+
+  void F5();
+  void F5(int = 0, int) {}                     // { dg-error "default" }
+
+  template<typename> void G1(int = 0, int);    // { dg-error "default" }
+
+  template<typename> void G2(int = 0, int) {}  // { dg-error "default" }
+
+  template<typename> void G3(int, int);
+
+  template<typename> void G4();
+  template<typename> void G4(int = 0, int);    // { dg-error "default" }
+
+  template<typename> void G5();
+  template<typename> void G5(int = 0, int) {}  // { dg-error "default" }
+
+  template<typename T> void G6(T, T)   {}
+  template<typename T> void G6(T* = 0, T*) {}  // { dg-error "default" }
+};
+
+template<typename T>
+void B<T>::F3(int = 0, int) {}  // { dg-error "default" }
+
+template<typename T> template<typename>
+void B<T>::G3(int = 0, int) {}  // { dg-error "default" }
======================================================================





More information about the Gcc-patches mailing list