This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH: 14035


This patch fixes PR c++/14035.  This PR was opened because of a cast
where we generated wrong-code for a C-style cast.  In particular, we
generated a copy constructor call instead of a derived-to-base
conversion.

The underlying problem was that we were not handling C-style casts as
one of const_cast, static_cast, or reinterpret_cast as required by
the standard.  (There are a few extra bits, but that's the basic
idea.)  So, I fixed that.

In the process, I found several other bugs:

1) We were accepting invalid const_casts:

+ struct B {};
+ struct D : public B {};
+ 
+ typedef int B::*bm;
+ typedef int D::*dm;
+ 
+ bm bp;
+ 
+ void f() {
+   const_cast<dm>(bp); // { dg-error "" }
+ }

2) And not accepting valid reinterpret_casts:

+ bool b;
+ 
+ void f() {
+   reinterpret_cast<void*>(b);
+ }

3) But accepting some other invalid reinterpret_casts:

+ struct S {};
+ 
+ S s;
+ 
+ void f() {
+   reinterpret_cast<const S>(s); // { dg-error "" }
+ }

4) And some C-style casts:

+ void (*p)();
+ 
+ void f() {
+   (void *)p; // { dg-error "" }
+ }

All of these were corrected.  The last one is only a pedwarn with
-pedantic, as casting function pointers to ordinary pointers types is
an extension we clearly want to support in the default mode.

I've also pruned out a few more uses of ocp_convert, which we should
eventually excise completely.

Tested on i686-pc-linux-gnu, applied on the mainline.  Although this
is a regression in 3.4, I do not intend to apply the patch there; I
think it's too invasive.  I'll be closing the PR shortly.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2004-10-19  Mark Mitchell  <mark@codesourcery.com>

	PR c++/14035
	* call.c (struct conversion): Add base_p.
	(convert_like): Add c_cast_p argument.
	(convert_like_with_conversion): Likewise.
	(build_conv): Clear base_p.
	(standard_conversion): Set it, for derived-to-base conversions.
	(convert_like_real): Add c_cast_p parameter.  Handle pointer
	conversions directly rather than relying on ocp_convert.
	(perform_direct_initialization_if_possible): Add c_cast_p
	parameter.
	* cp-tree.h (perform_direct_initialization_if_possible): Change
	prototype.
	(convert_member_func_to_ptr): New function.
	* typeck.c (check_for_casting_away_constness): Add diag_fn
	parameter.
	(build_static_cast_1): New function, split out from ...
	(build_static_cast): ... here.  Use build_static_cast_1.
	(build_reinterpret_cast_1): New function, split out from ...
	(build_reinterpret_cast): ... here.  Use build_reinterpret_cast_1.
	(build_const_cast_1): New function, split out from ...
	(build_const_cast): ... here.  Use build_const_cast_1.
	(build_c_cast): Rewrite to use build_const_cast_1,
	build_static_cast_1, and build_reinterpret_cast_1.
	(convert_member_func_to_ptr): New function.

2004-10-19  Mark Mitchell  <mark@codesourcery.com>

	PR c++/14035
	* g++.dg/conversion/reinterpret1.C: Adjust error markers.
	* g++.dg/conversion/const2.C: New test.
	* g++.dg/expr/reinterpret2.C: New test.
	* g++.dg/expr/reinterpret3.C: New test.
	* g++.dg/expr/cast2.C: New test.
	* g++.dg/expr/copy1.C: New test.
	* g++.dg/other/conversion1.C: Change error message.
	* g++.dg/parse/comma1.C: Use __extension__ to allow casts from
	function pointers to void *.
	* g++.old-deja/g++.mike/p10148.C: Likewise.

Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.513
diff -c -5 -p -r1.513 call.c
*** cp/call.c	18 Oct 2004 17:21:24 -0000	1.513
--- cp/call.c	19 Oct 2004 23:19:33 -0000
*************** struct conversion {
*** 90,99 ****
--- 90,102 ----
    BOOL_BITFIELD need_temporary_p : 1;
    /* If KIND is ck_identity or ck_base_conv, true to indicate that the
       copy constructor must be accessible, even though it is not being
       used.  */
    BOOL_BITFIELD check_copy_constructor_p : 1;
+   /* If KIND is ck_ptr, true to indicate that a conversion from a
+      pointer-to-derived to pointer-to-base is being performed.  */
+   BOOL_BITFIELD base_p : 1;
    /* The type of the expression resulting from the conversion.  */
    tree type;
    union {
      /* The next conversion in the chain.  Since the conversions are
         arranged from outermost to innermost, the NEXT conversion will
*************** static int equal_functions (tree, tree);
*** 123,138 ****
  static int joust (struct z_candidate *, struct z_candidate *, bool);
  static int compare_ics (conversion *, conversion *);
  static tree build_over_call (struct z_candidate *, int);
  static tree build_java_interface_fn_ref (tree, tree);
  #define convert_like(CONV, EXPR)				\
!   convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0, 		\
! 		     /*issue_conversion_warnings=*/true)
  #define convert_like_with_context(CONV, EXPR, FN, ARGNO)	\
!   convert_like_real ((CONV), (EXPR), (FN), (ARGNO), 0, 		\
! 		     /*issue_conversion_warnings=*/true)
! static tree convert_like_real (conversion *, tree, tree, int, int, bool);
  static void op_error (enum tree_code, enum tree_code, tree, tree,
  			    tree, const char *);
  static tree build_object_call (tree, tree);
  static tree resolve_args (tree);
  static struct z_candidate *build_user_type_conversion_1 (tree, tree, int);
--- 126,144 ----
  static int joust (struct z_candidate *, struct z_candidate *, bool);
  static int compare_ics (conversion *, conversion *);
  static tree build_over_call (struct z_candidate *, int);
  static tree build_java_interface_fn_ref (tree, tree);
  #define convert_like(CONV, EXPR)				\
!   convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0,		\
! 		     /*issue_conversion_warnings=*/true,	\
! 		     /*c_cast_p=*/false)
  #define convert_like_with_context(CONV, EXPR, FN, ARGNO)	\
!   convert_like_real ((CONV), (EXPR), (FN), (ARGNO), 0,		\
! 		     /*issue_conversion_warnings=*/true,	\
!                      /*c_cast_p=*/false)
! static tree convert_like_real (conversion *, tree, tree, int, int, bool,
! 			       bool);
  static void op_error (enum tree_code, enum tree_code, tree, tree,
  			    tree, const char *);
  static tree build_object_call (tree, tree);
  static tree resolve_args (tree);
  static struct z_candidate *build_user_type_conversion_1 (tree, tree, int);
*************** build_conv (conversion_kind code, tree t
*** 526,535 ****
--- 532,542 ----
        break;
      }
    t->rank = rank;
    t->user_conv_p = (code == ck_user || from->user_conv_p);
    t->bad_p = from->bad_p;
+   t->base_p = false;
    return t;
  }
  
  /* Build a representation of the identity conversion from EXPR to
     itself.  The TYPE should match the the type of EXPR, if EXPR is
*************** standard_conversion (tree to, tree from,
*** 719,728 ****
--- 726,736 ----
  	  from = 
  	    cp_build_qualified_type (TREE_TYPE (to),
  				     cp_type_quals (TREE_TYPE (from)));
  	  from = build_pointer_type (from);
  	  conv = build_conv (ck_ptr, from, conv);
+ 	  conv->base_p = true;
  	}
  
        if (tcode == POINTER_TYPE)
  	{
  	  to_pointee = TREE_TYPE (to);
*************** build_temp (tree expr, tree type, int fl
*** 4111,4125 ****
     ARGNUM are used for diagnostics.  ARGNUM is zero based, -1
     indicates the `this' argument of a method.  INNER is nonzero when
     being called to continue a conversion chain. It is negative when a
     reference binding will be applied, positive otherwise.  If
     ISSUE_CONVERSION_WARNINGS is true, warnings about suspicious
!    conversions will be emitted if appropriate.  */
  
  static tree
  convert_like_real (conversion *convs, tree expr, tree fn, int argnum, 
! 		   int inner, bool issue_conversion_warnings)
  {
    tree totype = convs->type;
    void (*diagnostic_fn)(const char *, ...);
  
    if (convs->bad_p
--- 4119,4136 ----
     ARGNUM are used for diagnostics.  ARGNUM is zero based, -1
     indicates the `this' argument of a method.  INNER is nonzero when
     being called to continue a conversion chain. It is negative when a
     reference binding will be applied, positive otherwise.  If
     ISSUE_CONVERSION_WARNINGS is true, warnings about suspicious
!    conversions will be emitted if appropriate.  If C_CAST_P is true,
!    this conversion is coming from a C-style cast; in that case,
!    conversions to inaccessible bases are permitted.  */
  
  static tree
  convert_like_real (conversion *convs, tree expr, tree fn, int argnum, 
! 		   int inner, bool issue_conversion_warnings,
! 		   bool c_cast_p)
  {
    tree totype = convs->type;
    void (*diagnostic_fn)(const char *, ...);
  
    if (convs->bad_p
*************** convert_like_real (conversion *convs, tr
*** 4131,4146 ****
        for (; t; t = convs->u.next)
  	{
  	  if (t->kind == ck_user || !t->bad_p)
  	    {
  	      expr = convert_like_real (t, expr, fn, argnum, 1,
! 					/*issue_conversion_warnings=*/false);
  	      break;
  	    }
  	  else if (t->kind == ck_ambig)
  	    return convert_like_real (t, expr, fn, argnum, 1,
! 				      /*issue_conversion_warnings=*/false);
  	  else if (t->kind == ck_identity)
  	    break;
  	}
        pedwarn ("invalid conversion from %qT to %qT", TREE_TYPE (expr), totype);
        if (fn)
--- 4142,4159 ----
        for (; t; t = convs->u.next)
  	{
  	  if (t->kind == ck_user || !t->bad_p)
  	    {
  	      expr = convert_like_real (t, expr, fn, argnum, 1,
! 					/*issue_conversion_warnings=*/false,
! 					/*c_cast_p=*/false);
  	      break;
  	    }
  	  else if (t->kind == ck_ambig)
  	    return convert_like_real (t, expr, fn, argnum, 1,
! 				      /*issue_conversion_warnings=*/false,
! 				      /*c_cast_p=*/false);
  	  else if (t->kind == ck_identity)
  	    break;
  	}
        pedwarn ("invalid conversion from %qT to %qT", TREE_TYPE (expr), totype);
        if (fn)
*************** convert_like_real (conversion *convs, tr
*** 4235,4245 ****
        break;
      };
  
    expr = convert_like_real (convs->u.next, expr, fn, argnum,
  			    convs->kind == ck_ref_bind ? -1 : 1,
! 			    /*issue_conversion_warnings=*/false);
    if (expr == error_mark_node)
      return error_mark_node;
  
    switch (convs->kind)
      {
--- 4248,4259 ----
        break;
      };
  
    expr = convert_like_real (convs->u.next, expr, fn, argnum,
  			    convs->kind == ck_ref_bind ? -1 : 1,
! 			    /*issue_conversion_warnings=*/false,
! 			    c_cast_p);
    if (expr == error_mark_node)
      return error_mark_node;
  
    switch (convs->kind)
      {
*************** convert_like_real (conversion *convs, tr
*** 4319,4329 ****
  
      case ck_qual:
        /* Warn about deprecated conversion if appropriate.  */
        string_conv_p (totype, expr, 1);
        break;
!       
      default:
        break;
      }
    return ocp_convert (totype, expr, CONV_IMPLICIT,
  		      LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
--- 4333,4358 ----
  
      case ck_qual:
        /* Warn about deprecated conversion if appropriate.  */
        string_conv_p (totype, expr, 1);
        break;
! 
!     case ck_ptr:
!       if (convs->base_p)
! 	{
! 	  tree binfo;
! 
! 	  binfo = lookup_base (TREE_TYPE (TREE_TYPE (expr)),
! 			       TREE_TYPE (totype), 
! 			       c_cast_p ? ba_unique : ba_check,
! 			       NULL);
! 	  if (binfo == error_mark_node)
! 	    return error_mark_node;
! 	  expr = build_base_path (PLUS_EXPR, expr, binfo, /*nonnull=*/0);
! 	}
!       return build_nop (totype, expr);
! 
      default:
        break;
      }
    return ocp_convert (totype, expr, CONV_IMPLICIT,
  		      LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
*************** perform_implicit_conversion (tree type, 
*** 6271,6284 ****
  }
  
  /* Convert EXPR to TYPE (as a direct-initialization) if that is
     permitted.  If the conversion is valid, the converted expression is
     returned.  Otherwise, NULL_TREE is returned, except in the case
!    that TYPE is a class type; in that case, an error is issued.  */
  
  tree
! perform_direct_initialization_if_possible (tree type, tree expr)
  {
    conversion *conv;
    void *p;
  
    if (type == error_mark_node || error_operand_p (expr))
--- 6300,6318 ----
  }
  
  /* Convert EXPR to TYPE (as a direct-initialization) if that is
     permitted.  If the conversion is valid, the converted expression is
     returned.  Otherwise, NULL_TREE is returned, except in the case
!    that TYPE is a class type; in that case, an error is issued.  If
!    C_CAST_P is ttrue, then this direction initialization is taking
!    place as part of a static_cast being attempted as part of a C-style
!    cast.  */
  
  tree
! perform_direct_initialization_if_possible (tree type, 
! 					   tree expr,
! 					   bool c_cast_p)
  {
    conversion *conv;
    void *p;
  
    if (type == error_mark_node || error_operand_p (expr))
*************** perform_direct_initialization_if_possibl
*** 6306,6316 ****
  			      LOOKUP_NORMAL);
    if (!conv || conv->bad_p)
      expr = NULL_TREE;
    else
      expr = convert_like_real (conv, expr, NULL_TREE, 0, 0, 
! 			      /*issue_conversion_warnings=*/false);
  
    /* Free all the conversions we allocated.  */
    obstack_free (&conversion_obstack, p);
  
    return expr;
--- 6340,6351 ----
  			      LOOKUP_NORMAL);
    if (!conv || conv->bad_p)
      expr = NULL_TREE;
    else
      expr = convert_like_real (conv, expr, NULL_TREE, 0, 0, 
! 			      /*issue_conversion_warnings=*/false,
! 			      c_cast_p);
  
    /* Free all the conversions we allocated.  */
    obstack_free (&conversion_obstack, p);
  
    return expr;
*************** initialize_reference (tree type, tree ex
*** 6447,6457 ****
  	base_conv_type = NULL_TREE;
        /* Perform the remainder of the conversion.  */
        expr = convert_like_real (conv, expr,
  				/*fn=*/NULL_TREE, /*argnum=*/0,
  				/*inner=*/-1,
! 				/*issue_conversion_warnings=*/true);
        if (!real_lvalue_p (expr))
  	{
  	  tree init;
  	  tree type;
  
--- 6482,6493 ----
  	base_conv_type = NULL_TREE;
        /* Perform the remainder of the conversion.  */
        expr = convert_like_real (conv, expr,
  				/*fn=*/NULL_TREE, /*argnum=*/0,
  				/*inner=*/-1,
! 				/*issue_conversion_warnings=*/true,
! 				/*c_cast_p=*/false);
        if (!real_lvalue_p (expr))
  	{
  	  tree init;
  	  tree type;
  
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.1064
diff -c -5 -p -r1.1064 cp-tree.h
*** cp/cp-tree.h	18 Oct 2004 17:21:22 -0000	1.1064
--- cp/cp-tree.h	19 Oct 2004 23:19:33 -0000
*************** extern tree cp_convert_parm_for_inlining
*** 3583,3593 ****
  extern bool is_properly_derived_from (tree, tree);
  extern tree initialize_reference (tree, tree, tree, tree *);
  extern tree make_temporary_var_for_ref_to_temp (tree, tree);
  extern tree strip_top_quals (tree);
  extern tree perform_implicit_conversion (tree, tree);
! extern tree perform_direct_initialization_if_possible (tree, tree);
  extern tree in_charge_arg_for_name (tree);
  extern tree build_cxx_call (tree, tree);
  #ifdef ENABLE_CHECKING
  extern void validate_conversion_obstack (void);
  #endif /* ENABLE_CHECKING */
--- 3583,3593 ----
  extern bool is_properly_derived_from (tree, tree);
  extern tree initialize_reference (tree, tree, tree, tree *);
  extern tree make_temporary_var_for_ref_to_temp (tree, tree);
  extern tree strip_top_quals (tree);
  extern tree perform_implicit_conversion (tree, tree);
! extern tree perform_direct_initialization_if_possible (tree, tree, bool);
  extern tree in_charge_arg_for_name (tree);
  extern tree build_cxx_call (tree, tree);
  #ifdef ENABLE_CHECKING
  extern void validate_conversion_obstack (void);
  #endif /* ENABLE_CHECKING */
*************** extern tree build_ptrmemfunc_access_expr
*** 4288,4297 ****
--- 4288,4298 ----
  extern tree build_address                       (tree);
  extern tree build_nop                           (tree, tree);
  extern tree non_reference                       (tree);
  extern tree lookup_anon_field                   (tree, tree);
  extern bool invalid_nonstatic_memfn_p           (tree);
+ extern tree convert_member_func_to_ptr          (tree, tree);
  
  /* in typeck2.c */
  extern void require_complete_eh_spec_types	(tree, tree);
  extern void cxx_incomplete_type_diagnostic	(tree, tree, int);
  #undef cxx_incomplete_type_error
Index: cp/cvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cvt.c,v
retrieving revision 1.168
diff -c -5 -p -r1.168 cvt.c
*** cp/cvt.c	18 Oct 2004 17:21:28 -0000	1.168
--- cp/cvt.c	19 Oct 2004 23:19:33 -0000
*************** cp_convert_to_pointer (tree type, tree e
*** 105,136 ****
    /* Handle anachronistic conversions from (::*)() to cv void* or (*)().  */
    if (TREE_CODE (type) == POINTER_TYPE
        && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
  	  || VOID_TYPE_P (TREE_TYPE (type))))
      {
!       /* Allow an implicit this pointer for pointer to member
! 	 functions.  */
!       if (TYPE_PTRMEMFUNC_P (intype))
! 	{
! 	  if (pedantic || warn_pmf2ptr)
! 	    pedwarn ("converting from `%T' to `%T'", intype, type);
! 	  if (TREE_CODE (expr) == PTRMEM_CST)
! 	    expr = build_address (PTRMEM_CST_MEMBER (expr));
! 	  else
! 	    {
! 	      tree decl = maybe_dummy_object (TYPE_PTRMEM_CLASS_TYPE (intype), 
! 					      0);
! 	      decl = build_address (decl);
! 	      expr = get_member_function_from_ptrfunc (&decl, expr);
! 	    }
! 	}
!       else if (TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE)
! 	{
! 	  if (pedantic || warn_pmf2ptr)
! 	    pedwarn ("converting from `%T' to `%T'", intype, type);
! 	  expr = build_addr_func (expr);
! 	}
        if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
  	return build_nop (type, expr);
        intype = TREE_TYPE (expr);
      }
  
--- 105,117 ----
    /* Handle anachronistic conversions from (::*)() to cv void* or (*)().  */
    if (TREE_CODE (type) == POINTER_TYPE
        && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
  	  || VOID_TYPE_P (TREE_TYPE (type))))
      {
!       if (TYPE_PTRMEMFUNC_P (intype)
! 	  || TREE_CODE (intype) == METHOD_TYPE)
! 	return convert_member_func_to_ptr (type, expr);
        if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
  	return build_nop (type, expr);
        intype = TREE_TYPE (expr);
      }
  
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.583
diff -c -5 -p -r1.583 typeck.c
*** cp/typeck.c	18 Oct 2004 17:21:29 -0000	1.583
--- cp/typeck.c	19 Oct 2004 23:19:33 -0000
*************** build_compound_expr (tree lhs, tree rhs)
*** 4466,4516 ****
      }
    
    return build2 (COMPOUND_EXPR, TREE_TYPE (rhs), lhs, rhs);
  }
  
! /* Issue an error message if casting from SRC_TYPE to DEST_TYPE casts
!    away constness.  DESCRIPTION explains what operation is taking
!    place.  */
  
  static void
  check_for_casting_away_constness (tree src_type, tree dest_type,
  				  const char *description)
  {
!   if (casts_away_constness (src_type, dest_type))
      error ("%s from type %qT to type %qT casts away constness",
  	   description, src_type, dest_type);
  }
  
! /* Return an expression representing static_cast<TYPE>(EXPR).  */
  
! tree
! build_static_cast (tree type, tree expr)
  {
    tree intype;
    tree result;
  
!   if (type == error_mark_node || expr == error_mark_node)
!     return error_mark_node;
! 
!   if (processing_template_decl)
!     {
!       expr = build_min (STATIC_CAST_EXPR, type, expr);
!       /* We don't know if it will or will not have side effects.  */
!       TREE_SIDE_EFFECTS (expr) = 1;
!       return expr;
!     }
! 
!   /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
!      Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
!   if (TREE_CODE (type) != REFERENCE_TYPE
!       && TREE_CODE (expr) == NOP_EXPR
!       && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
!     expr = TREE_OPERAND (expr, 0);
  
    intype = TREE_TYPE (expr);
  
    /* [expr.static.cast]
  
       An lvalue of type "cv1 B", where B is a class type, can be cast
       to type "reference to cv2 D", where D is a class derived (clause
       _class.derived_) from B, if a valid standard conversion from
--- 4466,4527 ----
      }
    
    return build2 (COMPOUND_EXPR, TREE_TYPE (rhs), lhs, rhs);
  }
  
! /* Issue a diagnostic message if casting from SRC_TYPE to DEST_TYPE
!    casts away constness.  DIAG_FN gives the function to call if we
!    need to issue a diagnostic; if it is NULL, no diagnostic will be
!    issued.  DESCRIPTION explains what operation is taking place.  */
  
  static void
  check_for_casting_away_constness (tree src_type, tree dest_type,
+ 				  void (*diag_fn)(const char *, ...),
  				  const char *description)
  {
!   if (diag_fn && casts_away_constness (src_type, dest_type))
      error ("%s from type %qT to type %qT casts away constness",
  	   description, src_type, dest_type);
  }
  
! /* Perform a static_cast from EXPR to TYPE.  When C_CAST_P is true,
!    this static_cast is being attempted as one of the possible casts
!    allowed by a C-style cast.  (In that case, accessibility of base
!    classes is not considered, and it is OK to cast away
!    constness.)  Return the result of the cast.  *VALID_P is set to
!    indicate whether or not the cast was valid.  */
  
! static tree
! build_static_cast_1 (tree type, tree expr, bool c_cast_p,
! 		     bool *valid_p)
  {
    tree intype;
    tree result;
+   tree orig;
+   void (*diag_fn)(const char*, ...);
+   const char *desc;
  
!   /* Assume the cast is valid.  */
!   *valid_p = true;
  
    intype = TREE_TYPE (expr);
  
+   /* Determine what to do when casting away constness.  */
+   if (c_cast_p)
+     {
+       /* C-style casts are allowed to cast away constness.  With
+ 	 WARN_CAST_QUAL, we still want to issue a warning.  */ 
+       diag_fn = warn_cast_qual ? warning : NULL;
+       desc = "cast";
+     }
+   else
+     {
+       /* A static_cast may not cast away constness.  */
+       diag_fn = error;
+       desc = "static_cast";
+     }
+       
    /* [expr.static.cast]
  
       An lvalue of type "cv1 B", where B is a class type, can be cast
       to type "reference to cv2 D", where D is a class derived (clause
       _class.derived_) from B, if a valid standard conversion from
*************** build_static_cast (tree type, tree expr)
*** 4534,4569 ****
        && real_lvalue_p (expr)
        && DERIVED_FROM_P (intype, TREE_TYPE (type))
        && can_convert (build_pointer_type (TYPE_MAIN_VARIANT (intype)),
  		      build_pointer_type (TYPE_MAIN_VARIANT 
  					  (TREE_TYPE (type))))
!       && at_least_as_qualified_p (TREE_TYPE (type), intype))
      {
        /* There is a standard conversion from "D*" to "B*" even if "B"
! 	 is ambiguous or inaccessible.  Therefore, we ask lookup_base
! 	 to check these conditions.  */
!       tree base = lookup_base (TREE_TYPE (type), intype, ba_check, NULL);
  
        /* Convert from "B*" to "D*".  This function will check that "B"
  	 is not a virtual base of "D".  */
        expr = build_base_path (MINUS_EXPR, build_address (expr), 
  			      base, /*nonnull=*/false);
        /* Convert the pointer to a reference -- but then remember that
  	 there are no expressions with reference type in C++.  */
        return convert_from_reference (build_nop (type, expr));
      }
  
    /* [expr.static.cast]
  
       An expression e can be explicitly converted to a type T using a
       static_cast of the form static_cast<T>(e) if the declaration T
       t(e);" is well-formed, for some invented temporary variable
       t.  */
!   result = perform_direct_initialization_if_possible (type, expr);
    if (result)
      {
        result = convert_from_reference (result);
        /* [expr.static.cast]
  
           If T is a reference type, the result is an lvalue; otherwise,
  	 the result is an rvalue.  */
        if (TREE_CODE (type) != REFERENCE_TYPE
--- 4545,4600 ----
        && real_lvalue_p (expr)
        && DERIVED_FROM_P (intype, TREE_TYPE (type))
        && can_convert (build_pointer_type (TYPE_MAIN_VARIANT (intype)),
  		      build_pointer_type (TYPE_MAIN_VARIANT 
  					  (TREE_TYPE (type))))
!       && (c_cast_p
! 	  || at_least_as_qualified_p (TREE_TYPE (type), intype)))
      {
+       tree base;
+ 
        /* There is a standard conversion from "D*" to "B*" even if "B"
! 	 is ambiguous or inaccessible.  If this is really a
! 	 static_cast, then we check both for inaccessibility and
! 	 ambiguity.  However, if this is a static_cast being performed
! 	 because the user wrote a C-style cast, then accessibility is
! 	 not considered.  */
!       base = lookup_base (TREE_TYPE (type), intype, 
! 			  c_cast_p ? ba_unique : ba_check, 
! 			  NULL);
  
        /* Convert from "B*" to "D*".  This function will check that "B"
  	 is not a virtual base of "D".  */
        expr = build_base_path (MINUS_EXPR, build_address (expr), 
  			      base, /*nonnull=*/false);
        /* Convert the pointer to a reference -- but then remember that
  	 there are no expressions with reference type in C++.  */
        return convert_from_reference (build_nop (type, expr));
      }
  
+   orig = expr;
+ 
    /* [expr.static.cast]
  
       An expression e can be explicitly converted to a type T using a
       static_cast of the form static_cast<T>(e) if the declaration T
       t(e);" is well-formed, for some invented temporary variable
       t.  */
!   result = perform_direct_initialization_if_possible (type, expr,
! 						      c_cast_p);
    if (result)
      {
        result = convert_from_reference (result);
+ 
+       /* Ignore any integer overflow caused by the cast.  */
+       if (TREE_CODE (result) == INTEGER_CST
+ 	  && CONSTANT_CLASS_P (orig))
+ 	{
+ 	  TREE_OVERFLOW (result) = TREE_OVERFLOW (orig);
+ 	  TREE_CONSTANT_OVERFLOW (result)
+ 	    = TREE_CONSTANT_OVERFLOW (orig);
+ 	}
        /* [expr.static.cast]
  
           If T is a reference type, the result is an lvalue; otherwise,
  	 the result is an rvalue.  */
        if (TREE_CODE (type) != REFERENCE_TYPE
*************** build_static_cast (tree type, tree expr)
*** 4596,4621 ****
  
           A value of integral _or enumeration_ type can be explicitly
  	 converted to an enumeration type.  */
        || (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
  	  && INTEGRAL_OR_ENUMERATION_TYPE_P (intype)))
!     /* Really, build_c_cast should defer to this function rather
!        than the other way around.  */
!     return build_c_cast (type, expr);
!   
    if (TYPE_PTR_P (type) && TYPE_PTR_P (intype)
        && CLASS_TYPE_P (TREE_TYPE (type))
        && CLASS_TYPE_P (TREE_TYPE (intype))
        && can_convert (build_pointer_type (TYPE_MAIN_VARIANT 
  					  (TREE_TYPE (intype))), 
  		      build_pointer_type (TYPE_MAIN_VARIANT 
  					  (TREE_TYPE (type)))))
      {
        tree base;
  
!       check_for_casting_away_constness (intype, type, "static_cast");
!       base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype), ba_check, 
  			  NULL);
        return build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false);
      }
    
    if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
--- 4627,4664 ----
  
           A value of integral _or enumeration_ type can be explicitly
  	 converted to an enumeration type.  */
        || (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
  	  && INTEGRAL_OR_ENUMERATION_TYPE_P (intype)))
!     {
!       expr = decl_constant_value (expr);
!       expr = ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL);
! 
!       /* Ignore any integer overflow caused by the cast.  */
!       if (TREE_CODE (expr) == INTEGER_CST
! 	  && CONSTANT_CLASS_P (orig))
! 	{
! 	  TREE_OVERFLOW (expr) = TREE_OVERFLOW (orig);
! 	  TREE_CONSTANT_OVERFLOW (expr) = TREE_CONSTANT_OVERFLOW (orig);
! 	}
!       return expr;
!     }
! 
    if (TYPE_PTR_P (type) && TYPE_PTR_P (intype)
        && CLASS_TYPE_P (TREE_TYPE (type))
        && CLASS_TYPE_P (TREE_TYPE (intype))
        && can_convert (build_pointer_type (TYPE_MAIN_VARIANT 
  					  (TREE_TYPE (intype))), 
  		      build_pointer_type (TYPE_MAIN_VARIANT 
  					  (TREE_TYPE (type)))))
      {
        tree base;
  
!       if (!c_cast_p)
! 	check_for_casting_away_constness (intype, type, diag_fn, desc);
!       base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype), 
! 			  c_cast_p ? ba_unique : ba_check, 
  			  NULL);
        return build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false);
      }
    
    if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
*************** build_static_cast (tree type, tree expr)
*** 4643,4653 ****
  	  t1 = intype;
  	  t2 = type;
  	}
        if (can_convert (t1, t2))
  	{
! 	  check_for_casting_away_constness (intype, type, "static_cast");
  	  if (TYPE_PTRMEM_P (type))
  	    {
  	      tree delta;
  
  	      if (TREE_CODE (expr) == PTRMEM_CST)
--- 4686,4697 ----
  	  t1 = intype;
  	  t2 = type;
  	}
        if (can_convert (t1, t2))
  	{
! 	  if (!c_cast_p)
! 	    check_for_casting_away_constness (intype, type, diag_fn, desc);
  	  if (TYPE_PTRMEM_P (type))
  	    {
  	      tree delta;
  
  	      if (TREE_CODE (expr) == PTRMEM_CST)
*************** build_static_cast (tree type, tree expr)
*** 4673,4865 ****
       original pointer type will have its original value.  */
    if (TREE_CODE (intype) == POINTER_TYPE 
        && VOID_TYPE_P (TREE_TYPE (intype))
        && TYPE_PTROB_P (type))
      {
!       check_for_casting_away_constness (intype, type, "static_cast");
        return build_nop (type, expr);
      }
  
!   error ("invalid static_cast from type %qT to type %qT", intype, type);
    return error_mark_node;
  }
  
  tree
! build_reinterpret_cast (tree type, tree expr)
  {
!   tree intype;
  
    if (type == error_mark_node || expr == error_mark_node)
      return error_mark_node;
  
    if (processing_template_decl)
      {
!       tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
!       
!       if (!TREE_SIDE_EFFECTS (t)
! 	  && type_dependent_expression_p (expr))
! 	/* There might turn out to be side effects inside expr.  */
! 	TREE_SIDE_EFFECTS (t) = 1;
!       return t;
      }
  
!   if (TREE_CODE (type) != REFERENCE_TYPE)
!     {
!       expr = decay_conversion (expr);
  
!       /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
! 	 Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
!       if (TREE_CODE (expr) == NOP_EXPR
! 	  && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
! 	expr = TREE_OPERAND (expr, 0);
!     }
  
    intype = TREE_TYPE (expr);
  
!   if (intype == error_mark_node)
      return error_mark_node;
  
    if (TREE_CODE (type) == REFERENCE_TYPE)
      {
        if (! real_lvalue_p (expr))
  	{
! 	  error ("invalid reinterpret_cast of an rvalue expression of type "
!                  "%qT to type %qT", intype, type);
  	  return error_mark_node;
  	}
        expr = build_unary_op (ADDR_EXPR, expr, 0);
        if (expr != error_mark_node)
! 	expr = build_reinterpret_cast
! 	  (build_pointer_type (TREE_TYPE (type)), expr);
        if (expr != error_mark_node)
  	expr = build_indirect_ref (expr, 0);
        return expr;
      }
-   else if (same_type_ignoring_top_level_qualifiers_p (intype, type))
-     return build_static_cast (type, expr);
  
!   if (TYPE_PTR_P (type) && (TREE_CODE (intype) == INTEGER_TYPE
! 			    || TREE_CODE (intype) == ENUMERAL_TYPE))
!     /* OK */;
!   else if (TREE_CODE (type) == INTEGER_TYPE && TYPE_PTR_P (intype))
      {
        if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
! 	pedwarn ("reinterpret_cast from %qT to %qT loses precision",
                   intype, type);
      }
    else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
  	   || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
      {
        expr = decl_constant_value (expr);
        return fold_if_not_in_template (build_nop (type, expr));
      }
    else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
  	   || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
      {
!       check_for_casting_away_constness (intype, type, "reinterpret_cast");
        expr = decl_constant_value (expr);
        return fold_if_not_in_template (build_nop (type, expr));
      }
    else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
  	   || (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
      {
!       pedwarn ("ISO C++ forbids casting between pointer-to-function and pointer-to-object");
        expr = decl_constant_value (expr);
        return fold_if_not_in_template (build_nop (type, expr));
      }
    else
      {
!       error ("invalid reinterpret_cast from type %qT to type %qT",
!              intype, type);
        return error_mark_node;
      }
        
    return cp_convert (type, expr);
  }
  
  tree
! build_const_cast (tree type, tree expr)
  {
-   tree intype;
- 
    if (type == error_mark_node || expr == error_mark_node)
      return error_mark_node;
  
    if (processing_template_decl)
      {
!       tree t = build_min (CONST_CAST_EXPR, type, expr);
        
        if (!TREE_SIDE_EFFECTS (t)
  	  && type_dependent_expression_p (expr))
  	/* There might turn out to be side effects inside expr.  */
  	TREE_SIDE_EFFECTS (t) = 1;
        return t;
      }
  
!   if (!POINTER_TYPE_P (type) && !TYPE_PTRMEM_P (type))
!     error ("invalid use of const_cast with type %qT, which is not a pointer, "
!            "reference, nor a pointer-to-data-member type", type);
!   else if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
!     {
!       error ("invalid use of const_cast with type %qT, which is a pointer "
!              "or reference to a function type", type);
        return error_mark_node;
      }
  
!   if (TREE_CODE (type) != REFERENCE_TYPE)
      {
!       expr = decay_conversion (expr);
! 
!       /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
! 	 Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
!       if (TREE_CODE (expr) == NOP_EXPR
! 	  && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
! 	expr = TREE_OPERAND (expr, 0);
      }
  
!   intype = TREE_TYPE (expr);
!   
!   if (same_type_ignoring_top_level_qualifiers_p (intype, type))
!     return build_static_cast (type, expr);
!   else if (TREE_CODE (type) == REFERENCE_TYPE)
      {
        if (! real_lvalue_p (expr))
  	{
! 	  error ("invalid const_cast of an rvalue of type %qT to type %qT",
!                  intype, type);
  	  return error_mark_node;
  	}
  
!       if (comp_ptr_ttypes_const (TREE_TYPE (type), intype))
  	{
  	  expr = build_unary_op (ADDR_EXPR, expr, 0);
! 	  expr = build1 (NOP_EXPR, type, expr);
  	  return convert_from_reference (expr);
  	}
      }
-   else if (((TREE_CODE (type) == POINTER_TYPE
- 	     && TREE_CODE (intype) == POINTER_TYPE)
- 	    || (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype)))
- 	   && comp_ptr_ttypes_const (TREE_TYPE (type), TREE_TYPE (intype)))
-     return cp_convert (type, expr);
  
!   error ("invalid const_cast from type %qT to type %qT", intype, type);
    return error_mark_node;
  }
  
! /* Build an expression representing a cast to type TYPE of expression EXPR.
  
!    ALLOW_NONCONVERTING is true if we should allow non-converting constructors
!    when doing the cast.  */
  
  tree
  build_c_cast (tree type, tree expr)
  {
    tree value = expr;
!   tree otype;
  
!   if (type == error_mark_node || expr == error_mark_node)
      return error_mark_node;
  
    if (processing_template_decl)
      {
        tree t = build_min (CAST_EXPR, type,
--- 4717,5104 ----
       original pointer type will have its original value.  */
    if (TREE_CODE (intype) == POINTER_TYPE 
        && VOID_TYPE_P (TREE_TYPE (intype))
        && TYPE_PTROB_P (type))
      {
!       if (!c_cast_p)
! 	check_for_casting_away_constness (intype, type, diag_fn, desc);
        return build_nop (type, expr);
      }
  
!   *valid_p = false;
    return error_mark_node;
  }
  
+ /* Return an expression representing static_cast<TYPE>(EXPR).  */
+ 
  tree
! build_static_cast (tree type, tree expr)
  {
!   tree result;
!   bool valid_p;
  
    if (type == error_mark_node || expr == error_mark_node)
      return error_mark_node;
  
    if (processing_template_decl)
      {
!       expr = build_min (STATIC_CAST_EXPR, type, expr);
!       /* We don't know if it will or will not have side effects.  */
!       TREE_SIDE_EFFECTS (expr) = 1;
!       return expr;
      }
  
!   /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
!      Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
!   if (TREE_CODE (type) != REFERENCE_TYPE
!       && TREE_CODE (expr) == NOP_EXPR
!       && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
!     expr = TREE_OPERAND (expr, 0);
  
!   result = build_static_cast_1 (type, expr, /*c_cast_p=*/false, &valid_p);
!   if (valid_p)
!     return result;
! 
!   error ("invalid static_cast from type %qT to type %qT", 
! 	 TREE_TYPE (expr), type);
!   return error_mark_node;
! }
! 
! /* EXPR is an expression with member function or pointer-to-member
!    function type.  TYPE is a pointer type.  Converting EXPR to TYPE is
!    not permitted by ISO C++, but we accept it in some modes.  If we
!    are not in one of those modes, issue a diagnostic.  Return the
!    converted expression.  */
! 
! tree
! convert_member_func_to_ptr (tree type, tree expr)
! {
!   tree intype;
!   tree decl;
  
    intype = TREE_TYPE (expr);
+   gcc_assert (TYPE_PTRMEMFUNC_P (intype)
+ 	      || TREE_CODE (intype) == METHOD_TYPE);
  
!   if (pedantic || warn_pmf2ptr)
!     pedwarn ("converting from `%T' to `%T'", intype, type);
!     
!   if (TREE_CODE (intype) == METHOD_TYPE)
!     expr = build_addr_func (expr);
!   else if (TREE_CODE (expr) == PTRMEM_CST)
!     expr = build_address (PTRMEM_CST_MEMBER (expr));
!   else
!     {
!       decl = maybe_dummy_object (TYPE_PTRMEM_CLASS_TYPE (intype), 0);
!       decl = build_address (decl);
!       expr = get_member_function_from_ptrfunc (&decl, expr);
!     }
! 
!   return build_nop (type, expr);
! }
! 
! /* Return a representation for a reinterpret_cast from EXPR to TYPE.
!    If C_CAST_P is true, this reinterpret cast is being done as part of
!    a C-style cast.  If VALID_P is non-NULL, *VALID_P is set to
!    indicate whether or not reinterpret_cast was valid.  */
! 
! static tree
! build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
! 			  bool *valid_p)
! {
!   tree intype;
! 
!   /* Assume the cast is invalid.  */
!   if (valid_p)
!     *valid_p = true;
! 
!   if (type == error_mark_node || error_operand_p (expr))
      return error_mark_node;
  
+   intype = TREE_TYPE (expr);
+ 
+   /* [expr.reinterpret.cast]
+      An lvalue expression of type T1 can be cast to the type
+      "reference to T2" if an expression of type "pointer to T1" can be
+      explicitly converted to the type "pointer to T2" using a
+      reinterpret_cast.  */
    if (TREE_CODE (type) == REFERENCE_TYPE)
      {
        if (! real_lvalue_p (expr))
  	{
! 	  error ("invalid cast of an rvalue expression of type "
!                  "%qT to type %qT", 
! 		 intype, type);
  	  return error_mark_node;
  	}
+ 
+       /* Warn about a reinterpret_cast from "A*" to "B&" if "A" and
+ 	 "B" are related class types; the reinterpret_cast does not
+ 	 adjust the pointer.  */
+       if (TYPE_PTR_P (intype)
+ 	  && (comptypes (TREE_TYPE (intype), TREE_TYPE (type),
+ 			 COMPARE_BASE | COMPARE_DERIVED)))
+ 	warning ("casting `%T' to `%T' does not dereference pointer",
+ 		 intype, type);
+ 
        expr = build_unary_op (ADDR_EXPR, expr, 0);
        if (expr != error_mark_node)
! 	expr = build_reinterpret_cast_1
! 	  (build_pointer_type (TREE_TYPE (type)), expr, c_cast_p,
! 	   valid_p);
        if (expr != error_mark_node)
  	expr = build_indirect_ref (expr, 0);
        return expr;
      }
  
!   /* As a G++ extension, we consider conversions from member
!      functions, and pointers to member functions to
!      pointer-to-function and pointer-to-void types.  If
!      -Wno-pmf-conversions has not been specified,
!      convert_member_func_to_ptr will issue an error message.  */
!   if ((TYPE_PTRMEMFUNC_P (intype) 
!        || TREE_CODE (intype) == METHOD_TYPE)
!       && TYPE_PTR_P (type)
!       && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
! 	  || VOID_TYPE_P (TREE_TYPE (type))))
!     return convert_member_func_to_ptr (type, expr);
! 
!   /* If the cast is not to a reference type, the lvalue-to-rvale,
!      array-to-pointer, and function-to-pointer conversions are
!      performed.  */
!   expr = decay_conversion (expr);
!   
!   /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
!      Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
!   if (TREE_CODE (expr) == NOP_EXPR
!       && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
!     expr = TREE_OPERAND (expr, 0);
! 
!   if (error_operand_p (expr))
!     return error_mark_node;
! 
!   intype = TREE_TYPE (expr);
! 
!   /* [expr.reinterpret.cast]
!      A pointer can be converted to any integral type large enough to
!      hold it.  */
!   if (CP_INTEGRAL_TYPE_P (type) && TYPE_PTR_P (intype))
      {
        if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
! 	pedwarn ("cast from %qT to %qT loses precision",
                   intype, type);
      }
+   /* [expr.reinterpret.cast]
+      A value of integral or enumeration type can be explicitly
+      converted to a pointer.  */
+   else if (TYPE_PTR_P (type) && INTEGRAL_OR_ENUMERATION_TYPE_P (intype))
+     /* OK */
+     ;
    else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
  	   || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
      {
        expr = decl_constant_value (expr);
        return fold_if_not_in_template (build_nop (type, expr));
      }
    else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
  	   || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
      {
!       if (!c_cast_p)
! 	check_for_casting_away_constness (intype, type, error, 
! 					  "reinterpret_cast");
!       /* Warn about possible alignment problems.  */
!       if (STRICT_ALIGNMENT && warn_cast_align
! 	  && !VOID_TYPE_P (type)
! 	  && TREE_CODE (TREE_TYPE (intype)) != FUNCTION_TYPE
! 	  && COMPLETE_TYPE_P (TREE_TYPE (type))
! 	  && COMPLETE_TYPE_P (TREE_TYPE (intype))
! 	  && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (intype)))
! 	warning ("cast from %qT to %qT increases required alignment of "
! 		 "target type",
! 		 intype, type);
        expr = decl_constant_value (expr);
        return fold_if_not_in_template (build_nop (type, expr));
      }
    else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
  	   || (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
      {
!       if (pedantic || !c_cast_p)
! 	pedwarn ("ISO C++ forbids casting between pointer-to-function and pointer-to-object");
        expr = decl_constant_value (expr);
        return fold_if_not_in_template (build_nop (type, expr));
      }
    else
      {
!       if (valid_p)
! 	*valid_p = false;
!       error ("invalid cast from type %qT to type %qT", intype, type);
        return error_mark_node;
      }
        
    return cp_convert (type, expr);
  }
  
  tree
! build_reinterpret_cast (tree type, tree expr)
  {
    if (type == error_mark_node || expr == error_mark_node)
      return error_mark_node;
  
    if (processing_template_decl)
      {
!       tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
        
        if (!TREE_SIDE_EFFECTS (t)
  	  && type_dependent_expression_p (expr))
  	/* There might turn out to be side effects inside expr.  */
  	TREE_SIDE_EFFECTS (t) = 1;
        return t;
      }
  
!   return build_reinterpret_cast_1 (type, expr, /*c_cast_p=*/false,
! 				   /*valid_p=*/NULL);
! }
! 
! /* Perform a const_cast from EXPR to TYPE.  If the cast is valid,
!    return an appropriate expression.  Otherwise, return
!    error_mark_node.  If the cast is not valid, and COMPLAIN is true,
!    then a diagnostic will be issued.  If VALID_P is non-NULL, its
!    value upon return will indicate whether or not the conversion
!    succeeded.  */
! 
! static tree
! build_const_cast_1 (tree dst_type, tree expr, bool complain,
! 		    bool *valid_p)
! {
!   tree src_type;
!   tree reference_type;
! 
!   /* Callers are responsible for handling error_mark_node as a
!      destination type.  */
!   gcc_assert (dst_type != error_mark_node);
!   /* In a template, callers should be building syntactic
!      representations of casts, not using this machinery.  */
!   gcc_assert (!processing_template_decl);
! 
!   /* Assume the conversion is invalid.  */
!   if (valid_p)
!     *valid_p = false;
! 
!   if (!POINTER_TYPE_P (dst_type) && !TYPE_PTRMEM_P (dst_type))
!     {
!       if (complain)
! 	error ("invalid use of const_cast with type %qT, "
! 	       "which is not a pointer, "
! 	       "reference, nor a pointer-to-data-member type", dst_type);
        return error_mark_node;
      }
  
!   if (TREE_CODE (TREE_TYPE (dst_type)) == FUNCTION_TYPE)
      {
!       if (complain)
! 	error ("invalid use of const_cast with type %qT, which is a pointer "
! 	       "or reference to a function type", dst_type);
!       return error_mark_node;
      }
  
!   src_type = TREE_TYPE (expr);
!   /* Expressions do not really have reference types.  */
!   if (TREE_CODE (src_type) == REFERENCE_TYPE)
!     src_type = TREE_TYPE (src_type);
! 
!   /* [expr.const.cast]
! 
!      An lvalue of type T1 can be explicitly converted to an lvalue of
!      type T2 using the cast const_cast<T2&> (where T1 and T2 are object
!      types) if a pointer to T1 can be explicitly converted to the type
!      pointer to T2 using a const_cast.  */
!   if (TREE_CODE (dst_type) == REFERENCE_TYPE)
      {
+       reference_type = dst_type;
        if (! real_lvalue_p (expr))
  	{
! 	  if (complain)
! 	    error ("invalid const_cast of an rvalue of type %qT to type %qT",
! 		   src_type, dst_type);
  	  return error_mark_node;
  	}
+       dst_type = build_pointer_type (TREE_TYPE (dst_type));
+       src_type = build_pointer_type (src_type);
+     }
+   else
+     {
+       reference_type = NULL_TREE;
+       /* If the destination type is not a reference type, the
+ 	 lvalue-to-rvalue, array-to-pointer, and function-to-pointer
+ 	 conversions are performed.  */
+       src_type = type_decays_to (src_type);
+       if (src_type == error_mark_node)
+ 	return error_mark_node;
+     }
  
!   if ((TYPE_PTR_P (src_type) || TYPE_PTRMEM_P (src_type))
!       && comp_ptr_ttypes_const (dst_type, src_type))
!     {
!       if (valid_p)
! 	*valid_p = true;
!       if (reference_type)
  	{
  	  expr = build_unary_op (ADDR_EXPR, expr, 0);
! 	  expr = build_nop (reference_type, expr);
  	  return convert_from_reference (expr);
  	}
+       else
+ 	{
+ 	  expr = decay_conversion (expr);
+ 	  /* build_c_cast puts on a NOP_EXPR to make the result not an
+ 	     lvalue.  Strip such NOP_EXPRs if VALUE is being used in
+ 	     non-lvalue context.  */
+ 	  if (TREE_CODE (expr) == NOP_EXPR
+ 	      && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ 	    expr = TREE_OPERAND (expr, 0);
+ 	  return build_nop (dst_type, expr);
+ 	}
      }
  
!   if (complain)
!     error ("invalid const_cast from type %qT to type %qT", 
! 	   src_type, dst_type);
    return error_mark_node;
  }
  
! tree
! build_const_cast (tree type, tree expr)
! {
!   if (type == error_mark_node || expr == error_mark_node)
!     return error_mark_node;
! 
!   if (processing_template_decl)
!     {
!       tree t = build_min (CONST_CAST_EXPR, type, expr);
!       
!       if (!TREE_SIDE_EFFECTS (t)
! 	  && type_dependent_expression_p (expr))
! 	/* There might turn out to be side effects inside expr.  */
! 	TREE_SIDE_EFFECTS (t) = 1;
!       return t;
!     }
! 
!   return build_const_cast_1 (type, expr, /*complain=*/true,
! 			     /*valid_p=*/NULL);
! }
  
! /* Build an expression representing an explicit C-style cast to type
!    TYPE of expression EXPR.  */
  
  tree
  build_c_cast (tree type, tree expr)
  {
    tree value = expr;
!   tree result;
!   bool valid_p;
  
!   if (type == error_mark_node || error_operand_p (expr))
      return error_mark_node;
  
    if (processing_template_decl)
      {
        tree t = build_min (CAST_EXPR, type,
*************** build_c_cast (tree type, tree expr)
*** 4904,5025 ****
      {
        error ("invalid cast to function type %qT", type);
        return error_mark_node;
      }
  
!   if (TREE_CODE (type) == VOID_TYPE)
!     {
!       /* Conversion to void does not cause any of the normal function to
!        * pointer, array to pointer and lvalue to rvalue decays.  */
!       
!       value = convert_to_void (value, /*implicit=*/NULL);
!       return value;
!     }
! 
!   if (!complete_type_or_else (type, NULL_TREE))
!     return error_mark_node;
! 
!   /* Convert functions and arrays to pointers and
!      convert references to their expanded types,
!      but don't convert any other types.  If, however, we are
!      casting to a class type, there's no reason to do this: the
!      cast will only succeed if there is a converting constructor,
!      and the default conversions will be done at that point.  In
!      fact, doing the default conversion here is actually harmful
!      in cases like this:
! 
!      typedef int A[2];
!      struct S { S(const A&); };
! 
!      since we don't want the array-to-pointer conversion done.  */
!   if (!IS_AGGR_TYPE (type))
!     {
!       if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
! 	  || (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
! 	      /* Don't do the default conversion on a ->* expression.  */
! 	      && ! (TREE_CODE (type) == POINTER_TYPE
! 		    && bound_pmf_p (value)))
! 	  || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
! 	  || TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
! 	value = decay_conversion (value);
!     }
!   else if (TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
!     /* However, even for class types, we still need to strip away
!        the reference type, since the call to convert_force below
!        does not expect the input expression to be of reference
!        type.  */
!     value = convert_from_reference (value);
! 	
!   otype = TREE_TYPE (value);
! 
!   /* Optionally warn about potentially worrisome casts.  */
! 
!   if (warn_cast_qual
!       && TREE_CODE (type) == POINTER_TYPE
!       && TREE_CODE (otype) == POINTER_TYPE
!       && !at_least_as_qualified_p (TREE_TYPE (type),
! 				   TREE_TYPE (otype)))
!     warning ("cast from %qT to %qT discards qualifiers from pointer "
!              "target type",
!              otype, type);
! 
!   if (TREE_CODE (type) == INTEGER_TYPE
!       && TYPE_PTR_P (otype)
!       && TYPE_PRECISION (type) != TYPE_PRECISION (otype))
!     warning ("cast from pointer to integer of different size");
! 
!   if (TYPE_PTR_P (type)
!       && TREE_CODE (otype) == INTEGER_TYPE
!       && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
!       /* Don't warn about converting any constant.  */
!       && !TREE_CONSTANT (value))
!     warning ("cast to pointer from integer of different size");
! 
!   if (TREE_CODE (type) == REFERENCE_TYPE)
!     value = (convert_from_reference
! 	     (convert_to_reference (type, value, CONV_C_CAST,
! 				    LOOKUP_COMPLAIN, NULL_TREE)));
!   else
!     {
!       tree ovalue;
! 
!       value = decl_constant_value (value);
! 
!       ovalue = value;
!       value = convert_force (type, value, CONV_C_CAST);
  
!       /* Ignore any integer overflow caused by the cast.  */
!       if (TREE_CODE (value) == INTEGER_CST)
  	{
! 	  TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
! 
! 	  if (CONSTANT_CLASS_P (ovalue))
! 	    TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
  	}
      }
  
!   /* Warn about possible alignment problems.  Do this here when we will have
!      instantiated any necessary template types.  */
!   if (STRICT_ALIGNMENT && warn_cast_align
!       && TREE_CODE (type) == POINTER_TYPE
!       && TREE_CODE (otype) == POINTER_TYPE
!       && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE
!       && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
!       && COMPLETE_TYPE_P (TREE_TYPE (otype))
!       && COMPLETE_TYPE_P (TREE_TYPE (type))
!       && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
!     warning ("cast from %qT to %qT increases required alignment of "
!              "target type",
!              otype, type);
! 
!     /* Always produce some operator for an explicit cast,
!        so we can tell (for -pedantic) that the cast is no lvalue.  */
!   if (TREE_CODE (type) != REFERENCE_TYPE && value == expr
!       && real_lvalue_p (value))
!     value = non_lvalue (value);
! 
!   return value;
  }
  
  /* Build an assignment expression of lvalue LHS from value RHS.
     MODIFYCODE is the code for a binary operator that we use
     to combine the old value of LHS with RHS to get the new value.
--- 5143,5194 ----
      {
        error ("invalid cast to function type %qT", type);
        return error_mark_node;
      }
  
!   /* A C-style cast can be a const_cast.  */
!   result = build_const_cast_1 (type, value, /*complain=*/false,
! 			       &valid_p);
!   if (valid_p)
!     return result;
  
!   /* Or a static cast.  */
!   result = build_static_cast_1 (type, value, /*c_cast_p=*/true,
! 				&valid_p);
!   /* Or a reinterpret_cast.  */
!   if (!valid_p)
!     result = build_reinterpret_cast_1 (type, value, /*c_cast_p=*/true,
! 				       &valid_p);
!   /* The static_cast or reinterpret_cast may be followed by a
!      const_cast.  */
!   if (valid_p 
!       /* A valid cast may result in errors if, for example, a
! 	 conversion to am ambiguous base class is required.  */
!       && !error_operand_p (result))
!     {
!       tree result_type;
! 
!       /* Non-class rvalues always have cv-unqualified type.  */
!       if (!CLASS_TYPE_P (type))
! 	type = TYPE_MAIN_VARIANT (type);
!       result_type = TREE_TYPE (result);
!       if (!CLASS_TYPE_P (result_type))
! 	result_type = TYPE_MAIN_VARIANT (result_type);
!       /* If the type of RESULT does not match TYPE, perform a
! 	 const_cast to make it match.  If the static_cast or
! 	 reinterpret_cast succeeded, we will differ by at most
! 	 cv-qualification, so the follow-on const_cast is guaranteed
! 	 to succeed.  */
!       if (!same_type_p (non_reference (type), non_reference (result_type)))
  	{
! 	  result = build_const_cast_1 (type, result, false, &valid_p);
! 	  gcc_assert (valid_p);
  	}
+       return result;
      }
  
!   return error_mark_node;
  }
  
  /* Build an assignment expression of lvalue LHS from value RHS.
     MODIFYCODE is the code for a binary operator that we use
     to combine the old value of LHS with RHS to get the new value.
*************** cp_has_mutable_p (tree type)
*** 6258,6268 ****
  
    return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type);
  }
  
  /* Subroutine of casts_away_constness.  Make T1 and T2 point at
!    exemplar types such that casting T1 to T2 is casting away castness
     if and only if there is no implicit conversion from T1 to T2.  */
  
  static void
  casts_away_constness_r (tree *t1, tree *t2)
  {
--- 6427,6437 ----
  
    return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type);
  }
  
  /* Subroutine of casts_away_constness.  Make T1 and T2 point at
!    exemplar types such that casting T1 to T2 is casting away constness
     if and only if there is no implicit conversion from T1 to T2.  */
  
  static void
  casts_away_constness_r (tree *t1, tree *t2)
  {
Index: testsuite/g++.dg/conversion/const2.C
===================================================================
RCS file: testsuite/g++.dg/conversion/const2.C
diff -N testsuite/g++.dg/conversion/const2.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/conversion/const2.C	19 Oct 2004 23:20:07 -0000
***************
*** 0 ****
--- 1,11 ----
+ struct B {};
+ struct D : public B {};
+ 
+ typedef int B::*bm;
+ typedef int D::*dm;
+ 
+ bm bp;
+ 
+ void f() {
+   const_cast<dm>(bp); // { dg-error "" }
+ }
Index: testsuite/g++.dg/conversion/reinterpret1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/conversion/reinterpret1.C,v
retrieving revision 1.1
diff -c -5 -p -r1.1 reinterpret1.C
*** testsuite/g++.dg/conversion/reinterpret1.C	10 Jun 2004 14:26:22 -0000	1.1
--- testsuite/g++.dg/conversion/reinterpret1.C	19 Oct 2004 23:20:07 -0000
***************
*** 1,6 ****
  // PR c++/15076
  
! struct Y { Y(int &); }; // { dg-error "" }
  
  int v;
  Y y1(reinterpret_cast<int>(v));  // { dg-error "" }
--- 1,6 ----
  // PR c++/15076
  
! struct Y { Y(int &); };
  
  int v;
  Y y1(reinterpret_cast<int>(v));  // { dg-error "" }
Index: testsuite/g++.dg/conversion/reinterpret2.C
===================================================================
RCS file: testsuite/g++.dg/conversion/reinterpret2.C
diff -N testsuite/g++.dg/conversion/reinterpret2.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/conversion/reinterpret2.C	19 Oct 2004 23:20:07 -0000
***************
*** 0 ****
--- 1,5 ----
+ bool b;
+ 
+ void f() {
+   reinterpret_cast<void*>(b);
+ }
Index: testsuite/g++.dg/conversion/reinterpret3.C
===================================================================
RCS file: testsuite/g++.dg/conversion/reinterpret3.C
diff -N testsuite/g++.dg/conversion/reinterpret3.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/conversion/reinterpret3.C	19 Oct 2004 23:20:07 -0000
***************
*** 0 ****
--- 1,7 ----
+ struct S {};
+ 
+ S s;
+ 
+ void f() {
+   reinterpret_cast<const S>(s); // { dg-error "" }
+ }
Index: testsuite/g++.dg/expr/cast2.C
===================================================================
RCS file: testsuite/g++.dg/expr/cast2.C
diff -N testsuite/g++.dg/expr/cast2.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/expr/cast2.C	19 Oct 2004 23:20:07 -0000
***************
*** 0 ****
--- 1,5 ----
+ void (*p)();
+ 
+ void f() {
+   (void *)p; // { dg-error "" }
+ }
Index: testsuite/g++.dg/expr/copy1.C
===================================================================
RCS file: testsuite/g++.dg/expr/copy1.C
diff -N testsuite/g++.dg/expr/copy1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/expr/copy1.C	19 Oct 2004 23:20:07 -0000
***************
*** 0 ****
--- 1,28 ----
+ // PR c++/14035
+ // { dg-do run }
+ 
+ extern "C" void abort();
+ 
+ struct Blob {
+   int x, y;
+   Blob() { }
+   Blob(const Blob &b) { abort (); }
+ };
+ struct Blobby : public Blob { };
+ 
+ struct Wooly {
+   operator const Blobby & ()
+   {
+     return myBlobby;
+   }
+   Blobby myBlobby;
+ };
+ 
+ void catcher(const Blob &blo)
+ { }
+ 
+ int main()
+ {
+   Wooly wooly;
+   catcher((const Blob &)wooly);
+ }
Index: testsuite/g++.dg/other/conversion1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/other/conversion1.C,v
retrieving revision 1.1
diff -c -5 -p -r1.1 conversion1.C
*** testsuite/g++.dg/other/conversion1.C	5 Aug 2002 03:56:16 -0000	1.1
--- testsuite/g++.dg/other/conversion1.C	19 Oct 2004 23:20:07 -0000
*************** class QObject
*** 11,17 ****
  
  int main()
  {
    long long m;
    
!   (void (QObject::*)()) m;    // { dg-error "invalid conversion" "" }
  }
--- 11,17 ----
  
  int main()
  {
    long long m;
    
!   (void (QObject::*)()) m;    // { dg-error "invalid cast" "" }
  }
Index: testsuite/g++.dg/parse/comma1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/parse/comma1.C,v
retrieving revision 1.2
diff -c -5 -p -r1.2 comma1.C
*** testsuite/g++.dg/parse/comma1.C	27 Feb 2004 00:31:49 -0000	1.2
--- testsuite/g++.dg/parse/comma1.C	19 Oct 2004 23:20:07 -0000
***************
*** 1,6 ****
--- 1,7 ----
  // PR c++/14278
+ // { dg-options "" }
  
  struct X { 
    X (int p);
  };
  
Index: testsuite/g++.old-deja/g++.brendan/operators4.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.brendan/operators4.C,v
retrieving revision 1.4
diff -c -5 -p -r1.4 operators4.C
*** testsuite/g++.old-deja/g++.brendan/operators4.C	1 May 2003 02:02:35 -0000	1.4
--- testsuite/g++.old-deja/g++.brendan/operators4.C	19 Oct 2004 23:20:07 -0000
*************** int fail ()
*** 42,56 ****
  int main ()
  {
  	base_ptr = new base;
  
  	ptr_to_func_of_char p0 = &function;
! 	vp = (void*) p0;
  	if (test2 (vp))
  		return fail ();
  	ptr_to_func_of_float p1 = &function;
! 	vp = (void*) p1;
  	if (test3 (vp))
  		return fail ();
  	ptr_to_method_of_char p2 = &base::method;
  	vp = (void*) p2; // { dg-error "" } 
  	if (test4 (vp))
--- 42,56 ----
  int main ()
  {
  	base_ptr = new base;
  
  	ptr_to_func_of_char p0 = &function;
! 	vp = __extension__ (void*) p0;
  	if (test2 (vp))
  		return fail ();
  	ptr_to_func_of_float p1 = &function;
! 	vp = __extension__ (void*) p1;
  	if (test3 (vp))
  		return fail ();
  	ptr_to_method_of_char p2 = &base::method;
  	vp = (void*) p2; // { dg-error "" } 
  	if (test4 (vp))
*************** int main ()
*** 66,83 ****
  
  int test2 (void* vp)
  {
  	char ch = 'x';
  
! 	return (((ptr_to_func_of_char)vp)(ch) !=  9901);
  }
  
  int test3 (void* vp)
  {
  	float flt = 9.9;
  
! 	return (((ptr_to_func_of_float)vp)(flt) !=  9902);
  }
  
  int test4 (void* vp)
  {
  	char ch = 'x';
--- 66,83 ----
  
  int test2 (void* vp)
  {
  	char ch = 'x';
  
! 	return ((__extension__ (ptr_to_func_of_char)vp)(ch) !=  9901);
  }
  
  int test3 (void* vp)
  {
  	float flt = 9.9;
  
! 	return ((__extension__ (ptr_to_func_of_float)vp)(flt) !=  9902);
  }
  
  int test4 (void* vp)
  {
  	char ch = 'x';
Index: testsuite/g++.old-deja/g++.mike/p10148.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.mike/p10148.C,v
retrieving revision 1.4
diff -c -5 -p -r1.4 p10148.C
*** testsuite/g++.old-deja/g++.mike/p10148.C	1 May 2003 02:02:45 -0000	1.4
--- testsuite/g++.old-deja/g++.mike/p10148.C	19 Oct 2004 23:20:07 -0000
*************** class TCRCB : public TCCB {
*** 21,31 ****
  public:
    virtual void eat ();
  };
  
  void TCRCB::eat () {
!  void *vp = (TIRD*)this->itc;
   this->itc();
  }
  
  int main() {
    TCRCB a;
--- 21,31 ----
  public:
    virtual void eat ();
  };
  
  void TCRCB::eat () {
!  void *vp = __extension__ (TIRD*)this->itc;
   this->itc();
  }
  
  int main() {
    TCRCB a;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]