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]: Reference binding of packed fields


Hi,
this patch prevents non-const reference bindings to packed fields.
It also prevents packing fields of non-pod type when the POD is
not packed itself.

Whilst, rth's comment 'don't do that then' is fine for explicitly taking
the address of a packed field, C++ reference binding happens much more
quietly, and some machines silently ignore the LSBs of an unaligned
memory address - bleah!

booted & tested on i686-pc-linux-gnu, ok?

nathan
--
Nathan Sidwell    ::   http://www.codesourcery.com   ::     CodeSourcery LLC
         The voices in my head said this was stupid too
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk

2003-07-16  Nathan Sidwell  <nathan@codesourcery.com>

	* cp-tree.h (enum cp_lvalue_kind): Add clk_packed.
	* tree.c (lvalue_p_1): Set it.
	* class.c (check_field): Don't allow non-packed non-POD fields to
	be packed.
	* call.c (reference_binding): Need a temporary for all bitfield
	and packed fields.
	(convert_like_real): Check it is ok to make a temporary here.

Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.407
diff -c -3 -p -r1.407 call.c
*** cp/call.c	14 Jul 2003 17:45:07 -0000	1.407
--- cp/call.c	16 Jul 2003 10:26:29 -0000
*************** reference_binding (tree rto, tree rfrom,
*** 1054,1063 ****
  	 lvalue.  */
        conv = build1 (IDENTITY_CONV, from, expr);
        conv = direct_reference_binding (rto, conv);
!       if ((lvalue_p & clk_bitfield) != 0 
! 	  && CP_TYPE_CONST_NON_VOLATILE_P (to))
  	/* For the purposes of overload resolution, we ignore the fact
! 	   this expression is a bitfield. (In particular,
  	   [over.ics.ref] says specifically that a function with a
  	   non-const reference parameter is viable even if the
  	   argument is a bitfield.)
--- 1054,1063 ----
  	 lvalue.  */
        conv = build1 (IDENTITY_CONV, from, expr);
        conv = direct_reference_binding (rto, conv);
!       if ((lvalue_p & clk_bitfield) != 0
! 	  || ((lvalue_p & clk_packed) != 0 && !TYPE_PACKED (to)))
  	/* For the purposes of overload resolution, we ignore the fact
! 	   this expression is a bitfield or packed field. (In particular,
  	   [over.ics.ref] says specifically that a function with a
  	   non-const reference parameter is viable even if the
  	   argument is a bitfield.)
*************** reference_binding (tree rto, tree rfrom,
*** 1068,1073 ****
--- 1068,1074 ----
  	   a temporary, so we just issue an error when the conversion
  	   actually occurs.  */
  	NEED_TEMPORARY_P (conv) = 1;
+ 					
        return conv;
      }
    else if (CLASS_TYPE_P (from) && !(flags & LOOKUP_NO_CONVERSION))
*************** convert_like_real (tree convs, tree expr
*** 4175,4180 ****
--- 4176,4198 ----
  	if (NEED_TEMPORARY_P (convs) || !non_cast_lvalue_p (expr))
  	  {
  	    tree type = TREE_TYPE (TREE_OPERAND (convs, 0));
+ 
+ 	    if (!CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type)))
+ 	      {
+ 		/* If the reference is volatile or non-const, we
+ 		   cannot create a temporary.  */
+ 		cp_lvalue_kind lvalue = real_lvalue_p (expr);
+ 		
+ 		if (lvalue & clk_bitfield)
+ 		  error ("cannot bind bitfield `%E' to `%T'",
+ 			 expr, ref_type);
+ 		else if (lvalue & clk_packed)
+ 		  error ("cannot bind packed field `%E' to `%T'",
+ 			 expr, ref_type);
+ 		else
+ 		  my_friendly_assert (0, 20030715);
+ 		return error_mark_node;
+ 	      }
  	    expr = build_target_expr_with_type (expr, type);
  	  }
  
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.552
diff -c -3 -p -r1.552 class.c
*** cp/class.c	14 Jul 2003 05:12:54 -0000	1.552
--- cp/class.c	16 Jul 2003 10:26:46 -0000
*************** check_field_decls (tree t, tree *access_
*** 3022,3028 ****
  
        if (TREE_CODE (x) == FIELD_DECL)
  	{
! 	  DECL_PACKED (x) |= TYPE_PACKED (t);
  
  	  if (DECL_C_BIT_FIELD (x) && integer_zerop (DECL_INITIAL (x)))
  	    /* We don't treat zero-width bitfields as making a class
--- 3022,3036 ----
  
        if (TREE_CODE (x) == FIELD_DECL)
  	{
! 	  if (TYPE_PACKED (t))
! 	    {
! 	      if (!pod_type_p (TREE_TYPE (x)) && !TYPE_PACKED (TREE_TYPE (x)))
! 		cp_warning_at
! 		  ("ignoring packed attribute on unpacked non-POD field `%#D'",
! 		   x);
! 	      else
! 		DECL_PACKED (x) = 1;
! 	    }
  
  	  if (DECL_C_BIT_FIELD (x) && integer_zerop (DECL_INITIAL (x)))
  	    /* We don't treat zero-width bitfields as making a class
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.877
diff -c -3 -p -r1.877 cp-tree.h
*** cp/cp-tree.h	14 Jul 2003 19:05:01 -0000	1.877
--- cp/cp-tree.h	16 Jul 2003 10:26:58 -0000
*************** typedef enum cp_lvalue_kind {
*** 2949,2955 ****
    clk_none = 0,     /* Things that are not an lvalue.  */
    clk_ordinary = 1, /* An ordinary lvalue.  */
    clk_class = 2,    /* An rvalue of class-type.  */
!   clk_bitfield = 4  /* An lvalue for a bit-field.  */
  } cp_lvalue_kind;
  
  /* The kinds of scopes we recognize.  */
--- 2949,2956 ----
    clk_none = 0,     /* Things that are not an lvalue.  */
    clk_ordinary = 1, /* An ordinary lvalue.  */
    clk_class = 2,    /* An rvalue of class-type.  */
!   clk_bitfield = 4, /* An lvalue for a bit-field.  */
!   clk_packed = 8    /* An lvalue for a packed field. */
  } cp_lvalue_kind;
  
  /* The kinds of scopes we recognize.  */
Index: cp/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.336
diff -c -3 -p -r1.336 tree.c
*** cp/tree.c	10 Jul 2003 16:47:48 -0000	1.336
--- cp/tree.c	16 Jul 2003 10:27:32 -0000
*************** lvalue_p_1 (tree ref, 
*** 100,110 ****
        op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
  				    treat_class_rvalues_as_lvalues,
  				    allow_cast_as_lvalue);
!       if (op1_lvalue_kind 
! 	  /* The "field" can be a FUNCTION_DECL or an OVERLOAD in some
! 	     situations.  */
! 	  && TREE_CODE (TREE_OPERAND (ref, 1)) == FIELD_DECL
! 	  && DECL_C_BIT_FIELD (TREE_OPERAND (ref, 1)))
  	{
  	  /* Clear the ordinary bit.  If this object was a class
  	     rvalue we want to preserve that information.  */
--- 100,111 ----
        op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
  				    treat_class_rvalues_as_lvalues,
  				    allow_cast_as_lvalue);
!       if (!op1_lvalue_kind 
! 	  /* The "field" can be a FUNCTION_DECL or an OVERLOAD in some	
!   	     situations.  */
!  	  || TREE_CODE (TREE_OPERAND (ref, 1)) != FIELD_DECL)
!  	;
!       else if (DECL_C_BIT_FIELD (TREE_OPERAND (ref, 1)))
  	{
  	  /* Clear the ordinary bit.  If this object was a class
  	     rvalue we want to preserve that information.  */
*************** lvalue_p_1 (tree ref, 
*** 112,117 ****
--- 113,121 ----
  	  /* The lvalue is for a btifield.  */
  	  op1_lvalue_kind |= clk_bitfield;
  	}
+       else if (DECL_PACKED (TREE_OPERAND (ref, 1)))
+ 	op1_lvalue_kind |= clk_packed;
+       
        return op1_lvalue_kind;
  
      case STRING_CST:
// { dg-do compile }

// Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 15 Jul 2003 <nathan@codesourcery.com>

// Packed fields are unsuitable for direct reference binding.

struct Unpacked { int i; };

void Ref (int &p);
void Ref (Unpacked &p);

struct  __attribute__ ((packed)) Packed
{
  char c;
  int i;
  Unpacked u;
};

void Foo (Packed &p)
{
  Ref (p.i); // { dg-error "cannot bind packed field" "" }
  Ref (p.u.i); // { dg-error "cannot bind packed field" "" }
  Ref (p.u); // { dg-error "cannot bind packed field" "" }
}
// { dg-do run }

// Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 15 Jul 2003 <nathan@codesourcery.com>

// Packed fields are unsuitable for direct reference binding.

struct Unpacked { int i; };

int ConstRef (int const &p, int const *ptr, int v)
{
  if (p != v)
    return 1;
  if (&p == ptr)
    return 2;
  return 0;
}

int ConstRef (Unpacked const &p, Unpacked const *ptr, int v)
{
  if (p.i != v)
    return 1;
  if (&p == ptr)
    return 2;
  return 0;
}

int Val (int p, int v)
{
  if (p != v)
    return 1;
  return 0;
}
int Val (Unpacked p, int v)
{
  if (p.i != v)
    return 1;
  return 0;
}

struct  __attribute__ ((packed)) Packed
{
  char c;
  int i;
  Unpacked u;
  char t;
};

int Foo (Packed &p, int i, int ui)
{
  int r;
  
  if ((r = Val (p.i, i)))
    return r;
  if ((r = Val (p.u.i, ui)))
    return r + 2;
  if ((r = Val (p.u, ui)))
    return r + 4;
  
  if ((r = ConstRef (p.i, &p.i, i)))
    return r + 6;
  if ((r = ConstRef (p.u.i, &p.u.i, ui)))
    return r + 8;
  if ((r = ConstRef (p.u, &p.u, ui)))
    return r + 10;

  return 0;
}

int main ()
{
  Packed p;

  p.c = 0x12;
  p.i = 0x3456789a;
  p.u.i = 0xbcdef00f;
  p.t = 0xed;

  return Foo (p, 0x3456789a, 0xbcdef00f);
}

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