PATCH: ice108, g++.bugs/900428_01.C

Nathan Sidwell nathan@acm.org
Tue Feb 16 02:03:00 GMT 1999


Hi,
attached is a patch (against the 19990208 snapshot) which started as a bug hunt
for ICE108. In fixing that and the resulting cascade of later ICE's, I
discovered that egcs is rather schizoprhenic about what it considers an
incomplete type. require_complete_type would return OK, even if the type is not
known (and possibly incomplete).

This patch fixes ice108, caused by passing an ambiguous overloaded function
address to a varadic function, and fixes the XFAILS on g++.bugs/900428_01.C.
Those are failures to diagnose dereferencing an incomplete type in a void
context. In addition, it adds diagnostics to all cases where an expression of
incomplete or unknown type is used in a void context.

convert_for_initialization, convert_arguments were both being over eager on
checking for an incomplete type. Those checks have been removed.
convert_for_assignment does the right thing, checking for a complete type after
overload disambiguation has occured. convert_for_ellipsis was not checking for
a complete type, and hence passing an ambiguous overloaded function address
caused the RTL converter to die horribly.

I have added an extra argument to complete_type_or_else, this does not change
the behaviour, but allows a more informative diagnostic in the case of an
incomplete type.

I have modified incomplete_type_error to show the location of any forwardly
declared type, which is not yet defined. It also now deals with UNKNOWN_TYPE
nodes, and can therefore deal with ambiguous overloaded function addresses.

I have changed require_complete_type to consider any type with a TYPE_SIZE of
size_zero_node to be incomplete. Without this, it would consider certain
incomplete types to be complete.

I have added a new function, require_complete_type_in_void to check that we are
correctly dealing with a complete type in a void context. This was currently
not being thoroughly checked. (the 900428_01 XFAILS). The only complication
here is that it is legitimate to return an incomplete reference from a function
call, but not dereference a pointer to an incomplete type returned from a
function call.

I have corrected the places where egcs was not dealing with qualified void
returns from function calls. These should be treated in the same way as plain
void.

The patches cause a number of changes in the testsuite, the 90042801 XFAILS
become PASSES. A number of other testcases fail with excess errors solely due
to the changes in incomplete_type_error. The patch includes amendments to all
those tests, to mark were new ERRORs are expected.

Here are the old and new check.g++ highlights for this sparc-sun-solaris-2.6
box

-- unpatched
FAIL: g++.brendan/asm-extn1.C caused compiler crash
FAIL: g++.pt/expr3.C (test for excess errors)

                === g++ Summary ===

# of expected passes            4845
# of unexpected failures        2
# of expected failures          88
# of untested testcases         6

--patched
FAIL: g++.brendan/asm-extn1.C caused compiler crash
FAIL: g++.pt/expr3.C (test for excess errors)

                === g++ Summary ===

# of expected passes            4872
# of unexpected failures        2
# of expected failures          70
# of untested testcases         6

I also include two additional test cases. the first, ice108.C, causes that ICE
without the patch (hidden in a `confused by previous errors' message, but you
get a naked ice108 if you remove the previous lines). The second, return.C,
contains undiagnosed errors. The testsuite output does not include these two
additional testcases.

Enjoy

nathan
-- 
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
      You can up the bandwidth, but you can't up the speed of light      
nathan@acm.org  http://www.cs.bris.ac.uk/~nathan/  nathan@cs.bris.ac.uk
egcs/gcc/cp/ChangeLog:
Mon Feb 15 14:40:43 GMT 1999  Nathan Sidwell  <nathan@acm.org>

	* typeck.c (complete_type_or_else): Add VALUE arg, for helpful
	diagnostics.
	cp-tree.h (complete_type_or_else): Added VALUE parameter.
	* init.c (build_new_1): Extra arg to complete_type_or_else.
	(build_delete): Likewise.
	* pt.c (tsubst): Likewise.
	* typeck.c (require_complete_type): Likewise.
	(pointer_int_sum): Likewise.
	(pointer_diff): Likewise.
	(build_component_ref): Likewise.
	
	* typeck2.c (incomplete_type_error): Always use cp_error.
	Show declaration of undefined type, if appropriate.
	Deal with UNKNOWN_TYPE nodes.
	
	* typeck.c (require_complete_type): Use TYPE_SIZE as
	size_zero_node to mean incomplete type.
	(require_complete_type_in_void): New function.
	(build_compound_expr): Call complete_type_in_void for LHS.
	(build_c_cast): Call complete_type_in_void for void cast.
	* decl.c (cplus_expand_expr_stmt): Void expression checks moved to
	require_complete_type_in_void. Call it.
	* cp-tree.h (require_complete_type_in_void): Prototype new function.

	* typeck.c (convert_arguments): Use alternative format for function decls.
	Don't require_complete_type here. Simplify diagnostic printing.
	(convert_for_initialization): Don't require_complete_type on RHS yet.
	* call.c (convert_arg_to_ellipsis): Call require_complete_type.
	
	* call.c (build_over_call): Cope with qualified void return type.
	* semantics.c (finish_call_expr): Likewise
	* typeck.c (build_function_call_real): Likewise
	(c_expand_return): Likewise
	* decl2.c (reparse_absdcl_as_expr): Cope with qualified void type.
	
	
Index: egcs/gcc/cp/call.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/call.c,v
retrieving revision 1.130
diff -c -3 -p -r1.130 call.c
*** call.c	1999/01/25 20:43:13	1.130
--- call.c	1999/02/12 19:59:17
*************** convert_arg_to_ellipsis (arg)
*** 3175,3180 ****
--- 3175,3182 ----
      /* Convert `short' and `char' to full-size `int'.  */
      arg = default_conversion (arg);
  
+   arg = require_complete_type (arg);
+   
    return arg;
  }
  
*************** build_over_call (cand, args, flags)
*** 3515,3521 ****
        }
  
    fn = build_call (fn, TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), converted_args);
!   if (TREE_TYPE (fn) == void_type_node)
      return fn;
    fn = require_complete_type (fn);
    if (IS_AGGR_TYPE (TREE_TYPE (fn)))
--- 3517,3523 ----
        }
  
    fn = build_call (fn, TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), converted_args);
!   if (TREE_CODE (TREE_TYPE (fn)) == VOID_TYPE)
      return fn;
    fn = require_complete_type (fn);
    if (IS_AGGR_TYPE (TREE_TYPE (fn)))
Index: egcs/gcc/cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.306
diff -c -3 -p -r1.306 decl.c
*** decl.c	1999/02/05 02:42:48	1.306
--- decl.c	1999/02/12 19:59:25
*************** cplus_expand_expr_stmt (exp)
*** 14359,14396 ****
    /* Arrange for all temps to disappear.  */
    expand_start_target_temps ();
  
!   if (TREE_TYPE (exp) == unknown_type_node)
      {
!       if (TREE_CODE (exp) == COMPONENT_REF)
! 	error ("invalid reference to a member function name, did you forget the ()?");
!       else
! 	error ("address of overloaded function with no contextual type information");
      }
-   else
-     {
-       if (TREE_CODE (exp) == FUNCTION_DECL)
- 	{
- 	  cp_warning ("reference, not call, to function `%D'", exp);
- 	  warning ("at this point in file");
- 	}
  
  #if 0
!       /* We should do this eventually, but right now this causes regex.o from
! 	 libg++ to miscompile, and tString to core dump.  */
!       exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
  #endif
  
!       /* Strip unused implicit INDIRECT_REFs of references.  */
!       if (TREE_CODE (exp) == INDIRECT_REF
! 	  && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE)
! 	exp = TREE_OPERAND (exp, 0);
  
!       /* If we don't do this, we end up down inside expand_expr
! 	 trying to do TYPE_MODE on the ERROR_MARK, and really
! 	 go outside the bounds of the type.  */
!       if (exp != error_mark_node)
! 	expand_expr_stmt (break_out_cleanups (exp));
!     }
  
    /* Clean up any pending cleanups.  This happens when a function call
       returns a cleanup-needing value that nobody uses.  */
--- 14359,14388 ----
    /* Arrange for all temps to disappear.  */
    expand_start_target_temps ();
  
!   exp = require_complete_type_in_void (exp);
!   
!   if (TREE_CODE (exp) == FUNCTION_DECL)
      {
!       cp_warning ("reference, not call, to function `%D'", exp);
!       warning ("at this point in file");
      }
  
  #if 0
!   /* We should do this eventually, but right now this causes regex.o from
!      libg++ to miscompile, and tString to core dump.  */
!   exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
  #endif
  
!   /* Strip unused implicit INDIRECT_REFs of references.  */
!   if (TREE_CODE (exp) == INDIRECT_REF
!       && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE)
!     exp = TREE_OPERAND (exp, 0);
  
!   /* If we don't do this, we end up down inside expand_expr
!      trying to do TYPE_MODE on the ERROR_MARK, and really
!      go outside the bounds of the type.  */
!   if (exp != error_mark_node)
!     expand_expr_stmt (break_out_cleanups (exp));
  
    /* Clean up any pending cleanups.  This happens when a function call
       returns a cleanup-needing value that nobody uses.  */
Index: egcs/gcc/cp/decl2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl2.c,v
retrieving revision 1.180
diff -c -3 -p -r1.180 decl2.c
*** decl2.c	1999/02/07 15:44:08	1.180
--- decl2.c	1999/02/12 19:59:26
*************** reparse_absdcl_as_expr (type, decl)
*** 3513,3519 ****
  
    decl = build_x_function_call (decl, NULL_TREE, current_class_ref);
  
!   if (TREE_CODE (decl) == CALL_EXPR && TREE_TYPE (decl) != void_type_node)
      decl = require_complete_type (decl);
  
    return decl;
--- 3513,3521 ----
  
    decl = build_x_function_call (decl, NULL_TREE, current_class_ref);
  
!   if (TREE_CODE (decl) == CALL_EXPR
!       && (! TREE_TYPE (decl)
!           || TREE_CODE (TREE_TYPE (decl)) != VOID_TYPE))
      decl = require_complete_type (decl);
  
    return decl;
Index: egcs/gcc/cp/init.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/init.c,v
retrieving revision 1.87
diff -c -3 -p -r1.87 init.c
*** init.c	1999/01/26 20:23:34	1.87
--- init.c	1999/02/12 19:59:28
*************** build_new_1 (exp)
*** 2163,2169 ****
        true_type = TREE_TYPE (true_type);
      }
  
!   if (!complete_type_or_else (true_type))
      return error_mark_node;
  
    if (has_array)
--- 2163,2169 ----
        true_type = TREE_TYPE (true_type);
      }
  
!   if (!complete_type_or_else (true_type, exp))
      return error_mark_node;
  
    if (has_array)
*************** build_delete (type, addr, auto_delete, f
*** 3014,3020 ****
    if (TREE_CODE (type) == POINTER_TYPE)
      {
        type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
!       if (!complete_type_or_else (type))
  	return error_mark_node;
        if (TREE_CODE (type) == ARRAY_TYPE)
  	goto handle_array;
--- 3014,3020 ----
    if (TREE_CODE (type) == POINTER_TYPE)
      {
        type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
!       if (type != void_type_node && !complete_type_or_else (type, addr))
  	return error_mark_node;
        if (TREE_CODE (type) == ARRAY_TYPE)
  	goto handle_array;
Index: egcs/gcc/cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.258
diff -c -3 -p -r1.258 pt.c
*** pt.c	1999/02/07 15:44:10	1.258
--- pt.c	1999/02/12 19:59:33
*************** tsubst (t, args, in_decl)
*** 6099,6105 ****
  	   it's a partial instantiation.  */
  	if (!uses_template_parms (ctx)
  	    && !TYPE_BEING_DEFINED (ctx)
! 	    && !complete_type_or_else (ctx))
  	  return error_mark_node;
  
  	f = make_typename_type (ctx, f);
--- 6099,6105 ----
  	   it's a partial instantiation.  */
  	if (!uses_template_parms (ctx)
  	    && !TYPE_BEING_DEFINED (ctx)
! 	    && !complete_type_or_else (ctx, NULL_TREE))
  	  return error_mark_node;
  
  	f = make_typename_type (ctx, f);
Index: egcs/gcc/cp/semantics.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/semantics.c,v
retrieving revision 1.40
diff -c -3 -p -r1.40 semantics.c
*** semantics.c	1999/01/20 13:11:59	1.40
--- semantics.c	1999/02/12 19:59:34
*************** finish_call_expr (fn, args, koenig)
*** 855,861 ****
    result = build_x_function_call (fn, args, current_class_ref);
  
    if (TREE_CODE (result) == CALL_EXPR
!       && TREE_TYPE (result) != void_type_node)
      result = require_complete_type (result);
  
    return result;
--- 855,862 ----
    result = build_x_function_call (fn, args, current_class_ref);
  
    if (TREE_CODE (result) == CALL_EXPR
!       && (! TREE_TYPE (result)
!           || TREE_CODE (TREE_TYPE (result)) != VOID_TYPE))
      result = require_complete_type (result);
  
    return result;
Index: egcs/gcc/cp/typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.138
diff -c -3 -p -r1.138 typeck.c
*** typeck.c	1999/01/26 00:50:29	1.138
--- typeck.c	1999/02/12 19:59:39
*************** require_complete_type (value)
*** 100,106 ****
  
    /* First, detect a valid value with a complete type.  */
    if (TYPE_SIZE (type) != 0
!       && type != void_type_node
        && ! (TYPE_LANG_SPECIFIC (type)
  	    && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type))
  	    && TYPE_SIZE (SIGNATURE_TYPE (type)) == 0))
--- 100,106 ----
  
    /* First, detect a valid value with a complete type.  */
    if (TYPE_SIZE (type) != 0
!       && TYPE_SIZE (type) != size_zero_node
        && ! (TYPE_LANG_SPECIFIC (type)
  	    && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type))
  	    && TYPE_SIZE (SIGNATURE_TYPE (type)) == 0))
*************** require_complete_type (value)
*** 122,133 ****
        return require_complete_type (value);
      }
  
!   if (complete_type_or_else (type))
      return value;
    else
      return error_mark_node;
  }
  
  /* Try to complete TYPE, if it is incomplete.  For example, if TYPE is
     a template instantiation, do the instantiation.  Returns TYPE,
     whether or not it could be completed, unless something goes
--- 122,226 ----
        return require_complete_type (value);
      }
  
!   if (complete_type_or_else (type, value))
      return value;
    else
      return error_mark_node;
  }
  
+ /* Makes sure EXPR is a complete type when used in a void context, like a
+    whole expression, or lhs of a comma operator. Issue a diagnostic and
+    return error_mark_node on failure. This is a little tricky, because some
+    valid void types look stunningly similar to invalid void types. We err on
+    the side of caution */
+ 
+ tree
+ require_complete_type_in_void (expr)
+      tree expr;
+ {
+   switch (TREE_CODE (expr))
+     {
+     case COND_EXPR:
+       {
+         tree op;
+         
+         op = TREE_OPERAND (expr,2);
+         op = require_complete_type_in_void (op);
+         TREE_OPERAND (expr,2) = op;
+         if (op == error_mark_node)
+           {
+             expr = op;
+             break;
+           }
+         
+         /* fallthrough */
+       }
+     
+     case COMPOUND_EXPR:
+       {
+         tree op;
+         
+         op = TREE_OPERAND (expr,1);
+         op = require_complete_type_in_void (op);
+         TREE_OPERAND (expr,1) = op;
+         if (op == error_mark_node)
+           {
+             expr = op;
+             break;
+           }
+         
+         break;
+       }
+     
+     case NON_LVALUE_EXPR:
+     case NOP_EXPR:
+       {
+         tree op;
+         
+         op = TREE_OPERAND (expr,0);
+         op = require_complete_type_in_void (op);
+         TREE_OPERAND (expr,0) = op;
+         if (op == error_mark_node)
+           {
+             expr = op;
+             break;
+           }
+         break;
+       }
+     
+     case CALL_EXPR:   /* function call return can be ignored */
+     case RTL_EXPR:    /* RTL nodes have no value */
+     case DELETE_EXPR: /* delete expressions have no type */
+     case VEC_DELETE_EXPR:
+     case INTEGER_CST: /* used for null pointer */
+     case EXIT_EXPR:   /* have no return */
+     case LOOP_EXPR:   /* have no return */
+     case BIND_EXPR:   /* have no return */
+     case THROW_EXPR:  /* have no return */
+     case MODIFY_EXPR: /* sometimes this has a void type, but that's ok */
+     case CONVERT_EXPR:  /* sometimes has a void type */
+       break;
+     
+     case INDIRECT_REF:
+       {
+         tree op = TREE_OPERAND (expr,0);
+         
+         /* Calling a function returning a reference has an implicit
+            dereference applied. We don't want to make that an error. */
+         if (TREE_CODE (op) == CALL_EXPR
+             && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE)
+           break;
+         /* else fallthrough */
+       }
+     
+     default:
+       expr = require_complete_type (expr);
+       break;
+     }
+ 
+   return expr;
+ }
+ 
  /* Try to complete TYPE, if it is incomplete.  For example, if TYPE is
     a template instantiation, do the instantiation.  Returns TYPE,
     whether or not it could be completed, unless something goes
*************** complete_type (type)
*** 161,180 ****
  }
  
  /* Like complete_type, but issue an error if the TYPE cannot be
!    completed.  Returns NULL_TREE if the type cannot be made 
!    complete.  */
  
  tree
! complete_type_or_else (type)
       tree type;
  {
    type = complete_type (type);
    if (type == error_mark_node)
      /* We already issued an error.  */
      return NULL_TREE;
!   else if (!TYPE_SIZE (type))
      {
!       incomplete_type_error (NULL_TREE, type);
        return NULL_TREE;
      }
    else
--- 254,274 ----
  }
  
  /* Like complete_type, but issue an error if the TYPE cannot be
!    completed.  VALUE is used for informative diagnostics.
!    Returns NULL_TREE if the type cannot be made complete.  */
  
  tree
! complete_type_or_else (type, value)
       tree type;
+      tree value;
  {
    type = complete_type (type);
    if (type == error_mark_node)
      /* We already issued an error.  */
      return NULL_TREE;
!   else if (!TYPE_SIZE (type) || TYPE_SIZE (type) == size_zero_node)
      {
!       incomplete_type_error (value, type);
        return NULL_TREE;
      }
    else
*************** build_component_ref (datum, component, b
*** 1996,2002 ****
        return error_mark_node;
      }
  
!   if (!complete_type_or_else (basetype))
      return error_mark_node;
  
    if (TREE_CODE (component) == BIT_NOT_EXPR)
--- 2090,2096 ----
        return error_mark_node;
      }
  
!   if (!complete_type_or_else (basetype, datum))
      return error_mark_node;
  
    if (TREE_CODE (component) == BIT_NOT_EXPR)
*************** build_function_call_real (function, para
*** 2927,2933 ****
  
      if (require_complete)
        {
! 	if (value_type == void_type_node)
  	  return result;
  	result = require_complete_type (result);
        }
--- 3021,3027 ----
  
      if (require_complete)
        {
! 	if (TREE_CODE (value_type) == VOID_TYPE)
  	  return result;
  	result = require_complete_type (result);
        }
*************** convert_arguments (typelist, values, fnd
*** 3002,3008 ****
  	{
  	  if (fndecl)
  	    {
! 	      cp_error_at ("too many arguments to %s `%+D'", called_thing,
  			   fndecl);
  	      error ("at this point in file");
  	    }
--- 3096,3102 ----
  	{
  	  if (fndecl)
  	    {
! 	      cp_error_at ("too many arguments to %s `%+#D'", called_thing,
  			   fndecl);
  	      error ("at this point in file");
  	    }
*************** convert_arguments (typelist, values, fnd
*** 3031,3038 ****
  	      || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE
  	      || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)
  	    val = default_conversion (val);
- 
- 	  val = require_complete_type (val);
  	}
  
        if (val == error_mark_node)
--- 3125,3130 ----
*************** convert_arguments (typelist, values, fnd
*** 3107,3115 ****
  	{
  	  if (fndecl)
  	    {
! 	      char *buf = (char *)alloca (32 + strlen (called_thing));
! 	      sprintf (buf, "too few arguments to %s `%%#D'", called_thing);
! 	      cp_error_at (buf, fndecl);
  	      error ("at this point in file");
  	    }
  	  else
--- 3199,3206 ----
  	{
  	  if (fndecl)
  	    {
! 	      cp_error_at ("too few arguments to %s `%+#D'",
! 	                   called_thing, fndecl);
  	      error ("at this point in file");
  	    }
  	  else
*************** pointer_int_sum (resultcode, ptrop, into
*** 3989,3995 ****
  
    register tree result_type = TREE_TYPE (ptrop);
  
!   if (!complete_type_or_else (result_type))
      return error_mark_node;
  
    if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
--- 4080,4086 ----
  
    register tree result_type = TREE_TYPE (ptrop);
  
!   if (!complete_type_or_else (result_type, ptrop))
      return error_mark_node;
  
    if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
*************** pointer_diff (op0, op1, ptrtype)
*** 4081,4087 ****
    tree restype = ptrdiff_type_node;
    tree target_type = TREE_TYPE (ptrtype);
  
!   if (!complete_type_or_else (target_type))
      return error_mark_node;
  
    if (pedantic || warn_pointer_arith)
--- 4172,4178 ----
    tree restype = ptrdiff_type_node;
    tree target_type = TREE_TYPE (ptrtype);
  
!   if (!complete_type_or_else (target_type, NULL_TREE))
      return error_mark_node;
  
    if (pedantic || warn_pointer_arith)
*************** build_compound_expr (list)
*** 5294,5299 ****
--- 5385,5391 ----
       tree list;
  {
    register tree rest;
+   tree first;
  
    if (TREE_READONLY_DECL_P (TREE_VALUE (list)))
      TREE_VALUE (list) = decl_constant_value (TREE_VALUE (list));
*************** build_compound_expr (list)
*** 5313,5326 ****
  	return TREE_VALUE (list);
      }
  
    rest = build_compound_expr (TREE_CHAIN (list));
  
    /* When pedantic, a compound expression cannot be a constant expression.  */
!   if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)) && ! pedantic)
      return rest;
  
    return build (COMPOUND_EXPR, TREE_TYPE (rest),
! 		break_out_cleanups (TREE_VALUE (list)), rest);
  }
  
  tree
--- 5405,5425 ----
  	return TREE_VALUE (list);
      }
  
+   first = TREE_VALUE (list);
+   first = require_complete_type_in_void (first);
+   if (first == error_mark_node)
+     return error_mark_node;
+   
    rest = build_compound_expr (TREE_CHAIN (list));
+   if (rest == error_mark_node)
+     return error_mark_node;
  
    /* When pedantic, a compound expression cannot be a constant expression.  */
!   if (! TREE_SIDE_EFFECTS (first) && ! pedantic)
      return rest;
  
    return build (COMPOUND_EXPR, TREE_TYPE (rest),
! 		break_out_cleanups (first), rest);
  }
  
  tree
*************** build_c_cast (type, expr)
*** 5692,5698 ****
      warning ("cast to pointer from integer of different size");
  #endif
  
!   if (TREE_CODE (type) == REFERENCE_TYPE)
      value = (convert_from_reference
  	     (convert_to_reference (type, value, CONV_C_CAST,
  				    LOOKUP_COMPLAIN, NULL_TREE)));
--- 5791,5799 ----
      warning ("cast to pointer from integer of different size");
  #endif
  
!   if (TREE_CODE (type) == VOID_TYPE)
!     value = require_complete_type_in_void (value);
!   else if (TREE_CODE (type) == REFERENCE_TYPE)
      value = (convert_from_reference
  	     (convert_to_reference (type, value, CONV_C_CAST,
  				    LOOKUP_COMPLAIN, NULL_TREE)));
*************** convert_for_initialization (exp, type, r
*** 6973,6984 ****
  	}
        return rhs;
      }      
- 
-   rhs = require_complete_type (rhs);
-   if (rhs == error_mark_node)
-     return error_mark_node;
  
!   if (exp != 0) exp = require_complete_type (exp);
    if (exp == error_mark_node)
      return error_mark_node;
  
--- 7074,7082 ----
  	}
        return rhs;
      }      
  
!   if (exp != 0)
!     exp = require_complete_type (exp);
    if (exp == error_mark_node)
      return error_mark_node;
  
*************** c_expand_return (retval)
*** 7178,7184 ****
    if (retval == result
        || DECL_CONSTRUCTOR_P (current_function_decl))
      /* It's already done for us.  */;
!   else if (TREE_TYPE (retval) == void_type_node)
      {
        pedwarn ("return of void value in function returning non-void");
        expand_expr_stmt (retval);
--- 7276,7282 ----
    if (retval == result
        || DECL_CONSTRUCTOR_P (current_function_decl))
      /* It's already done for us.  */;
!   else if (TREE_CODE (TREE_TYPE (retval)) == VOID_TYPE)
      {
        pedwarn ("return of void value in function returning non-void");
        expand_expr_stmt (retval);
Index: egcs/gcc/cp/typeck2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck2.c,v
retrieving revision 1.49
diff -c -3 -p -r1.49 typeck2.c
*** typeck2.c	1999/02/06 17:12:29	1.49
--- typeck2.c	1999/02/12 19:59:40
***************
*** 1,6 ****
  /* Report error messages, build initializers, and perform
     some front-end optimizations for C++ compiler.
!    Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
     Hacked by Michael Tiemann (tiemann@cygnus.com)
  
  This file is part of GNU CC.
--- 1,6 ----
  /* Report error messages, build initializers, and perform
     some front-end optimizations for C++ compiler.
!    Copyright (C) 1987, 88, 89, 92-98, 1999 Free Software Foundation, Inc.
     Hacked by Michael Tiemann (tiemann@cygnus.com)
  
  This file is part of GNU CC.
*************** incomplete_type_error (value, type)
*** 213,267 ****
       tree value;
       tree type;
  {
-   char *errmsg = 0;
- 
    /* Avoid duplicate error message.  */
    if (TREE_CODE (type) == ERROR_MARK)
      return;
- 
-   if (value != 0 && (TREE_CODE (value) == VAR_DECL
- 		     || TREE_CODE (value) == PARM_DECL))
-     cp_error ("`%D' has incomplete type", value);
-   else
-     {
-     retry:
-       /* We must print an error message.  Be clever about what it says.  */
  
!       switch (TREE_CODE (type))
! 	{
! 	case RECORD_TYPE:
! 	case UNION_TYPE:
! 	case ENUMERAL_TYPE:
! 	  errmsg = "invalid use of undefined type `%#T'";
! 	  break;
! 
! 	case VOID_TYPE:
! 	  error ("invalid use of void expression");
! 	  return;
! 
! 	case ARRAY_TYPE:
! 	  if (TYPE_DOMAIN (type))
! 	    {
! 	      type = TREE_TYPE (type);
! 	      goto retry;
! 	    }
! 	  error ("invalid use of array with unspecified bounds");
! 	  return;
! 
! 	case OFFSET_TYPE:
! 	  error ("invalid use of member type (did you forget the `&' ?)");
! 	  return;
! 
! 	case TEMPLATE_TYPE_PARM:
! 	  error ("invalid use of template type parameter");
! 	  return;
! 
! 	default:
! 	  my_friendly_abort (108);
! 	}
  
!       cp_error (errmsg, type);
      }
  }
  
  /* Like error(), but don't call report_error_function().  */
--- 213,274 ----
       tree value;
       tree type;
  {
    /* Avoid duplicate error message.  */
    if (TREE_CODE (type) == ERROR_MARK)
      return;
  
! retry:
!   /* We must print an error message.  Be clever about what it says.  */
  
!   switch (TREE_CODE (type))
!     {
!     case RECORD_TYPE:
!     case UNION_TYPE:
!     case ENUMERAL_TYPE:
!       cp_error ("invalid use of undefined type `%#T'", type);
!       cp_error_at ("forward declaration of `%#T'", type);
!       break;
! 
!     case VOID_TYPE:
!       cp_error ("invalid use of void expression");
!       break;
! 
!     case ARRAY_TYPE:
!       if (TYPE_DOMAIN (type))
!         {
!           type = TREE_TYPE (type);
!           goto retry;
!         }
!       cp_error ("invalid use of array with unspecified bounds");
!       break;
! 
!     case OFFSET_TYPE:
!     bad_member:
!       cp_error ("invalid use of member (did you forget the `&' ?)");
!       break;
! 
!     case TEMPLATE_TYPE_PARM:
!       cp_error ("invalid use of template type parameter");
!       break;
! 
!     case UNKNOWN_TYPE:
!       if (value && TREE_CODE (value) == COMPONENT_REF)
!         goto bad_member;
!       else if (value && TREE_CODE (value) == ADDR_EXPR)
!         cp_error ("address of overloaded function with no contextual type information");
!       else if (value && TREE_CODE (value) == OVERLOAD)
!         cp_error ("overloaded function with no contextual type information");
!       else
!         cp_error ("insufficient contextual information to determine type");
!       break;
!     
!     default:
!       my_friendly_abort (108);
      }
+ 
+   if (value != 0 && (TREE_CODE (value) == VAR_DECL
+ 		     || TREE_CODE (value) == PARM_DECL))
+     cp_error_at ("incomplete `%D' defined here", value);
  }
  
  /* Like error(), but don't call report_error_function().  */
Index: egcs/gcc/cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.195
diff -c -3 -p -r1.195 cp-tree.h
*** cp-tree.h	1999/02/07 15:44:05	1.195
--- cp-tree.h	1999/02/12 19:59:43
*************** extern int string_conv_p			PROTO((tree, 
*** 3322,3329 ****
  extern tree condition_conversion		PROTO((tree));
  extern tree target_type				PROTO((tree));
  extern tree require_complete_type		PROTO((tree));
  extern tree complete_type			PROTO((tree));
! extern tree complete_type_or_else               PROTO((tree));
  extern int type_unknown_p			PROTO((tree));
  extern int fntype_p				PROTO((tree));
  extern tree commonparms				PROTO((tree, tree));
--- 3322,3330 ----
  extern tree condition_conversion		PROTO((tree));
  extern tree target_type				PROTO((tree));
  extern tree require_complete_type		PROTO((tree));
+ extern tree require_complete_type_in_void	PROTO((tree));
  extern tree complete_type			PROTO((tree));
! extern tree complete_type_or_else               PROTO((tree, tree));
  extern int type_unknown_p			PROTO((tree));
  extern int fntype_p				PROTO((tree));
  extern tree commonparms				PROTO((tree, tree));
Index: egcs/gcc/testsuite/g++.old-deja/g++.bugs/900121_01.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.bugs/900121_01.C,v
retrieving revision 1.2
diff -c -3 -p -r1.2 900121_01.C
*** 900121_01.C	1998/12/16 21:28:20	1.2
--- 900121_01.C	1999/02/12 19:59:43
***************
*** 6,12 ****
  
  // keywords: abort, incomplete types, reference types, formal parameters
  
! struct s0;
  
  void function (struct s0 &arg1, struct s0 &arg2)
  {
--- 6,12 ----
  
  // keywords: abort, incomplete types, reference types, formal parameters
  
! struct s0;              // ERROR - forward declaration
  
  void function (struct s0 &arg1, struct s0 &arg2)
  {
Index: egcs/gcc/testsuite/g++.old-deja/g++.bugs/900214_01.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.bugs/900214_01.C,v
retrieving revision 1.2
diff -c -3 -p -r1.2 900214_01.C
*** 900214_01.C	1998/12/16 21:28:53	1.2
--- 900214_01.C	1999/02/12 19:59:43
***************
*** 7,13 ****
  
  // keywords: friends, incomplete types, function members
  
! struct A;
  
  struct B {
    friend void A::foo();		// ERROR - type A is incomplete
--- 7,13 ----
  
  // keywords: friends, incomplete types, function members
  
! struct A;                       // ERROR - forward declaration
  
  struct B {
    friend void A::foo();		// ERROR - type A is incomplete
Index: egcs/gcc/testsuite/g++.old-deja/g++.bugs/900428_01.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.bugs/900428_01.C,v
retrieving revision 1.2
diff -c -3 -p -r1.2 900428_01.C
*** 900428_01.C	1998/12/16 21:29:34	1.2
--- 900428_01.C	1999/02/12 19:59:43
*************** int i;
*** 17,51 ****
  
  void *pv;
  volatile void *pvv;
! struct s;
! extern struct s es, *ps;
! extern volatile struct s evs, *pvs;
  
  void pv_test ()
  {
!   *pv;			// ERROR - , XFAIL *-*-*
!   (i ? *pv : *pv);	// ERROR - , XFAIL *-*-*
!   *pv, *pv;		// ERROR - , XFAIL *-*-*
! 
!   *pvv;			// ERROR - , XFAIL *-*-*
!   (i ? *pvv : *pvv);	// ERROR - , XFAIL *-*-*
!   *pvv, *pvv;		// ERROR - , XFAIL *-*-*
! 
!   es;			// ERROR - , XFAIL *-*-*
!   (i ? es : es);	// ERROR - , XFAIL *-*-*
!   es, es;		// ERROR - , XFAIL *-*-*
! 
!   evs;			// ERROR - , XFAIL *-*-*
!   (i ? evs : evs);	// ERROR - , XFAIL *-*-*
!   evs, evs;		// ERROR - , XFAIL *-*-*
! 
!   *ps;			// ERROR - , XFAIL *-*-*
!   (i ? *ps : *ps);	// ERROR - , XFAIL *-*-*
!   *ps, *ps;		// ERROR - , XFAIL *-*-*
! 
!   *pvs;			// ERROR - , XFAIL *-*-*
!   (i ? *pvs : *pvs);	// ERROR - , XFAIL *-*-*
!   *pvs, *pvs;		// ERROR - , XFAIL *-*-*
  }
  
  int main () { return 0; }
--- 17,51 ----
  
  void *pv;
  volatile void *pvv;
! struct s;               // ERROR - forward declaration
! extern struct s es, *ps;  // ERROR - defined here
! extern volatile struct s evs, *pvs; // ERROR - defined here
  
  void pv_test ()
  {
!   *pv;			// ERROR - invalid void
!   (i ? *pv : *pv);	// ERROR - invalid void
!   *pv, *pv;		// ERROR - invalid void
! 
!   *pvv;			// ERROR - invalid void
!   (i ? *pvv : *pvv);	// ERROR - invalid void
!   *pvv, *pvv;		// ERROR - invalid void
! 
!   es;			// ERROR - incomplete
!   (i ? es : es);	// ERROR - undefined type
!   es, es;		// ERROR - incomplete
! 
!   evs;			// ERROR - incomplete
!   (i ? evs : evs);	// ERROR - undefined type
!   evs, evs;		// ERROR - incomplete
! 
!   *ps;			// ERROR - undefined type
!   (i ? *ps : *ps);	// ERROR - undefined type
!   *ps, *ps;		// ERROR - undefined type
! 
!   *pvs;			// ERROR - undefined type
!   (i ? *pvs : *pvs);	// ERROR - undefined type
!   *pvs, *pvs;		// ERROR - undefined type
  }
  
  int main () { return 0; }
Index: egcs/gcc/testsuite/g++.old-deja/g++.mike/p7868.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.mike/p7868.C,v
retrieving revision 1.2
diff -c -3 -p -r1.2 p7868.C
*** p7868.C	1998/12/16 21:48:24	1.2
--- p7868.C	1999/02/12 19:59:43
***************
*** 4,16 ****
  struct DIAGTYP {
  };
  struct DIAGTYP1 {
!   struct DIAGTYP;
    void bar() { new struct DIAGTYP; }	// ERROR - undefined
    void foo() { new struct DIAGTYP1; }
  };
  
  int main () {
!   struct DIAGTYP;
    struct DIAGTYP  *lerror_desc;
    lerror_desc= new struct DIAGTYP;	// ERROR - undefined
  }
--- 4,16 ----
  struct DIAGTYP {
  };
  struct DIAGTYP1 {
!   struct DIAGTYP;       // ERROR - forward declaration
    void bar() { new struct DIAGTYP; }	// ERROR - undefined
    void foo() { new struct DIAGTYP1; }
  };
  
  int main () {
!   struct DIAGTYP;               // ERROR - forward declaration
    struct DIAGTYP  *lerror_desc;
    lerror_desc= new struct DIAGTYP;	// ERROR - undefined
  }
Index: egcs/gcc/testsuite/g++.old-deja/g++.pt/crash5.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/crash5.C,v
retrieving revision 1.2
diff -c -3 -p -r1.2 crash5.C
*** crash5.C	1998/12/16 21:54:26	1.2
--- crash5.C	1999/02/12 19:59:43
***************
*** 3,9 ****
  template <class T, int i>
  struct K {
  	void f();
! };
  
  template <class T>
  void
--- 3,9 ----
  template <class T, int i>
  struct K {
  	void f();
! };  // ERROR - forward declaration
  
  template <class T>
  void
Index: egcs/gcc/testsuite/g++.old-deja/g++.pt/typename8.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/typename8.C,v
retrieving revision 1.2
diff -c -3 -p -r1.2 typename8.C
*** typename8.C	1998/12/16 22:02:32	1.2
--- typename8.C	1999/02/12 19:59:43
*************** public:
*** 16,22 ****
    }
  };
  
! class B : public A< B >
  {
  public:
    typedef int myT;
--- 16,22 ----
    }
  };
  
! class B : public A< B > // ERROR - forward declaration
  {
  public:
    typedef int myT;


More information about the Gcc-patches mailing list