PATCH for type-checking improvements

Mark Mitchell mark@markmitchell.com
Thu Oct 1 20:46:00 GMT 1998


This patch (which I did *not* check in) removes an oddity in the way
g++ deals with type qualifiers.  In particular, for something like
`const int i', g++ records the type as `int' and sets TREE_READONLY on
the VAR_DECL.  While I'm well aware that top-level qualifiers don't
matter in many situations, there are those where they do, and besides
this behavior is wicked counter-intuitive.  

The `const'-ness of the type and the `const'-ness of the expression
should be orthogonal.  For example, a `const' object with a `mutable'
member is not TREE_READONLY, and a non-`const' object which the
compiler determines is never written could well be TREE_READONLY.

This patch makes the top-level qualifiers part of the type.  (Of
course, the DECL is still marked that way too, but those bits are now
used only to guide the back-end as it lays out objects and to aid in
optimzation.)

Don't let the ChangeLog fool you; this is a relatively simple change,
repeated in several places.  (There are also a few improvements to
error-recovery where I found the compiler looking at the TREE_TYPE of
an ERROR_MARK, for example.)  There is at least one real bug fixed by
this change (in the test-case below).  This test-case previously
failed to compile since S::X was considered of a different type than
S::X + 3.

Jason?

-- 
Mark Mitchell 			mark@markmitchell.com
Mark Mitchell Consulting	http://www.markmitchell.com

1998-10-01  Mark Mitchell  <mark@markmitchell.com>

	* class.c (current_class_ptr, current_class_ref): Clarify
	documentation.
	* cvt.c (ocp_convert): Don't expect fold to remove all trivial
	NOP type conversions.
	* decl.c (decls_match): Use comptypes directly; ignore
	qualifiers on the DECL.
	(duplicate_decls): Remove qualifier checks on DECL.
	(grokdeclarator): Make the type built up include top-level
	qualifiers.
	* decl2.c (do_dtors): Fix spelling error.
	* error.c (dump_simple_decl): Don't look at qualifiers on the decl
	when printing type information.
	* init.c (build_new_1): Add documentation.  Deal with the fact
	that type of allocated memory now contains qualifiers.
	* lex.c (is_global): Improve error-recovery.
	* sig.c (build_member_function_pointer): Don't cast away const
	on fields of sigtable_entry_type.
	* tree.c (lvalue_type): Don't look at top-level qualifiers on
	expressions.
	* typeck.c (decay_conversion): Likewise.
	(build_component_ref): Make sure the type of the COMPONENT_REF
	contains top-level qualifiers, as appropriate.  Improve
	error-hadnling. 
	(build_indirect_ref): Simplify.  Don't strip top-level qualifiers.
	(build_array_ref): Likewise.
	(build_unary_op): Improve error-recovery.
	(unary_complex_lvalue): Make taking the address a bound member
	function an error, not a sorry.
	(build_conditional_expr): Look at the type qualifiers, not the
	qualifiers on the expression itself.
	
Index: testsuite/g++.old-deja/g++.pt/overload3.C
===================================================================
RCS file: overload3.C
diff -N overload3.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- overload3.C	Thu Oct  1 19:12:13 1998
***************
*** 0 ****
--- 1,18 ----
+ // Build don't link:
+ 
+ template <class T>
+ void g(T, T);
+ 
+ template <class T>
+ void g(int*, T);
+ 
+ struct S
+ {
+   void f() const
+     {
+       g(X, X+3);
+     }
+ 
+   double X[3];
+ };
+ 
Index: cp/class.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/class.c,v
retrieving revision 1.87
diff -c -p -r1.87 class.c
*** class.c	1998/10/01 12:31:18	1.87
--- class.c	1998/10/02 02:13:14
*************** static tree *current_class_base, *curren
*** 48,55 ****
  static int current_class_stacksize;
  int current_class_depth;
  
! /* The current_class_ptr is the pointer to the current class.
!    current_class_ref is the actual current class.  */
  tree current_class_ptr, current_class_ref;
  
  /* The following two can be derived from the previous one */
--- 48,56 ----
  static int current_class_stacksize;
  int current_class_depth;
  
! /* When we're processing a member function, current_class_ptr is the
!    PARM_DECL for the `this' pointer.  The current_class_ref is an
!    expression for `*this'.  */
  tree current_class_ptr, current_class_ref;
  
  /* The following two can be derived from the previous one */
Index: cp/cvt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cvt.c,v
retrieving revision 1.32
diff -c -p -r1.32 cvt.c
*** cvt.c	1998/09/25 08:59:51	1.32
--- cvt.c	1998/10/02 02:13:18
*************** ocp_convert (type, expr, convtype, flags
*** 664,672 ****
        && TYPE_HAS_CONSTRUCTOR (type))
      /* We need a new temporary; don't take this shortcut.  */;
    else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e)))
!     /* Trivial conversion: cv-qualifiers do not matter on rvalues.  */
!     return fold (build1 (NOP_EXPR, type, e));
!   
    if (code == VOID_TYPE && (convtype & CONV_STATIC))
      return build1 (CONVERT_EXPR, type, e);
  
--- 664,682 ----
        && TYPE_HAS_CONSTRUCTOR (type))
      /* We need a new temporary; don't take this shortcut.  */;
    else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e)))
!     {
!       if (comptypes (type, TREE_TYPE (e), 1))
! 	/* The call to fold will not always remove the NOP_EXPR as
! 	   might be expected, since if one of the types is a typedef;
! 	   the comparsion in fold is just equality of pointers, not a
! 	   call to comptypes.  */
! 	;
!       else
! 	e = build1 (NOP_EXPR, type, e);
! 
!       return fold (e);
!     }
! 
    if (code == VOID_TYPE && (convtype & CONV_STATIC))
      return build1 (CONVERT_EXPR, type, e);
  
Index: cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.217
diff -c -p -r1.217 decl.c
*** decl.c	1998/09/28 17:34:29	1.217
--- decl.c	1998/10/02 02:14:05
*************** decls_match (newdecl, olddecl)
*** 2571,2590 ****
  	types_match = TREE_TYPE (newdecl) == NULL_TREE;
        else if (TREE_TYPE (newdecl) == NULL_TREE)
  	types_match = 0;
-       /* Qualifiers must match, and they may be present on either, the type
- 	 or the decl.  */
-       else if ((TREE_READONLY (newdecl)
- 		|| TYPE_READONLY (TREE_TYPE (newdecl)))
- 	       == (TREE_READONLY (olddecl)
- 		   || TYPE_READONLY (TREE_TYPE (olddecl)))
- 	       && (TREE_THIS_VOLATILE (newdecl)
- 		    || TYPE_VOLATILE (TREE_TYPE (newdecl)))
- 		   == (TREE_THIS_VOLATILE (olddecl)
- 		       || TYPE_VOLATILE (TREE_TYPE (olddecl))))
- 	types_match = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (newdecl)),
- 				 TYPE_MAIN_VARIANT (TREE_TYPE (olddecl)), 1);
        else
! 	types_match = 0;
      }
  
    return types_match;
--- 2571,2579 ----
  	types_match = TREE_TYPE (newdecl) == NULL_TREE;
        else if (TREE_TYPE (newdecl) == NULL_TREE)
  	types_match = 0;
        else
! 	types_match = comptypes (TREE_TYPE (newdecl),
! 				 TREE_TYPE (olddecl), 1);
      }
  
    return types_match;
*************** duplicate_decls (newdecl, olddecl)
*** 2908,2920 ****
  			     olddecl);
  	    }
  	}
-       /* These bits are logically part of the type for non-functions.  */
-       else if (TREE_READONLY (newdecl) != TREE_READONLY (olddecl)
- 	       || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl))
- 	{
- 	  cp_pedwarn ("type qualifiers for `%#D'", newdecl);
- 	  cp_pedwarn_at ("conflict with previous decl `%#D'", olddecl);
- 	}
      }
  
    /* If new decl is `static' and an `extern' was seen previously,
--- 2897,2902 ----
*************** grokdeclarator (declarator, declspecs, d
*** 9062,9068 ****
  
    constp = !! RIDBIT_SETP (RID_CONST, specbits) + TYPE_READONLY (type);
    volatilep = !! RIDBIT_SETP (RID_VOLATILE, specbits) + TYPE_VOLATILE (type);
!   type = build_type_variant (type, 0, 0);
    staticp = 0;
    inlinep = !! RIDBIT_SETP (RID_INLINE, specbits);
    virtualp = RIDBIT_SETP (RID_VIRTUAL, specbits);
--- 9044,9050 ----
  
    constp = !! RIDBIT_SETP (RID_CONST, specbits) + TYPE_READONLY (type);
    volatilep = !! RIDBIT_SETP (RID_VOLATILE, specbits) + TYPE_VOLATILE (type);
!   type = cp_build_type_variant (type, constp, volatilep);
    staticp = 0;
    inlinep = !! RIDBIT_SETP (RID_INLINE, specbits);
    virtualp = RIDBIT_SETP (RID_VIRTUAL, specbits);
*************** grokdeclarator (declarator, declspecs, d
*** 9795,9800 ****
--- 9777,9783 ----
  		    pedwarn ("discarding `volatile' applied to a reference");
  		  constp = volatilep = 0;
  		}
+ 	      type = cp_build_type_variant (type, constp, volatilep);
  	    }
  	  declarator = TREE_OPERAND (declarator, 0);
  	  ctype = NULL_TREE;
*************** grokparms (first_parm, funcdef_flag)
*** 10881,10887 ****
  					 NULL_TREE);
  		  if (! decl)
  		    continue;
! 		  type = TREE_TYPE (decl);
  		  if (TREE_CODE (type) == VOID_TYPE)
  		    decl = void_type_node;
  		  else if (TREE_CODE (type) == METHOD_TYPE)
--- 10864,10874 ----
  					 NULL_TREE);
  		  if (! decl)
  		    continue;
! 
! 		  /* Top-level qualifiers on the parameters are
! 		     ignored for function types.  */
! 		  type = TYPE_MAIN_VARIANT (TREE_TYPE (decl));
! 
  		  if (TREE_CODE (type) == VOID_TYPE)
  		    decl = void_type_node;
  		  else if (TREE_CODE (type) == METHOD_TYPE)
Index: cp/decl2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl2.c,v
retrieving revision 1.137
diff -c -p -r1.137 decl2.c
*** decl2.c	1998/09/28 17:34:31	1.137
--- decl2.c	1998/10/02 02:14:13
*************** do_dtors (start)
*** 3185,3191 ****
  
  	       Access control for implicit calls to the constructors,
  	       the conversion functions, or the destructor called to
! 	       create and destroy a static data member is per- formed as
  	       if these calls appeared in the scope of the member's
  	       class.  
  
--- 3185,3191 ----
  
  	       Access control for implicit calls to the constructors,
  	       the conversion functions, or the destructor called to
! 	       create and destroy a static data member is performed as
  	       if these calls appeared in the scope of the member's
  	       class.  
  
Index: cp/error.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/error.c,v
retrieving revision 1.53
diff -c -p -r1.53 error.c
*** error.c	1998/09/09 00:52:42	1.53
--- error.c	1998/10/02 02:14:17
*************** dump_simple_decl (t, type, v)
*** 667,673 ****
      {
        dump_type_prefix (type, v, 0);
        OB_PUTC (' ');
-       dump_readonly_or_volatile (t, after);
      }
    if (DECL_CLASS_SCOPE_P (t))
      {
--- 667,672 ----
Index: cp/init.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/init.c,v
retrieving revision 1.66
diff -c -p -r1.66 init.c
*** init.c	1998/09/25 08:59:57	1.66
--- init.c	1998/10/02 02:14:27
*************** build_new_1 (exp)
*** 2391,2402 ****
        if (! TYPE_NEEDS_CONSTRUCTING (type)
  	  && ! IS_AGGR_TYPE (type) && ! has_array)
  	{
! 	  /* New 2.0 interpretation: `new int (10)' means
! 	     allocate an int, and initialize it with 10.  */
  	  tree deref;
  
  	  rval = save_expr (rval);
  	  deref = build_indirect_ref (rval, NULL_PTR);
  	  TREE_READONLY (deref) = 0;
  
  	  if (TREE_CHAIN (init) != NULL_TREE)
--- 2391,2416 ----
        if (! TYPE_NEEDS_CONSTRUCTING (type)
  	  && ! IS_AGGR_TYPE (type) && ! has_array)
  	{
! 	  /* We are processing something like `new int (10)', which
! 	     means allocate an int, and initialize it with 10.  */
  	  tree deref;
+ 	  tree deref_type;
  
+ 	  /* At present RVAL is a temporary variable, created to hold
+ 	     the value from the call to `operator new'.  We transform
+ 	     it to (*RVAL = INIT, RVAL).  */
  	  rval = save_expr (rval);
  	  deref = build_indirect_ref (rval, NULL_PTR);
+ 
+ 	  /* Even for something like `new const int (10)' we must
+ 	     allow the expression to be non-const while we do the
+ 	     initialization.  */
+ 	  deref_type = TREE_TYPE (deref);
+ 	  if (TYPE_READONLY (deref_type))
+ 	    TREE_TYPE (deref) 
+ 	      = cp_build_type_variant (deref_type,
+ 				       /*constp=*/0,
+ 				       TYPE_VOLATILE (deref_type));
  	  TREE_READONLY (deref) = 0;
  
  	  if (TREE_CHAIN (init) != NULL_TREE)
Index: cp/lex.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/lex.c,v
retrieving revision 1.77
diff -c -p -r1.77 lex.c
*** lex.c	1998/09/25 08:59:58	1.77
--- lex.c	1998/10/02 02:14:40
*************** is_global (d)
*** 2853,2858 ****
--- 2853,2861 ----
    while (1)
      switch (TREE_CODE (d))
        {
+       case ERROR_MARK:
+ 	return 1;
+ 
        case OVERLOAD: d = OVL_FUNCTION (d); continue;
        case TREE_LIST: d = TREE_VALUE (d); continue;
        default:
Index: cp/sig.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/sig.c,v
retrieving revision 1.10
diff -c -p -r1.10 sig.c
*** sig.c	1998/09/07 14:25:30	1.10
--- sig.c	1998/10/02 02:14:43
*************** build_member_function_pointer (member)
*** 321,327 ****
    GNU_xref_ref (current_function_decl, name);
  
    entry = build_lang_field_decl (FIELD_DECL, get_identifier (name),
! 				 TYPE_MAIN_VARIANT (sigtable_entry_type));
    TREE_CONSTANT (entry) = 1;
    TREE_READONLY (entry) = 1;
  
--- 321,327 ----
    GNU_xref_ref (current_function_decl, name);
  
    entry = build_lang_field_decl (FIELD_DECL, get_identifier (name),
! 				 sigtable_entry_type);
    TREE_CONSTANT (entry) = 1;
    TREE_READONLY (entry) = 1;
  
Index: cp/tree.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/tree.c,v
retrieving revision 1.67
diff -c -p -r1.67 tree.c
*** tree.c	1998/10/01 12:31:22	1.67
--- tree.c	1998/10/02 02:14:49
*************** lvalue_type (arg)
*** 2571,2579 ****
    tree type = TREE_TYPE (arg);
    if (TREE_CODE (arg) == OVERLOAD)
      type = unknown_type_node;
-   else if (TREE_CODE (type) != ARRAY_TYPE)
-     type = cp_build_type_variant
-       (type, TREE_READONLY (arg), TREE_THIS_VOLATILE (arg));
    return type;
  }
  
--- 2571,2576 ----
Index: cp/typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.110
diff -c -p -r1.110 typeck.c
*** typeck.c	1998/09/25 09:00:03	1.110
--- typeck.c	1998/10/02 02:15:10
*************** decay_conversion (exp)
*** 1684,1692 ****
    if (code == ARRAY_TYPE)
      {
        register tree adr;
-       tree restype;
        tree ptrtype;
-       int constp, volatilep;
  
        if (TREE_CODE (exp) == INDIRECT_REF)
  	{
--- 1684,1690 ----
*************** decay_conversion (exp)
*** 1718,1738 ****
  	  return error_mark_node;
  	}
  
!       constp = volatilep = 0;
!       if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'r'
! 	  || TREE_CODE_CLASS (TREE_CODE (exp)) == 'd')
! 	{
! 	  constp = TREE_READONLY (exp);
! 	  volatilep = TREE_THIS_VOLATILE (exp);
! 	}
! 
!       restype = TREE_TYPE (type);
!       if (TYPE_READONLY (type) || TYPE_VOLATILE (type)
! 	  || constp || volatilep)
! 	restype = cp_build_type_variant (restype,
! 					 TYPE_READONLY (type) || constp,
! 					 TYPE_VOLATILE (type) || volatilep);
!       ptrtype = build_pointer_type (restype);
  
        if (TREE_CODE (exp) == VAR_DECL)
  	{
--- 1716,1722 ----
  	  return error_mark_node;
  	}
  
!       ptrtype = build_pointer_type (TREE_TYPE (type));
  
        if (TREE_CODE (exp) == VAR_DECL)
  	{
*************** build_component_ref (datum, component, b
*** 1954,1967 ****
       tree datum, component, basetype_path;
       int protect;
  {
!   register tree basetype = TREE_TYPE (datum);
    register enum tree_code code;
    register tree field = NULL;
    register tree ref;
  
    if (processing_template_decl)
      return build_min_nt (COMPONENT_REF, datum, component);
  
    /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference
       inside it.  */
    switch (TREE_CODE (datum))
--- 1938,1961 ----
       tree datum, component, basetype_path;
       int protect;
  {
!   register tree basetype;
    register enum tree_code code;
    register tree field = NULL;
    register tree ref;
+   tree field_type;
+   int constp;
+   int volatilep;
  
    if (processing_template_decl)
      return build_min_nt (COMPONENT_REF, datum, component);
+   
+   if (datum == error_mark_node 
+       || TREE_TYPE (datum) == error_mark_node)
+     return error_mark_node;
  
+   /* BASETYPE holds the type of the class containing the COMPONENT.  */
+   basetype = TYPE_MAIN_VARIANT (TREE_TYPE (datum));
+     
    /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference
       inside it.  */
    switch (TREE_CODE (datum))
*************** build_component_ref (datum, component, b
*** 1995,2007 ****
    if (code == REFERENCE_TYPE)
      {
        datum = convert_from_reference (datum);
!       basetype = TREE_TYPE (datum);
        code = TREE_CODE (basetype);
      }
    if (TREE_CODE (datum) == OFFSET_REF)
      {
        datum = resolve_offset_ref (datum);
!       basetype = TREE_TYPE (datum);
        code = TREE_CODE (basetype);
      }
  
--- 1989,2001 ----
    if (code == REFERENCE_TYPE)
      {
        datum = convert_from_reference (datum);
!       basetype = TYPE_MAIN_VARIANT (TREE_TYPE (datum));
        code = TREE_CODE (basetype);
      }
    if (TREE_CODE (datum) == OFFSET_REF)
      {
        datum = resolve_offset_ref (datum);
!       basetype = TYPE_MAIN_VARIANT (TREE_TYPE (datum));
        code = TREE_CODE (basetype);
      }
  
*************** build_component_ref (datum, component, b
*** 2086,2092 ****
  		  tree access, fndecl;
  
  		  /* Unique, so use this one now.  */
! 		  basetype = TREE_PURPOSE (fndecls);
  		  fndecl = TREE_VALUE (fndecls);
  		  access = compute_access (TREE_PURPOSE (fndecls), fndecl);
  		  if (access == access_public_node)
--- 2080,2086 ----
  		  tree access, fndecl;
  
  		  /* Unique, so use this one now.  */
! 		  basetype = TYPE_MAIN_VARIANT (TREE_PURPOSE (fndecls));
  		  fndecl = TREE_VALUE (fndecls);
  		  access = compute_access (TREE_PURPOSE (fndecls), fndecl);
  		  if (access == access_public_node)
*************** build_component_ref (datum, component, b
*** 2198,2212 ****
  	}
      }
  
!   ref = fold (build (COMPONENT_REF, TREE_TYPE (field),
  		     break_out_cleanups (datum), field));
  
!   if (TREE_READONLY (datum) || TREE_READONLY (field))
      TREE_READONLY (ref) = 1;
!   if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field))
      TREE_THIS_VOLATILE (ref) = 1;
-   if (DECL_LANG_SPECIFIC (field) && DECL_MUTABLE_P (field))
-     TREE_READONLY (ref) = 0;
  
    return ref;
  }
--- 2192,2231 ----
  	}
      }
  
!   /* Compute the type of the field, as described in [expr.ref].  */
!   constp = 0;
!   volatilep = 0;
!   field_type = TREE_TYPE (field);
!   if (TREE_CODE (field_type) == REFERENCE_TYPE)
!     /* The standard says that the type of the result should be the
!        type referred to by the reference.  But for now, at least, we
!        do the conversion from reference type later.  */
!     ;
!   else
!     {
!       /* A field is const (volatile) if the enclosing object, or the
! 	 field itself, is const (volatile).  But, a mutable field is
! 	 not const, even within a const object.  */
!       constp = (!(DECL_LANG_SPECIFIC (field) 
! 		  && DECL_MUTABLE_P (field))
! 		&& (TYPE_READONLY (field_type)
! 		    || TYPE_READONLY (TREE_TYPE (datum))));
!       volatilep = (TYPE_VOLATILE (field_type)
! 		   || TYPE_VOLATILE (TREE_TYPE (datum)));
!       if (!IS_SIGNATURE (field_type))
! 	field_type = cp_build_type_variant (field_type, constp, volatilep);
!     }
! 
!   ref = fold (build (COMPONENT_REF, field_type,
  		     break_out_cleanups (datum), field));
  
!   /* Mark the expression const or volatile, as appropriate.  Even
!      though we've dealt with the type above, we still have to mark the
!      expression itself.  */
!   if (constp)
      TREE_READONLY (ref) = 1;
!   else if (volatilep)
      TREE_THIS_VOLATILE (ref) = 1;
  
    return ref;
  }
*************** build_indirect_ref (ptr, errorstring)
*** 2270,2298 ****
  
    if (TREE_CODE (type) == POINTER_TYPE || TREE_CODE (type) == REFERENCE_TYPE)
      {
        if (TREE_CODE (pointer) == ADDR_EXPR
  	  && !flag_volatile
! 	  && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (pointer, 0)))
! 	      == TYPE_MAIN_VARIANT (TREE_TYPE (type)))
! 	  && (TREE_READONLY (TREE_OPERAND (pointer, 0))
! 	      == TYPE_READONLY (TREE_TYPE (type)))
! 	  && (TREE_THIS_VOLATILE (TREE_OPERAND (pointer, 0))
! 	      == TYPE_VOLATILE (TREE_TYPE (type))))
  	return TREE_OPERAND (pointer, 0);
        else
  	{
! 	  tree t = TREE_TYPE (type);
! 	  register tree ref = build1 (INDIRECT_REF,
! 				      TYPE_MAIN_VARIANT (t), pointer);
  
  	  /* We *must* set TREE_READONLY when dereferencing a pointer to const,
  	     so that we get the proper error message if the result is used
  	     to assign to.  Also, &* is supposed to be a no-op.  */
  	  TREE_READONLY (ref) = TYPE_READONLY (t);
  	  TREE_SIDE_EFFECTS (ref)
! 	    = (TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer)
  	       || flag_volatile);
- 	  TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
  	  return ref;
  	}
      }
--- 2289,2320 ----
  
    if (TREE_CODE (type) == POINTER_TYPE || TREE_CODE (type) == REFERENCE_TYPE)
      {
+       /* [expr.unary.op]
+ 	 
+ 	 If the type of the expression is "pointer to T," the type
+ 	 of  the  result  is  "T."   
+ 
+          We must use the canonical variant because certain */
+       tree t = canonical_type_variant (TREE_TYPE (type));
+ 
        if (TREE_CODE (pointer) == ADDR_EXPR
  	  && !flag_volatile
! 	  && comptypes (t, TREE_TYPE (TREE_OPERAND (pointer, 0)), 1))
! 	/* The POINTER was something like `&x'.  We simplify `*&x' to
! 	   `x'.  */
  	return TREE_OPERAND (pointer, 0);
        else
  	{
! 	  tree ref = build1 (INDIRECT_REF, t, pointer);
  
  	  /* We *must* set TREE_READONLY when dereferencing a pointer to const,
  	     so that we get the proper error message if the result is used
  	     to assign to.  Also, &* is supposed to be a no-op.  */
  	  TREE_READONLY (ref) = TYPE_READONLY (t);
+ 	  TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
  	  TREE_SIDE_EFFECTS (ref)
! 	    = (TREE_THIS_VOLATILE (ref) || TREE_SIDE_EFFECTS (pointer)
  	       || flag_volatile);
  	  return ref;
  	}
      }
*************** build_array_ref (array, idx)
*** 2403,2425 ****
  	    warning ("subscripting array declared `register'");
  	}
  
!       type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
        rval = build (ARRAY_REF, type, array, idx);
        /* Array ref is const/volatile if the array elements are
  	 or if the array is..  */
        TREE_READONLY (rval)
! 	|= (TYPE_READONLY (TREE_TYPE (TREE_TYPE (array)))
! 	    | TREE_READONLY (array));
        TREE_SIDE_EFFECTS (rval)
! 	|= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array)))
! 	    | TREE_SIDE_EFFECTS (array));
        TREE_THIS_VOLATILE (rval)
! 	|= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array)))
! 	    /* This was added by rms on 16 Nov 91.
! 	       It fixes  vol struct foo *a;  a->elts[1] 
! 	       in an inline function.
! 	       Hope it doesn't break something else.  */
! 	    | TREE_THIS_VOLATILE (array));
        return require_complete_type (fold (rval));
      }
  
--- 2425,2440 ----
  	    warning ("subscripting array declared `register'");
  	}
  
!       type = TREE_TYPE (TREE_TYPE (array));
        rval = build (ARRAY_REF, type, array, idx);
        /* Array ref is const/volatile if the array elements are
  	 or if the array is..  */
        TREE_READONLY (rval)
! 	|= (TYPE_READONLY (type) | TREE_READONLY (array));
        TREE_SIDE_EFFECTS (rval)
! 	|= (TYPE_VOLATILE (type) | TREE_SIDE_EFFECTS (array));
        TREE_THIS_VOLATILE (rval)
! 	|= (TYPE_VOLATILE (type) | TREE_THIS_VOLATILE (array));
        return require_complete_type (fold (rval));
      }
  
*************** build_unary_op (code, xarg, noconvert)
*** 4720,4726 ****
  	       && !lvalue_or_else (arg, "unary `&'"))
  	return error_mark_node;
  
!       argtype = build_pointer_type (argtype);
  
        if (mark_addressable (arg) == 0)
  	return error_mark_node;
--- 4735,4742 ----
  	       && !lvalue_or_else (arg, "unary `&'"))
  	return error_mark_node;
  
!       if (argtype != error_mark_node)
! 	argtype = build_pointer_type (argtype);
  
        if (mark_addressable (arg) == 0)
  	return error_mark_node;
*************** unary_complex_lvalue (code, arg)
*** 4876,4882 ****
  	      {
  		/* Don't know if this should return address to just
  		   _DECL, or actual address resolved in this expression.  */
! 		sorry ("address of bound pointer-to-member expression");
  		return error_mark_node;
  	      }
  
--- 4892,4898 ----
  	      {
  		/* Don't know if this should return address to just
  		   _DECL, or actual address resolved in this expression.  */
! 		cp_error ("address of bound pointer-to-member expression");
  		return error_mark_node;
  	      }
  
*************** build_conditional_expr (ifexp, op1, op2)
*** 5115,5122 ****
        if (type1 != type2)
  	type1 = cp_build_type_variant
  			(type1,
! 			 TREE_READONLY (op1) || TREE_READONLY (op2),
! 			 TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2));
        /* ??? This is a kludge to deal with the fact that
  	 we don't sort out integers and enums properly, yet.  */
        result = fold (build (COND_EXPR, type1, ifexp, op1, op2));
--- 5131,5138 ----
        if (type1 != type2)
  	type1 = cp_build_type_variant
  			(type1,
! 			 TYPE_READONLY (op1) || TYPE_READONLY (op2),
! 			 TYPE_VOLATILE (op1) || TYPE_VOLATILE (op2));
        /* ??? This is a kludge to deal with the fact that
  	 we don't sort out integers and enums properly, yet.  */
        result = fold (build (COND_EXPR, type1, ifexp, op1, op2));



More information about the Gcc-patches mailing list