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: PR 10990 and 10931


This patch fixes two regressions: one in static_cast and one with
dynamic_cast.  Both are solved by implementing functions that
dogmatically adhere to the standard -- and in the process several
other bugs are fixed.  For example, static_cast no longer permits
casts to inaccessible base classes.

Tested on i686-pc-linux-gnu, applied on the mainline.  I'll apply the
same patch to the branch as soon as I can test it there.

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

2003-06-25  Mark Mitchell  <mark@codesourcery.com>

	PR c++/10990
	* search.c (lookup_base_r): Rely on accessible_p, rather than
	trying to emulate that logic here.

	PR c++/10931
	* call.c (convert_like): Pass issue_conversion_warnings.
	(convert_like_with_context): Likewise.
	(convert_like_real): Add issue_conversion_warnings parameter.
	(perform_direct_initialization_if_possible): New function.
	* cp-tree.h (perform_direct_initialization_if_possible): Declare it.
	* typeck.c (check_for_casting_away_constness): New function.
	(build_static_cast): Rewrite.
	
2003-06-25  Mark Mitchell  <mark@codesourcery.com>

	PR c++/10990
	* g++.dg/rtti/dyncast1.C: New test.
	* g++.dg/abi/mangle4.C: Correct base-specifier access.
	* g++.dg/lookup/scoped1.C: Remove XFAIL.
	* g++.old-deja/g++.martin/pmf1.C: Correct base-specifier access.
	
	PR c++/10931
	* g++.dg/expr/static_cast1.C: New test.
	
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.388
diff -c -5 -p -r1.388 call.c
*** cp/call.c	20 Jun 2003 00:48:36 -0000	1.388
--- cp/call.c	26 Jun 2003 00:03:19 -0000
*************** static struct z_candidate * tourney (str
*** 43,57 ****
  static int equal_functions (tree, tree);
  static int joust (struct z_candidate *, struct z_candidate *, bool);
  static int compare_ics (tree, tree);
  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)
! #define convert_like_with_context(CONV, EXPR, FN, ARGNO) \
!   convert_like_real ((CONV), (EXPR), (FN), (ARGNO), 0)
! static tree convert_like_real (tree, tree, tree, int, int);
  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);
--- 43,59 ----
  static int equal_functions (tree, tree);
  static int joust (struct z_candidate *, struct z_candidate *, bool);
  static int compare_ics (tree, tree);
  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 (tree, 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);
*************** enforce_access (tree basetype_path, tree
*** 4107,4124 ****
      }
  
    return true;
  }
  
! /* Perform the conversions in CONVS on the expression EXPR. 
!    FN and 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.  */
  
  static tree
! convert_like_real (tree convs, tree expr, tree fn, int argnum, int inner)
  {
    int savew, savee;
  
    tree totype = TREE_TYPE (convs);
  
--- 4109,4129 ----
      }
  
    return true;
  }
  
! /* Perform the conversions in CONVS on the expression EXPR.  FN and
!    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 (tree convs, tree expr, tree fn, int argnum, int inner,
! 		   bool issue_conversion_warnings)
  {
    int savew, savee;
  
    tree totype = TREE_TYPE (convs);
  
*************** convert_like_real (tree convs, tree expr
*** 4130,4154 ****
        tree t = convs; 
        for (; t; t = TREE_OPERAND (t, 0))
  	{
  	  if (TREE_CODE (t) == USER_CONV || !ICS_BAD_FLAG (t))
  	    {
! 	      expr = convert_like_real (t, expr, fn, argnum, 1);
  	      break;
  	    }
  	  else if (TREE_CODE (t) == AMBIG_CONV)
! 	    return convert_like_real (t, expr, fn, argnum, 1);
  	  else if (TREE_CODE (t) == IDENTITY_CONV)
  	    break;
  	}
        pedwarn ("invalid conversion from `%T' to `%T'", TREE_TYPE (expr), totype);
        if (fn)
  	pedwarn ("  initializing argument %P of `%D'", argnum, fn);
        return cp_convert (totype, expr);
      }
    
!   if (!inner)
      expr = dubious_conversion_warnings
               (totype, expr, "argument", fn, argnum);
    switch (TREE_CODE (convs))
      {
      case USER_CONV:
--- 4135,4161 ----
        tree t = convs; 
        for (; t; t = TREE_OPERAND (t, 0))
  	{
  	  if (TREE_CODE (t) == USER_CONV || !ICS_BAD_FLAG (t))
  	    {
! 	      expr = convert_like_real (t, expr, fn, argnum, 1,
! 					/*issue_conversion_warnings=*/false);
  	      break;
  	    }
  	  else if (TREE_CODE (t) == AMBIG_CONV)
! 	    return convert_like_real (t, expr, fn, argnum, 1,
! 				      /*issue_conversion_warnings=*/false);
  	  else if (TREE_CODE (t) == IDENTITY_CONV)
  	    break;
  	}
        pedwarn ("invalid conversion from `%T' to `%T'", TREE_TYPE (expr), totype);
        if (fn)
  	pedwarn ("  initializing argument %P of `%D'", argnum, fn);
        return cp_convert (totype, expr);
      }
    
!   if (issue_conversion_warnings)
      expr = dubious_conversion_warnings
               (totype, expr, "argument", fn, argnum);
    switch (TREE_CODE (convs))
      {
      case USER_CONV:
*************** convert_like_real (tree convs, tree expr
*** 4242,4252 ****
      default:
        break;
      };
  
    expr = convert_like_real (TREE_OPERAND (convs, 0), expr, fn, argnum,
!                             TREE_CODE (convs) == REF_BIND ? -1 : 1);
    if (expr == error_mark_node)
      return error_mark_node;
  
    switch (TREE_CODE (convs))
      {
--- 4249,4260 ----
      default:
        break;
      };
  
    expr = convert_like_real (TREE_OPERAND (convs, 0), expr, fn, argnum,
!                             TREE_CODE (convs) == REF_BIND ? -1 : 1,
! 			    /*issue_conversion_warnings=*/false);
    if (expr == error_mark_node)
      return error_mark_node;
  
    switch (TREE_CODE (convs))
      {
*************** perform_implicit_conversion (tree type, 
*** 6048,6057 ****
--- 6056,6084 ----
        error ("could not convert `%E' to `%T'", expr, type);
        return error_mark_node;
      }
  
    return convert_like (conv, expr);
+ }
+ 
+ /* 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.  */
+ 
+ tree
+ perform_direct_initialization_if_possible (tree type, tree expr)
+ {
+   tree conv;
+   
+   if (type == error_mark_node || error_operand_p (expr))
+     return error_mark_node;
+   conv = implicit_conversion (type, TREE_TYPE (expr), expr,
+ 			      LOOKUP_NORMAL);
+   if (!conv || ICS_BAD_FLAG (conv))
+     return NULL_TREE;
+   return convert_like_real (conv, expr, NULL_TREE, 0, 0, 
+ 			    /*issue_conversion_warnings=*/false);
  }
  
  /* DECL is a VAR_DECL whose type is a REFERENCE_TYPE.  The reference
     is being bound to a temporary.  Create and return a new VAR_DECL
     with the indicated TYPE; this variable will store the value to
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.858
diff -c -5 -p -r1.858 cp-tree.h
*** cp/cp-tree.h	20 Jun 2003 02:40:33 -0000	1.858
--- cp/cp-tree.h	26 Jun 2003 00:03:19 -0000
*************** extern tree cp_convert_parm_for_inlining
*** 3519,3528 ****
--- 3519,3529 ----
  extern bool is_properly_derived_from (tree, tree);
  extern tree initialize_reference (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, tree);
  
  /* in class.c */
  extern tree build_base_path			(enum tree_code, tree, tree, int);
Index: cp/search.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/search.c,v
retrieving revision 1.265
diff -c -5 -p -r1.265 search.c
*** cp/search.c	17 Jun 2003 16:58:17 -0000	1.265
--- cp/search.c	26 Jun 2003 00:03:19 -0000
*************** lookup_base_r (tree binfo, tree base, ba
*** 186,197 ****
        /* We have found a base. Check against what we have found
           already.  */
        found = bk_same_type;
        if (is_virtual)
  	found = bk_via_virtual;
-       if (is_non_public)
- 	found = bk_inaccessible;
        
        if (!*binfo_ptr)
  	*binfo_ptr = binfo;
        else if (binfo != *binfo_ptr)
  	{
--- 186,195 ----
*************** lookup_base (tree t, tree base, base_acc
*** 315,348 ****
    base = complete_type (TYPE_MAIN_VARIANT (base));
    
    bk = lookup_base_r (t_binfo, base, access & ~ba_quiet,
  		      0, 0, 0, &binfo);
  
!   switch (bk)
!     {
!     case bk_inaccessible:
!       binfo = NULL_TREE;
!       if (!(access & ba_quiet))
! 	{
! 	  error ("`%T' is an inaccessible base of `%T'", base, t);
! 	  binfo = error_mark_node;
! 	}
!       break;
!     case bk_ambig:
!       if (access != ba_any)
! 	{
! 	  binfo = NULL_TREE;
! 	  if (!(access & ba_quiet))
! 	    {
! 	      error ("`%T' is an ambiguous base of `%T'", base, t);
! 	      binfo = error_mark_node;
! 	    }
! 	}
!       break;
!     default:;
!     }
!   
    if (kind_ptr)
      *kind_ptr = bk;
    
    return binfo;
  }
--- 313,378 ----
    base = complete_type (TYPE_MAIN_VARIANT (base));
    
    bk = lookup_base_r (t_binfo, base, access & ~ba_quiet,
  		      0, 0, 0, &binfo);
  
!   /* Check that the base is unambiguous and accessible.  */
!   if (access != ba_any)
!     switch (bk)
!       {
!       case bk_not_base:
! 	break;
! 
!       case bk_ambig:
! 	binfo = NULL_TREE;
! 	if (!(access & ba_quiet))
! 	  {
! 	    error ("`%T' is an ambiguous base of `%T'", base, t);
! 	    binfo = error_mark_node;
! 	  }
! 	break;
! 
!       default:
! 	if (access != ba_ignore
! 	    /* If BASE is incomplete, then BASE and TYPE are probably
! 	       the same, in which case BASE is accessible.  If they
! 	       are not the same, then TYPE is invalid.  In that case,
! 	       there's no need to issue another error here, and
! 	       there's no implicit typedef to use in the code that
! 	       follows, so we skip the check.  */
! 	    && COMPLETE_TYPE_P (base))
! 	  {
! 	    tree decl;
! 
! 	    /* [class.access.base]
! 
! 	       A base class is said to be accessible if an invented public
! 	       member of the base class is accessible.  */
! 	    /* Rather than inventing a public member, we use the implicit
! 	       public typedef created in the scope of every class.  */
! 	    decl = TYPE_FIELDS (base);
! 	    while (TREE_CODE (decl) != TYPE_DECL
! 		   || !DECL_ARTIFICIAL (decl)
! 		   || DECL_NAME (decl) != constructor_name (base))
! 	      decl = TREE_CHAIN (decl);
! 	    while (ANON_AGGR_TYPE_P (t))
! 	      t = TYPE_CONTEXT (t);
! 	    if (!accessible_p (t, decl))
! 	      {
! 		if (!(access & ba_quiet))
! 		  {
! 		    error ("`%T' is an inaccessible base of `%T'", base, t);
! 		    binfo = error_mark_node;
! 		  }
! 		else
! 		  binfo = NULL_TREE;
! 		bk = bk_inaccessible;
! 	      }
! 	  }
! 	break;
!       }
! 
    if (kind_ptr)
      *kind_ptr = bk;
    
    return binfo;
  }
*************** dfs_accessible_p (tree binfo, void *data
*** 786,796 ****
  
    return NULL_TREE;
  }
  
  /* Returns nonzero if it is OK to access DECL through an object
!    indiated by BINFO in the context of DERIVED.  */
  
  static int
  protected_accessible_p (tree decl, tree derived, tree binfo)
  {
    access_kind access;
--- 816,826 ----
  
    return NULL_TREE;
  }
  
  /* Returns nonzero if it is OK to access DECL through an object
!    indicated by BINFO in the context of DERIVED.  */
  
  static int
  protected_accessible_p (tree decl, tree derived, tree binfo)
  {
    access_kind access;
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.466
diff -c -5 -p -r1.466 typeck.c
*** cp/typeck.c	18 Jun 2003 19:17:04 -0000	1.466
--- cp/typeck.c	26 Jun 2003 00:03:19 -0000
*************** build_compound_expr (tree list)
*** 4762,4776 ****
      return rest;
  
    return build (COMPOUND_EXPR, TREE_TYPE (rest), first, rest);
  }
  
  tree
  build_static_cast (tree type, tree expr)
  {
    tree intype;
!   int ok;
  
    if (type == error_mark_node || expr == error_mark_node)
      return error_mark_node;
  
    if (TREE_CODE (expr) == OFFSET_REF)
--- 4762,4789 ----
      return rest;
  
    return build (COMPOUND_EXPR, TREE_TYPE (rest), first, rest);
  }
  
+ /* Issue an error message if casting from SRC_TYPE to DEST_TYPE casts
+    away constness.  */
+ 
+ static void
+ check_for_casting_away_constness (tree src_type, tree dest_type)
+ {
+   if (casts_away_constness (src_type, dest_type))
+     error ("static_cast from type `%T' to type `%T' casts away constness",
+ 	   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 (TREE_CODE (expr) == OFFSET_REF)
*************** build_static_cast (tree type, tree expr)
*** 4787,4878 ****
    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);
  
    if (TREE_CODE (type) == VOID_TYPE)
      {
!       expr = convert_to_void (expr, /*implicit=*/NULL);
!       return expr;
      }
  
!   if (TREE_CODE (type) == REFERENCE_TYPE)
!     return (convert_from_reference
! 	    (convert_to_reference (type, expr, CONV_STATIC|CONV_IMPLICIT,
! 				   LOOKUP_COMPLAIN, NULL_TREE)));
! 
!   if (IS_AGGR_TYPE (type))
!     return build_cplus_new (type, (build_special_member_call
! 				   (NULL_TREE, complete_ctor_identifier, 
! 				    build_tree_list (NULL_TREE, expr),
! 				    TYPE_BINFO (type), LOOKUP_NORMAL)));
!   
!   intype = TREE_TYPE (expr);
! 
!   /* FIXME handle casting to array type.  */
  
!   ok = 0;
!   if (IS_AGGR_TYPE (intype)
!       ? can_convert_arg (type, intype, expr)
!       : can_convert_arg (strip_all_pointer_quals (type),
!                          strip_all_pointer_quals (intype), expr))
!     /* This is a standard conversion.  */
!     ok = 1;
!   else if (TYPE_PTROB_P (type) && TYPE_PTROB_P (intype))
      {
!       /* They're pointers to objects. They must be aggregates that
!          are related non-virtually.  */
!       base_kind kind;
!       
!       if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype))
! 	  && lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
! 			  ba_ignore | ba_quiet, &kind)
! 	  && kind != bk_via_virtual)
! 	ok = 1;
      }
!   else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
      {
!       /* They're pointers to members. The pointed to objects must be
! 	 the same (ignoring CV qualifiers), and the containing classes
! 	 must be related non-virtually.  */
!       base_kind kind;
!       
!       if (same_type_p
! 	  (strip_all_pointer_quals (TREE_TYPE (TREE_TYPE (type))),
! 	   strip_all_pointer_quals (TREE_TYPE (TREE_TYPE (intype))))
!  	  && (lookup_base (TYPE_OFFSET_BASETYPE (TREE_TYPE (intype)),
! 			   TYPE_OFFSET_BASETYPE (TREE_TYPE (type)),
! 			   ba_ignore | ba_quiet, &kind))
!  	  && kind != bk_via_virtual)
!   	ok = 1;
      }
!   else if (TREE_CODE (intype) != BOOLEAN_TYPE
! 	   && TREE_CODE (type) != ARRAY_TYPE
! 	   && TREE_CODE (type) != FUNCTION_TYPE
! 	   && can_convert (intype, strip_all_pointer_quals (type)))
!     ok = 1;
!   else if (TREE_CODE (intype) == ENUMERAL_TYPE
!            && TREE_CODE (type) == ENUMERAL_TYPE)
!     /* DR 128: "A value of integral _or enumeration_ type can be explicitly
!        converted to an enumeration type."
!        The integral to enumeration will be accepted by the previous clause.
!        We need to explicitly check for enumeration to enumeration.  */
!     ok = 1;
! 
    /* [expr.static.cast]
  
!      The static_cast operator shall not be used to cast away
!      constness.  */
!   if (ok && casts_away_constness (intype, type))
      {
!       error ("static_cast from type `%T' to type `%T' casts away constness",
! 		intype, type);
!       return error_mark_node;
      }
- 
-   if (ok)
-     return build_c_cast (type, expr);
  
    error ("invalid static_cast from type `%T' to type `%T'", intype, type);
    return error_mark_node;
  }
  
--- 4800,4952 ----
    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 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)
+     return result;
+   
+   /* [expr.static.cast]
+ 
+      Any expression can be explicitly converted to type cv void.  */
    if (TREE_CODE (type) == VOID_TYPE)
+     return convert_to_void (expr, /*implicit=*/NULL);
+ 
+   /* [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
+      "pointer to D" to "pointer to B" exists (_conv.ptr_), cv2 is the
+      same cv-qualification as, or greater cv-qualification than, cv1,
+      and B is not a virtual base class of D.  */
+   if (TREE_CODE (type) == REFERENCE_TYPE
+       && CLASS_TYPE_P (TREE_TYPE (type))
+       && CLASS_TYPE_P (intype)
+       && real_non_cast_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))
      {
!       /* At this point we have checked all of the conditions except
! 	 that B is not a virtual base class of D.  That will be
! 	 checked by build_base_path.  */
!       tree base = lookup_base (TREE_TYPE (type), intype, ba_any, NULL);
! 
!       /* Convert from B* to D*.  */
!       expr = build_base_path (MINUS_EXPR, build_address (expr), 
! 			      base, /*nonnull=*/false);
!       /* Convert the pointer to a reference.  */
!       return build_nop (type, expr);
      }
  
!   /* [expr.static.cast]
  
!      The inverse of any standard conversion sequence (clause _conv_),
!      other than the lvalue-to-rvalue (_conv.lval_), array-to-pointer
!      (_conv.array_), function-to-pointer (_conv.func_), and boolean
!      (_conv.bool_) conversions, can be performed explicitly using
!      static_cast subject to the restriction that the explicit
!      conversion does not cast away constness (_expr.const.cast_), and
!      the following additional rules for specific cases:  */
!   /* For reference, the conversions not excluded are: integral
!      promotions, floating point promotion, integral conversions,
!      floating point conversions, floating-integral conversions,
!      pointer conversions, and pointer to member conversions.  */
!   if ((ARITHMETIC_TYPE_P (type) && ARITHMETIC_TYPE_P (intype))
!       /* DR 128
! 
!          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);
!       base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype), 
! 			  ba_check | ba_quiet, NULL);
!       return build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false);
      }
!   if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
!       || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
      {
!       tree c1;
!       tree c2;
!       tree t1;
!       tree t2;
! 
!       c1 = TYPE_PTRMEM_CLASS_TYPE (intype);
!       c2 = TYPE_PTRMEM_CLASS_TYPE (type);
! 
!       if (TYPE_PTRMEM_P (type))
! 	{
! 	  t1 = (build_ptrmem_type 
! 		(c1,
! 		 TYPE_MAIN_VARIANT (TYPE_PTRMEM_POINTED_TO_TYPE (intype))));
! 	  t2 = (build_ptrmem_type 
! 		(c2,
! 		 TYPE_MAIN_VARIANT (TYPE_PTRMEM_POINTED_TO_TYPE (type))));
! 	}
!       else
! 	{
! 	  t1 = intype;
! 	  t2 = type;
! 	}
!       if (can_convert (t1, t2))
! 	{
! 	  check_for_casting_away_constness (intype, type);
! 	  if (TYPE_PTRMEM_P (type))
! 	    {
! 	      if (TREE_CODE (expr) == PTRMEM_CST)
! 		expr = cplus_expand_constant (expr);
! 	      expr = cp_build_binary_op (PLUS_EXPR, 
! 					 cp_convert (ptrdiff_type_node, expr),
! 					 get_delta_difference (c1, c2, 
! 							       /*force=*/1));
! 	      return build_nop (type, expr);
! 	    }
! 	  else
! 	    return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 
! 				     /*force=*/1);
! 	}
      }
!     
    /* [expr.static.cast]
  
!      An rvalue of type "pointer to cv void" can be explicitly
!      converted to a pointer to object type.  A value of type pointer
!      to object converted to "pointer to cv void" and back to the
!      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);
!       return build_nop (type, expr);
      }
  
    error ("invalid static_cast from type `%T' to type `%T'", intype, type);
    return error_mark_node;
  }
  
Index: testsuite/g++.dg/abi/mangle4.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/abi/mangle4.C,v
retrieving revision 1.1
diff -c -5 -p -r1.1 mangle4.C
*** testsuite/g++.dg/abi/mangle4.C	18 Nov 2001 06:24:45 -0000	1.1
--- testsuite/g++.dg/abi/mangle4.C	26 Jun 2003 00:03:19 -0000
***************
*** 1,10 ****
  // Test mangling of type casts
  // { dg-do compile }
  
  class A {};
! class B : A {};
  
  template<const A* a> class C {};
  template<const B* b> class D {};
  template<B* b> class E {};
  
--- 1,10 ----
  // Test mangling of type casts
  // { dg-do compile }
  
  class A {};
! class B : public A {};
  
  template<const A* a> class C {};
  template<const B* b> class D {};
  template<B* b> class E {};
  
Index: testsuite/g++.dg/expr/static_cast1.C
===================================================================
RCS file: testsuite/g++.dg/expr/static_cast1.C
diff -N testsuite/g++.dg/expr/static_cast1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/expr/static_cast1.C	26 Jun 2003 00:03:19 -0000
***************
*** 0 ****
--- 1,5 ----
+ void foo(int x)
+ {
+     static_cast<const unsigned int&>(x);
+ }
+ 
Index: testsuite/g++.dg/lookup/scoped1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/lookup/scoped1.C,v
retrieving revision 1.2
diff -c -5 -p -r1.2 scoped1.C
*** testsuite/g++.dg/lookup/scoped1.C	28 Dec 2002 07:48:06 -0000	1.2
--- testsuite/g++.dg/lookup/scoped1.C	26 Jun 2003 00:03:19 -0000
*************** struct C: public B
*** 15,22 ****
    void g ()
    {
      ::A::i1 = 1;
      ::A::i2 = 1;		// { dg-error "(access)|(context)" "" }
      ::A::f1 ();
!     ::A::f2 ();			// { dg-error "access" "" { xfail *-*-* } }
    }
  };
--- 15,22 ----
    void g ()
    {
      ::A::i1 = 1;
      ::A::i2 = 1;		// { dg-error "(access)|(context)" "" }
      ::A::f1 ();
!     ::A::f2 ();			// { dg-error "" }
    }
  };
Index: testsuite/g++.dg/rtti/dyncast1.C
===================================================================
RCS file: testsuite/g++.dg/rtti/dyncast1.C
diff -N testsuite/g++.dg/rtti/dyncast1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/rtti/dyncast1.C	26 Jun 2003 00:03:19 -0000
***************
*** 0 ****
--- 1,23 ----
+ class JunkBase
+ {
+ public:
+     virtual void DoSomething( void ) = 0;
+ protected:
+     virtual ~JunkBase( void ) {};
+     JunkBase( void ) {}
+ };
+ 
+ class Junk : protected JunkBase
+ {
+ public:
+     Junk( void ) : JunkBase() {}
+     virtual ~Junk( void ) {}
+ protected:
+     inline JunkBase * AsBase( void )
+     { return dynamic_cast< JunkBase * >( this ); }
+     virtual void DoSomething( void ) { }
+ };
+ 
+ 
+ 
+ 
Index: testsuite/g++.old-deja/g++.martin/pmf1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.martin/pmf1.C,v
retrieving revision 1.2
diff -c -5 -p -r1.2 pmf1.C
*** testsuite/g++.old-deja/g++.martin/pmf1.C	1 May 2003 02:02:44 -0000	1.2
--- testsuite/g++.old-deja/g++.martin/pmf1.C	26 Jun 2003 00:03:19 -0000
***************
*** 3,13 ****
  // Check for pointer-to-virtual-function calls on 
  // bases without virtual functions.
  
  struct B{};
  
! struct D:B{
    virtual void foo();
  };
  
  void D::foo(){}
  
--- 3,13 ----
  // Check for pointer-to-virtual-function calls on 
  // bases without virtual functions.
  
  struct B{};
  
! struct D: public B{
    virtual void foo();
  };
  
  void D::foo(){}
  


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