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: Use OFFSET_TYPE for pointers to data members


This patch removes a long-standing wart in the C++ front-end's tree
structure: the fact that pointers to data members were represented as
a POINTER_TYPE pointing to an OFFSET_TYPE, rather than directly as an
OFFSET_TYPE.  They are now just OFFSET_TYPEs.

(Ideally, both pointers-to-data-members and
pointers-to-function-members would be some new PTRMEM_TYPE until the
code got lowered; then they would split into OFFSET_TYPE/RECORD_TYPE
as appropriate.  But, things are not yet ideal...)

Tested on i686-pc-linux-gnu, applied on the mainline.

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

2003-07-22  Mark Mitchell  <mark@codesourcery.com>

	* fold-const.c (force_fit_type): Handle OFFSET_TYPE.
	* varasam.c (output_constant): Likewise.

2003-07-22  Mark Mitchell  <mark@codesourcery.com>

	Eliminate use of POINTER_TYPE for pointers-to-members.
	* call.c (standard_conversion): Rework pointer-to-member handling.
	Add comments.
	(add_builtin_candidate): Likewise.
	(resolve_scoped_fn_name): Remove.
	(build_conditional_expr): Rework pointer-to-member handling.
	(compare_ics): Likewise.
	* class.c (check_field_decls): Use TYPE_PTR_P.
	* cp-lang.c (cp_var_mod_type_p): Rework pointer-to-member
	handling.
	* cp-tree.h (SCALAR_TYPE_P): Use TYPE_PTR_TO_MEMBER_P.
	(TYPE_PTRMEM_P): Add comment.
	(TYPE_PTR_P): Simplify.
	(TYPE_PTROB_P): Correct definition.
	(TYPE_PTR_TO_MEMBER_P): New macro.
	(TYPE_PTRMEM_CLASS_TYPE): Adjust.
	(TYPE_PTRMEM_POINTED_TO_TYPE): Likewise.
	(resolved_scoped_fn_name): Remove declaration.
	(build_offset_ref): Change prototype.
	(resolve_offset_ref): Remove.
	(comp_target_types): Remove.
	* cvt.c (cp_convert_to_pointer): Rework pointer-to-member
	handling.
	(convert_to_reference): Use can_convert.
	(ocp_convert): Improve error handling.  Rework pointer-to-member
	handling.
	(perform_qualification_conversions): Rework pointer-to-member
	handling.
	* decl.c (build_ptrmem_type): Handle functions too.
	(create_array_type_for_decl): Remove OFFSET_TYPE error message.
	(grokdeclarator): Use OFFSET_TYPE for pointers to data members.
	(grokparms): Remove OFFSET_TYPE error message.
	* dump.c (cp_dump_tree): Rework pointer-to-member handling.
	* error.c (dump_type_prefix): Likewise.
	* expr.c (cplus_expand_constant): Use build_nop.
	* init.c (build_offset_ref): Add address_p parameter.  Fold in
	necessary bits from resolve_offset_ref.
	(resolve_offset_ref): Remove.
	* parser.c (cp_parser_postfix_expression): Remove special case
	code for OFFSET_TYPE.
	* pt.c (convert_nontype_argument): Rework pointer-to-member
	handling.
	(convert_template_argument): Likewise.
	(unify): Likewise.
	(invalid_nontype_parm_type_p): Likewise.
	(dependent_type_p_r): Likewise.
	* rtti.c (get_tinfo_decl): Remove OFFSET_TYPE special case.
	(target_incomplete_p_): Rework pointer-to-member
	handling.
	(get_pseudo_ti_init): Likewise.
	(get_pseudo_ti_desc): Likewise.
	* semantics.c (finish_qualified_id_expr): Adjust call to
	build_offset_ref.  Remove use of resolve_offset_ref.
	* tree.c (pod_type_p): Use TYPE_PTR_TO_MEMBER_P.
	* typeck.c (target_type): Use TYPE_PTRMEM_P.
	(type_unknown_p): Remove obsolete code about the time before
	non-dependent expressions were handled correctly.
	(qualify_type_recursive): Remove.
	(composite_pointer_type_r): New function.
	(composite_pointer_type): Use it.
	(merge_types): Remove dead comments.
	(comp_cv_target_types): Remove.
	(comp_target_types): Likewise.
	(comp_target_parms): Likewise.
	(cxx_sizeof_or_alignof_type): Remove OFFSET_TYPE error.
	(build_indirect_ref): Use TYPE_PTR_TO_MEMBER_P.
	(build_binary_op): Do not use of comp_target_types.
	(pointer_diff): Remove OFFSET_TYPE case.
	(build_unary_op): Adjust pointer-to-member handling.
	(unary_complex_lvalue): Likewise.
	(check_for_casting_away_constness): Add description parameter.
	(build_static_cast): Pass it.
	(build_reinterpret_cast): Use check_for_casting_away_constness.
	(build_const_cast): Adjust pointer-to-member handling.
	(build_c_cast): Likewise.
	(convert_for_assignment): Remove OFFSET_TYPE error message.
	(comp_ptr_ttypes_real): Adjust pointer-to-member handling.
	(comp_ptr_ttypes_reinterpret): Remove.
	(casts_away_constness_r): Adjust pointer-to-member handling.
	(casts_away_constness): Liekwise.
	(strip_all_pointer_quals): Remove.
	* typeck2.c (digest_init): Adjust pointer-to-member handling.
	(build_m_component_ref): Likewise.

Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.282
diff -c -5 -p -r1.282 fold-const.c
*** fold-const.c	19 Jul 2003 14:47:05 -0000	1.282
--- fold-const.c	22 Jul 2003 21:24:04 -0000
*************** force_fit_type (tree t, int overflow)
*** 191,201 ****
      return overflow;
  
    low = TREE_INT_CST_LOW (t);
    high = TREE_INT_CST_HIGH (t);
  
!   if (POINTER_TYPE_P (TREE_TYPE (t)))
      prec = POINTER_SIZE;
    else
      prec = TYPE_PRECISION (TREE_TYPE (t));
  
    /* First clear all bits that are beyond the type's precision.  */
--- 191,202 ----
      return overflow;
  
    low = TREE_INT_CST_LOW (t);
    high = TREE_INT_CST_HIGH (t);
  
!   if (POINTER_TYPE_P (TREE_TYPE (t))
!       || TREE_CODE (TREE_TYPE (t)) == OFFSET_TYPE)
      prec = POINTER_SIZE;
    else
      prec = TYPE_PRECISION (TREE_TYPE (t));
  
    /* First clear all bits that are beyond the type's precision.  */
Index: varasm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varasm.c,v
retrieving revision 1.374
diff -c -5 -p -r1.374 varasm.c
*** varasm.c	19 Jul 2003 14:47:14 -0000	1.374
--- varasm.c	22 Jul 2003 21:24:04 -0000
*************** output_constant (tree exp, unsigned HOST
*** 3693,3702 ****
--- 3693,3703 ----
      case BOOLEAN_TYPE:
      case INTEGER_TYPE:
      case ENUMERAL_TYPE:
      case POINTER_TYPE:
      case REFERENCE_TYPE:
+     case OFFSET_TYPE:
        if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
  					   EXPAND_INITIALIZER),
  			      size, align, 0))
  	error ("initializer for integer value is too complicated");
        break;
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.411
diff -c -5 -p -r1.411 call.c
*** cp/call.c	22 Jul 2003 09:53:25 -0000	1.411
--- cp/call.c	22 Jul 2003 21:24:05 -0000
*************** standard_conversion (tree to, tree from,
*** 640,654 ****
      }
  
    if (same_type_p (from, to))
      return conv;
  
!   if ((tcode == POINTER_TYPE || TYPE_PTRMEMFUNC_P (to))
        && expr && null_ptr_cst_p (expr))
!     {
!       conv = build_conv (STD_CONV, to, conv);
!     }
    else if ((tcode == INTEGER_TYPE && fcode == POINTER_TYPE)
  	   || (tcode == POINTER_TYPE && fcode == INTEGER_TYPE))
      {
        /* For backwards brain damage compatibility, allow interconversion of
  	 pointers and integers with a pedwarn.  */
--- 640,652 ----
      }
  
    if (same_type_p (from, to))
      return conv;
  
!   if ((tcode == POINTER_TYPE || TYPE_PTR_TO_MEMBER_P (to))
        && expr && null_ptr_cst_p (expr))
!     conv = build_conv (STD_CONV, to, conv);
    else if ((tcode == INTEGER_TYPE && fcode == POINTER_TYPE)
  	   || (tcode == POINTER_TYPE && fcode == INTEGER_TYPE))
      {
        /* For backwards brain damage compatibility, allow interconversion of
  	 pointers and integers with a pedwarn.  */
*************** standard_conversion (tree to, tree from,
*** 661,697 ****
        /* For backwards brain damage compatibility, allow interconversion of
  	 enums and integers with a pedwarn.  */
        conv = build_conv (STD_CONV, to, conv);
        ICS_BAD_FLAG (conv) = 1;
      }
!   else if (tcode == POINTER_TYPE && fcode == POINTER_TYPE)
      {
!       enum tree_code ufcode = TREE_CODE (TREE_TYPE (from));
!       enum tree_code utcode = TREE_CODE (TREE_TYPE (to));
  
!       if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (from),
! 						     TREE_TYPE (to)))
  	;
!       else if (utcode == VOID_TYPE && ufcode != OFFSET_TYPE
! 	       && ufcode != FUNCTION_TYPE)
  	{
  	  from = build_pointer_type
  	    (cp_build_qualified_type (void_type_node, 
  				      cp_type_quals (TREE_TYPE (from))));
  	  conv = build_conv (PTR_CONV, from, conv);
  	}
!       else if (ufcode == OFFSET_TYPE && utcode == OFFSET_TYPE)
  	{
! 	  tree fbase = TYPE_OFFSET_BASETYPE (TREE_TYPE (from));
! 	  tree tbase = TYPE_OFFSET_BASETYPE (TREE_TYPE (to));
  
  	  if (DERIVED_FROM_P (fbase, tbase)
  	      && (same_type_ignoring_top_level_qualifiers_p
! 		  (TREE_TYPE (TREE_TYPE (from)),
! 		   TREE_TYPE (TREE_TYPE (to)))))
  	    {
! 	      from = build_ptrmem_type (tbase, TREE_TYPE (TREE_TYPE (from)));
  	      conv = build_conv (PMEM_CONV, from, conv);
  	    }
  	}
        else if (IS_AGGR_TYPE (TREE_TYPE (from))
  	       && IS_AGGR_TYPE (TREE_TYPE (to)))
--- 659,699 ----
        /* For backwards brain damage compatibility, allow interconversion of
  	 enums and integers with a pedwarn.  */
        conv = build_conv (STD_CONV, to, conv);
        ICS_BAD_FLAG (conv) = 1;
      }
!   else if ((tcode == POINTER_TYPE && fcode == POINTER_TYPE)
! 	   || (TYPE_PTRMEM_P (to) && TYPE_PTRMEM_P (from)))
      {
!       tree to_pointee;
!       tree from_pointee;
  
!       if (tcode == POINTER_TYPE
! 	  && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (from),
! 							TREE_TYPE (to)))
  	;
!       else if (VOID_TYPE_P (TREE_TYPE (to))
! 	       && !TYPE_PTRMEM_P (from)
! 	       && TREE_CODE (TREE_TYPE (from)) != FUNCTION_TYPE)
  	{
  	  from = build_pointer_type
  	    (cp_build_qualified_type (void_type_node, 
  				      cp_type_quals (TREE_TYPE (from))));
  	  conv = build_conv (PTR_CONV, from, conv);
  	}
!       else if (TYPE_PTRMEM_P (from))
  	{
! 	  tree fbase = TYPE_PTRMEM_CLASS_TYPE (from);
! 	  tree tbase = TYPE_PTRMEM_CLASS_TYPE (to);
  
  	  if (DERIVED_FROM_P (fbase, tbase)
  	      && (same_type_ignoring_top_level_qualifiers_p
! 		  (TYPE_PTRMEM_POINTED_TO_TYPE (from),
! 		   TYPE_PTRMEM_POINTED_TO_TYPE (to))))
  	    {
! 	      from = build_ptrmem_type (tbase, 
! 					TYPE_PTRMEM_POINTED_TO_TYPE (from));
  	      conv = build_conv (PMEM_CONV, from, conv);
  	    }
  	}
        else if (IS_AGGR_TYPE (TREE_TYPE (from))
  	       && IS_AGGR_TYPE (TREE_TYPE (to)))
*************** standard_conversion (tree to, tree from,
*** 704,721 ****
  	      from = build_pointer_type (from);
  	      conv = build_conv (PTR_CONV, from, conv);
  	    }
  	}
  
        if (same_type_p (from, to))
  	/* OK */;
!       else if (comp_ptr_ttypes (TREE_TYPE (to), TREE_TYPE (from)))
  	conv = build_conv (QUAL_CONV, to, conv);
        else if (expr && string_conv_p (to, expr, 0))
  	/* converting from string constant to char *.  */
  	conv = build_conv (QUAL_CONV, to, conv);
!       else if (ptr_reasonably_similar (TREE_TYPE (to), TREE_TYPE (from)))
  	{
  	  conv = build_conv (PTR_CONV, to, conv);
  	  ICS_BAD_FLAG (conv) = 1;
  	}
        else
--- 706,734 ----
  	      from = build_pointer_type (from);
  	      conv = build_conv (PTR_CONV, from, conv);
  	    }
  	}
  
+       if (tcode == POINTER_TYPE)
+ 	{
+ 	  to_pointee = TREE_TYPE (to);
+ 	  from_pointee = TREE_TYPE (from);
+ 	}
+       else
+ 	{
+ 	  to_pointee = to;
+ 	  from_pointee = from;
+ 	}
+ 
        if (same_type_p (from, to))
  	/* OK */;
!       else if (comp_ptr_ttypes (to_pointee, from_pointee))
  	conv = build_conv (QUAL_CONV, to, conv);
        else if (expr && string_conv_p (to, expr, 0))
  	/* converting from string constant to char *.  */
  	conv = build_conv (QUAL_CONV, to, conv);
!       else if (ptr_reasonably_similar (to_pointee, from_pointee))
  	{
  	  conv = build_conv (PTR_CONV, to, conv);
  	  ICS_BAD_FLAG (conv) = 1;
  	}
        else
*************** standard_conversion (tree to, tree from,
*** 743,760 ****
        from = build_ptrmemfunc_type (build_pointer_type (from));
        conv = build_conv (PMEM_CONV, from, conv);
      }
    else if (tcode == BOOLEAN_TYPE)
      {
!       if (! (INTEGRAL_CODE_P (fcode) || fcode == REAL_TYPE
! 	     || fcode == POINTER_TYPE || TYPE_PTRMEMFUNC_P (from)))
! 	return 0;
  
!       conv = build_conv (STD_CONV, to, conv);
!       if (fcode == POINTER_TYPE
! 	  || (TYPE_PTRMEMFUNC_P (from) && ICS_STD_RANK (conv) < PBOOL_RANK))
! 	ICS_STD_RANK (conv) = PBOOL_RANK;
      }
    /* We don't check for ENUMERAL_TYPE here because there are no standard
       conversions to enum type.  */
    else if (tcode == INTEGER_TYPE || tcode == BOOLEAN_TYPE
  	   || tcode == REAL_TYPE)
--- 756,784 ----
        from = build_ptrmemfunc_type (build_pointer_type (from));
        conv = build_conv (PMEM_CONV, from, conv);
      }
    else if (tcode == BOOLEAN_TYPE)
      {
!       /* [conv.bool]
  
!           An rvalue of arithmetic, enumeration, pointer, or pointer to
! 	  member type can be converted to an rvalue of type bool.  */
!       if (ARITHMETIC_TYPE_P (from)
! 	  || fcode == ENUMERAL_TYPE
! 	  || fcode == POINTER_TYPE
! 	  || TYPE_PTR_TO_MEMBER_P (from))
! 	{
! 	  conv = build_conv (STD_CONV, to, conv);
! 	  if (fcode == POINTER_TYPE
! 	      || TYPE_PTRMEM_P (from)
! 	      || (TYPE_PTRMEMFUNC_P (from) 
! 		  && ICS_STD_RANK (conv) < PBOOL_RANK))
! 	    ICS_STD_RANK (conv) = PBOOL_RANK;
! 	  return conv;
! 	}
!       
!       return NULL_TREE;
      }
    /* We don't check for ENUMERAL_TYPE here because there are no standard
       conversions to enum type.  */
    else if (tcode == INTEGER_TYPE || tcode == BOOLEAN_TYPE
  	   || tcode == REAL_TYPE)
*************** add_builtin_candidate (struct z_candidat
*** 1590,1601 ****
       functions of the form
  	     T       operator+(T);
  	     T       operator-(T);  */
  
      case CONVERT_EXPR: /* unary + */
!       if (TREE_CODE (type1) == POINTER_TYPE
! 	  && TREE_CODE (TREE_TYPE (type1)) != OFFSET_TYPE)
  	break;
      case NEGATE_EXPR:
        if (ARITHMETIC_TYPE_P (type1))
  	break;
        return;
--- 1614,1624 ----
       functions of the form
  	     T       operator+(T);
  	     T       operator-(T);  */
  
      case CONVERT_EXPR: /* unary + */
!       if (TREE_CODE (type1) == POINTER_TYPE)
  	break;
      case NEGATE_EXPR:
        if (ARITHMETIC_TYPE_P (type1))
  	break;
        return;
*************** add_builtin_candidate (struct z_candidat
*** 1616,1631 ****
  	     CV12 T& operator->*(CV1 C1*, CV2 T C2::*);
       where CV12 is the union of CV1 and CV2.  */
  
      case MEMBER_REF:
        if (TREE_CODE (type1) == POINTER_TYPE
! 	  && (TYPE_PTRMEMFUNC_P (type2) || TYPE_PTRMEM_P (type2)))
  	{
  	  tree c1 = TREE_TYPE (type1);
! 	  tree c2 = (TYPE_PTRMEMFUNC_P (type2)
! 		     ? TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type2)))
! 		     : TYPE_OFFSET_BASETYPE (TREE_TYPE (type2)));
  
  	  if (IS_AGGR_TYPE (c1) && DERIVED_FROM_P (c2, c1)
  	      && (TYPE_PTRMEMFUNC_P (type2)
  		  || is_complete (TREE_TYPE (TREE_TYPE (type2)))))
  	    break;
--- 1639,1652 ----
  	     CV12 T& operator->*(CV1 C1*, CV2 T C2::*);
       where CV12 is the union of CV1 and CV2.  */
  
      case MEMBER_REF:
        if (TREE_CODE (type1) == POINTER_TYPE
! 	  && TYPE_PTR_TO_MEMBER_P (type2))
  	{
  	  tree c1 = TREE_TYPE (type1);
! 	  tree c2 = TYPE_PTRMEM_CLASS_TYPE (type2);
  
  	  if (IS_AGGR_TYPE (c1) && DERIVED_FROM_P (c2, c1)
  	      && (TYPE_PTRMEMFUNC_P (type2)
  		  || is_complete (TREE_TYPE (TREE_TYPE (type2)))))
  	    break;
*************** add_builtin_candidate (struct z_candidat
*** 1691,1708 ****
      case EQ_EXPR:
      case NE_EXPR:
        if ((TYPE_PTRMEMFUNC_P (type1) && TYPE_PTRMEMFUNC_P (type2))
  	  || (TYPE_PTRMEM_P (type1) && TYPE_PTRMEM_P (type2)))
  	break;
!       if ((TYPE_PTRMEMFUNC_P (type1) || TYPE_PTRMEM_P (type1))
! 	  && null_ptr_cst_p (args[1]))
  	{
  	  type2 = type1;
  	  break;
  	}
!       if ((TYPE_PTRMEMFUNC_P (type2) || TYPE_PTRMEM_P (type2))
! 	  && null_ptr_cst_p (args[0]))
  	{
  	  type1 = type2;
  	  break;
  	}
        /* FALLTHROUGH */
--- 1712,1727 ----
      case EQ_EXPR:
      case NE_EXPR:
        if ((TYPE_PTRMEMFUNC_P (type1) && TYPE_PTRMEMFUNC_P (type2))
  	  || (TYPE_PTRMEM_P (type1) && TYPE_PTRMEM_P (type2)))
  	break;
!       if (TYPE_PTR_TO_MEMBER_P (type1) && null_ptr_cst_p (args[1]))
  	{
  	  type2 = type1;
  	  break;
  	}
!       if (TYPE_PTR_TO_MEMBER_P (type2) && null_ptr_cst_p (args[0]))
  	{
  	  type1 = type2;
  	  break;
  	}
        /* FALLTHROUGH */
*************** add_builtin_candidate (struct z_candidat
*** 1869,1884 ****
  	  && promoted_arithmetic_type_p (type2))
  	/* That's OK.  */
  	break;
  
        /* Otherwise, the types should be pointers.  */
!       if (!(TREE_CODE (type1) == POINTER_TYPE
! 	    || TYPE_PTRMEM_P (type1)
! 	    || TYPE_PTRMEMFUNC_P (type1))
! 	  || !(TREE_CODE (type2) == POINTER_TYPE
! 	       || TYPE_PTRMEM_P (type2)
! 	       || TYPE_PTRMEMFUNC_P (type2)))
  	return;
        
        /* We don't check that the two types are the same; the logic
  	 below will actually create two candidates; one in which both
  	 parameter types are TYPE1, and one in which both parameter
--- 1888,1899 ----
  	  && promoted_arithmetic_type_p (type2))
  	/* That's OK.  */
  	break;
  
        /* Otherwise, the types should be pointers.  */
!       if (!(TYPE_PTR_P (type1) || TYPE_PTR_TO_MEMBER_P (type1))
! 	  || !(TYPE_PTR_P (type2) || TYPE_PTR_TO_MEMBER_P (type2)))
  	return;
        
        /* We don't check that the two types are the same; the logic
  	 below will actually create two candidates; one in which both
  	 parameter types are TYPE1, and one in which both parameter
*************** add_builtin_candidate (struct z_candidat
*** 1892,1903 ****
    /* If we're dealing with two pointer types or two enumeral types,
       we need candidates for both of them.  */
    if (type2 && !same_type_p (type1, type2)
        && TREE_CODE (type1) == TREE_CODE (type2)
        && (TREE_CODE (type1) == REFERENCE_TYPE
! 	  || (TREE_CODE (type1) == POINTER_TYPE
! 	      && TYPE_PTRMEM_P (type1) == TYPE_PTRMEM_P (type2))
  	  || TYPE_PTRMEMFUNC_P (type1)
  	  || IS_AGGR_TYPE (type1)
  	  || TREE_CODE (type1) == ENUMERAL_TYPE))
      {
        build_builtin_candidate
--- 1907,1918 ----
    /* If we're dealing with two pointer types or two enumeral types,
       we need candidates for both of them.  */
    if (type2 && !same_type_p (type1, type2)
        && TREE_CODE (type1) == TREE_CODE (type2)
        && (TREE_CODE (type1) == REFERENCE_TYPE
! 	  || (TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
! 	  || (TYPE_PTRMEM_P (type1) && TYPE_PTRMEM_P (type2))
  	  || TYPE_PTRMEMFUNC_P (type1)
  	  || IS_AGGR_TYPE (type1)
  	  || TREE_CODE (type1) == ENUMERAL_TYPE))
      {
        build_builtin_candidate
*************** build_user_type_conversion (tree totype,
*** 2603,2682 ****
        return convert_from_reference (convert_like (cand->second_conv, expr));
      }
    return NULL_TREE;
  }
  
- /* Find the possibly overloaded set of functions corresponding to a
-    call of the form SCOPE::NAME (...). NAME might be a
-    TEMPLATE_ID_EXPR, OVERLOAD, _DECL, or IDENTIFIER_NODE.  */
- 
- tree
- resolve_scoped_fn_name (tree scope, tree name)
- {
-   tree fn = NULL_TREE;
-   tree template_args = NULL_TREE;
-   bool is_template_id = TREE_CODE (name) == TEMPLATE_ID_EXPR;
-   
-   if (is_template_id)
-     {
-       template_args = TREE_OPERAND (name, 1);
-       name = TREE_OPERAND (name, 0);
-     }
-   if (TREE_CODE (name) == OVERLOAD)
-     name = DECL_NAME (get_first_fn (name));
-   
-   if (TREE_CODE (scope) == NAMESPACE_DECL)
-     fn = lookup_namespace_name (scope, name);
-   else if (!CLASS_TYPE_P (scope))
-     {
-       error ("`%T' is not a class type", scope);
-       return error_mark_node;
-     }
-   else
-     {
-       if (!TYPE_BEING_DEFINED (scope)
- 	  && !COMPLETE_TYPE_P (complete_type (scope)))
- 	{
- 	  error ("incomplete type '%T' cannot be used to name a scope",
- 		 scope);
- 	  return error_mark_node;
- 	}
-       
-       if (BASELINK_P (name))
- 	fn = name;
-       else
- 	fn = lookup_member (scope, name, /*protect=*/1, /*want_type=*/false);
-       if (fn && current_class_type)
- 	fn = (adjust_result_of_qualified_name_lookup 
- 	      (fn, scope, current_class_type));
- 
-       /* It might be the name of a function pointer member.  */
-       if (fn && TREE_CODE (fn) == FIELD_DECL)
- 	fn = finish_non_static_data_member (fn, current_class_ref, scope);
-     }
-   
-   if (!fn)
-     {
-       error ("'%D' has no member named '%E'", scope, name);
-       return error_mark_node;
-     }
-   if (is_template_id)
-     {
-       tree fns = fn;
- 
-       if (BASELINK_P (fn))
- 	fns = BASELINK_FUNCTIONS (fns);
-       fns = build_nt (TEMPLATE_ID_EXPR, fns, template_args);
-       if (BASELINK_P (fn))
- 	BASELINK_FUNCTIONS (fn) = fns;
-       else
- 	fn = fns;
-     }
-   
-   return fn;
- }
- 
  /* Do any initial processing on the arguments to a function call.  */
  
  static tree
  resolve_args (tree args)
  {
--- 2618,2627 ----
*************** build_conditional_expr (tree arg1, tree 
*** 3377,3395 ****
         qualification conversions (_conv.qual_) are performed to bring
         them to a common type, whose cv-qualification shall match the
         cv-qualification of either the second or the third operand.
         The result is of the common type.  */
    else if ((null_ptr_cst_p (arg2) 
! 	    && (TYPE_PTR_P (arg3_type) || TYPE_PTRMEM_P (arg3_type)
! 		|| TYPE_PTRMEMFUNC_P (arg3_type)))
  	   || (null_ptr_cst_p (arg3) 
! 	       && (TYPE_PTR_P (arg2_type) || TYPE_PTRMEM_P (arg2_type)
! 		|| TYPE_PTRMEMFUNC_P (arg2_type)))
  	   || (TYPE_PTR_P (arg2_type) && TYPE_PTR_P (arg3_type))
  	   || (TYPE_PTRMEM_P (arg2_type) && TYPE_PTRMEM_P (arg3_type))
! 	   || (TYPE_PTRMEMFUNC_P (arg2_type) 
! 	       && TYPE_PTRMEMFUNC_P (arg3_type)))
      {
        result_type = composite_pointer_type (arg2_type, arg3_type, arg2,
  					    arg3, "conditional expression");
        arg2 = perform_implicit_conversion (result_type, arg2);
        arg3 = perform_implicit_conversion (result_type, arg3);
--- 3322,3337 ----
         qualification conversions (_conv.qual_) are performed to bring
         them to a common type, whose cv-qualification shall match the
         cv-qualification of either the second or the third operand.
         The result is of the common type.  */
    else if ((null_ptr_cst_p (arg2) 
! 	    && (TYPE_PTR_P (arg3_type) || TYPE_PTR_TO_MEMBER_P (arg3_type)))
  	   || (null_ptr_cst_p (arg3) 
! 	       && (TYPE_PTR_P (arg2_type) || TYPE_PTR_TO_MEMBER_P (arg2_type)))
  	   || (TYPE_PTR_P (arg2_type) && TYPE_PTR_P (arg3_type))
  	   || (TYPE_PTRMEM_P (arg2_type) && TYPE_PTRMEM_P (arg3_type))
! 	   || (TYPE_PTRMEMFUNC_P (arg2_type) && TYPE_PTRMEMFUNC_P (arg3_type)))
      {
        result_type = composite_pointer_type (arg2_type, arg3_type, arg2,
  					    arg3, "conditional expression");
        arg2 = perform_implicit_conversion (result_type, arg2);
        arg3 = perform_implicit_conversion (result_type, arg3);
*************** compare_ics (tree ics1, tree ics2)
*** 5399,5427 ****
      }
    /* The rules for pointers to members A::* are just like the rules
       for pointers A*, except opposite: if B is derived from A then
       A::* converts to B::*, not vice versa.  For that reason, we
       switch the from_ and to_ variables here.  */
!   else if (TYPE_PTRMEM_P (from_type1)
! 	   && TYPE_PTRMEM_P (from_type2)
! 	   && TYPE_PTRMEM_P (to_type1)
! 	   && TYPE_PTRMEM_P (to_type2))
!     {
!       deref_to_type1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (from_type1));
!       deref_to_type2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (from_type2));
!       deref_from_type1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (to_type1));
!       deref_from_type2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (to_type2));
!     }
!   else if (TYPE_PTRMEMFUNC_P (from_type1)
! 	   && TYPE_PTRMEMFUNC_P (from_type2)
! 	   && TYPE_PTRMEMFUNC_P (to_type1)
! 	   && TYPE_PTRMEMFUNC_P (to_type2))
!     {
!       deref_to_type1 = TYPE_PTRMEMFUNC_OBJECT_TYPE (from_type1);
!       deref_to_type2 = TYPE_PTRMEMFUNC_OBJECT_TYPE (from_type2);
!       deref_from_type1 = TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type1);
!       deref_from_type2 = TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type2);
      }
  
    if (deref_from_type1 != NULL_TREE
        && IS_AGGR_TYPE_CODE (TREE_CODE (deref_from_type1))
        && IS_AGGR_TYPE_CODE (TREE_CODE (deref_from_type2)))
--- 5341,5361 ----
      }
    /* The rules for pointers to members A::* are just like the rules
       for pointers A*, except opposite: if B is derived from A then
       A::* converts to B::*, not vice versa.  For that reason, we
       switch the from_ and to_ variables here.  */
!   else if ((TYPE_PTRMEM_P (from_type1) && TYPE_PTRMEM_P (from_type2)
! 	    && TYPE_PTRMEM_P (to_type1) && TYPE_PTRMEM_P (to_type2))
! 	   || (TYPE_PTRMEMFUNC_P (from_type1)
! 	       && TYPE_PTRMEMFUNC_P (from_type2)
! 	       && TYPE_PTRMEMFUNC_P (to_type1)
! 	       && TYPE_PTRMEMFUNC_P (to_type2)))
!     {
!       deref_to_type1 = TYPE_PTRMEM_CLASS_TYPE (from_type1);
!       deref_to_type2 = TYPE_PTRMEM_CLASS_TYPE (from_type2);
!       deref_from_type1 = TYPE_PTRMEM_CLASS_TYPE (to_type1);
!       deref_from_type2 = TYPE_PTRMEM_CLASS_TYPE (to_type2);
      }
  
    if (deref_from_type1 != NULL_TREE
        && IS_AGGR_TYPE_CODE (TREE_CODE (deref_from_type1))
        && IS_AGGR_TYPE_CODE (TREE_CODE (deref_from_type2)))
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.555
diff -c -5 -p -r1.555 class.c
*** cp/class.c	22 Jul 2003 09:53:25 -0000	1.555
--- cp/class.c	22 Jul 2003 21:24:05 -0000
*************** check_field_decls (tree t, tree *access_
*** 3076,3086 ****
              cp_warning_at ("non-static reference `%#D' in class without a constructor", x);
  	}
  
        type = strip_array_types (type);
        
!       if (TREE_CODE (type) == POINTER_TYPE)
  	has_pointers = 1;
  
        if (DECL_MUTABLE_P (x) || TYPE_HAS_MUTABLE_P (type))
  	CLASSTYPE_HAS_MUTABLE (t) = 1;
  
--- 3076,3086 ----
              cp_warning_at ("non-static reference `%#D' in class without a constructor", x);
  	}
  
        type = strip_array_types (type);
        
!       if (TYPE_PTR_P (type))
  	has_pointers = 1;
  
        if (DECL_MUTABLE_P (x) || TYPE_HAS_MUTABLE_P (type))
  	CLASSTYPE_HAS_MUTABLE (t) = 1;
  
Index: cp/cp-lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-lang.c,v
retrieving revision 1.56
diff -c -5 -p -r1.56 cp-lang.c
*** cp/cp-lang.c	11 Jul 2003 08:33:18 -0000	1.56
--- cp/cp-lang.c	22 Jul 2003 21:24:05 -0000
*************** cp_tree_size (enum tree_code code)
*** 362,372 ****
  static bool
  cp_var_mod_type_p (tree type)
  {
    /* If TYPE is a pointer-to-member, it is variably modified if either
       the class or the member are variably modified.  */
!   if (TYPE_PTRMEM_P (type) || TYPE_PTRMEMFUNC_P (type))
      return (variably_modified_type_p (TYPE_PTRMEM_CLASS_TYPE (type))
  	    || variably_modified_type_p (TYPE_PTRMEM_POINTED_TO_TYPE (type)));
  
    /* All other types are not variably modified.  */
    return false;
--- 362,372 ----
  static bool
  cp_var_mod_type_p (tree type)
  {
    /* If TYPE is a pointer-to-member, it is variably modified if either
       the class or the member are variably modified.  */
!   if (TYPE_PTR_TO_MEMBER_P (type))
      return (variably_modified_type_p (TYPE_PTRMEM_CLASS_TYPE (type))
  	    || variably_modified_type_p (TYPE_PTRMEM_POINTED_TO_TYPE (type)));
  
    /* All other types are not variably modified.  */
    return false;
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.883
diff -c -5 -p -r1.883 cp-tree.h
*** cp/cp-tree.h	22 Jul 2003 09:53:26 -0000	1.883
--- cp/cp-tree.h	22 Jul 2003 21:24:06 -0000
*************** struct lang_decl GTY(())
*** 2419,2430 ****
     pointer-to-member types, are collectively called scalar types.  */
  #define SCALAR_TYPE_P(TYPE)			\
    (ARITHMETIC_TYPE_P (TYPE)			\
     || TREE_CODE (TYPE) == ENUMERAL_TYPE		\
     || TYPE_PTR_P (TYPE)				\
!    || TYPE_PTRMEM_P (TYPE)			\
!    || TYPE_PTRMEMFUNC_P (TYPE))
  
  /* [dcl.init.aggr]
  
     An aggregate is an array or a class with no user-declared
     constructors, no private or protected non-static data members, no
--- 2419,2429 ----
     pointer-to-member types, are collectively called scalar types.  */
  #define SCALAR_TYPE_P(TYPE)			\
    (ARITHMETIC_TYPE_P (TYPE)			\
     || TREE_CODE (TYPE) == ENUMERAL_TYPE		\
     || TYPE_PTR_P (TYPE)				\
!    || TYPE_PTR_TO_MEMBER_P (TYPE))
  
  /* [dcl.init.aggr]
  
     An aggregate is an array or a class with no user-declared
     constructors, no private or protected non-static data members, no
*************** struct lang_decl GTY(())
*** 2506,2523 ****
  /* Nonzero for class type means that assignment of this type can use
     a bitwise copy.  */
  #define TYPE_HAS_TRIVIAL_ASSIGN_REF(NODE) \
    (TYPE_HAS_ASSIGN_REF (NODE) && ! TYPE_HAS_COMPLEX_ASSIGN_REF (NODE))
  
! #define TYPE_PTRMEM_P(NODE)					\
!   (TREE_CODE (NODE) == POINTER_TYPE				\
!    && TREE_CODE (TREE_TYPE (NODE)) == OFFSET_TYPE)
! #define TYPE_PTR_P(NODE)				\
!   (TREE_CODE (NODE) == POINTER_TYPE			\
!    && TREE_CODE (TREE_TYPE (NODE)) != OFFSET_TYPE)
! #define TYPE_PTROB_P(NODE)						\
!   (TYPE_PTR_P (NODE) && TREE_CODE (TREE_TYPE (NODE)) != FUNCTION_TYPE	\
     && TREE_CODE (TREE_TYPE (NODE)) != VOID_TYPE)
  #define TYPE_PTROBV_P(NODE)						\
    (TYPE_PTR_P (NODE) && TREE_CODE (TREE_TYPE (NODE)) != FUNCTION_TYPE)
  #define TYPE_PTRFN_P(NODE)				\
    (TREE_CODE (NODE) == POINTER_TYPE			\
--- 2505,2523 ----
  /* Nonzero for class type means that assignment of this type can use
     a bitwise copy.  */
  #define TYPE_HAS_TRIVIAL_ASSIGN_REF(NODE) \
    (TYPE_HAS_ASSIGN_REF (NODE) && ! TYPE_HAS_COMPLEX_ASSIGN_REF (NODE))
  
! /* Returns true if NODE is a pointer-to-data-member.  */
! #define TYPE_PTRMEM_P(NODE)			\
!   (TREE_CODE (NODE) == OFFSET_TYPE)
! #define TYPE_PTR_P(NODE)			\
!   (TREE_CODE (NODE) == POINTER_TYPE)
! #define TYPE_PTROB_P(NODE)				\
!   (TYPE_PTR_P (NODE) 					\
!    && TREE_CODE (TREE_TYPE (NODE)) != FUNCTION_TYPE	\
!    && TREE_CODE (TREE_TYPE (NODE)) != METHOD_TYPE	\
     && TREE_CODE (TREE_TYPE (NODE)) != VOID_TYPE)
  #define TYPE_PTROBV_P(NODE)						\
    (TYPE_PTR_P (NODE) && TREE_CODE (TREE_TYPE (NODE)) != FUNCTION_TYPE)
  #define TYPE_PTRFN_P(NODE)				\
    (TREE_CODE (NODE) == POINTER_TYPE			\
*************** struct lang_decl GTY(())
*** 2534,2543 ****
--- 2534,2547 ----
     && TYPE_PTRMEMFUNC_FLAG (NODE))
  
  #define TYPE_PTRMEMFUNC_FLAG(NODE) \
    (LANG_TYPE_CLASS_CHECK (NODE)->ptrmemfunc_flag)
  
+ /* Returns true if NODE is a pointer-to-member.  */
+ #define TYPE_PTR_TO_MEMBER_P(NODE) \
+   (TYPE_PTRMEM_P (NODE) || TYPE_PTRMEMFUNC_P (NODE))
+ 
  /* Indicates when overload resolution may resolve to a pointer to
     member function. [expr.unary.op]/3 */
  #define PTRMEM_OK_P(NODE) TREE_LANG_FLAG_0 (NODE)
  
  /* Get the POINTER_TYPE to the METHOD_TYPE associated with this
*************** struct lang_decl GTY(())
*** 2572,2588 ****
     X'.  To get at the `const X' you have to look at the
     TYPE_PTRMEM_POINTED_TO_TYPE; there, the first parameter will have
     type `const X*'.  */
  #define TYPE_PTRMEM_CLASS_TYPE(NODE)			\
    (TYPE_PTRMEM_P (NODE)					\
!    ? TYPE_OFFSET_BASETYPE (TREE_TYPE (NODE))		\
     : TYPE_PTRMEMFUNC_OBJECT_TYPE (NODE))
  
  /* For a pointer-to-member type of the form `T X::*', this is `T'.  */
  #define TYPE_PTRMEM_POINTED_TO_TYPE(NODE)		\
     (TYPE_PTRMEM_P (NODE)				\
!     ? TREE_TYPE (TREE_TYPE (NODE))			\
      : TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (NODE)))
  
  /* For a pointer-to-member constant `X::Y' this is the RECORD_TYPE for
     `X'.  */
  #define PTRMEM_CST_CLASS(NODE) \
--- 2576,2592 ----
     X'.  To get at the `const X' you have to look at the
     TYPE_PTRMEM_POINTED_TO_TYPE; there, the first parameter will have
     type `const X*'.  */
  #define TYPE_PTRMEM_CLASS_TYPE(NODE)			\
    (TYPE_PTRMEM_P (NODE)					\
!    ? TYPE_OFFSET_BASETYPE (NODE)		\
     : TYPE_PTRMEMFUNC_OBJECT_TYPE (NODE))
  
  /* For a pointer-to-member type of the form `T X::*', this is `T'.  */
  #define TYPE_PTRMEM_POINTED_TO_TYPE(NODE)		\
     (TYPE_PTRMEM_P (NODE)				\
!     ? TREE_TYPE (NODE)					\
      : TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (NODE)))
  
  /* For a pointer-to-member constant `X::Y' this is the RECORD_TYPE for
     `X'.  */
  #define PTRMEM_CST_CLASS(NODE) \
*************** extern tree build_addr_func (tree);
*** 3525,3535 ****
  extern tree build_call (tree, tree);
  extern tree build_method_call (tree, tree, tree, tree, int);
  extern bool null_ptr_cst_p (tree);
  extern bool sufficient_parms_p (tree);
  extern tree type_decays_to (tree);
- extern tree resolve_scoped_fn_name (tree, tree);
  extern tree build_user_type_conversion (tree, tree, int);
  extern tree build_new_function_call (tree, tree);
  extern tree build_operator_new_call (tree, tree, tree *, tree *);
  extern tree build_new_method_call (tree, tree, tree, tree, int);
  extern tree build_special_member_call (tree, tree, tree, tree, int);
--- 3529,3538 ----
*************** extern tree build_aggr_init			(tree, tre
*** 3874,3885 ****
  extern tree build_init				(tree, tree, int);
  extern int is_aggr_type				(tree, int);
  extern tree get_aggr_from_typedef		(tree, int);
  extern tree get_type_value			(tree);
  extern tree build_zero_init       		(tree, tree, bool);
! extern tree build_offset_ref			(tree, tree);
! extern tree resolve_offset_ref			(tree);
  extern tree build_new				(tree, tree, tree, int);
  extern tree build_vec_init			(tree, tree, tree, int);
  extern tree build_x_delete			(tree, int, tree);
  extern tree build_delete			(tree, tree, special_function_kind, int, int);
  extern void push_base_cleanups			(void);
--- 3877,3887 ----
  extern tree build_init				(tree, tree, int);
  extern int is_aggr_type				(tree, int);
  extern tree get_aggr_from_typedef		(tree, int);
  extern tree get_type_value			(tree);
  extern tree build_zero_init       		(tree, tree, bool);
! extern tree build_offset_ref			(tree, tree, bool);
  extern tree build_new				(tree, tree, tree, int);
  extern tree build_vec_init			(tree, tree, tree, int);
  extern tree build_x_delete			(tree, int, tree);
  extern tree build_delete			(tree, tree, special_function_kind, int, int);
  extern void push_base_cleanups			(void);
*************** extern tree complete_type_or_diagnostic 
*** 4270,4280 ****
  extern int type_unknown_p			(tree);
  extern tree commonparms				(tree, tree);
  extern tree original_type			(tree);
  extern bool comp_except_specs			(tree, tree, bool);
  extern bool comptypes				(tree, tree, int);
- extern int comp_target_types			(tree, tree, int);
  extern bool compparms				(tree, tree);
  extern int comp_cv_qualification                (tree, tree);
  extern int comp_cv_qual_signature               (tree, tree);
  extern tree expr_sizeof				(tree);
  extern tree cxx_sizeof_or_alignof_type    (tree, enum tree_code, int);
--- 4272,4281 ----
Index: cp/cvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cvt.c,v
retrieving revision 1.142
diff -c -5 -p -r1.142 cvt.c
*** cp/cvt.c	8 Jul 2003 01:38:41 -0000	1.142
--- cp/cvt.c	22 Jul 2003 21:24:06 -0000
*************** cp_convert_to_pointer (tree type, tree e
*** 178,236 ****
  	      /* Add any qualifier conversions.  */
  	      return build_nop (type, expr);
  	    }
  	}
  
!       if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
  	{
! 	  tree b1; 
! 	  tree b2;
! 	  tree binfo;
! 	  enum tree_code code = PLUS_EXPR;
! 	  base_kind bk;
  
! 	  b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type));
! 	  b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype));
! 	  binfo = lookup_base (b1, b2, ba_check, &bk);
! 	  if (!binfo)
! 	    {
! 	      binfo = lookup_base (b2, b1, ba_check, &bk);
! 	      code = MINUS_EXPR;
! 	    }
! 	  if (binfo == error_mark_node)
! 	    return error_mark_node;
  
!           if (bk == bk_via_virtual)
  	    {
! 	      if (force)
! 	        warning ("pointer to member cast from `%T' to `%T' is via virtual base",
! 	                    TREE_TYPE (intype), TREE_TYPE (type));
!               else
!                 {
! 		  error ("pointer to member cast from `%T' to `%T' is via virtual base",
! 			    TREE_TYPE (intype), TREE_TYPE (type));
! 	          return error_mark_node;
! 	        }
! 	      /* This is a reinterpret cast, whose result is unspecified.
! 	         We choose to do nothing.  */
! 	      return build1 (NOP_EXPR, type, expr);
  	    }
! 	      
! 	  if (TREE_CODE (expr) == PTRMEM_CST)
! 	    expr = cplus_expand_constant (expr);
! 
! 	  if (binfo)
! 	    expr = size_binop (code, convert (sizetype, expr),
! 			       BINFO_OFFSET (binfo));
! 	}
!       else if (TYPE_PTRMEMFUNC_P (type))
! 	{
! 	  error ("cannot convert `%E' from type `%T' to type `%T'",
! 		    expr, intype, type);
! 	  return error_mark_node;
  	}
  
        return build_nop (type, expr);
      }
    else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))
      return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
    else if (TYPE_PTRMEMFUNC_P (intype))
--- 178,238 ----
  	      /* Add any qualifier conversions.  */
  	      return build_nop (type, expr);
  	    }
  	}
  
!       if (TYPE_PTRMEMFUNC_P (type))
  	{
! 	  error ("cannot convert `%E' from type `%T' to type `%T'",
! 		    expr, intype, type);
! 	  return error_mark_node;
! 	}
  
!       return build_nop (type, expr);
!     }
!   else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
!     {
!       tree b1; 
!       tree b2;
!       tree binfo;
!       enum tree_code code = PLUS_EXPR;
!       base_kind bk;
! 
!       b1 = TYPE_PTRMEM_CLASS_TYPE (type);
!       b2 = TYPE_PTRMEM_CLASS_TYPE (intype);
!       binfo = lookup_base (b1, b2, ba_check, &bk);
!       if (!binfo)
! 	{
! 	  binfo = lookup_base (b2, b1, ba_check, &bk);
! 	  code = MINUS_EXPR;
! 	}
!       if (binfo == error_mark_node)
! 	return error_mark_node;
  
!       if (bk == bk_via_virtual)
! 	{
! 	  if (force)
! 	    warning ("pointer to member cast from `%T' to `%T' is via virtual base",
! 		     intype, type);
! 	  else
  	    {
! 	      error ("pointer to member cast from `%T' to `%T' is via virtual base",
! 		     intype, type);
! 	      return error_mark_node;
  	    }
! 	  /* This is a reinterpret cast, whose result is unspecified.
! 	     We choose to do nothing.  */
! 	  return build1 (NOP_EXPR, type, expr);
  	}
  
+       if (TREE_CODE (expr) == PTRMEM_CST)
+ 	expr = cplus_expand_constant (expr);
+ 
+       if (binfo && !integer_zerop (BINFO_OFFSET (binfo)))
+ 	expr = size_binop (code, 
+ 			   build_nop (sizetype, expr),
+ 			   BINFO_OFFSET (binfo));
        return build_nop (type, expr);
      }
    else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))
      return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
    else if (TYPE_PTRMEMFUNC_P (intype))
*************** cp_convert_to_pointer (tree type, tree e
*** 251,262 ****
        error ("cannot convert `%E' from type `%T' to type `%T'",
  		expr, intype, type);
        return error_mark_node;
      }
  
-   my_friendly_assert (form != OFFSET_TYPE, 186);
- 
    if (integer_zerop (expr))
      {
        if (TYPE_PTRMEMFUNC_P (type))
  	return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
  
--- 253,262 ----
*************** cp_convert_to_pointer (tree type, tree e
*** 269,280 ****
        TREE_TYPE (expr) = type;
        /* Fix up the representation of -1 if appropriate.  */
        force_fit_type (expr, 0);
        return expr;
      }
!   else if ((TYPE_PTRMEM_P (type) || TYPE_PTRMEMFUNC_P (type))
! 	   && INTEGRAL_CODE_P (form))
      {
        error ("invalid conversion from '%T' to '%T'", intype, type);
        return error_mark_node;
      }
  
--- 269,279 ----
        TREE_TYPE (expr) = type;
        /* Fix up the representation of -1 if appropriate.  */
        force_fit_type (expr, 0);
        return expr;
      }
!   else if (TYPE_PTR_TO_MEMBER_P (type) && INTEGRAL_CODE_P (form))
      {
        error ("invalid conversion from '%T' to '%T'", intype, type);
        return error_mark_node;
      }
  
*************** convert_to_reference (tree reftype, tree
*** 452,462 ****
  {
    register tree type = TYPE_MAIN_VARIANT (TREE_TYPE (reftype));
    register tree intype;
    tree rval = NULL_TREE;
    tree rval_as_conversion = NULL_TREE;
!   int i;
  
    if (TREE_CODE (type) == FUNCTION_TYPE 
        && TREE_TYPE (expr) == unknown_type_node)
      expr = instantiate_type (type, expr, 
  			     (flags & LOOKUP_COMPLAIN)
--- 451,461 ----
  {
    register tree type = TYPE_MAIN_VARIANT (TREE_TYPE (reftype));
    register tree intype;
    tree rval = NULL_TREE;
    tree rval_as_conversion = NULL_TREE;
!   bool can_convert_intype_to_type;
  
    if (TREE_CODE (type) == FUNCTION_TYPE 
        && TREE_TYPE (expr) == unknown_type_node)
      expr = instantiate_type (type, expr, 
  			     (flags & LOOKUP_COMPLAIN)
*************** convert_to_reference (tree reftype, tree
*** 471,483 ****
  
    my_friendly_assert (TREE_CODE (intype) != REFERENCE_TYPE, 364);
  
    intype = TYPE_MAIN_VARIANT (intype);
  
!   i = comp_target_types (type, intype, 0);
! 
!   if (i <= 0 && (convtype & CONV_IMPLICIT) && IS_AGGR_TYPE (intype)
        && ! (flags & LOOKUP_NO_CONVERSION))
      {
        /* Look for a user-defined conversion to lvalue that we can use.  */
  
        rval_as_conversion
--- 470,482 ----
  
    my_friendly_assert (TREE_CODE (intype) != REFERENCE_TYPE, 364);
  
    intype = TYPE_MAIN_VARIANT (intype);
  
!   can_convert_intype_to_type = can_convert (type, intype);
!   if (!can_convert_intype_to_type
!       && (convtype & CONV_IMPLICIT) && IS_AGGR_TYPE (intype)
        && ! (flags & LOOKUP_NO_CONVERSION))
      {
        /* Look for a user-defined conversion to lvalue that we can use.  */
  
        rval_as_conversion
*************** convert_to_reference (tree reftype, tree
*** 487,502 ****
  	  && real_lvalue_p (rval_as_conversion))
  	{
  	  expr = rval_as_conversion;
  	  rval_as_conversion = NULL_TREE;
  	  intype = type;
! 	  i = 1;
  	}
      }
  
!   if (((convtype & CONV_STATIC) && i == -1)
!       || ((convtype & CONV_IMPLICIT) && i == 1))
      {
        if (flags & LOOKUP_COMPLAIN)
  	{
  	  tree ttl = TREE_TYPE (reftype);
  	  tree ttr = lvalue_type (expr);
--- 486,501 ----
  	  && real_lvalue_p (rval_as_conversion))
  	{
  	  expr = rval_as_conversion;
  	  rval_as_conversion = NULL_TREE;
  	  intype = type;
! 	  can_convert_intype_to_type = 1;
  	}
      }
  
!   if (((convtype & CONV_STATIC) && can_convert (intype, type))
!       || ((convtype & CONV_IMPLICIT) && can_convert_intype_to_type))
      {
        if (flags & LOOKUP_COMPLAIN)
  	{
  	  tree ttl = TREE_TYPE (reftype);
  	  tree ttr = lvalue_type (expr);
*************** convert_to_reference (tree reftype, tree
*** 548,559 ****
      {
        /* If we found a way to convert earlier, then use it.  */
        return rval;
      }
  
-   my_friendly_assert (TREE_CODE (intype) != OFFSET_TYPE, 189);
- 
    if (flags & LOOKUP_COMPLAIN)
      error ("cannot convert type `%T' to type `%T'", intype, reftype);
  
    if (flags & LOOKUP_SPECULATIVELY)
      return NULL_TREE;
--- 547,556 ----
*************** tree
*** 616,627 ****
  ocp_convert (tree type, tree expr, int convtype, int flags)
  {
    register tree e = expr;
    register enum tree_code code = TREE_CODE (type);
  
!   if (e == error_mark_node
!       || TREE_TYPE (e) == error_mark_node)
      return error_mark_node;
  
    complete_type (type);
    complete_type (TREE_TYPE (expr));
  
--- 613,623 ----
  ocp_convert (tree type, tree expr, int convtype, int flags)
  {
    register tree e = expr;
    register enum tree_code code = TREE_CODE (type);
  
!   if (error_operand_p (e) || type == error_mark_node)
      return error_mark_node;
  
    complete_type (type);
    complete_type (TREE_TYPE (expr));
  
*************** ocp_convert (tree type, tree expr, int c
*** 669,685 ****
      {
        e = convert_to_void (e, /*implicit=*/NULL);
        return e;
      }
  
-   /* Just convert to the type of the member.  */
-   if (code == OFFSET_TYPE)
-     {
-       type = TREE_TYPE (type);
-       code = TREE_CODE (type);
-     }
- 
    if (INTEGRAL_CODE_P (code))
      {
        tree intype = TREE_TYPE (e);
        /* enum = enum, enum = int, enum = float, (enum)pointer are all
           errors.  */
--- 665,674 ----
*************** ocp_convert (tree type, tree expr, int c
*** 719,730 ****
  	    warning ("the address of `%D', will always be `true'", fn);
  	  return cp_truthvalue_conversion (e);
  	}
        return fold (convert_to_integer (type, e));
      }
!   if (code == POINTER_TYPE || code == REFERENCE_TYPE
!       || TYPE_PTRMEMFUNC_P (type))
      return fold (cp_convert_to_pointer (type, e, false));
    if (code == VECTOR_TYPE)
      return fold (convert_to_vector (type, e));
    if (code == REAL_TYPE || code == COMPLEX_TYPE)
      {
--- 708,718 ----
  	    warning ("the address of `%D', will always be `true'", fn);
  	  return cp_truthvalue_conversion (e);
  	}
        return fold (convert_to_integer (type, e));
      }
!   if (POINTER_TYPE_P (type) || TYPE_PTR_TO_MEMBER_P (type))
      return fold (cp_convert_to_pointer (type, e, false));
    if (code == VECTOR_TYPE)
      return fold (convert_to_vector (type, e));
    if (code == REAL_TYPE || code == COMPLEX_TYPE)
      {
*************** type_promotes_to (tree type)
*** 1176,1187 ****
     the conversion was impossible.  */
  
  tree 
  perform_qualification_conversions (tree type, tree expr)
  {
!   if (TREE_CODE (type) == POINTER_TYPE
!       && TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE
!       && comp_ptr_ttypes (TREE_TYPE (type), TREE_TYPE (TREE_TYPE (expr))))
!     return build1 (NOP_EXPR, type, expr);
    else
      return error_mark_node;
  }
--- 1164,1185 ----
     the conversion was impossible.  */
  
  tree 
  perform_qualification_conversions (tree type, tree expr)
  {
!   tree expr_type;
! 
!   expr_type = TREE_TYPE (expr);
! 
!   if (TYPE_PTR_P (type) && TYPE_PTR_P (expr_type)
!       && comp_ptr_ttypes (TREE_TYPE (type), TREE_TYPE (expr_type)))
!     return build_nop (type, expr);
!   else if (TYPE_PTR_TO_MEMBER_P (type)
! 	   && TYPE_PTR_TO_MEMBER_P (expr_type)
! 	   && same_type_p (TYPE_PTRMEM_CLASS_TYPE (type),
! 			   TYPE_PTRMEM_CLASS_TYPE (expr_type))
! 	   && comp_ptr_ttypes (TYPE_PTRMEM_POINTED_TO_TYPE (type),
! 			       TYPE_PTRMEM_POINTED_TO_TYPE (expr_type)))
!     return build_nop (type, expr);
    else
      return error_mark_node;
  }
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1095
diff -c -5 -p -r1.1095 decl.c
*** cp/decl.c	22 Jul 2003 16:49:45 -0000	1.1095
--- cp/decl.c	22 Jul 2003 21:24:07 -0000
*************** build_ptrmemfunc_type (tree type)
*** 9282,9292 ****
  /* Create and return a pointer to data member type.  */
  
  tree
  build_ptrmem_type (tree class_type, tree member_type)
  {
!   return build_pointer_type (build_offset_type (class_type, member_type));
  }
  
  /* DECL is a VAR_DECL defined in-class, whose TYPE is also given.
     Check to see that the definition is valid.  Issue appropriate error
     messages.  Return 1 if the definition is particularly bad, or 0
--- 9282,9311 ----
  /* Create and return a pointer to data member type.  */
  
  tree
  build_ptrmem_type (tree class_type, tree member_type)
  {
!   if (TREE_CODE (member_type) == METHOD_TYPE)
!     {
!       tree arg_types;
! 
!       arg_types = TYPE_ARG_TYPES (member_type);
!       class_type = (cp_build_qualified_type 
! 		    (class_type,
! 		     cp_type_quals (TREE_TYPE (TREE_VALUE (arg_types)))));
!       member_type 
! 	= build_cplus_method_type (class_type, 
! 				   TREE_TYPE (member_type),
! 				   TREE_CHAIN (arg_types));
!       return build_ptrmemfunc_type (build_pointer_type (member_type));
!     }
!   else
!     {
!       my_friendly_assert (TREE_CODE (member_type) != FUNCTION_TYPE,
! 			  20030716);
!       return build_offset_type (class_type, member_type);
!     }
  }
  
  /* DECL is a VAR_DECL defined in-class, whose TYPE is also given.
     Check to see that the definition is valid.  Issue appropriate error
     messages.  Return 1 if the definition is particularly bad, or 0
*************** create_array_type_for_decl (tree name, t
*** 9519,9532 ****
  
      case REFERENCE_TYPE:
        error_msg = "array of references";
        break;
  
-     case OFFSET_TYPE:
-       error_msg = "array of data members";
-       break;
- 
      case METHOD_TYPE:
        error_msg = "array of function members";
        break;
  
      default:
--- 9538,9547 ----
*************** grokdeclarator (tree declarator,
*** 11358,11369 ****
  	  type = build_pointer_type (TREE_TYPE (type));
  	  type_quals = TYPE_UNQUALIFIED;
  	}
        else if (TREE_CODE (type) == FUNCTION_TYPE)
  	type = build_pointer_type (type);
-       else if (TREE_CODE (type) == OFFSET_TYPE)
- 	type = build_pointer_type (type);
      }
  
    {
      register tree decl;
  
--- 11373,11382 ----
*************** grokparms (tree first_parm)
*** 11986,12001 ****
  	     ignored for function types.  */
  	  type = TYPE_MAIN_VARIANT (type);
  	  if (TREE_CODE (type) == METHOD_TYPE)
  	    {
  	      error ("parameter `%D' invalidly declared method type", decl);
- 	      type = build_pointer_type (type);
- 	      TREE_TYPE (decl) = type;
- 	    }
- 	  else if (TREE_CODE (type) == OFFSET_TYPE)
- 	    {
- 	      error ("parameter `%D' invalidly declared offset type", decl);
  	      type = build_pointer_type (type);
  	      TREE_TYPE (decl) = type;
  	    }
  	  else if (abstract_virtuals_error (decl, type))
  	    any_error = 1;  /* Seems like a good idea.  */
--- 11999,12008 ----
Index: cp/dump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/dump.c,v
retrieving revision 1.72
diff -c -5 -p -r1.72 dump.c
*** cp/dump.c	29 Jun 2003 12:02:58 -0000	1.72
--- cp/dump.c	22 Jul 2003 21:24:07 -0000
*************** cp_dump_tree (void* dump_info, tree t)
*** 235,264 ****
  	  dump_string (di, "unnamed");
  	  return true;
  	}
        break;
  
!     case POINTER_TYPE:
!       if (TYPE_PTRMEM_P (t))
! 	{
! 	  dump_string (di, "ptrmem");
! 	  dump_child ("ptd", TYPE_PTRMEM_POINTED_TO_TYPE (t));
! 	  dump_child ("cls", TYPE_PTRMEM_CLASS_TYPE (t));
! 	  return true;
! 	}
!       break;
  
      case RECORD_TYPE:
-     case UNION_TYPE:
        if (TYPE_PTRMEMFUNC_P (t))
  	{
  	  dump_string (di, "ptrmem");
  	  dump_child ("ptd", TYPE_PTRMEM_POINTED_TO_TYPE (t));
  	  dump_child ("cls", TYPE_PTRMEM_CLASS_TYPE (t));
  	  return true;
  	}
  
        /* Is it a type used as a base? */
        if (TYPE_CONTEXT (t) && TREE_CODE (TYPE_CONTEXT (t)) == TREE_CODE (t)
  	  && CLASSTYPE_AS_BASE (TYPE_CONTEXT (t)) == t)
  	{
  	  dump_child ("bfld", TYPE_CONTEXT (t));
--- 235,261 ----
  	  dump_string (di, "unnamed");
  	  return true;
  	}
        break;
  
!     case OFFSET_TYPE:
!       dump_string (di, "ptrmem");
!       dump_child ("ptd", TYPE_PTRMEM_POINTED_TO_TYPE (t));
!       dump_child ("cls", TYPE_PTRMEM_CLASS_TYPE (t));
!       return true;
  
      case RECORD_TYPE:
        if (TYPE_PTRMEMFUNC_P (t))
  	{
  	  dump_string (di, "ptrmem");
  	  dump_child ("ptd", TYPE_PTRMEM_POINTED_TO_TYPE (t));
  	  dump_child ("cls", TYPE_PTRMEM_CLASS_TYPE (t));
  	  return true;
  	}
+       /* Fall through.  */
  
+     case UNION_TYPE:
        /* Is it a type used as a base? */
        if (TYPE_CONTEXT (t) && TREE_CODE (TYPE_CONTEXT (t)) == TREE_CODE (t)
  	  && CLASSTYPE_AS_BASE (TYPE_CONTEXT (t)) == t)
  	{
  	  dump_child ("bfld", TYPE_CONTEXT (t));
Index: cp/error.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/error.c,v
retrieving revision 1.224
diff -c -5 -p -r1.224 error.c
*** cp/error.c	16 Jul 2003 00:09:45 -0000	1.224
--- cp/error.c	22 Jul 2003 21:24:07 -0000
*************** dump_type_prefix (tree t, int flags)
*** 585,607 ****
      case REFERENCE_TYPE:
        {
  	tree sub = TREE_TYPE (t);
  
  	padding = dump_type_prefix (sub, flags);
! 	/* A tree for a member pointer looks like pointer to offset,
! 	   so let the OFFSET_TYPE case handle it.  */
! 	if (!TYPE_PTRMEM_P (t))
  	  {
! 	    if (TREE_CODE (sub) == ARRAY_TYPE)
!               {
!                 output_add_space (scratch_buffer);
!                 print_left_paren (scratch_buffer);
!               }
!             output_add_character
!               (scratch_buffer, "&*"[TREE_CODE (t) == POINTER_TYPE]);
! 	    padding = dump_qualifiers (t, before);
  	  }
        }
        break;
  
      case OFFSET_TYPE:
      offset_type:
--- 585,602 ----
      case REFERENCE_TYPE:
        {
  	tree sub = TREE_TYPE (t);
  
  	padding = dump_type_prefix (sub, flags);
! 	if (TREE_CODE (sub) == ARRAY_TYPE)
  	  {
! 	    output_add_space (scratch_buffer);
! 	    print_left_paren (scratch_buffer);
  	  }
+ 	output_add_character
+ 	  (scratch_buffer, "&*"[TREE_CODE (t) == POINTER_TYPE]);
+ 	padding = dump_qualifiers (t, before);
        }
        break;
  
      case OFFSET_TYPE:
      offset_type:
Index: cp/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/expr.c,v
retrieving revision 1.72
diff -c -5 -p -r1.72 expr.c
*** cp/expr.c	12 Mar 2003 22:24:48 -0000	1.72
--- cp/expr.c	22 Jul 2003 21:24:07 -0000
*************** cplus_expand_constant (tree cst)
*** 49,63 ****
        
  	/* Find the member.  */
  	member = PTRMEM_CST_MEMBER (cst);
  
  	if (TREE_CODE (member) == FIELD_DECL) 
! 	  {
! 	    /* Find the offset for the field.  */
! 	    tree offset = byte_position (member);
! 	    cst = fold (build1 (NOP_EXPR, type, offset));
! 	  }
  	else
  	  {
  	    tree delta;
  	    tree pfn;
  
--- 49,60 ----
        
  	/* Find the member.  */
  	member = PTRMEM_CST_MEMBER (cst);
  
  	if (TREE_CODE (member) == FIELD_DECL) 
! 	  /* Find the offset for the field.  */
! 	  cst = fold (build_nop (type, byte_position (member)));
  	else
  	  {
  	    tree delta;
  	    tree pfn;
  
Index: cp/init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.331
diff -c -5 -p -r1.331 init.c
*** cp/init.c	16 Jul 2003 00:09:45 -0000	1.331
--- cp/init.c	22 Jul 2003 21:24:07 -0000
*************** get_type_value (tree name)
*** 1335,1356 ****
      return IDENTIFIER_TYPE_VALUE (name);
    else
      return NULL_TREE;
  }
  
! /* Build a reference to a member of an aggregate.  This is not a
!    C++ `&', but really something which can have its address taken,
!    and then act as a pointer to member, for example TYPE :: FIELD
!    can have its address taken by saying & TYPE :: FIELD.
  
     @@ Prints out lousy diagnostics for operator <typename>
     @@ fields.
  
     @@ This function should be rewritten and placed in search.c.  */
  
  tree
! build_offset_ref (tree type, tree name)
  {
    tree decl;
    tree member;
    tree basebinfo = NULL_TREE;
    tree orig_name = name;
--- 1335,1357 ----
      return IDENTIFIER_TYPE_VALUE (name);
    else
      return NULL_TREE;
  }
  
! /* Build a reference to a member of an aggregate.  This is not a C++
!    `&', but really something which can have its address taken, and
!    then act as a pointer to member, for example TYPE :: FIELD can have
!    its address taken by saying & TYPE :: FIELD.  ADDRESS_P is true if
!    this expression is the operand of "&".
  
     @@ Prints out lousy diagnostics for operator <typename>
     @@ fields.
  
     @@ This function should be rewritten and placed in search.c.  */
  
  tree
! build_offset_ref (tree type, tree name, bool address_p)
  {
    tree decl;
    tree member;
    tree basebinfo = NULL_TREE;
    tree orig_name = name;
*************** build_offset_ref (tree type, tree name)
*** 1433,1444 ****
        
        if (member == error_mark_node)
  	return error_mark_node;
      }
  
    /* A lot of this logic is now handled in lookup_member.  */
!   if (member && BASELINK_P (member))
      {
        /* Go from the TREE_BASELINK to the member function info.  */
        tree fnfields = member;
        tree t = BASELINK_FUNCTIONS (fnfields);
  
--- 1434,1470 ----
        
        if (member == error_mark_node)
  	return error_mark_node;
      }
  
+   if (!member)
+     {
+       error ("`%D' is not a member of type `%T'", name, type);
+       return error_mark_node;
+     }
+ 
+   if (TREE_CODE (member) == TYPE_DECL)
+     {
+       TREE_USED (member) = 1;
+       return member;
+     }
+   /* static class members and class-specific enum
+      values can be returned without further ado.  */
+   if (TREE_CODE (member) == VAR_DECL || TREE_CODE (member) == CONST_DECL)
+     {
+       mark_used (member);
+       return convert_from_reference (member);
+     }
+ 
+   if (TREE_CODE (member) == FIELD_DECL && DECL_C_BIT_FIELD (member))
+     {
+       error ("invalid pointer to bit-field `%D'", member);
+       return error_mark_node;
+     }
+ 
    /* A lot of this logic is now handled in lookup_member.  */
!   if (BASELINK_P (member))
      {
        /* Go from the TREE_BASELINK to the member function info.  */
        tree fnfields = member;
        tree t = BASELINK_FUNCTIONS (fnfields);
  
*************** build_offset_ref (tree type, tree name)
*** 1473,1577 ****
  	  /* unique functions are handled easily.  */
  	  perform_or_defer_access_check (basebinfo, t);
  	  mark_used (t);
  	  if (DECL_STATIC_FUNCTION_P (t))
  	    return t;
! 	  t = build (OFFSET_REF, TREE_TYPE (t), decl, t);
! 	  PTRMEM_OK_P (t) = 1;
! 	  return t;
  	}
- 
-       TREE_TYPE (fnfields) = unknown_type_node;
-       
-       t = build (OFFSET_REF, unknown_type_node, decl, fnfields);
-       PTRMEM_OK_P (t) = 1;
-       return t;
      }
  
!   if (member == NULL_TREE)
      {
!       error ("`%D' is not a member of type `%T'", name, type);
!       return error_mark_node;
!     }
  
!   if (TREE_CODE (member) == TYPE_DECL)
!     {
!       TREE_USED (member) = 1;
!       return member;
!     }
!   /* static class members and class-specific enum
!      values can be returned without further ado.  */
!   if (TREE_CODE (member) == VAR_DECL || TREE_CODE (member) == CONST_DECL)
!     {
!       mark_used (member);
!       return convert_from_reference (member);
!     }
  
!   if (TREE_CODE (member) == FIELD_DECL && DECL_C_BIT_FIELD (member))
!     {
!       error ("invalid pointer to bit-field `%D'", member);
!       return error_mark_node;
!     }
  
!   /* static class functions too.  */
!   if (TREE_CODE (member) == FUNCTION_DECL
!       && TREE_CODE (TREE_TYPE (member)) == FUNCTION_TYPE)
!     abort ();
  
    /* In member functions, the form `type::name' is no longer
       equivalent to `this->type::name', at least not until
       resolve_offset_ref.  */
!   member = build (OFFSET_REF, build_offset_type (type, TREE_TYPE (member)), 
! 		  decl, member);
    PTRMEM_OK_P (member) = 1;
-   return member;
- }
- 
- /* If a OFFSET_REF made it through to here, then it did
-    not have its address taken.  */
- 
- tree
- resolve_offset_ref (tree exp)
- {
-   tree member;
- 
-   my_friendly_assert (TREE_CODE (exp) == OFFSET_REF, 20030703);
- 
-   member = TREE_OPERAND (exp, 1);
- 
-   /* If MEMBER is non-static, then the program has fallen afoul of
-      [expr.prim]:
- 
-        An id-expression that denotes a nonstatic data member or
-        nonstatic member function of a class can only be used:
- 
-        -- as part of a class member access (_expr.ref_) in which the
-        object-expression refers to the member's class or a class
-        derived from that class, or
- 
-        -- to form a pointer to member (_expr.unary.op_), or
- 
-        -- in the body of a nonstatic member function of that class or
-        of a class derived from that class (_class.mfct.nonstatic_), or
- 
-        -- in a mem-initializer for a constructor for that class or for
-        a class derived from that class (_class.base.init_).  */
-   if (DECL_NONSTATIC_MEMBER_FUNCTION_P (member))
-     {
-       /* In Microsoft mode, treat a non-static member function as if
- 	 it were a pointer-to-member.  */
-       if (flag_ms_extensions)
- 	return build_unary_op (ADDR_EXPR, exp, 0);
-       error ("invalid use of non-static member function `%D'", member);
-       return error_mark_node;
-     }
-   else if (TREE_CODE (member) == FIELD_DECL)
-     {
-       error ("invalid use of non-static data member `%D'", member);
-       return error_mark_node;
-     }
- 
    return member;
  }
  
  /* If DECL is a `const' declaration, and its value is a known
     constant, then return that value.  */
--- 1499,1562 ----
  	  /* unique functions are handled easily.  */
  	  perform_or_defer_access_check (basebinfo, t);
  	  mark_used (t);
  	  if (DECL_STATIC_FUNCTION_P (t))
  	    return t;
! 	  member = t;
! 	}
!       else
! 	{
! 	  TREE_TYPE (fnfields) = unknown_type_node;
! 	  member = fnfields;
  	}
      }
  
!   if (!address_p)
      {
!       /* If MEMBER is non-static, then the program has fallen afoul of
! 	 [expr.prim]:
  
! 	   An id-expression that denotes a nonstatic data member or
! 	   nonstatic member function of a class can only be used:
  
! 	   -- as part of a class member access (_expr.ref_) in which the
! 	   object-expression refers to the member's class or a class
! 	   derived from that class, or
! 
! 	   -- to form a pointer to member (_expr.unary.op_), or
! 
! 	   -- in the body of a nonstatic member function of that class or
! 	   of a class derived from that class (_class.mfct.nonstatic_), or
  
! 	   -- in a mem-initializer for a constructor for that class or for
! 	   a class derived from that class (_class.base.init_).  */
!       if (DECL_NONSTATIC_MEMBER_FUNCTION_P (member))
! 	{
! 	  /* In Microsoft mode, treat a non-static member function as if
! 	     it were a pointer-to-member.  */
! 	  if (flag_ms_extensions)
! 	    {
! 	      member = build (OFFSET_REF, TREE_TYPE (member), decl, member);
! 	      PTRMEM_OK_P (member) = 1;
! 	      return build_unary_op (ADDR_EXPR, member, 0);
! 	    }
! 	  error ("invalid use of non-static member function `%D'", member);
! 	  return error_mark_node;
! 	}
!       else if (TREE_CODE (member) == FIELD_DECL)
! 	{
! 	  error ("invalid use of non-static data member `%D'", member);
! 	  return error_mark_node;
! 	}
!       return member;
!     }
  
    /* In member functions, the form `type::name' is no longer
       equivalent to `this->type::name', at least not until
       resolve_offset_ref.  */
!   member = build (OFFSET_REF, TREE_TYPE (member), decl, member);
    PTRMEM_OK_P (member) = 1;
    return member;
  }
  
  /* If DECL is a `const' declaration, and its value is a known
     constant, then return that value.  */
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.86
diff -c -5 -p -r1.86 parser.c
*** cp/parser.c	19 Jul 2003 16:09:47 -0000	1.86
--- cp/parser.c	22 Jul 2003 21:24:08 -0000
*************** cp_parser_postfix_expression (cp_parser 
*** 3579,3599 ****
  		   that our internal representation of an expression
  		   may have reference type even when the standard says
  		   it does not.  Therefore, we have to manually obtain
  		   the underlying type here.  */
  		scope = non_reference (scope);
- 		/* If the SCOPE is an OFFSET_TYPE, then we grab the
- 		   type of the field.  We get an OFFSET_TYPE for
- 		   something like:
- 
- 		     S::T.a ...
- 
- 		   Probably, we should not get an OFFSET_TYPE here;
- 		   that transformation should be made only if `&S::T'
- 		   is written.  */
- 		if (TREE_CODE (scope) == OFFSET_TYPE)
- 		  scope = TREE_TYPE (scope);
  		/* The type of the POSTFIX_EXPRESSION must be
  		   complete.  */
  		scope = complete_type_or_else (scope, NULL_TREE);
  		/* Let the name lookup machinery know that we are
  		   processing a class member access expression.  */
--- 3579,3588 ----
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.733
diff -c -5 -p -r1.733 pt.c
*** cp/pt.c	19 Jul 2003 16:09:47 -0000	1.733
--- cp/pt.c	22 Jul 2003 21:24:09 -0000
*************** convert_nontype_argument (tree type, tre
*** 3002,3013 ****
    if (is_overloaded_fn (expr))
      /* OK for now.  We'll check that it has external linkage later.
         Check this first since if expr_type is the unknown_type_node
         we would otherwise complain below.  */
      ;
!   else if (TYPE_PTRMEM_P (expr_type)
! 	   || TYPE_PTRMEMFUNC_P (expr_type))
      {
        if (TREE_CODE (expr) != PTRMEM_CST)
  	goto bad_argument;
      }
    else if (TYPE_PTR_P (expr_type)
--- 3002,3012 ----
    if (is_overloaded_fn (expr))
      /* OK for now.  We'll check that it has external linkage later.
         Check this first since if expr_type is the unknown_type_node
         we would otherwise complain below.  */
      ;
!   else if (TYPE_PTR_TO_MEMBER_P (expr_type))
      {
        if (TREE_CODE (expr) != PTRMEM_CST)
  	goto bad_argument;
      }
    else if (TYPE_PTR_P (expr_type)
*************** convert_nontype_argument (tree type, tre
*** 3036,3047 ****
  		  if (TREE_CODE (TREE_TYPE (expr_type)) == FUNCTION_TYPE)
  		    error ("it must be the address of a function with external linkage");
  		  else
  		    error ("it must be the address of an object with external linkage");
  		}
! 	      else if (TYPE_PTRMEM_P (expr_type)
! 		       || TYPE_PTRMEMFUNC_P (expr_type))
  		error ("it must be a pointer-to-member of the form `&X::Y'");
  
  	      return NULL_TREE;
  	    }
  
--- 3035,3045 ----
  		  if (TREE_CODE (TREE_TYPE (expr_type)) == FUNCTION_TYPE)
  		    error ("it must be the address of a function with external linkage");
  		  else
  		    error ("it must be the address of an object with external linkage");
  		}
! 	      else if (TYPE_PTR_TO_MEMBER_P (expr_type))
  		error ("it must be a pointer-to-member of the form `&X::Y'");
  
  	      return NULL_TREE;
  	    }
  
*************** convert_nontype_argument (tree type, tre
*** 3068,3080 ****
  	{
  	  error ("address of non-extern `%E' cannot be used as template argument", referent); 
  	  return error_mark_node;
  	}
      }
!   else if (INTEGRAL_TYPE_P (expr_type) 
! 	   || TYPE_PTRMEM_P (expr_type) 
! 	   || TYPE_PTRMEMFUNC_P (expr_type))
      {
        if (! TREE_CONSTANT (expr))
  	{
  	non_constant:
  	  error ("non-constant `%E' cannot be used as template argument",
--- 3066,3076 ----
  	{
  	  error ("address of non-extern `%E' cannot be used as template argument", referent); 
  	  return error_mark_node;
  	}
      }
!   else if (INTEGRAL_TYPE_P (expr_type) || TYPE_PTR_TO_MEMBER_P (expr_type))
      {
        if (! TREE_CONSTANT (expr))
  	{
  	non_constant:
  	  error ("non-constant `%E' cannot be used as template argument",
*************** convert_nontype_argument (tree type, tre
*** 3115,3149 ****
  	   simplify to integer constants.  For example, `3 % 0',
  	   remains a TRUNC_MOD_EXPR.  */
  	goto non_constant;
        
        return expr;
! 	
      case POINTER_TYPE:
        {
  	tree type_pointed_to = TREE_TYPE (type);
   
! 	if (TYPE_PTRMEM_P (type))
! 	  {
! 	    tree e;
! 
! 	    /* For a non-type template-parameter of type pointer to data
! 	       member, qualification conversions (_conv.qual_) are
! 	       applied.  */
! 	    e = perform_qualification_conversions (type, expr);
! 	    if (TREE_CODE (e) == NOP_EXPR)
! 	      /* The call to perform_qualification_conversions will
! 		 insert a NOP_EXPR over EXPR to do express conversion,
! 		 if necessary.  But, that will confuse us if we use
! 		 this (converted) template parameter to instantiate
! 		 another template; then the thing will not look like a
! 		 valid template argument.  So, just make a new
! 		 constant, of the appropriate type.  */
! 	      e = make_ptrmem_cst (type, PTRMEM_CST_MEMBER (expr));
! 	    return e;
! 	  }
! 	else if (TREE_CODE (type_pointed_to) == FUNCTION_TYPE)
  	  { 
  	    /* For a non-type template-parameter of type pointer to
  	       function, only the function-to-pointer conversion
  	       (_conv.func_) is applied.  If the template-argument
  	       represents a set of overloaded functions (or a pointer to
--- 3111,3146 ----
  	   simplify to integer constants.  For example, `3 % 0',
  	   remains a TRUNC_MOD_EXPR.  */
  	goto non_constant;
        
        return expr;
! 
!     case OFFSET_TYPE:
!       {
! 	tree e;
! 
! 	/* For a non-type template-parameter of type pointer to data
! 	   member, qualification conversions (_conv.qual_) are
! 	   applied.  */
! 	e = perform_qualification_conversions (type, expr);
! 	if (TREE_CODE (e) == NOP_EXPR)
! 	  /* The call to perform_qualification_conversions will
! 	     insert a NOP_EXPR over EXPR to do express conversion,
! 	     if necessary.  But, that will confuse us if we use
! 	     this (converted) template parameter to instantiate
! 	     another template; then the thing will not look like a
! 	     valid template argument.  So, just make a new
! 	     constant, of the appropriate type.  */
! 	  e = make_ptrmem_cst (type, PTRMEM_CST_MEMBER (expr));
! 	return e;
!       }
! 
      case POINTER_TYPE:
        {
  	tree type_pointed_to = TREE_TYPE (type);
   
! 	if (TREE_CODE (type_pointed_to) == FUNCTION_TYPE)
  	  { 
  	    /* For a non-type template-parameter of type pointer to
  	       function, only the function-to-pointer conversion
  	       (_conv.func_) is applied.  If the template-argument
  	       represents a set of overloaded functions (or a pointer to
*************** convert_template_argument (tree parm, 
*** 3419,3430 ****
    int is_type, requires_type, is_tmpl_type, requires_tmpl_type;
    
    inner_args = INNERMOST_TEMPLATE_ARGS (args);
  
    if (TREE_CODE (arg) == TREE_LIST 
!       && TREE_TYPE (arg) != NULL_TREE
!       && TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
      {  
        /* The template argument was the name of some
  	 member function.  That's usually
  	 invalid, but static members are OK.  In any
  	 case, grab the underlying fields/functions
--- 3416,3426 ----
    int is_type, requires_type, is_tmpl_type, requires_tmpl_type;
    
    inner_args = INNERMOST_TEMPLATE_ARGS (args);
  
    if (TREE_CODE (arg) == TREE_LIST 
!       && TREE_CODE (TREE_VALUE (arg)) == OFFSET_REF)
      {  
        /* The template argument was the name of some
  	 member function.  That's usually
  	 invalid, but static members are OK.  In any
  	 case, grab the underlying fields/functions
*************** tsubst (tree t, tree args, tsubst_flags_
*** 6813,6837 ****
  	    
  	    return error_mark_node;
  	  }
  	my_friendly_assert (TREE_CODE (type) != METHOD_TYPE, 20011231);
  	if (TREE_CODE (type) == FUNCTION_TYPE)
! 	  /* This is really a method type. The cv qualifiers of the
! 	     this pointer should _not_ be determined by the cv
! 	     qualifiers of the class type.  They should be held
! 	     somewhere in the FUNCTION_TYPE, but we don't do that at
! 	     the moment.  Consider
! 	        typedef void (Func) () const;
! 
! 		template <typename T1> void Foo (Func T1::*);
! 
! 	      */
! 	  return build_cplus_method_type (TYPE_MAIN_VARIANT (r),
! 					  TREE_TYPE (type),
! 					  TYPE_ARG_TYPES (type));
  	else
! 	  return build_offset_type (r, type);
        }
      case FUNCTION_TYPE:
      case METHOD_TYPE:
        {
  	tree fntype;
--- 6809,6838 ----
  	    
  	    return error_mark_node;
  	  }
  	my_friendly_assert (TREE_CODE (type) != METHOD_TYPE, 20011231);
  	if (TREE_CODE (type) == FUNCTION_TYPE)
! 	  {
! 	    /* This is really a method type. The cv qualifiers of the
! 	       this pointer should _not_ be determined by the cv
! 	       qualifiers of the class type.  They should be held
! 	       somewhere in the FUNCTION_TYPE, but we don't do that at
! 	       the moment.  Consider
! 		  typedef void (Func) () const;
! 
! 		  template <typename T1> void Foo (Func T1::*);
! 
! 		*/
! 	    tree method_type;
! 
! 	    method_type = build_cplus_method_type (TYPE_MAIN_VARIANT (r),
! 						   TREE_TYPE (type),
! 						   TYPE_ARG_TYPES (type));
! 	    return build_ptrmemfunc_type (build_pointer_type (method_type));
! 	  }
  	else
! 	  return build_ptrmem_type (r, type);
        }
      case FUNCTION_TYPE:
      case METHOD_TYPE:
        {
  	tree fntype;
*************** unify (tree tparms, tree targs, tree par
*** 9509,9524 ****
  	  else if (targ)
  	    return 1;
  	}
        else
  	{
- 	  /* If ARG is an offset type, we're trying to unify '*T' with
- 	     'U C::*', which is ill-formed. See the comment in the
- 	     POINTER_TYPE case about this ugliness.  */
- 	  if (TREE_CODE (arg) == OFFSET_TYPE)
- 	    return 1;
- 	  
  	  /* If PARM is `const T' and ARG is only `int', we don't have
  	     a match unless we are allowing additional qualification.
  	     If ARG is `const int' and PARM is just `T' that's OK;
  	     that binds `const int' to `T'.  */
  	  if (!check_cv_quals_for_unify (strict_in | UNIFY_ALLOW_LESS_CV_QUAL, 
--- 9510,9519 ----
*************** unify (tree tparms, tree targs, tree par
*** 9615,9636 ****
  	if (TREE_CODE (TREE_TYPE (arg)) == RECORD_TYPE)
  	  /* The derived-to-base conversion only persists through one
  	     level of pointers.  */
  	  strict |= (strict_in & UNIFY_ALLOW_DERIVED);
  
- 	if (TREE_CODE (TREE_TYPE (parm)) == OFFSET_TYPE
- 	    && TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
- 	  {
- 	    /* Avoid getting confused about cv-quals; don't recurse here.
- 	       Pointers to members should really be just OFFSET_TYPE, not
- 	       this two-level nonsense...  */
- 
- 	    parm = TREE_TYPE (parm);
- 	    arg = TREE_TYPE (arg);
- 	    goto offset;
- 	  }
- 
  	return unify (tparms, targs, TREE_TYPE (parm), 
  		      TREE_TYPE (arg), strict);
        }
  
      case REFERENCE_TYPE:
--- 9610,9619 ----
*************** unify (tree tparms, tree targs, tree par
*** 9780,9790 ****
        return type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm),
  				    TYPE_ARG_TYPES (arg), 1, 
  				    DEDUCE_EXACT, 0, -1);
  
      case OFFSET_TYPE:
-     offset:
        if (TREE_CODE (arg) != OFFSET_TYPE)
  	return 1;
        if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
  		 TYPE_OFFSET_BASETYPE (arg), UNIFY_ALLOW_NONE))
  	return 1;
--- 9763,9772 ----
*************** invalid_nontype_parm_type_p (tree type, 
*** 11284,11296 ****
  {
    if (INTEGRAL_TYPE_P (type))
      return 0;
    else if (POINTER_TYPE_P (type))
      return 0;
!   else if (TYPE_PTRMEM_P (type))
!     return 0;
!   else if (TYPE_PTRMEMFUNC_P (type))
      return 0;
    else if (TREE_CODE (type) == TEMPLATE_TYPE_PARM)
      return 0;
    else if (TREE_CODE (type) == TYPENAME_TYPE)
      return 0;
--- 11266,11276 ----
  {
    if (INTEGRAL_TYPE_P (type))
      return 0;
    else if (POINTER_TYPE_P (type))
      return 0;
!   else if (TYPE_PTR_TO_MEMBER_P (type))
      return 0;
    else if (TREE_CODE (type) == TEMPLATE_TYPE_PARM)
      return 0;
    else if (TREE_CODE (type) == TYPENAME_TYPE)
      return 0;
*************** dependent_type_p_r (tree type)
*** 11323,11333 ****
      return true;
    /* -- a cv-qualified type where the cv-unqualified type is
          dependent.  */
    type = TYPE_MAIN_VARIANT (type);
    /* -- a compound type constructed from any dependent type.  */
!   if (TYPE_PTRMEM_P (type) || TYPE_PTRMEMFUNC_P (type))
      return (dependent_type_p (TYPE_PTRMEM_CLASS_TYPE (type))
  	    || dependent_type_p (TYPE_PTRMEM_POINTED_TO_TYPE 
  					   (type)));
    else if (TREE_CODE (type) == POINTER_TYPE
  	   || TREE_CODE (type) == REFERENCE_TYPE)
--- 11303,11313 ----
      return true;
    /* -- a cv-qualified type where the cv-unqualified type is
          dependent.  */
    type = TYPE_MAIN_VARIANT (type);
    /* -- a compound type constructed from any dependent type.  */
!   if (TYPE_PTR_TO_MEMBER_P (type))
      return (dependent_type_p (TYPE_PTRMEM_CLASS_TYPE (type))
  	    || dependent_type_p (TYPE_PTRMEM_POINTED_TO_TYPE 
  					   (type)));
    else if (TREE_CODE (type) == POINTER_TYPE
  	   || TREE_CODE (type) == REFERENCE_TYPE)
Index: cp/rtti.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/rtti.c,v
retrieving revision 1.169
diff -c -5 -p -r1.169 rtti.c
*** cp/rtti.c	19 Jul 2003 16:09:47 -0000	1.169
--- cp/rtti.c	22 Jul 2003 21:24:09 -0000
*************** get_tinfo_decl (tree type)
*** 329,340 ****
        error ("cannot create type information for type `%T' because its size is variable", 
  	     type);
        return error_mark_node;
      }
  
-   if (TREE_CODE (type) == OFFSET_TYPE)
-     type = TREE_TYPE (type);
    if (TREE_CODE (type) == METHOD_TYPE)
      type = build_function_type (TREE_TYPE (type),
  				TREE_CHAIN (TYPE_ARG_TYPES (type)));
  
    /* For a class type, the variable is cached in the type node
--- 329,338 ----
*************** qualifier_flags (tree type)
*** 713,735 ****
     contains a pointer to member of an incomplete class.  */
  
  static bool
  target_incomplete_p (tree type)
  {
!   while (TREE_CODE (type) == POINTER_TYPE)
      if (TYPE_PTRMEM_P (type))
        {
!         if (!COMPLETE_TYPE_P (TYPE_PTRMEM_CLASS_TYPE (type)))
!           return true;
!         type = TYPE_PTRMEM_POINTED_TO_TYPE (type);
        }
!     else
        type = TREE_TYPE (type);
!   if (!COMPLETE_OR_VOID_TYPE_P (type))
!     return true;
!   
!   return false;
  }
  
  /* Return a CONSTRUCTOR for the common part of the type_info objects. This
     is the vtable pointer and NTBS name.  The NTBS name is emitted as a
     comdat const char array, so it becomes a unique key for the type. Generate
--- 711,731 ----
     contains a pointer to member of an incomplete class.  */
  
  static bool
  target_incomplete_p (tree type)
  {
!   while (true)
      if (TYPE_PTRMEM_P (type))
        {
! 	if (!COMPLETE_TYPE_P (TYPE_PTRMEM_CLASS_TYPE (type)))
! 	  return true;
! 	type = TYPE_PTRMEM_POINTED_TO_TYPE (type);
        }
!     else if (TREE_CODE (type) == POINTER_TYPE)
        type = TREE_TYPE (type);
!     else
!       return !COMPLETE_OR_VOID_TYPE_P (type);
  }
  
  /* Return a CONSTRUCTOR for the common part of the type_info objects. This
     is the vtable pointer and NTBS name.  The NTBS name is emitted as a
     comdat const char array, so it becomes a unique key for the type. Generate
*************** static tree
*** 997,1012 ****
  get_pseudo_ti_init (tree type, tree var_desc, bool *non_public_p)
  {
    my_friendly_assert (at_eof, 20021120);
    switch (TREE_CODE (type))
      {
      case POINTER_TYPE:
!       if (TYPE_PTRMEM_P (type))
! 	return ptm_initializer (var_desc, type, non_public_p);
!       else
! 	return ptr_initializer (var_desc, type, non_public_p);
!       break;
      case ENUMERAL_TYPE:
        return generic_initializer (var_desc, type);
        break;
      case FUNCTION_TYPE:
        return generic_initializer (var_desc, type);
--- 993,1006 ----
  get_pseudo_ti_init (tree type, tree var_desc, bool *non_public_p)
  {
    my_friendly_assert (at_eof, 20021120);
    switch (TREE_CODE (type))
      {
+     case OFFSET_TYPE:
+       return ptm_initializer (var_desc, type, non_public_p);
      case POINTER_TYPE:
!       return ptr_initializer (var_desc, type, non_public_p);
      case ENUMERAL_TYPE:
        return generic_initializer (var_desc, type);
        break;
      case FUNCTION_TYPE:
        return generic_initializer (var_desc, type);
*************** create_pseudo_type_info (const char *rea
*** 1162,1173 ****
  static tree
  get_pseudo_ti_desc (tree type)
  {
    switch (TREE_CODE (type))
      {
      case POINTER_TYPE:
!       return TYPE_PTRMEM_P (type) ? ptm_desc_type_node : ptr_desc_type_node;
      case ENUMERAL_TYPE:
        return enum_desc_type_node;
      case FUNCTION_TYPE:
        return func_desc_type_node;
      case ARRAY_TYPE:
--- 1156,1169 ----
  static tree
  get_pseudo_ti_desc (tree type)
  {
    switch (TREE_CODE (type))
      {
+     case OFFSET_TYPE:
+       return ptm_desc_type_node;
      case POINTER_TYPE:
!       return ptr_desc_type_node;
      case ENUMERAL_TYPE:
        return enum_desc_type_node;
      case FUNCTION_TYPE:
        return func_desc_type_node;
      case ARRAY_TYPE:
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.332
diff -c -5 -p -r1.332 semantics.c
*** cp/semantics.c	21 Jul 2003 08:28:33 -0000	1.332
--- cp/semantics.c	22 Jul 2003 21:24:09 -0000
*************** finish_qualified_id_expr (tree qualifyin
*** 1365,1375 ****
       permits a pointer-to-member.  */
    if (address_p && done)
      {
        if (TREE_CODE (expr) == SCOPE_REF)
  	expr = TREE_OPERAND (expr, 1);
!       expr = build_offset_ref (qualifying_class, expr);
        return expr;
      }
  
    if (TREE_CODE (expr) == FIELD_DECL)
      expr = finish_non_static_data_member (expr, current_class_ref,
--- 1365,1376 ----
       permits a pointer-to-member.  */
    if (address_p && done)
      {
        if (TREE_CODE (expr) == SCOPE_REF)
  	expr = TREE_OPERAND (expr, 1);
!       expr = build_offset_ref (qualifying_class, expr, 
! 			       /*address_p=*/true);
        return expr;
      }
  
    if (TREE_CODE (expr) == FIELD_DECL)
      expr = finish_non_static_data_member (expr, current_class_ref,
*************** finish_qualified_id_expr (tree qualifyin
*** 1394,1410 ****
  		(maybe_dummy_object (qualifying_class, NULL),
  		 expr,
  		 BASELINK_ACCESS_BINFO (expr),
  		 /*preserve_reference=*/false));
        else if (done)
! 	{
! 	  /* The expression is a qualified name whose address is not
! 	     being taken.  */
! 	  expr = build_offset_ref (qualifying_class, expr);
! 	  if (TREE_CODE (expr) == OFFSET_REF)
! 	    expr = resolve_offset_ref (expr);
! 	}
      }
  
    return expr;
  }
  
--- 1395,1407 ----
  		(maybe_dummy_object (qualifying_class, NULL),
  		 expr,
  		 BASELINK_ACCESS_BINFO (expr),
  		 /*preserve_reference=*/false));
        else if (done)
! 	/* The expression is a qualified name whose address is not
! 	   being taken.  */
! 	expr = build_offset_ref (qualifying_class, expr, /*address_p=*/false);
      }
  
    return expr;
  }
  
Index: cp/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.338
diff -c -5 -p -r1.338 tree.c
*** cp/tree.c	22 Jul 2003 09:53:26 -0000	1.338
--- cp/tree.c	22 Jul 2003 21:24:09 -0000
*************** pod_type_p (tree t)
*** 1773,1786 ****
      return 1;  /* integral, character or enumeral type */
    if (FLOAT_TYPE_P (t))
      return 1;
    if (TYPE_PTR_P (t))
      return 1; /* pointer to non-member */
!   if (TYPE_PTRMEM_P (t))
!     return 1; /* pointer to member object */
!   if (TYPE_PTRMEMFUNC_P (t))
!     return 1; /* pointer to member function */
    
    if (! CLASS_TYPE_P (t))
      return 0; /* other non-class type (reference or function) */
    if (CLASSTYPE_NON_POD_P (t))
      return 0;
--- 1773,1784 ----
      return 1;  /* integral, character or enumeral type */
    if (FLOAT_TYPE_P (t))
      return 1;
    if (TYPE_PTR_P (t))
      return 1; /* pointer to non-member */
!   if (TYPE_PTR_TO_MEMBER_P (t))
!     return 1; /* pointer to member */
    
    if (! CLASS_TYPE_P (t))
      return 0; /* other non-class type (reference or function) */
    if (CLASSTYPE_NON_POD_P (t))
      return 0;
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.483
diff -c -5 -p -r1.483 typeck.c
*** cp/typeck.c	19 Jul 2003 16:09:47 -0000	1.483
--- cp/typeck.c	22 Jul 2003 21:24:10 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 46,71 ****
  #include "target.h"
  
  static tree convert_for_assignment (tree, tree, const char *, tree, int);
  static tree cp_pointer_int_sum (enum tree_code, tree, tree);
  static tree rationalize_conditional_expr (enum tree_code, tree);
- static int comp_target_parms (tree, tree);
  static int comp_ptr_ttypes_real (tree, tree, int);
  static int comp_ptr_ttypes_const (tree, tree);
- static int comp_ptr_ttypes_reinterpret (tree, tree);
  static bool comp_except_types (tree, tree, bool);
  static bool comp_array_types (tree, tree, bool);
  static tree common_base_type (tree, tree);
  static tree lookup_anon_field (tree, tree);
  static tree pointer_diff (tree, tree, tree);
- static tree qualify_type_recursive (tree, tree);
  static tree get_delta_difference (tree, tree, int);
- static int comp_cv_target_types (tree, tree, int);
  static void casts_away_constness_r (tree *, tree *);
  static bool casts_away_constness (tree, tree);
  static void maybe_warn_about_returning_address_of_local (tree);
- static tree strip_all_pointer_quals (tree);
  static tree lookup_destructor (tree, tree, tree);
  
  /* Return the target type of TYPE, which means return T for:
     T*, T&, T[], T (...), and otherwise, just T.  */
  
--- 46,66 ----
*************** target_type (tree type)
*** 75,85 ****
    type = non_reference (type);
    while (TREE_CODE (type) == POINTER_TYPE
  	 || TREE_CODE (type) == ARRAY_TYPE
  	 || TREE_CODE (type) == FUNCTION_TYPE
  	 || TREE_CODE (type) == METHOD_TYPE
! 	 || TREE_CODE (type) == OFFSET_TYPE)
      type = TREE_TYPE (type);
    return type;
  }
  
  /* Do `exp = require_complete_type (exp);' to make sure exp
--- 70,80 ----
    type = non_reference (type);
    while (TREE_CODE (type) == POINTER_TYPE
  	 || TREE_CODE (type) == ARRAY_TYPE
  	 || TREE_CODE (type) == FUNCTION_TYPE
  	 || TREE_CODE (type) == METHOD_TYPE
! 	 || TYPE_PTRMEM_P (type))
      type = TREE_TYPE (type);
    return type;
  }
  
  /* Do `exp = require_complete_type (exp);' to make sure exp
*************** complete_type_or_diagnostic (tree type, 
*** 167,226 ****
  int
  type_unknown_p (tree exp)
  {
    return (TREE_CODE (exp) == OVERLOAD
            || TREE_CODE (exp) == TREE_LIST
! 	  || TREE_TYPE (exp) == unknown_type_node
! 	  /* Until we get the type of non type-dependent expressions
! 	     correct, we can have non-type dependent expressions with
! 	     no type.  */
! 	  || (TREE_TYPE (exp)
! 	      && TREE_CODE (TREE_TYPE (exp)) == OFFSET_TYPE
! 	      && TREE_TYPE (TREE_TYPE (exp)) == unknown_type_node));
  }
  
- /* Return a pointer or pointer to member type similar to T1, with a
-    cv-qualification signature that is the union of the cv-qualification
-    signatures of T1 and T2: [expr.rel], [expr.eq].  */
- 
- static tree
- qualify_type_recursive (tree t1, tree t2)
- {
-   if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2))
-       || (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2)))
-     {
-       tree tt1;
-       tree tt2;
-       tree b1;
-       int type_quals;
-       tree tgt;
-       tree attributes = (*targetm.merge_type_attributes) (t1, t2);
- 
-       if (TYPE_PTRMEM_P (t1))
- 	{
- 	  b1 = TYPE_PTRMEM_CLASS_TYPE (t1);
- 	  tt1 = TYPE_PTRMEM_POINTED_TO_TYPE (t1);
- 	  tt2 = TYPE_PTRMEM_POINTED_TO_TYPE (t2);
- 	}
-       else
- 	{
- 	  b1 = NULL_TREE;
- 	  tt1 = TREE_TYPE (t1);
- 	  tt2 = TREE_TYPE (t2);
- 	}
- 
-       type_quals = (cp_type_quals (tt1) | cp_type_quals (tt2));
-       tgt = qualify_type_recursive (tt1, tt2);
-       tgt = cp_build_qualified_type (tgt, type_quals);
-       if (b1)
- 	t1 = build_ptrmem_type (b1, tgt);
-       else
- 	t1 = build_pointer_type (tgt);
-       t1 = build_type_attribute_variant (t1, attributes);
-     }
-   return t1;
- }
  
  /* Return the common type of two parameter lists.
     We assume that comptypes has already been done and returned 1;
     if that isn't so, this may crash.
  
--- 162,174 ----
  int
  type_unknown_p (tree exp)
  {
    return (TREE_CODE (exp) == OVERLOAD
            || TREE_CODE (exp) == TREE_LIST
! 	  || TREE_TYPE (exp) == unknown_type_node);
  }
  
  
  /* Return the common type of two parameter lists.
     We assume that comptypes has already been done and returned 1;
     if that isn't so, this may crash.
  
*************** type_after_usual_arithmetic_conversions 
*** 445,533 ****
           compelling reason to choose one or the other.  */
        return build_type_attribute_variant (t1, attributes);
      }
  }
  
  /* Return the composite pointer type (see [expr.rel]) for T1 and T2.
     ARG1 and ARG2 are the values with those types.  The LOCATION is a
!    string describing the current location, in case an error occurs.  */
  
  tree 
  composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
  			const char* location)
  {
!   tree result_type;
!   tree attributes;
  
    /* [expr.rel]
  
       If one operand is a null pointer constant, the composite pointer
       type is the type of the other operand.  */
    if (null_ptr_cst_p (arg1))
      return t2;
    if (null_ptr_cst_p (arg2))
      return t1;
   
-   /* Deal with pointer-to-member functions in the same way as we deal
-      with pointers to functions.  */
-   if (TYPE_PTRMEMFUNC_P (t1))
-     t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
-   if (TYPE_PTRMEMFUNC_P (t2))
-     t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
-   
-   /* Merge the attributes.  */
-   attributes = (*targetm.merge_type_attributes) (t1, t2);
- 
    /* We have:
  
         [expr.rel]
  
         If one of the operands has type "pointer to cv1 void*", then
         the other has type "pointer to cv2T", and the composite pointer
         type is "pointer to cv12 void", where cv12 is the union of cv1
         and cv2.
  
      If either type is a pointer to void, make sure it is T1.  */
!   if (VOID_TYPE_P (TREE_TYPE (t2)))
      {
        tree t;
        t = t1;
        t1 = t2;
        t2 = t;
      }
    /* Now, if T1 is a pointer to void, merge the qualifiers.  */
!   if (VOID_TYPE_P (TREE_TYPE (t1)))
      {
        if (pedantic && TYPE_PTRFN_P (t2))
  	pedwarn ("ISO C++ forbids %s between pointer of type `void *' and pointer-to-function", location);
!       t1 = TREE_TYPE (t1);
!       t2 = TREE_TYPE (t2);
!       result_type = cp_build_qualified_type (void_type_node,
! 					     (cp_type_quals (t1)
! 					      | cp_type_quals (t2)));
        result_type = build_pointer_type (result_type);
      }
!   else
!     {
!       tree full1 = qualify_type_recursive (t1, t2);
!       tree full2 = qualify_type_recursive (t2, t1);
! 
!       int val = comp_target_types (full1, full2, 1);
! 
!       if (val > 0)
! 	result_type = full1;
!       else if (val < 0)
! 	result_type = full2;
        else
  	{
! 	  pedwarn ("%s between distinct pointer types `%T' and `%T' lacks a cast",
! 		      location, t1, t2);
! 	  result_type = ptr_type_node;
  	}
      }
  
!   return build_type_attribute_variant (result_type, attributes);
  }
  
  /* Return the merged type of two types.
     We assume that comptypes has already been done and returned 1;
     if that isn't so, this may crash.
--- 393,573 ----
           compelling reason to choose one or the other.  */
        return build_type_attribute_variant (t1, attributes);
      }
  }
  
+ /* Subroutine of composite_pointer_type to implement the recursive
+    case.  See that function for documentation fo the parameters.  */
+ 
+ static tree
+ composite_pointer_type_r (tree t1, tree t2, const char* location)
+ {
+   tree pointee1;
+   tree pointee2;
+   tree result_type;
+   tree attributes;
+ 
+   /* Determine the types pointed to by T1 and T2.  */
+   if (TREE_CODE (t1) == POINTER_TYPE)
+     {
+       pointee1 = TREE_TYPE (t1);
+       pointee2 = TREE_TYPE (t2);
+     }
+   else if (TYPE_PTR_TO_MEMBER_P (t1))
+     {
+       pointee1 = TYPE_PTRMEM_POINTED_TO_TYPE (t1);
+       pointee2 = TYPE_PTRMEM_POINTED_TO_TYPE (t2);
+     }
+ 
+   /* [expr.rel]
+ 
+      Otherwise, the composite pointer type is a pointer type
+      similar (_conv.qual_) to the type of one of the operands,
+      with a cv-qualification signature (_conv.qual_) that is the
+      union of the cv-qualification signatures of the operand
+      types.  */
+   if (same_type_ignoring_top_level_qualifiers_p (pointee1, pointee2))
+     result_type = pointee1;
+   else if ((TREE_CODE (pointee1) == POINTER_TYPE
+ 	    && TREE_CODE (pointee2) == POINTER_TYPE)
+ 	   || (TYPE_PTR_TO_MEMBER_P (pointee1)
+ 	       && TYPE_PTR_TO_MEMBER_P (pointee2)))
+     result_type = composite_pointer_type_r (pointee1, pointee2, location);
+   else
+     {
+       pedwarn ("%s between distinct pointer types `%T' and `%T' "
+ 	       "lacks a cast",
+ 	       location, t1, t2);
+       result_type = void_type_node;
+     }
+   result_type = cp_build_qualified_type (result_type,
+ 					 (cp_type_quals (pointee1)
+ 					  | cp_type_quals (pointee2)));
+   result_type = build_pointer_type (result_type);
+   /* If the original types were pointers to members, so is the
+      result.  */
+   if (TYPE_PTR_TO_MEMBER_P (t1))
+     {
+       if (!same_type_p (TYPE_PTRMEM_CLASS_TYPE (t1),
+ 			TYPE_PTRMEM_CLASS_TYPE (t2)))
+ 	pedwarn ("%s between distinct pointer types `%T' and `%T' "
+ 		 "lacks a cast",
+ 		 location, t1, t2);
+       result_type = build_ptrmem_type (TYPE_PTRMEM_CLASS_TYPE (t1),
+ 				       result_type);
+     }
+ 
+   /* Merge the attributes.  */
+   attributes = (*targetm.merge_type_attributes) (t1, t2);
+   return build_type_attribute_variant (result_type, attributes);
+ }
+ 
  /* Return the composite pointer type (see [expr.rel]) for T1 and T2.
     ARG1 and ARG2 are the values with those types.  The LOCATION is a
!    string describing the current location, in case an error occurs. 
! 
!    This routine also implements the computation of a common type for
!    pointers-to-members as per [expr.eq].  */
  
  tree 
  composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
  			const char* location)
  {
!   tree class1;
!   tree class2;
  
    /* [expr.rel]
  
       If one operand is a null pointer constant, the composite pointer
       type is the type of the other operand.  */
    if (null_ptr_cst_p (arg1))
      return t2;
    if (null_ptr_cst_p (arg2))
      return t1;
   
    /* We have:
  
         [expr.rel]
  
         If one of the operands has type "pointer to cv1 void*", then
         the other has type "pointer to cv2T", and the composite pointer
         type is "pointer to cv12 void", where cv12 is the union of cv1
         and cv2.
  
      If either type is a pointer to void, make sure it is T1.  */
!   if (TREE_CODE (t2) == POINTER_TYPE && VOID_TYPE_P (TREE_TYPE (t2)))
      {
        tree t;
        t = t1;
        t1 = t2;
        t2 = t;
      }
+ 
    /* Now, if T1 is a pointer to void, merge the qualifiers.  */
!   if (TREE_CODE (t1) == POINTER_TYPE && VOID_TYPE_P (TREE_TYPE (t1)))
      {
+       tree attributes;
+       tree result_type;
+ 
        if (pedantic && TYPE_PTRFN_P (t2))
  	pedwarn ("ISO C++ forbids %s between pointer of type `void *' and pointer-to-function", location);
!       result_type 
! 	= cp_build_qualified_type (void_type_node,
! 				   (cp_type_quals (TREE_TYPE (t1))
! 				    | cp_type_quals (TREE_TYPE (t2))));
        result_type = build_pointer_type (result_type);
+       /* Merge the attributes.  */
+       attributes = (*targetm.merge_type_attributes) (t1, t2);
+       return build_type_attribute_variant (result_type, attributes);
+     }
+ 
+   /* [expr.eq] permits the application of a pointer conversion to
+      bring the pointers to a common type.  */
+   if (TREE_CODE (t1) == POINTER_TYPE && TREE_CODE (t2) == POINTER_TYPE
+       && CLASS_TYPE_P (TREE_TYPE (t1))
+       && CLASS_TYPE_P (TREE_TYPE (t2))
+       && !same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (t1),
+ 						     TREE_TYPE (t2)))
+     {
+       class1 = TREE_TYPE (t1);
+       class2 = TREE_TYPE (t2);
+ 
+       if (DERIVED_FROM_P (class1, class2))
+ 	t2 = (build_pointer_type 
+ 	      (cp_build_qualified_type (class1, TYPE_QUALS (class2))));
+       else if (DERIVED_FROM_P (class2, class1))
+ 	t1 = (build_pointer_type 
+ 	      (cp_build_qualified_type (class2, TYPE_QUALS (class1))));
+       else
+ 	{
+ 	  error ("%s between distinct pointer types `%T' and `%T' "
+ 		 "lacks a cast", location, t1, t2);
+ 	  return error_mark_node;
+ 	}
      }
!   /* [expr.eq] permits the application of a pointer-to-member
!      conversion to change the class type of one of the types.  */
!   else if (TYPE_PTR_TO_MEMBER_P (t1)
! 	   && !same_type_p (TYPE_PTRMEM_CLASS_TYPE (t1),
! 			    TYPE_PTRMEM_CLASS_TYPE (t2)))
!     {
!       class1 = TYPE_PTRMEM_CLASS_TYPE (t1);
!       class2 = TYPE_PTRMEM_CLASS_TYPE (t2);
! 
!       if (DERIVED_FROM_P (class1, class2))
! 	t1 = build_ptrmem_type (class2, TYPE_PTRMEM_POINTED_TO_TYPE (t1));
!       else if (DERIVED_FROM_P (class2, class1))
! 	t2 = build_ptrmem_type (class1, TYPE_PTRMEM_POINTED_TO_TYPE (t2));
        else
  	{
! 	  error ("%s between distinct pointer-to-member types `%T' and `%T' "
! 		 "lacks a cast", location, t1, t2);
! 	  return error_mark_node;
  	}
      }
  
!   return composite_pointer_type_r (t1, t2, location);
  }
  
  /* Return the merged type of two types.
     We assume that comptypes has already been done and returned 1;
     if that isn't so, this may crash.
*************** merge_types (tree t1, tree t2)
*** 555,566 ****
      return t1;
  
    /* Merge the attributes.  */
    attributes = (*targetm.merge_type_attributes) (t1, t2);
  
-   /* Treat an enum type as the unsigned integer type of the same width.  */
- 
    if (TYPE_PTRMEMFUNC_P (t1))
      t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
    if (TYPE_PTRMEMFUNC_P (t2))
      t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
  
--- 595,604 ----
*************** common_type (tree t1, tree t2)
*** 704,714 ****
    else if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2))
  	   || (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2))
  	   || (TYPE_PTRMEMFUNC_P (t1) && TYPE_PTRMEMFUNC_P (t2)))
      return composite_pointer_type (t1, t2, error_mark_node, error_mark_node,
  				   "conversion");
- 
    else
      abort ();
  }
  
  /* Compare two exception specifier types for exactness or subsetness, if
--- 742,751 ----
*************** comptypes (tree t1, tree t2, int strict)
*** 993,1202 ****
        break;
      }
    return false;
  }
  
- /* Subroutine of comp_target-types.  Make sure that the cv-quals change
-    only in the same direction as the target type.  */
- 
- static int
- comp_cv_target_types (tree ttl, tree ttr, int nptrs)
- {
-   int t;
- 
-   if (!at_least_as_qualified_p (ttl, ttr)
-       && !at_least_as_qualified_p (ttr, ttl))
-     /* The qualifications are incomparable.  */
-     return 0;
- 
-   if (TYPE_MAIN_VARIANT (ttl) == TYPE_MAIN_VARIANT (ttr))
-     return more_qualified_p (ttr, ttl) ? -1 : 1;
- 
-   t = comp_target_types (ttl, ttr, nptrs);
-   if ((t == 1 && at_least_as_qualified_p (ttl, ttr)) 
-       || (t == -1 && at_least_as_qualified_p (ttr, ttl)))
-     return t;
- 
-   return 0;
- }
- 
- /* Return 1 or -1 if TTL and TTR are pointers to types that are equivalent,
-    ignoring their qualifiers, 0 if not. Return 1 means that TTR can be
-    converted to TTL. Return -1 means that TTL can be converted to TTR but
-    not vice versa.
- 
-    NPTRS is the number of pointers we can strip off and keep cool.
-    This is used to permit (for aggr A, aggr B) A, B* to convert to A*,
-    but to not permit B** to convert to A**.
- 
-    This should go away.  Callers should use can_convert or something
-    similar instead.  (jason 17 Apr 1997)  */
- 
- int
- comp_target_types (tree ttl, tree ttr, int nptrs)
- {
-   ttl = TYPE_MAIN_VARIANT (ttl);
-   ttr = TYPE_MAIN_VARIANT (ttr);
-   if (same_type_p (ttl, ttr))
-     return 1;
- 
-   if (TREE_CODE (ttr) != TREE_CODE (ttl))
-     return 0;
- 
-   if ((TREE_CODE (ttr) == POINTER_TYPE
-        || TREE_CODE (ttr) == REFERENCE_TYPE)
-       /* If we get a pointer with nptrs == 0, we don't allow any tweaking
- 	 of the type pointed to.  This is necessary for reference init
- 	 semantics.  We won't get here from a previous call with nptrs == 1;
- 	 for multi-level pointers we end up in comp_ptr_ttypes.  */
-       && nptrs > 0)
-     {
-       int is_ptr = TREE_CODE (ttr) == POINTER_TYPE;
- 
-       ttl = TREE_TYPE (ttl);
-       ttr = TREE_TYPE (ttr);
- 
-       if (is_ptr)
- 	{
- 	  if (TREE_CODE (ttl) == UNKNOWN_TYPE
- 	      || TREE_CODE (ttr) == UNKNOWN_TYPE)
- 	    return 1;
- 	  else if (TREE_CODE (ttl) == VOID_TYPE
- 		   && TREE_CODE (ttr) != FUNCTION_TYPE
- 		   && TREE_CODE (ttr) != METHOD_TYPE
- 		   && TREE_CODE (ttr) != OFFSET_TYPE)
- 	    return 1;
- 	  else if (TREE_CODE (ttr) == VOID_TYPE
- 		   && TREE_CODE (ttl) != FUNCTION_TYPE
- 		   && TREE_CODE (ttl) != METHOD_TYPE
- 		   && TREE_CODE (ttl) != OFFSET_TYPE)
- 	    return -1;
- 	  else if (TREE_CODE (ttl) == POINTER_TYPE
- 		   || TREE_CODE (ttl) == ARRAY_TYPE)
- 	    {
- 	      if (comp_ptr_ttypes (ttl, ttr))
- 		return 1;
- 	      else if (comp_ptr_ttypes (ttr, ttl))
- 		return -1;
- 	      return 0;
- 	    }
- 	}
- 
-       /* Const and volatile mean something different for function types,
- 	 so the usual checks are not appropriate.  */
-       if (TREE_CODE (ttl) == FUNCTION_TYPE || TREE_CODE (ttl) == METHOD_TYPE)
- 	return comp_target_types (ttl, ttr, nptrs - 1);
- 
-       return comp_cv_target_types (ttl, ttr, nptrs - 1);
-     }
- 
-   my_friendly_assert (TREE_CODE (ttr) != ARRAY_TYPE, 20030617);
-   if (TREE_CODE (ttr) == FUNCTION_TYPE || TREE_CODE (ttr) == METHOD_TYPE)
-     {
-       tree argsl, argsr;
-       int saw_contra = 0;
- 
-       if (pedantic)
- 	{
- 	  if (!same_type_p (TREE_TYPE (ttl), TREE_TYPE (ttr)))
- 	    return 0;
- 	}
-       else
- 	{
- 	  switch (comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), -1))
- 	    {
- 	    case 0:
- 	      return 0;
- 	    case -1:
- 	      saw_contra = 1;
- 	    }
- 	}
- 
-       argsl = TYPE_ARG_TYPES (ttl);
-       argsr = TYPE_ARG_TYPES (ttr);
- 
-       /* Compare 'this' here, not in comp_target_parms.  */
-       if (TREE_CODE (ttr) == METHOD_TYPE)
- 	{
- 	  tree tl = TYPE_METHOD_BASETYPE (ttl);
- 	  tree tr = TYPE_METHOD_BASETYPE (ttr);
- 
- 	  if (!same_or_base_type_p (tr, tl))
- 	    {
- 	      if (same_or_base_type_p (tl, tr))
- 		saw_contra = 1;
- 	      else
- 		return 0;
- 	    }
- 
- 	  argsl = TREE_CHAIN (argsl);
- 	  argsr = TREE_CHAIN (argsr);
- 	}
- 
- 	switch (comp_target_parms (argsl, argsr))
- 	  {
- 	  case 0:
- 	    return 0;
- 	  case -1:
- 	    saw_contra = 1;
- 	  }
- 
- 	return saw_contra ? -1 : 1;
-     }
-   /* for C++ */
-   else if (TREE_CODE (ttr) == OFFSET_TYPE)
-     {
-       int base;
- 
-       /* Contravariance: we can assign a pointer to base member to a pointer
- 	 to derived member.  Note difference from simple pointer case, where
- 	 we can pass a pointer to derived to a pointer to base.  */
-       if (same_or_base_type_p (TYPE_OFFSET_BASETYPE (ttr),
- 			       TYPE_OFFSET_BASETYPE (ttl)))
- 	base = 1;
-       else if (same_or_base_type_p (TYPE_OFFSET_BASETYPE (ttl),
- 				    TYPE_OFFSET_BASETYPE (ttr)))
- 	{
- 	  tree tmp = ttl;
- 	  ttl = ttr;
- 	  ttr = tmp;
- 	  base = -1;
- 	}
-       else
- 	return 0;
- 
-       ttl = TREE_TYPE (ttl);
-       ttr = TREE_TYPE (ttr);
- 
-       if (TREE_CODE (ttl) == POINTER_TYPE
- 	  || TREE_CODE (ttl) == ARRAY_TYPE)
- 	{
- 	  if (comp_ptr_ttypes (ttl, ttr))
- 	    return base;
- 	  return 0;
- 	}
-       else
- 	{
- 	  if (comp_cv_target_types (ttl, ttr, nptrs) == 1)
- 	    return base;
- 	  return 0;
- 	}
-     }
-   else if (IS_AGGR_TYPE (ttl))
-     {
-       if (nptrs < 0)
- 	return 0;
-       if (same_or_base_type_p (ttl, ttr))
- 	return 1;
-       if (same_or_base_type_p (ttr, ttl))
- 	return -1;
-       return 0;
-     }
- 
-   return 0;
- }
- 
  /* Returns 1 if TYPE1 is at least as qualified as TYPE2.  */
  
  bool
  at_least_as_qualified_p (tree type1, tree type2)
  {
--- 1030,1039 ----
*************** compparms (tree parms1, tree parms2)
*** 1331,1414 ****
  	return false;
      }
    return true;
  }
  
- /* This really wants return whether or not parameter type lists
-    would make their owning functions assignment compatible or not.
- 
-    The return value is like for comp_target_types.
- 
-    This should go away, possibly with the exception of the empty parmlist
-    conversion; there are no conversions between function types in C++.
-    (jason 17 Apr 1997)  */
- 
- static int
- comp_target_parms (tree parms1, tree parms2)
- {
-   register tree t1 = parms1, t2 = parms2;
-   int warn_contravariance = 0;
- 
-   /* In C, an unspecified parmlist matches any specified parmlist
-      whose argument types don't need default promotions.  This is not
-      true for C++, but let's do it anyway for unfixed headers.  */
- 
-   if (t1 == 0 && t2 != 0)
-     {
-       pedwarn ("ISO C++ prohibits conversion from `%#T' to `(...)'",
- 		  parms2);
-       return self_promoting_args_p (t2);
-     }
-   if (t2 == 0)
-     return self_promoting_args_p (t1);
- 
-   for (; t1 || t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
-     {
-       tree p1, p2;
- 
-       /* If one parmlist is shorter than the other, they fail to match.  */
-       if (!t1 || !t2)
- 	return 0;
-       p1 = TREE_VALUE (t1);
-       p2 = TREE_VALUE (t2);
-       if (same_type_p (p1, p2))
- 	continue;
- 
-       if (pedantic)
- 	return 0;
- 
-       if ((TREE_CODE (p1) == POINTER_TYPE && TREE_CODE (p2) == POINTER_TYPE)
- 	  || (TREE_CODE (p1) == REFERENCE_TYPE
- 	      && TREE_CODE (p2) == REFERENCE_TYPE))
- 	{
- 	  /* The following is wrong for contravariance,
- 	     but many programs depend on it.  */
- 	  if (TREE_TYPE (p1) == void_type_node)
- 	    continue;
- 	  if (TREE_TYPE (p2) == void_type_node)
- 	    {
- 	      warn_contravariance = 1;
- 	      continue;
- 	    }
- 	  if (IS_AGGR_TYPE (TREE_TYPE (p1))
- 	      && !same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (p1),
- 							     TREE_TYPE (p2)))
- 	    return 0;
- 	}
-       /* Note backwards order due to contravariance.  */
-       if (comp_target_types (p2, p1, 1) <= 0)
- 	{
- 	  if (comp_target_types (p1, p2, 1) > 0)
- 	    {
- 	      warn_contravariance = 1;
- 	      continue;
- 	    }
- 	  return 0;
- 	}
-     }
-   return warn_contravariance ? -1 : 1;
- }
  
  tree
  cxx_sizeof_or_alignof_type (tree type, enum tree_code op, int complain)
  {
    enum tree_code type_code;
--- 1168,1177 ----
*************** cxx_sizeof_or_alignof_type (tree type, e
*** 1428,1443 ****
      {
        if (complain && (pedantic || warn_pointer_arith))
  	pedwarn ("invalid application of `%s' to a member function", op_name);
        value = size_one_node;
      }
-   else if (type_code == OFFSET_TYPE)
-     {
-       if (complain)
- 	error ("invalid application of `%s' to non-static member", op_name);
-       value = size_zero_node;
-     }
    else
      value = c_sizeof_or_alignof_type (complete_type (type), op, complain);
  
    return value;
  }
--- 1191,1200 ----
*************** build_indirect_ref (tree ptr, const char
*** 2275,2285 ****
  	  return ref;
  	}
      }
    /* `pointer' won't be an error_mark_node if we were given a
       pointer to member, so it's cool to check for this here.  */
!   else if (TYPE_PTRMEM_P (type) || TYPE_PTRMEMFUNC_P (type))
      error ("invalid use of `%s' on pointer to member", errorstring);
    else if (pointer != error_mark_node)
      {
        if (errorstring)
  	error ("invalid type argument of `%s'", errorstring);
--- 2032,2042 ----
  	  return ref;
  	}
      }
    /* `pointer' won't be an error_mark_node if we were given a
       pointer to member, so it's cool to check for this here.  */
!   else if (TYPE_PTR_TO_MEMBER_P (type))
      error ("invalid use of `%s' on pointer to member", errorstring);
    else if (pointer != error_mark_node)
      {
        if (errorstring)
  	error ("invalid type argument of `%s'", errorstring);
*************** build_binary_op (enum tree_code code, tr
*** 3008,3018 ****
  
      case MINUS_EXPR:
        /* Subtraction of two similar pointers.
  	 We must subtract them as integers, then divide by object size.  */
        if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
! 	  && comp_target_types (type0, type1, 1))
  	return pointer_diff (op0, op1, common_type (type0, type1));
        /* Handle pointer minus int.  Just like pointer plus int.  */
        else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
  	return cp_pointer_int_sum (MINUS_EXPR, op0, op1);
        else
--- 2765,2776 ----
  
      case MINUS_EXPR:
        /* Subtraction of two similar pointers.
  	 We must subtract them as integers, then divide by object size.  */
        if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
! 	  && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (type0),
! 							TREE_TYPE (type1)))
  	return pointer_diff (op0, op1, common_type (type0, type1));
        /* Handle pointer minus int.  Just like pointer plus int.  */
        else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
  	return cp_pointer_int_sum (MINUS_EXPR, op0, op1);
        else
*************** build_binary_op (enum tree_code code, tr
*** 3170,3185 ****
        if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
  	   || code0 == COMPLEX_TYPE)
  	  && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
  	      || code1 == COMPLEX_TYPE))
  	short_compare = 1;
!       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
  	result_type = composite_pointer_type (type0, type1, op0, op1,
  					      "comparison");
!       else if (code0 == POINTER_TYPE && null_ptr_cst_p (op1))
  	result_type = type0;
!       else if (code1 == POINTER_TYPE && null_ptr_cst_p (op0))
  	result_type = type1;
        else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
  	{
  	  result_type = type0;
  	  error ("ISO C++ forbids comparison between pointer and integer");
--- 2928,2946 ----
        if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
  	   || code0 == COMPLEX_TYPE)
  	  && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
  	      || code1 == COMPLEX_TYPE))
  	short_compare = 1;
!       else if ((code0 == POINTER_TYPE && code1 == POINTER_TYPE)
! 	       || (TYPE_PTRMEM_P (type0) && TYPE_PTRMEM_P (type1)))
  	result_type = composite_pointer_type (type0, type1, op0, op1,
  					      "comparison");
!       else if ((code0 == POINTER_TYPE || TYPE_PTRMEM_P (type0))
! 	       && null_ptr_cst_p (op1))
  	result_type = type0;
!       else if ((code1 == POINTER_TYPE || TYPE_PTRMEM_P (type1))
! 	       && null_ptr_cst_p (op0))
  	result_type = type1;
        else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
  	{
  	  result_type = type0;
  	  error ("ISO C++ forbids comparison between pointer and integer");
*************** pointer_diff (register tree op0, registe
*** 3654,3665 ****
  	pedwarn ("ISO C++ forbids using pointer of type `void *' in subtraction");
        if (TREE_CODE (target_type) == FUNCTION_TYPE)
  	pedwarn ("ISO C++ forbids using pointer to a function in subtraction");
        if (TREE_CODE (target_type) == METHOD_TYPE)
  	pedwarn ("ISO C++ forbids using pointer to a method in subtraction");
-       if (TREE_CODE (target_type) == OFFSET_TYPE)
- 	pedwarn ("ISO C++ forbids using pointer to a member in subtraction");
      }
  
    /* First do the subtraction as integers;
       then drop through to build the divide operator.  */
  
--- 3415,3424 ----
*************** pointer_diff (register tree op0, registe
*** 3669,3684 ****
  
    /* This generates an error if op1 is a pointer to an incomplete type.  */
    if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
      error ("invalid use of a pointer to an incomplete type in pointer arithmetic");
  
!   op1 = ((TREE_CODE (target_type) == VOID_TYPE
! 	  || TREE_CODE (target_type) == FUNCTION_TYPE
! 	  || TREE_CODE (target_type) == METHOD_TYPE
! 	  || TREE_CODE (target_type) == OFFSET_TYPE)
! 	 ? integer_one_node
! 	 : size_in_bytes (target_type));
  
    /* Do the division.  */
  
    result = build (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1));
  
--- 3428,3440 ----
  
    /* This generates an error if op1 is a pointer to an incomplete type.  */
    if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
      error ("invalid use of a pointer to an incomplete type in pointer arithmetic");
  
!   op1 = (TYPE_PTROB_P (ptrtype) 
! 	 ? size_in_bytes (target_type)
! 	 : integer_one_node);
  
    /* Do the division.  */
  
    result = build (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1));
  
*************** build_unary_op (enum tree_code code, tre
*** 3997,4017 ****
  	    
  	/* Compute the increment.  */
  
  	if (TREE_CODE (argtype) == POINTER_TYPE)
  	  {
- 	    enum tree_code tmp = TREE_CODE (TREE_TYPE (argtype));
  	    tree type = complete_type (TREE_TYPE (argtype));
  	    
  	    if (!COMPLETE_OR_VOID_TYPE_P (type))
  	      error ("cannot %s a pointer to incomplete type `%T'",
  			((code == PREINCREMENT_EXPR
  			  || code == POSTINCREMENT_EXPR)
  			 ? "increment" : "decrement"), TREE_TYPE (argtype));
  	    else if ((pedantic || warn_pointer_arith)
! 		     && (tmp == FUNCTION_TYPE || tmp == METHOD_TYPE
! 			 || tmp == VOID_TYPE || tmp == OFFSET_TYPE))
  	      pedwarn ("ISO C++ forbids %sing a pointer of type `%T'",
  			  ((code == PREINCREMENT_EXPR
  			    || code == POSTINCREMENT_EXPR)
  			   ? "increment" : "decrement"), argtype);
  	    inc = cxx_sizeof_nowarn (TREE_TYPE (argtype));
--- 3753,3771 ----
  	    
  	/* Compute the increment.  */
  
  	if (TREE_CODE (argtype) == POINTER_TYPE)
  	  {
  	    tree type = complete_type (TREE_TYPE (argtype));
  	    
  	    if (!COMPLETE_OR_VOID_TYPE_P (type))
  	      error ("cannot %s a pointer to incomplete type `%T'",
  			((code == PREINCREMENT_EXPR
  			  || code == POSTINCREMENT_EXPR)
  			 ? "increment" : "decrement"), TREE_TYPE (argtype));
  	    else if ((pedantic || warn_pointer_arith)
! 		     && !TYPE_PTROB_P (argtype))
  	      pedwarn ("ISO C++ forbids %sing a pointer of type `%T'",
  			  ((code == PREINCREMENT_EXPR
  			    || code == POSTINCREMENT_EXPR)
  			   ? "increment" : "decrement"), argtype);
  	    inc = cxx_sizeof_nowarn (TREE_TYPE (argtype));
*************** build_unary_op (enum tree_code code, tre
*** 4070,4086 ****
  	    if (code == POSTDECREMENT_EXPR || code == PREDECREMENT_EXPR)
  	      {
  		error ("invalid use of `--' on bool variable `%D'", arg);
  		return error_mark_node;
  	      }
- #if 0
- 	    /* This will only work if someone can convince Kenner to accept
- 	       my patch to expand_increment. (jason)  */
- 	    val = build (code, TREE_TYPE (arg), arg, inc);
- #else
  	    val = boolean_increment (code, arg);
- #endif
  	  }
  	else
  	  val = build (code, TREE_TYPE (arg), arg, inc);
  
  	TREE_SIDE_EFFECTS (val) = 1;
--- 3824,3834 ----
*************** build_unary_op (enum tree_code code, tre
*** 4090,4099 ****
--- 3838,3851 ----
      case ADDR_EXPR:
        /* Note that this operation never does default_conversion
  	 regardless of NOCONVERT.  */
  
        argtype = lvalue_type (arg);
+ 
+       if (TREE_CODE (arg) == OFFSET_REF)
+ 	goto offset_ref;
+ 
        if (TREE_CODE (argtype) == REFERENCE_TYPE)
  	{
  	  arg = build1
  	    (CONVERT_EXPR,
  	     build_pointer_type (TREE_TYPE (argtype)), arg);
*************** build_unary_op (enum tree_code code, tre
*** 4181,4193 ****
  		pedwarn ("ISO C++ forbids taking the address of a bound member"
  			 " function to form a pointer to member function."
  			 "  Say `&%T::%D'",
  			 base, name);
  	    }
! 	  arg = build_offset_ref (base, name);
          }
!         
        if (type_unknown_p (arg))
  	return build1 (ADDR_EXPR, unknown_type_node, arg);
  	
        /* Handle complex lvalues (when permitted)
  	 by reduction to simpler cases.  */
--- 3933,3946 ----
  		pedwarn ("ISO C++ forbids taking the address of a bound member"
  			 " function to form a pointer to member function."
  			 "  Say `&%T::%D'",
  			 base, name);
  	    }
! 	  arg = build_offset_ref (base, name, /*address_p=*/true);
          }
! 
!     offset_ref:        
        if (type_unknown_p (arg))
  	return build1 (ADDR_EXPR, unknown_type_node, arg);
  	
        /* Handle complex lvalues (when permitted)
  	 by reduction to simpler cases.  */
*************** unary_complex_lvalue (enum tree_code cod
*** 4336,4350 ****
        return arg;
      }
  
    if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE
        || TREE_CODE (TREE_TYPE (arg)) == METHOD_TYPE
!       || TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
      {
-       /* The representation of something of type OFFSET_TYPE
- 	 is really the representation of a pointer to it.
- 	 Here give the representation its true type.  */
        tree t;
  
        my_friendly_assert (TREE_CODE (arg) != SCOPE_REF, 313);
  
        if (TREE_CODE (arg) != OFFSET_REF)
--- 4089,4100 ----
        return arg;
      }
  
    if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE
        || TREE_CODE (TREE_TYPE (arg)) == METHOD_TYPE
!       || TREE_CODE (arg) == OFFSET_REF)
      {
        tree t;
  
        my_friendly_assert (TREE_CODE (arg) != SCOPE_REF, 313);
  
        if (TREE_CODE (arg) != OFFSET_REF)
*************** build_compound_expr (tree list)
*** 4597,4614 ****
  
    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
--- 4347,4366 ----
  
    return build (COMPOUND_EXPR, TREE_TYPE (rest), first, rest);
  }
  
  /* 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 `%T' to type `%T' casts away constness",
! 	   description, src_type, dest_type);
  }
  
  /* Return an expression representing static_cast<TYPE>(EXPR).  */
  
  tree
*************** build_static_cast (tree type, tree expr)
*** 4724,4734 ****
  		      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))
--- 4476,4486 ----
  		      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 | ba_quiet, 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)
*** 4756,4774 ****
  	  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);
--- 4508,4529 ----
  	  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)
  		expr = cplus_expand_constant (expr);
! 	      delta = get_delta_difference (c1, c2, /*force=*/1);
! 	      if (!integer_zerop (delta))
! 		expr = cp_build_binary_op (PLUS_EXPR, 
! 					   build_nop (ptrdiff_type_node, expr),
! 					   delta);
  	      return build_nop (type, expr);
  	    }
  	  else
  	    return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 
  				     /*force=*/1);
*************** build_static_cast (tree type, tree expr)
*** 4783,4793 ****
       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;
--- 4538,4548 ----
       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 `%T' to type `%T'", intype, type);
    return error_mark_node;
*************** build_reinterpret_cast (tree type, tree 
*** 4854,4867 ****
        return fold (build1 (NOP_EXPR, type, expr));
      }
    else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
  	   || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
      {
!       if (! comp_ptr_ttypes_reinterpret (TREE_TYPE (type), TREE_TYPE (intype)))
! 	pedwarn ("reinterpret_cast from `%T' to `%T' casts away const (or volatile)",
! 		    intype, type);
! 
        expr = decl_constant_value (expr);
        return fold (build1 (NOP_EXPR, type, expr));
      }
    else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
  	   || (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
--- 4609,4619 ----
        return fold (build1 (NOP_EXPR, 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 (build1 (NOP_EXPR, type, expr));
      }
    else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
  	   || (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
*************** build_const_cast (tree type, tree expr)
*** 4930,4941 ****
  	  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
  	   && comp_ptr_ttypes_const (TREE_TYPE (type), TREE_TYPE (intype)))
      return cp_convert (type, expr);
  
    error ("invalid const_cast from type `%T' to type `%T'", intype, type);
    return error_mark_node;
--- 4682,4694 ----
  	  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 `%T' to type `%T'", intype, type);
    return error_mark_node;
*************** build_c_cast (tree type, tree expr)
*** 5046,5060 ****
  				   TREE_TYPE (otype)))
      warning ("cast from `%T' to `%T' discards qualifiers from pointer target type",
                  otype, type);
  
    if (TREE_CODE (type) == INTEGER_TYPE
!       && TREE_CODE (otype) == POINTER_TYPE
        && TYPE_PRECISION (type) != TYPE_PRECISION (otype))
      warning ("cast from pointer to integer of different size");
  
!   if (TREE_CODE (type) == POINTER_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");
--- 4799,4813 ----
  				   TREE_TYPE (otype)))
      warning ("cast from `%T' to `%T' 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");
*************** dubious_conversion_warnings (tree type, 
*** 5783,5799 ****
  
  static tree
  convert_for_assignment (tree type, tree rhs,
  			const char *errtype, tree fndecl, int parmnum)
  {
-   register enum tree_code codel = TREE_CODE (type);
    register tree rhstype;
    register enum tree_code coder;
  
-   if (codel == OFFSET_TYPE)
-     abort ();
- 
    /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
    if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
      rhs = TREE_OPERAND (rhs, 0);
  
    rhstype = TREE_TYPE (rhs);
--- 5536,5548 ----
*************** check_return_expr (tree retval)
*** 6264,6274 ****
     const-qualified.  */
  
  static int
  comp_ptr_ttypes_real (tree to, tree from, int constp)
  {
!   int to_more_cv_qualified = 0;
  
    for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
      {
        if (TREE_CODE (to) != TREE_CODE (from))
  	return 0;
--- 6013,6023 ----
     const-qualified.  */
  
  static int
  comp_ptr_ttypes_real (tree to, tree from, int constp)
  {
!   bool to_more_cv_qualified = false;
  
    for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
      {
        if (TREE_CODE (to) != TREE_CODE (from))
  	return 0;
*************** comp_ptr_ttypes_real (tree to, tree from
*** 6287,6298 ****
  
  	  if (!at_least_as_qualified_p (from, to))
  	    {
  	      if (constp == 0)
  		return 0;
! 	      else
! 		++to_more_cv_qualified;
  	    }
  
  	  if (constp > 0)
  	    constp &= TYPE_READONLY (to);
  	}
--- 6036,6046 ----
  
  	  if (!at_least_as_qualified_p (from, to))
  	    {
  	      if (constp == 0)
  		return 0;
! 	      to_more_cv_qualified = true;
  	    }
  
  	  if (constp > 0)
  	    constp &= TYPE_READONLY (to);
  	}
*************** comp_ptr_ttypes_const (tree to, tree fro
*** 6367,6410 ****
        if (TREE_CODE (to) != POINTER_TYPE)
  	return same_type_ignoring_top_level_qualifiers_p (to, from);
      }
  }
  
- /* Like comp_ptr_ttypes, for reinterpret_cast.  */
- 
- static int
- comp_ptr_ttypes_reinterpret (tree to, tree from)
- {
-   int constp = 1;
- 
-   for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
-     {
-       if (TREE_CODE (from) == OFFSET_TYPE)
- 	from = TREE_TYPE (from);
-       if (TREE_CODE (to) == OFFSET_TYPE)
- 	to = TREE_TYPE (to);
- 
-       /* Const and volatile mean something different for function types,
- 	 so the usual checks are not appropriate.  */
-       if (TREE_CODE (from) != FUNCTION_TYPE && TREE_CODE (from) != METHOD_TYPE
- 	  && TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
- 	{
- 	  if (!at_least_as_qualified_p (to, from))
- 	    return 0;
- 
- 	  if (! constp
- 	      && !at_least_as_qualified_p (from, to))
- 	    return 0;
- 	  constp &= TYPE_READONLY (to);
- 	}
- 
-       if (TREE_CODE (from) != POINTER_TYPE
- 	  || TREE_CODE (to) != POINTER_TYPE)
- 	return 1;
-     }
- }
- 
  /* Returns the type qualifiers for this type, including the qualifiers on the
     elements for an array type.  */
  
  int
  cp_type_quals (tree type)
--- 6115,6124 ----
*************** casts_away_constness_r (tree *t1, tree *
*** 6440,6452 ****
       For multi-level pointer to members and multi-level mixed pointers
       and pointers to members (conv.qual), the "member" aspect of a
       pointer to member level is ignored when determining if a const
       cv-qualifier has been cast away.  */
    if (TYPE_PTRMEM_P (*t1))
!     *t1 = build_pointer_type (TREE_TYPE (TREE_TYPE (*t1)));
    if (TYPE_PTRMEM_P (*t2))
!     *t2 = build_pointer_type (TREE_TYPE (TREE_TYPE (*t2)));
  
    /* [expr.const.cast]
  
       For  two  pointer types:
  
--- 6154,6166 ----
       For multi-level pointer to members and multi-level mixed pointers
       and pointers to members (conv.qual), the "member" aspect of a
       pointer to member level is ignored when determining if a const
       cv-qualifier has been cast away.  */
    if (TYPE_PTRMEM_P (*t1))
!     *t1 = build_pointer_type (TYPE_PTRMEM_POINTED_TO_TYPE (*t1));
    if (TYPE_PTRMEM_P (*t2))
!     *t2 = build_pointer_type (TYPE_PTRMEM_POINTED_TO_TYPE (*t2));
  
    /* [expr.const.cast]
  
       For  two  pointer types:
  
*************** casts_away_constness (tree t1, tree t2)
*** 6511,6522 ****
         of type T1" to the type "pointer to data member of Y of type
         T2" casts away constness if a cast from an rvalue of type
         "pointer to T1" to the type "pointer to T2" casts away
         constness.  */
      return casts_away_constness
!       (build_pointer_type (TREE_TYPE (TREE_TYPE (t1))),
!        build_pointer_type (TREE_TYPE (TREE_TYPE (t2))));
  
    /* Casting away constness is only something that makes sense for
       pointer or reference types.  */
    if (TREE_CODE (t1) != POINTER_TYPE 
        || TREE_CODE (t2) != POINTER_TYPE)
--- 6225,6236 ----
         of type T1" to the type "pointer to data member of Y of type
         T2" casts away constness if a cast from an rvalue of type
         "pointer to T1" to the type "pointer to T2" casts away
         constness.  */
      return casts_away_constness
!       (build_pointer_type (TYPE_PTRMEM_POINTED_TO_TYPE (t1)),
!        build_pointer_type (TYPE_PTRMEM_POINTED_TO_TYPE (t2)));
  
    /* Casting away constness is only something that makes sense for
       pointer or reference types.  */
    if (TREE_CODE (t1) != POINTER_TYPE 
        || TREE_CODE (t2) != POINTER_TYPE)
*************** casts_away_constness (tree t1, tree t2)
*** 6528,6554 ****
    casts_away_constness_r (&t1, &t2);
    if (!can_convert (t2, t1))
      return true;
  
    return false;
- }
- 
- /* Returns TYPE with its cv qualifiers removed
-    TYPE is T cv* .. *cv where T is not a pointer type,
-    returns T * .. *. (If T is an array type, then the cv qualifiers
-    above are those of the array members.)  */
- 
- static tree
- strip_all_pointer_quals (tree type)
- {
-   if (TREE_CODE (type) == POINTER_TYPE)
-     return build_pointer_type (strip_all_pointer_quals (TREE_TYPE (type)));
-   else if (TREE_CODE (type) == OFFSET_TYPE)
-     return build_offset_type (TYPE_OFFSET_BASETYPE (type),
- 			      strip_all_pointer_quals (TREE_TYPE (type)));
-   else
-     return TYPE_MAIN_VARIANT (type);
  }
  
  /* If T is a REFERENCE_TYPE return the type to which T refers.
     Otherwise, return T itself.  */
  
--- 6242,6251 ----
Index: cp/typeck2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck2.c,v
retrieving revision 1.144
diff -c -5 -p -r1.144 typeck2.c
*** cp/typeck2.c	9 Jul 2003 08:48:04 -0000	1.144
--- cp/typeck2.c	22 Jul 2003 21:24:10 -0000
*************** digest_init (tree type, tree init, tree*
*** 504,514 ****
       and signature pointers and references.  */
  
    if (code == INTEGER_TYPE || code == REAL_TYPE || code == POINTER_TYPE
        || code == ENUMERAL_TYPE || code == REFERENCE_TYPE
        || code == BOOLEAN_TYPE || code == COMPLEX_TYPE
!       || TYPE_PTRMEMFUNC_P (type))
      {
        if (raw_constructor)
  	{
  	  if (element == 0)
  	    {
--- 504,514 ----
       and signature pointers and references.  */
  
    if (code == INTEGER_TYPE || code == REAL_TYPE || code == POINTER_TYPE
        || code == ENUMERAL_TYPE || code == REFERENCE_TYPE
        || code == BOOLEAN_TYPE || code == COMPLEX_TYPE
!       || TYPE_PTR_TO_MEMBER_P (type))
      {
        if (raw_constructor)
  	{
  	  if (element == 0)
  	    {
*************** build_m_component_ref (tree datum, tree 
*** 1068,1079 ****
  
    if (datum == error_mark_node || component == error_mark_node)
      return error_mark_node;
  
    ptrmem_type = TREE_TYPE (component);
!   if (!TYPE_PTRMEM_P (ptrmem_type) 
!       && !TYPE_PTRMEMFUNC_P (ptrmem_type))
      {
        error ("`%E' cannot be used as a member pointer, since it is of type `%T'", 
  	     component, ptrmem_type);
        return error_mark_node;
      }
--- 1068,1078 ----
  
    if (datum == error_mark_node || component == error_mark_node)
      return error_mark_node;
  
    ptrmem_type = TREE_TYPE (component);
!   if (!TYPE_PTR_TO_MEMBER_P (ptrmem_type))
      {
        error ("`%E' cannot be used as a member pointer, since it is of type `%T'", 
  	     component, ptrmem_type);
        return error_mark_node;
      }
*************** build_m_component_ref (tree datum, tree 
*** 1105,1118 ****
  	 things are not as complex as they are for references to
  	 non-static data members.  */
        type = cp_build_qualified_type (type,
  				      (cp_type_quals (type)  
  				       | cp_type_quals (TREE_TYPE (datum))));
! 
!       datum = build_base_path (PLUS_EXPR, build_address (datum), binfo, 1);
!       component = cp_convert (ptrdiff_type_node, component);
!       datum = build (PLUS_EXPR, build_pointer_type (type), datum, component);
        return build_indirect_ref (datum, 0);
      }
    else
      return build (OFFSET_REF, type, datum, component);
  }
--- 1104,1119 ----
  	 things are not as complex as they are for references to
  	 non-static data members.  */
        type = cp_build_qualified_type (type,
  				      (cp_type_quals (type)  
  				       | cp_type_quals (TREE_TYPE (datum))));
!       /* Build an expression for "object + offset" where offset is the
! 	 value stored in the pointer-to-data-member.  */
!       datum = build (PLUS_EXPR, build_pointer_type (type),
! 		     build_base_path (PLUS_EXPR, build_address (datum), 
! 				      binfo, 1),
! 		     build_nop (ptrdiff_type_node, component));
        return build_indirect_ref (datum, 0);
      }
    else
      return build (OFFSET_REF, type, datum, component);
  }


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