[c] don't expand &a.b to pointer arithmetic

Richard Henderson rth@redhat.com
Mon Aug 30 19:07:00 GMT 2004


Final patch for C.

The only bit of note is the varasm changes.  These are to preserve some
level of backward compatibility with hand-written offsetof macros, and
other bits of ugliness in our testsuite.  While these things are surely
not conformant in any interesting sense, I saw no reason to break them
either.

Tested i686-linux.


r~


        * c-typeck.c (build_unary_op): Don't expand ADDR_EXPR of a
        COMPONENT_REF to pointer arithmetic. 
        * varasm.c (initializer_constant_valid_p): Allow "&(*c).f", for
        constant "c" as a valid constant initializer.  Allow narrowing of
        differences against the same base object, for any base object.

Index: gcc/c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.363
diff -u -p -r1.363 c-typeck.c
--- gcc/c-typeck.c	27 Aug 2004 00:37:48 -0000	1.363
+++ gcc/c-typeck.c	30 Aug 2004 18:02:51 -0000
@@ -2514,44 +2514,24 @@ build_unary_op (enum tree_code code, tre
 					  TREE_READONLY (arg),
 					  TREE_THIS_VOLATILE (arg));
 
-      argtype = build_pointer_type (argtype);
-
       if (!c_mark_addressable (arg))
 	return error_mark_node;
 
-      {
-	tree addr;
-
-	if (TREE_CODE (arg) == COMPONENT_REF)
-	  {
-	    tree field = TREE_OPERAND (arg, 1);
-
-	    addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), flag);
-
-	    if (DECL_C_BIT_FIELD (field))
-	      {
-		error ("attempt to take address of bit-field structure member `%s'",
-		       IDENTIFIER_POINTER (DECL_NAME (field)));
-		return error_mark_node;
-	      }
+      if (TREE_CODE (arg) == COMPONENT_REF
+	  && DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
+	{
+	  error ("attempt to take address of bit-field structure member `%D'",
+		 TREE_OPERAND (arg, 1));
+	  return error_mark_node;
+	}
 
-	    addr = fold (build2 (PLUS_EXPR, argtype,
-				 convert (argtype, addr),
-				 convert (argtype, byte_position (field))));
-	    
-	    /* If the folded PLUS_EXPR is not a constant address, wrap
-               it in an ADDR_EXPR.  */
-	    if (!TREE_CONSTANT (addr))
-	      addr = build1 (ADDR_EXPR, argtype, arg);
-	  }
-	else
-	  addr = build1 (ADDR_EXPR, argtype, arg);
+      argtype = build_pointer_type (argtype);
+      val = build1 (ADDR_EXPR, argtype, arg);
 
-	if (TREE_CODE (arg) == COMPOUND_LITERAL_EXPR)
-	  TREE_INVARIANT (addr) = TREE_CONSTANT (addr) = 1;
+      if (TREE_CODE (arg) == COMPOUND_LITERAL_EXPR)
+	TREE_INVARIANT (val) = TREE_CONSTANT (val) = 1;
 
-	return addr;
-      }
+      return val;
 
     default:
       break;
Index: gcc/varasm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varasm.c,v
retrieving revision 1.445
diff -u -p -r1.445 varasm.c
--- gcc/varasm.c	19 Aug 2004 06:16:37 -0000	1.445
+++ gcc/varasm.c	30 Aug 2004 18:02:54 -0000
@@ -3463,7 +3463,14 @@ initializer_constant_valid_p (tree value
 
     case ADDR_EXPR:
     case FDESC_EXPR:
-      return staticp (TREE_OPERAND (value, 0)) ? TREE_OPERAND (value, 0) : 0;
+      value = staticp (TREE_OPERAND (value, 0));
+      /* "&(*a).f" is like unto pointer arithmetic.  If "a" turns out to
+	 be a constant, this is old-skool offsetof-like nonsense.  */
+      if (value
+	  && TREE_CODE (value) == INDIRECT_REF
+	  && TREE_CONSTANT (TREE_OPERAND (value, 0)))
+	return null_pointer_node;
+      return value;
 
     case VIEW_CONVERT_EXPR:
     case NON_LVALUE_EXPR:
@@ -3565,16 +3572,17 @@ initializer_constant_valid_p (tree value
 	  /* Since GCC guarantees that string constants are unique in the
 	     generated code, a subtraction between two copies of the same
 	     constant string is absolute.  */
-	  if (valid0 && TREE_CODE (valid0) == STRING_CST &&
-	      valid1 && TREE_CODE (valid1) == STRING_CST &&
-	      TREE_STRING_POINTER (valid0) == TREE_STRING_POINTER (valid1))
+	  if (valid0 && TREE_CODE (valid0) == STRING_CST
+	      && valid1 && TREE_CODE (valid1) == STRING_CST
+	      && operand_equal_p (valid0, valid1, 1))
 	    return null_pointer_node;
 	}
 
-      /* Support differences between labels.  */
+      /* Support narrowing differences.  */
       if (INTEGRAL_TYPE_P (endtype))
 	{
 	  tree op0, op1;
+
 	  op0 = TREE_OPERAND (value, 0);
 	  op1 = TREE_OPERAND (value, 1);
 
@@ -3609,11 +3617,25 @@ initializer_constant_valid_p (tree value
 	      op1 = inner;
 	    }
 
-	  if (TREE_CODE (op0) == ADDR_EXPR
-	      && TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL
-	      && TREE_CODE (op1) == ADDR_EXPR
-	      && TREE_CODE (TREE_OPERAND (op1, 0)) == LABEL_DECL)
-	    return null_pointer_node;
+	  op0 = initializer_constant_valid_p (op0, endtype);
+	  op1 = initializer_constant_valid_p (op1, endtype);
+
+	  /* Both initializers must be known.  */
+	  if (op0 && op1)
+	    {
+	      if (op0 == op1)
+		return null_pointer_node;
+
+	      /* Support differences between labels.  */
+	      if (TREE_CODE (op0) == LABEL_DECL
+		  && TREE_CODE (op1) == LABEL_DECL)
+		return null_pointer_node;
+
+	      if (TREE_CODE (op0) == STRING_CST
+		  && TREE_CODE (op1) == STRING_CST
+		  && operand_equal_p (op0, op1, 1))
+		return null_pointer_node;
+	    }
 	}
       break;
 



More information about the Gcc-patches mailing list