From ee8a6a3ee5d35c2e188225c2bbb58c2cca69a2ab Mon Sep 17 00:00:00 2001
From: Richard Henderson <rth@redhat.com>
Date: Thu, 26 Aug 2004 17:37:48 -0700
Subject: [PATCH] c-typeck.c (build_offsetof): Remove.

        * c-typeck.c (build_offsetof): Remove.
        * c-tree.h (build_offsetof): Remove.
        * c-common.c (fold_offsetof_1, fold_offsetof): New.
        * c-common.h (fold_offsetof): Declare.
        * c-parse.in (offsetof_base): New.
        (offsetof_member_designator): Use it.  Build references, not just
        a tree list.
        (primary): Use fold_offsetof, not build_offsetof.

From-SVN: r86651
---
 gcc/ChangeLog  | 11 +++++++++
 gcc/c-common.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/c-common.h |  2 ++
 gcc/c-parse.in | 24 ++++++++++++-------
 gcc/c-tree.h   |  1 -
 gcc/c-typeck.c | 28 ----------------------
 6 files changed, 94 insertions(+), 37 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index cf1dc09c719c..84af91f9e9e3 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2004-08-26  Richard Henderson  <rth@redhat.com>
+
+	* c-typeck.c (build_offsetof): Remove.
+	* c-tree.h (build_offsetof): Remove.
+	* c-common.c (fold_offsetof_1, fold_offsetof): New.
+	* c-common.h (fold_offsetof): Declare.
+	* c-parse.in (offsetof_base): New.
+	(offsetof_member_designator): Use it.  Build references, not just
+	a tree list.
+	(primary): Use fold_offsetof, not build_offsetof.
+
 2004-08-26  Richard Henderson  <rth@redhat.com>
 
 	* tree.c (staticp): Return the static object.
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 8b7ee2c94eac..03531d3ca035 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -5436,4 +5436,69 @@ c_warn_unused_result (tree *top_p)
     }
 }
 
+/* Build the result of __builtin_offsetof.  EXPR is a nested sequence of
+   component references, with an INDIRECT_REF at the bottom; much like
+   the traditional rendering of offsetof as a macro.  Returns the folded
+   and properly cast result.  */
+
+static tree
+fold_offsetof_1 (tree expr)
+{
+  enum tree_code code = PLUS_EXPR;
+  tree base, off, t;
+
+  switch (TREE_CODE (expr))
+    {
+    case ERROR_MARK:
+      return expr;
+
+    case INDIRECT_REF:
+      return size_zero_node;
+
+    case COMPONENT_REF:
+      base = fold_offsetof_1 (TREE_OPERAND (expr, 0));
+      if (base == error_mark_node)
+	return base;
+
+      t = TREE_OPERAND (expr, 1);
+      if (DECL_C_BIT_FIELD (t))
+	{
+	  error ("attempt to take address of bit-field structure "
+		 "member `%s'", IDENTIFIER_POINTER (DECL_NAME (t)));
+	  return error_mark_node;
+	}
+      off = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (t),
+			size_int (tree_low_cst (DECL_FIELD_BIT_OFFSET (t), 1)
+				  / BITS_PER_UNIT));
+      break;
+
+    case ARRAY_REF:
+      base = fold_offsetof_1 (TREE_OPERAND (expr, 0));
+      if (base == error_mark_node)
+	return base;
+
+      t = TREE_OPERAND (expr, 1);
+      if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0)
+	{
+	  code = MINUS_EXPR;
+	  t = fold (build1 (NEGATE_EXPR, TREE_TYPE (t), t));
+	}
+      t = convert (sizetype, t);
+      off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
+      break;
+
+    default:
+      abort ();
+    }
+
+  return size_binop (code, base, off);
+}
+
+tree
+fold_offsetof (tree expr)
+{
+  /* Convert back from the internal sizetype to size_t.  */
+  return convert (size_type_node, fold_offsetof_1 (expr));
+}
+
 #include "gt-c-common.h"
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 94f3249b21bc..e9a91d50fdd7 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -870,6 +870,8 @@ extern void c_warn_unused_result (tree *);
 
 extern void verify_sequence_points (tree);
 
+extern tree fold_offsetof (tree);
+
 /* In c-gimplify.c  */
 extern void c_genericize (tree);
 extern int c_gimplify_expr (tree *, tree *, tree *);
diff --git a/gcc/c-parse.in b/gcc/c-parse.in
index 85927d4f359e..c28b1565c842 100644
--- a/gcc/c-parse.in
+++ b/gcc/c-parse.in
@@ -275,6 +275,9 @@ static GTY(()) tree all_prefix_attributes;
    all_prefix_attributes.  */
 static GTY(()) tree declspec_stack;
 
+/* INDIRECT_REF with a TREE_TYPE of the type being queried for offsetof.  */
+static tree offsetof_base;
+
 /* PUSH_DECLSPEC_STACK is called from setspecs; POP_DECLSPEC_STACK
    should be called from the productions making use of setspecs.  */
 #define PUSH_DECLSPEC_STACK						 \
@@ -681,8 +684,15 @@ primary:
 		{ $$.value = build_va_arg ($3.value, groktypename ($5));
 		  $$.original_code = ERROR_MARK; }
 
-	| OFFSETOF '(' typename ',' offsetof_member_designator ')'
-		{ $$.value = build_offsetof (groktypename ($3), $5);
+	| OFFSETOF '(' typename ','
+		{ tree type = groktypename ($3);
+		  if (type == error_mark_node)
+		    offsetof_base = error_mark_node;
+		  else
+		    offsetof_base = build1 (INDIRECT_REF, type, NULL);
+		}
+	  offsetof_member_designator ')'
+		{ $$.value = fold_offsetof ($6);
 		  $$.original_code = ERROR_MARK; }
 	| OFFSETOF '(' error ')'
 		{ $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
@@ -753,17 +763,15 @@ primary:
 
 /* This is the second argument to __builtin_offsetof.  We must have one
    identifier, and beyond that we want to accept sub structure and sub
-   array references.  We return tree list where each element has
-   PURPOSE set for component refs or VALUE set for array refs.  We'll
-   turn this into something real inside build_offsetof.  */
+   array references.  */
 
 offsetof_member_designator:
 	  identifier
-		{ $$ = tree_cons ($1, NULL_TREE, NULL_TREE); }
+		{ $$ = build_component_ref (offsetof_base, $1); }
 	| offsetof_member_designator '.' identifier
-		{ $$ = tree_cons ($3, NULL_TREE, $1); }
+		{ $$ = build_component_ref ($1, $3); }
 	| offsetof_member_designator '[' expr ']'
-		{ $$ = tree_cons (NULL_TREE, $3.value, $1); }
+		{ $$ = build_array_ref ($1, $3.value); }
 	;
 
 old_style_parm_decls:
diff --git a/gcc/c-tree.h b/gcc/c-tree.h
index 5c99f47aa0ef..f9f06eb517c1 100644
--- a/gcc/c-tree.h
+++ b/gcc/c-tree.h
@@ -277,7 +277,6 @@ extern tree c_finish_return (tree);
 extern tree c_finish_bc_stmt (tree *, bool);
 extern tree c_finish_goto_label (tree);
 extern tree c_finish_goto_ptr (tree);
-extern tree build_offsetof (tree, tree);
 
 /* Set to 0 at beginning of a function definition, set to 1 if
    a return statement that specifies a return value is seen.  */
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index ca6e9f372a73..aa04ac0d24a7 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -7583,31 +7583,3 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
     return result;
   }
 }
-
-/* Build the result of __builtin_offsetof.  TYPE is the first argument to
-   offsetof, i.e. a type.  LIST is a tree_list that encodes component and
-   array references; PURPOSE is set for the former and VALUE is set for
-   the later.  */
-
-tree
-build_offsetof (tree type, tree list)
-{
-  tree t;
-
-  /* Build "*(type *)0".  */
-  t = convert (build_pointer_type (type), null_pointer_node);
-  t = build_indirect_ref (t, "");
-
-  /* Build COMPONENT and ARRAY_REF expressions as needed.  */
-  for (list = nreverse (list); list ; list = TREE_CHAIN (list))
-    if (TREE_PURPOSE (list))
-      t = build_component_ref (t, TREE_PURPOSE (list));
-    else
-      t = build_array_ref (t, TREE_VALUE (list));
-
-  /* Finalize the offsetof expression.  For now all we need to do is take
-     the address of the expression we created, and cast that to an integer
-     type; this mirrors the traditional macro implementation of offsetof.  */
-  t = build_unary_op (ADDR_EXPR, t, 0);
-  return convert (size_type_node, t);
-}
-- 
GitLab