[PATCH] Re: [rfc] __builtin_offsetof for c and c++

Andrew Pinski pinskia@physics.uc.edu
Mon Feb 9 06:53:00 GMT 2004


I decided to update RTH's patch to not to ICE for C++ testcase that 
Gaby gave,
basically the patch needed to use build_reinterpret_cast or 
build_static_cast
instead of convert and build_x_unary_op instead of build_unary_op.

I mainly did this so the C and C++ front-ends will no longer lower too 
soon
&t->x as they do right now which can cause an aliasing problem, see PR 
14029.

Ok for the mainline and tree-ssa?

Thanks,
Andrew Pinski


2004-02-08  Richard Henderson  <rth@redhat.com>
             Andrew Pinski  <pinskia@physics.uc.edu>

         * c-parse.in (OFFSETOF, offsetof_member_designator): New.
         (primary): Handle offsetof.  Add error productions for faux 
functions.
         Move component_ref objc checking to build_component_ref.
         (reswords): Add __builtin_offsetof.
         (rid_to_yy): Add offsetof.
         * c-tree.h (build_offsetof): Declare.
         * c-common.h (objc_is_public): Declare.
         * c-typeck.c (build_component_ref): Check objc_is_public.
         (build_offsetof): New.
         * stub-objc.c (objc_is_public): New.
         * objc/objc-act.c (objc_is_public): Rename from is_public.
         * objc/objc-act.h (is_public): Remove decl.

         * ginclude/stddef.h (offsetof): Use __builtin_offsetof.

cp/
         * lex.c (reswords): Rename "__offsetof" to "__builtin_offsetof".
         * parser.c (struct cp_parser): Remove in_offsetof_p.
         (cp_parser_new): Don't set it.
         (cp_parser_unary_expression): Don't check it.
         (cp_parser_postfix_open_square_expression): Split out from ...
         (cp_parser_primary_expression): ... here.
         (cp_parser_postfix_dot_deref_expression): Likewise.
         (cp_parser_builtin_offsetof): New.



Index: c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.141.2.46
diff -u -p -r1.141.2.46 c-common.h
--- c-common.h	6 Feb 2004 15:20:29 -0000	1.141.2.46
+++ c-common.h	9 Feb 2004 05:51:03 -0000
@@ -1286,6 +1286,7 @@ extern tree objc_message_selector (void)
  extern tree lookup_objc_ivar (tree);
  extern void *get_current_scope (void);
  extern void objc_mark_locals_volatile (void *);
+extern int objc_is_public (tree, tree);

  /* In c-ppoutput.c  */
  extern void init_pp_output (FILE *);
Index: c-parse.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-parse.in,v
retrieving revision 1.144.2.28
diff -u -p -r1.144.2.28 c-parse.in
--- c-parse.in	30 Jan 2004 13:13:33 -0000	1.144.2.28
+++ c-parse.in	9 Feb 2004 05:51:05 -0000
@@ -145,7 +145,7 @@ do {									\
  %token ATTRIBUTE EXTENSION LABEL
  %token REALPART IMAGPART VA_ARG CHOOSE_EXPR TYPES_COMPATIBLE_P
  %token PTR_VALUE PTR_BASE PTR_EXTENT
-%token FUNC_NAME
+%token FUNC_NAME OFFSETOF

  /* Add precedence rules to solve dangling else s/r conflict */
  %nonassoc IF
@@ -198,6 +198,7 @@ do {									\
  %type <ttype> maybe_type_quals_attrs typespec_nonattr typespec_attr
  %type <ttype> typespec_reserved_nonattr typespec_reserved_attr
  %type <ttype> typespec_nonreserved_nonattr
+%type <ttype> offsetof_member_designator

  %type <ttype> scspec SCSPEC STATIC TYPESPEC TYPE_QUAL maybe_type_qual
  %type <ttype> initdecls notype_initdecls initdcl notype_initdcl
@@ -261,7 +262,6 @@ static int compstmt_count;
     used by the stmt-rule immediately after simple_if returns.  */
  static location_t if_stmt_locus;

-
  /* List of types and structure classes of the current declaration.  */
  static GTY(()) tree current_declspecs;
  static GTY(()) tree prefix_attributes;
@@ -688,18 +688,27 @@ primary:
  		{ $$ = build_function_call ($1, $3); }
  	| VA_ARG '(' expr_no_commas ',' typename ')'
  		{ $$ = build_va_arg ($3, groktypename ($5)); }
-
-      | CHOOSE_EXPR '(' expr_no_commas ',' expr_no_commas ',' 
expr_no_commas ')'
+	| VA_ARG '(' error ')'
+		{ $$ = error_mark_node; }
+	| OFFSETOF '(' typename ',' offsetof_member_designator ')'
+		{ $$ = build_offsetof (groktypename ($3), $5); }
+	| OFFSETOF '(' error ')'
+		{ $$ = error_mark_node; }
+	| CHOOSE_EXPR '(' expr_no_commas ',' expr_no_commas ','
+			  expr_no_commas ')'
  		{
                    tree c;

                    c = fold ($3);
                    STRIP_NOPS (c);
                    if (TREE_CODE (c) != INTEGER_CST)
-                    error ("first argument to __builtin_choose_expr 
not a constant");
+                    error ("first argument to __builtin_choose_expr 
not"
+			   " a constant");
                    $$ = integer_zerop (c) ? $7 : $5;
  		}
-      | TYPES_COMPATIBLE_P '(' typename ',' typename ')'
+	| CHOOSE_EXPR '(' error ')'
+		{ $$ = error_mark_node; }
+	| TYPES_COMPATIBLE_P '(' typename ',' typename ')'
  		{
  		  tree e1, e2;

@@ -709,27 +718,16 @@ primary:
  		  $$ = comptypes (e1, e2, COMPARE_STRICT)
  		    ? build_int_2 (1, 0) : build_int_2 (0, 0);
  		}
+	| TYPES_COMPATIBLE_P '(' error ')'
+		{ $$ = error_mark_node; }
  	| primary '[' expr ']'   %prec '.'
  		{ $$ = build_array_ref ($1, $3); }
  	| primary '.' identifier
-		{
-@@ifobjc
-		    if (!is_public ($1, $3))
-		      $$ = error_mark_node;
-		    else
-@@end_ifobjc
-		      $$ = build_component_ref ($1, $3);
-		}
+		{ $$ = build_component_ref ($1, $3); }
  	| primary POINTSAT identifier
  		{
                    tree expr = build_indirect_ref ($1, "->");
-
-@@ifobjc
-		      if (!is_public (expr, $3))
-			$$ = error_mark_node;
-		      else
-@@end_ifobjc
-			$$ = build_component_ref (expr, $3);
+		  $$ = build_component_ref (expr, $3);
  		}
  	| primary PLUSPLUS
  		{ $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); }
@@ -749,6 +747,21 @@ primary:
  @@end_ifobjc
  	;

+/* 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.  */
+
+offsetof_member_designator:
+	  identifier
+		{ $$ = tree_cons ($1, NULL_TREE, NULL_TREE); }
+	| offsetof_member_designator '.' identifier
+		{ $$ = tree_cons ($3, NULL_TREE, $1); }
+	| offsetof_member_designator '[' expr ']'
+		{ $$ = tree_cons (NULL_TREE, $3, $1); }
+	;
+
  old_style_parm_decls:
  	old_style_parm_decls_1
  	{
@@ -3288,6 +3301,7 @@ static const struct resword reswords[] =
    { "__attribute",	RID_ATTRIBUTE,	0 },
    { "__attribute__",	RID_ATTRIBUTE,	0 },
    { "__builtin_choose_expr", RID_CHOOSE_EXPR, 0 },
+  { "__builtin_offsetof", RID_OFFSETOF, 0 },
    { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, 0 },
    { "__builtin_va_arg",	RID_VA_ARG,	0 },
    { "__complex",	RID_COMPLEX,	0 },
@@ -3484,7 +3498,7 @@ static const short rid_to_yy[RID_MAX] =
    /* RID_FALSE */	0,
    /* RID_NAMESPACE */	0,
    /* RID_NEW */		0,
-  /* RID_OFFSETOF */    0,
+  /* RID_OFFSETOF */    OFFSETOF,
    /* RID_OPERATOR */	0,
    /* RID_THIS */	0,
    /* RID_THROW */	0,
Index: c-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-tree.h,v
retrieving revision 1.99.2.28
diff -u -p -r1.99.2.28 c-tree.h
--- c-tree.h	5 Jan 2004 22:33:06 -0000	1.99.2.28
+++ c-tree.h	9 Feb 2004 05:51:05 -0000
@@ -303,6 +303,7 @@ extern void c_finish_case (void);
  extern tree simple_asm_stmt (tree);
  extern tree build_asm_stmt (tree, tree, tree, tree, tree);
  extern tree c_convert_parm_for_inlining (tree, tree, tree, int);
+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.  */
Index: c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.196.2.38
diff -u -p -r1.196.2.38 c-typeck.c
--- c-typeck.c	4 Feb 2004 02:24:24 -0000	1.196.2.38
+++ c-typeck.c	9 Feb 2004 05:51:07 -0000
@@ -1299,6 +1299,9 @@ build_component_ref (tree datum, tree co
    tree field = NULL;
    tree ref;

+  if (!objc_is_public (datum, component))
+    return error_mark_node;
+
    /* If DATUM is a COMPOUND_EXPR, move our reference inside it.
       Ensure that the arguments are not lvalues; otherwise,
       if the component is an array, it would wrongly decay to a pointer 
in
@@ -7066,3 +7069,30 @@ build_binary_op (enum tree_code code, tr
    }
  }

+/* 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);
+}
Index: stub-objc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/stub-objc.c,v
retrieving revision 2.1.4.1
diff -u -p -r2.1.4.1 stub-objc.c
--- stub-objc.c	6 Oct 2003 17:36:39 -0000	2.1.4.1
+++ stub-objc.c	9 Feb 2004 05:51:07 -0000
@@ -69,3 +69,8 @@ objc_message_selector (void)
    return 0;
  }

+int
+objc_is_public (tree expr ATTRIBUTE_UNUSED, tree identifier 
ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
Index: cp/lex.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/lex.c,v
retrieving revision 1.284.2.21
diff -u -p -r1.284.2.21 lex.c
--- cp/lex.c	30 Jan 2004 13:16:23 -0000	1.284.2.21
+++ cp/lex.c	9 Feb 2004 05:51:08 -0000
@@ -254,6 +254,7 @@ static const struct resword reswords[] =
    { "__attribute",	RID_ATTRIBUTE,	0 },
    { "__attribute__",	RID_ATTRIBUTE,	0 },
    { "__builtin_va_arg",	RID_VA_ARG,	0 },
+  { "__builtin_offsetof", RID_OFFSETOF, 0 },
    { "__complex",	RID_COMPLEX,	0 },
    { "__complex__",	RID_COMPLEX,	0 },
    { "__const",		RID_CONST,	0 },
@@ -266,8 +267,6 @@ static const struct resword reswords[] =
    { "__inline__",	RID_INLINE,	0 },
    { "__label__",	RID_LABEL,	0 },
    { "__null",		RID_NULL,	0 },
-  { "__offsetof",       RID_OFFSETOF,   0 },
-  { "__offsetof__",     RID_OFFSETOF,   0 },
    { "__real",		RID_REALPART,	0 },
    { "__real__",		RID_REALPART,	0 },
    { "__restrict",	RID_RESTRICT,	0 },
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.32.2.19
diff -u -p -r1.32.2.19 parser.c
--- cp/parser.c	30 Jan 2004 13:16:26 -0000	1.32.2.19
+++ cp/parser.c	9 Feb 2004 05:51:13 -0000
@@ -1230,9 +1230,6 @@ typedef struct cp_parser GTY(())
       been seen that makes the expression non-constant.  */
    bool non_integral_constant_expression_p;

-  /* TRUE if we are parsing the argument to "__offsetof__".  */
-  bool in_offsetof_p;
-
    /* TRUE if local variable names and `this' are forbidden in the
       current context.  */
    bool local_variables_forbidden_p;
@@ -1340,6 +1337,10 @@ static tree cp_parser_class_or_namespace
    (cp_parser *, bool, bool, bool, bool, bool);
  static tree cp_parser_postfix_expression
    (cp_parser *, bool);
+static tree cp_parser_postfix_open_square_expression
+  (cp_parser *, tree, bool);
+static tree cp_parser_postfix_dot_deref_expression
+  (cp_parser *, enum cpp_ttype, tree, bool, cp_id_kind *);
  static tree cp_parser_parenthesized_expression_list
    (cp_parser *, bool, bool *);
  static void cp_parser_pseudo_destructor_name
@@ -1396,6 +1397,8 @@ static tree cp_parser_expression
    (cp_parser *);
  static tree cp_parser_constant_expression
    (cp_parser *, bool, bool *);
+static tree cp_parser_builtin_offsetof
+  (cp_parser *);

  /* Statements [gram.stmt.stmt]  */

@@ -2238,9 +2241,6 @@ cp_parser_new (void)
    parser->allow_non_integral_constant_expression_p = false;
    parser->non_integral_constant_expression_p = false;

-  /* We are not parsing offsetof.  */
-  parser->in_offsetof_p = false;
-
    /* Local variable names are not forbidden.  */
    parser->local_variables_forbidden_p = false;

@@ -2523,27 +2523,7 @@ cp_parser_primary_expression (cp_parser
  	  }

  	case RID_OFFSETOF:
-	  {
-	    tree expression;
-	    bool saved_in_offsetof_p;
-
-	    /* Consume the "__offsetof__" token.  */
-	    cp_lexer_consume_token (parser->lexer);
-	    /* Consume the opening `('.  */
-	    cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
-	    /* Parse the parenthesized (almost) constant-expression.  */
-	    saved_in_offsetof_p = parser->in_offsetof_p;
-	    parser->in_offsetof_p = true;
-	    expression
-	      = cp_parser_constant_expression (parser,
-					       /*allow_non_constant_p=*/false,
-					       /*non_constant_p=*/NULL);
-	    parser->in_offsetof_p = saved_in_offsetof_p;
-	    /* Consume the closing ')'.  */
-	    cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
-
-	    return expression;
-	  }
+	  return cp_parser_builtin_offsetof (parser);

  	default:
  	  cp_parser_error (parser, "expected primary-expression");
@@ -3436,10 +3416,7 @@ cp_parser_postfix_expression (cp_parser
  	   can be used in constant-expressions.  */
  	if (parser->integral_constant_expression_p
  	    && !dependent_type_p (type)
-	    && !INTEGRAL_OR_ENUMERATION_TYPE_P (type)
-	    /* A cast to pointer or reference type is allowed in the
-	       implementation of "offsetof".  */
-	    && !(parser->in_offsetof_p && POINTER_TYPE_P (type)))
+	    && !INTEGRAL_OR_ENUMERATION_TYPE_P (type))
  	  {
  	    if (!parser->allow_non_integral_constant_expression_p)
  	      return (cp_parser_non_integral_constant_expression
@@ -3675,31 +3652,11 @@ cp_parser_postfix_expression (cp_parser
        switch (token->type)
  	{
  	case CPP_OPEN_SQUARE:
-	  /* postfix-expression [ expression ] */
-	  {
-	    tree index;
-
-	    /* Consume the `[' token.  */
-	    cp_lexer_consume_token (parser->lexer);
-	    /* Parse the index expression.  */
-	    index = cp_parser_expression (parser);
-	    /* Look for the closing `]'.  */
-	    cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
-
-	    /* Build the ARRAY_REF.  */
-	    postfix_expression
-	      = grok_array_decl (postfix_expression, index);
-	    idk = CP_ID_KIND_NONE;
-	    /* Array references are not permitted in
-	       constant-expressions.  */
-	    if (parser->integral_constant_expression_p)
-	      {
-		if (!parser->allow_non_integral_constant_expression_p)
-		  postfix_expression
-		    = cp_parser_non_integral_constant_expression ("an array 
reference");
-		parser->non_integral_constant_expression_p = true;
-	      }
-	  }
+	  postfix_expression
+	    = cp_parser_postfix_open_square_expression (parser,
+							postfix_expression,
+							false);
+	  idk = CP_ID_KIND_NONE;
  	  break;

  	case CPP_OPEN_PAREN:
@@ -3804,133 +3761,15 @@ cp_parser_postfix_expression (cp_parser
  	     postfix-expression . pseudo-destructor-name
  	     postfix-expression -> template [opt] id-expression
  	     postfix-expression -> pseudo-destructor-name */
-	  {
-	    tree name;
-	    bool dependent_p;
-	    bool template_p;
-	    tree scope = NULL_TREE;
-	    enum cpp_ttype token_type = token->type;
-
-	    /* If this is a `->' operator, dereference the pointer.  */
-	    if (token->type == CPP_DEREF)
-	      postfix_expression = build_x_arrow (postfix_expression);
-	    /* Check to see whether or not the expression is
-	       type-dependent.  */
-	    dependent_p = type_dependent_expression_p (postfix_expression);
-	    /* The identifier following the `->' or `.' is not
-	       qualified.  */
-	    parser->scope = NULL_TREE;
-	    parser->qualifying_scope = NULL_TREE;
-	    parser->object_scope = NULL_TREE;
-	    idk = CP_ID_KIND_NONE;
-	    /* Enter the scope corresponding to the type of the object
-	       given by the POSTFIX_EXPRESSION.  */
-	    if (!dependent_p
-		&& TREE_TYPE (postfix_expression) != NULL_TREE)
-	      {
-		scope = TREE_TYPE (postfix_expression);
-		/* According to the standard, no expression should
-		   ever have reference type.  Unfortunately, we do not
-		   currently match the standard in this respect in
-		   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);
-		/* 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.  */
-		parser->context->object_type = scope;
-		/* If something went wrong, we want to be able to
-		   discern that case, as opposed to the case where
-		   there was no SCOPE due to the type of expression
-		   being dependent.  */
-		if (!scope)
-		  scope = error_mark_node;
-		/* If the SCOPE was erroneous, make the various
-		   semantic analysis functions exit quickly -- and
-		   without issuing additional error messages.  */
-		if (scope == error_mark_node)
-		  postfix_expression = error_mark_node;
-	      }
-
-	    /* Consume the `.' or `->' operator.  */
-	    cp_lexer_consume_token (parser->lexer);
-	    /* If the SCOPE is not a scalar type, we are looking at an
-	       ordinary class member access expression, rather than a
-	       pseudo-destructor-name.  */
-	    if (!scope || !SCALAR_TYPE_P (scope))
-	      {
-		template_p = cp_parser_optional_template_keyword (parser);
-		/* Parse the id-expression.  */
-		name = cp_parser_id_expression (parser,
-						template_p,
-						/*check_dependency_p=*/true,
-						/*template_p=*/NULL,
-						/*declarator_p=*/false);
-		/* In general, build a SCOPE_REF if the member name is
-		   qualified.  However, if the name was not dependent
-		   and has already been resolved; there is no need to
-		   build the SCOPE_REF.  For example;
-
-                     struct X { void f(); };
-                     template <typename T> void f(T* t) { t->X::f(); }
-
-                   Even though "t" is dependent, "X::f" is not and has
-		   been resolved to a BASELINK; there is no need to
-		   include scope information.  */
-
-		/* But we do need to remember that there was an explicit
-		   scope for virtual function calls.  */
-		if (parser->scope)
-		  idk = CP_ID_KIND_QUALIFIED;
-
-		if (name != error_mark_node
-		    && !BASELINK_P (name)
-		    && parser->scope)
-		  {
-		    name = build_nt (SCOPE_REF, parser->scope, name);
-		    parser->scope = NULL_TREE;
-		    parser->qualifying_scope = NULL_TREE;
-		    parser->object_scope = NULL_TREE;
-		  }
-		postfix_expression
-		  = finish_class_member_access_expr (postfix_expression, name);
-	      }
-	    /* Otherwise, try the pseudo-destructor-name production.  */
-	    else
-	      {
-		tree s = NULL_TREE;
-		tree type;
-
-		/* Parse the pseudo-destructor-name.  */
-		cp_parser_pseudo_destructor_name (parser, &s, &type);
-		/* Form the call.  */
-		postfix_expression
-		  = finish_pseudo_destructor_expr (postfix_expression,
-						   s, TREE_TYPE (type));
-	      }
+	
+          /* Consume the `.' or `->' operator.  */
+	  cp_lexer_consume_token (parser->lexer);

-	    /* We no longer need to look up names in the scope of the
-	       object on the left-hand side of the `.' or `->'
-	       operator.  */
-	    parser->context->object_type = NULL_TREE;
-	    /* These operators may not appear in constant-expressions.  */
-	    if (parser->integral_constant_expression_p
-		/* The "->" operator is allowed in the implementation
-		   of "offsetof".  The "." operator may appear in the
-		   name of the member.  */
-		&& !parser->in_offsetof_p)
-	      {
-		if (!parser->allow_non_integral_constant_expression_p)
-		  postfix_expression
-		    = (cp_parser_non_integral_constant_expression
-		       (token_type == CPP_DEREF ? "'->'" : "`.'"));
-		parser->non_integral_constant_expression_p = true;
-	      }
-	  }
+	  postfix_expression
+	    = cp_parser_postfix_dot_deref_expression (parser, token->type,
+						      postfix_expression,
+						      false, &idk);
+	
  	  break;

  	case CPP_PLUS_PLUS:
@@ -3981,6 +3820,182 @@ cp_parser_postfix_expression (cp_parser
    return error_mark_node;
  }

+/* A subroutine of cp_parser_postfix_expression that also gets hijacked
+   by cp_parser_builtin_offsetof.  We're looking for
+
+     postfix-expression [ expression ]
+
+   FOR_OFFSETOF is set if we're being called in that context, which
+   changes how we deal with integer constant expressions.  */
+
+static tree
+cp_parser_postfix_open_square_expression (cp_parser *parser,
+					  tree postfix_expression,
+					  bool for_offsetof)
+{
+  tree index;
+
+  /* Consume the `[' token.  */
+  cp_lexer_consume_token (parser->lexer);
+
+  /* Parse the index expression.  */
+  /* ??? For offsetof, there is a question of what to allow here.  If
+     offsetof is not being used in an integral constant expression 
context,
+     then we *could* get the right answer by computing the value at 
runtime.
+     If we are in an integral constant expression context, then we 
might
+     could accept any constant expression; hard to say without 
analysis.
+     Rather than open the barn door too wide right away, allow only 
integer
+     constant expresions here.  */
+  if (for_offsetof)
+    index = cp_parser_constant_expression (parser, false, NULL);
+  else
+    index = cp_parser_expression (parser);
+
+  /* Look for the closing `]'.  */
+  cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
+
+  /* Build the ARRAY_REF.  */
+  postfix_expression = grok_array_decl (postfix_expression, index);
+
+  /* When not doing offsetof, array references are not permitted in
+     constant-expressions.  */
+  if (!for_offsetof && parser->integral_constant_expression_p)
+    {
+      if (!parser->allow_non_integral_constant_expression_p)
+	postfix_expression
+	  = cp_parser_non_integral_constant_expression ("an array reference");
+	parser->non_integral_constant_expression_p = true;
+    }
+
+  return postfix_expression;
+}
+
+/* A subroutine of cp_parser_postfix_expression that also gets hijacked
+   by cp_parser_builtin_offsetof.  We're looking for
+
+     postfix-expression . template [opt] id-expression
+     postfix-expression . pseudo-destructor-name
+     postfix-expression -> template [opt] id-expression
+     postfix-expression -> pseudo-destructor-name
+
+   FOR_OFFSETOF is set if we're being called in that context.  That 
sorta
+   limits what of the above we'll actually accept, but nevermind.
+   TOKEN_TYPE is the "." or "->" token, which will already have been
+   removed from the stream.  */
+
+static tree
+cp_parser_postfix_dot_deref_expression (cp_parser *parser,
+					enum cpp_ttype token_type,
+                                        tree postfix_expression,
+                                        bool for_offsetof, cp_id_kind 
*idk)
+{
+  tree name;
+  bool dependent_p;
+  bool template_p;
+  tree scope = NULL_TREE;
+
+  /* If this is a `->' operator, dereference the pointer.  */
+  if (token_type == CPP_DEREF)
+    postfix_expression = build_x_arrow (postfix_expression);
+  /* Check to see whether or not the expression is type-dependent.  */
+  dependent_p = type_dependent_expression_p (postfix_expression);
+  /* The identifier following the `->' or `.' is not qualified.  */
+  parser->scope = NULL_TREE;
+  parser->qualifying_scope = NULL_TREE;
+  parser->object_scope = NULL_TREE;
+  *idk = CP_ID_KIND_NONE;
+  /* Enter the scope corresponding to the type of the object
+     given by the POSTFIX_EXPRESSION.  */
+  if (!dependent_p && TREE_TYPE (postfix_expression) != NULL_TREE)
+    {
+      scope = TREE_TYPE (postfix_expression);
+      /* According to the standard, no expression should ever have
+	 reference type.  Unfortunately, we do not currently match
+	 the standard in this respect in 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);
+      /* 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.  */
+      parser->context->object_type = scope;
+      /* If something went wrong, we want to be able to discern that 
case,
+	 as opposed to the case where there was no SCOPE due to the type
+	 of expression being dependent.  */
+      if (!scope)
+	scope = error_mark_node;
+    }
+
+  /* If the SCOPE is not a scalar type, we are looking at an
+     ordinary class member access expression, rather than a
+     pseudo-destructor-name.  */
+  if (!scope || !SCALAR_TYPE_P (scope))
+    {
+      template_p = cp_parser_optional_template_keyword (parser);
+      /* Parse the id-expression.  */
+      name = cp_parser_id_expression (parser, template_p,
+				      /*check_dependency_p=*/true,
+				      /*template_p=*/NULL,
+				      /*declarator_p=*/false);
+      /* In general, build a SCOPE_REF if the member name is qualified.
+	 However, if the name was not dependent and has already been
+	 resolved; there is no need to build the SCOPE_REF.  For example;
+
+             struct X { void f(); };
+             template <typename T> void f(T* t) { t->X::f(); }
+
+	 Even though "t" is dependent, "X::f" is not and has been resolved
+	 to a BASELINK; there is no need to include scope information.  */
+
+      /* But we do need to remember that there was an explicit scope 
for
+	 virtual function calls.  */
+      if (parser->scope)
+	*idk = CP_ID_KIND_QUALIFIED;
+
+      if (name != error_mark_node && !BASELINK_P (name) && 
parser->scope)
+	{
+	  name = build_nt (SCOPE_REF, parser->scope, name);
+	  parser->scope = NULL_TREE;
+	  parser->qualifying_scope = NULL_TREE;
+	  parser->object_scope = NULL_TREE;
+	}
+      postfix_expression
+	= finish_class_member_access_expr (postfix_expression, name);
+    }
+  /* Otherwise, try the pseudo-destructor-name production.  */
+  else
+    {
+      tree s = NULL_TREE;
+      tree type;
+
+      /* Parse the pseudo-destructor-name.  */
+      cp_parser_pseudo_destructor_name (parser, &s, &type);
+      /* Form the call.  */
+      postfix_expression
+	= finish_pseudo_destructor_expr (postfix_expression,
+					 s, TREE_TYPE (type));
+    }
+
+  /* We no longer need to look up names in the scope of the object on
+     the left-hand side of the `.' or `->' operator.  */
+  parser->context->object_type = NULL_TREE;
+
+  /* Outside of offsetof, these operators may not appear in
+     constant-expressions.  */
+  if (!for_offsetof && parser->integral_constant_expression_p)
+    {
+      if (!parser->allow_non_integral_constant_expression_p)
+	postfix_expression
+	  = (cp_parser_non_integral_constant_expression
+	     (token_type == CPP_DEREF ? "`->'" : "`.'"));
+      parser->non_integral_constant_expression_p = true;
+    }
+
+  return postfix_expression;
+}
+
  /* Parse a parenthesized expression-list.

     expression-list:
@@ -4327,10 +4342,7 @@ cp_parser_unary_expression (cp_parser *p
  	  break;

  	case ADDR_EXPR:
-	  /* The "&" operator is allowed in the implementation of
-	     "offsetof".  */
-	  if (!parser->in_offsetof_p)
-	    non_constant_p = "`&'";
+	  non_constant_p = "`&'";
  	  /* Fall through.  */
  	case BIT_NOT_EXPR:
  	  expression = build_x_unary_op (unary_operator, cast_expression);
@@ -5353,6 +5365,92 @@ cp_parser_constant_expression (cp_parser
    parser->non_integral_constant_expression_p = 
saved_non_integral_constant_expression_p;

    return expression;
+}
+
+/* Parse __builtin_offsetof.
+
+   offsetof-expression:
+     "__builtin_offsetof" "(" type-id "," offsetof-member-designator 
")"
+
+   offsetof-member-designator:
+     id-expression
+     | offsetof-member-designator "." id-expression
+     | offsetof-member-designator "[" expression "]"
+*/
+
+static tree
+cp_parser_builtin_offsetof (cp_parser *parser)
+{
+  int save_ice_p, save_non_ice_p;
+  tree type, expr;
+  cp_id_kind dummy;
+
+  /* We're about to accept non-integral-constant things, but will
+     definitely yield an integral constant expression.  Save and
+     restore these values around our local parsing.  */
+  save_ice_p = parser->integral_constant_expression_p;
+  save_non_ice_p = parser->non_integral_constant_expression_p;
+
+  /* Consume the "__builtin_offsetof" token.  */
+  cp_lexer_consume_token (parser->lexer);
+  /* Consume the opening `('.  */
+  cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+  /* Parse the type-id.  */
+  type = cp_parser_type_id (parser);
+  /* Look for the `,'.  */
+  cp_parser_require (parser, CPP_COMMA, "`,'");
+
+  /* Build the (type *)null that begins the traditional offsetof 
macro.  */
+  expr = build_static_cast (build_pointer_type (type), 
null_pointer_node);
+
+  /* Parse the offsetof-member-designator.  We begin as if we saw 
"expr->".  */
+  expr = cp_parser_postfix_dot_deref_expression (parser, CPP_DEREF, 
expr,
+						 true, &dummy);
+  while (true)
+    {
+      cp_token *token = cp_lexer_peek_token (parser->lexer);
+      switch (token->type)
+	{
+	case CPP_OPEN_SQUARE:
+	  /* offsetof-member-designator "[" expression "]" */
+	  expr = cp_parser_postfix_open_square_expression (parser, expr, 
true);
+	  break;
+
+	case CPP_DOT:
+	  /* offsetof-member-designator "." identifier */
+	  expr = cp_parser_postfix_dot_deref_expression (parser, CPP_DOT, 
expr,
+							 true, &dummy);
+	  break;
+
+	case CPP_CLOSE_PAREN:
+	  /* Consume the "__builtin_offsetof" token.  */
+	  cp_lexer_consume_token (parser->lexer);
+	  goto finish;
+
+	default:
+	  /* Error.  We know the following require will fail, but
+	     that gives the proper error message.  */
+	  cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+	  cp_parser_skip_to_closing_parenthesis (parser, true, false, true);
+	  expr = error_mark_node;
+	  goto egress;
+	}
+    }
+
+ finish:
+  /* We've finished the parsing, now finish with the semantics.  At 
present
+     we're just mirroring the traditional macro implementation.  Better
+     would be to do the lowering of the ADDR_EXPR to flat pointer 
arithmetic
+     here rather than in build_x_unary_op.  */
+  expr = build_reinterpret_cast (build_reference_type 
(char_type_node), expr);
+  expr = build_x_unary_op (ADDR_EXPR, expr);
+  expr = build_reinterpret_cast (size_type_node, expr);
+
+ egress:
+  parser->integral_constant_expression_p = save_ice_p;
+  parser->non_integral_constant_expression_p = save_non_ice_p;
+
+  return expr;
  }

  /* Statements [gram.stmt.stmt]  */
Index: ginclude/stddef.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ginclude/stddef.h,v
retrieving revision 1.14.8.6
diff -u -p -r1.14.8.6 stddef.h
--- ginclude/stddef.h	3 Jan 2004 23:03:27 -0000	1.14.8.6
+++ ginclude/stddef.h	9 Feb 2004 05:51:14 -0000
@@ -1,4 +1,5 @@
-/* Copyright (C) 1989, 1997, 1998, 1999, 2000, 2002 Free Software 
Foundation, Inc.
+/* Copyright (C) 1989, 1997, 1998, 1999, 2000, 2002, 2003
+   Free Software Foundation, Inc.

  This file is part of GCC.

@@ -410,16 +411,8 @@ typedef __WINT_TYPE__ wint_t;
  #ifdef _STDDEF_H

  /* Offset of member MEMBER in a struct of type TYPE. */
-#ifndef __cplusplus
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-#else
-/* The cast to "char &" below avoids problems with user-defined
-   "operator &", which can appear in a POD type.  */
-#define offsetof(TYPE, MEMBER)				\
-  (__offsetof__ (reinterpret_cast <size_t>		\
-                 (&reinterpret_cast <char &>		\
-                  (static_cast<TYPE *> (0)->MEMBER))))
-#endif /* C++ */
+#define offsetof(TYPE, MEMBER)  __builtin_offsetof (TYPE, MEMBER)
+
  #endif /* _STDDEF_H was defined this time */

  #endif /* !_STDDEF_H && !_STDDEF_H_ && !_ANSI_STDDEF_H && !__STDDEF_H__
Index: objc/objc-act.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.137.2.31
diff -u -p -r1.137.2.31 objc-act.c
--- objc/objc-act.c	30 Jan 2004 13:16:59 -0000	1.137.2.31
+++ objc/objc-act.c	9 Feb 2004 05:51:16 -0000
@@ -6500,7 +6500,7 @@ is_private (tree decl)
  /* We have an instance variable reference;, check to see if it is 
public.  */

  int
-is_public (tree expr, tree identifier)
+objc_is_public (tree expr, tree identifier)
  {
    tree basetype = TREE_TYPE (expr);
    enum tree_code code = TREE_CODE (basetype);
Index: objc/objc-act.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.h,v
retrieving revision 1.10.2.9
diff -u -p -r1.10.2.9 objc-act.h
--- objc/objc-act.h	19 Oct 2003 00:00:59 -0000	1.10.2.9
+++ objc/objc-act.h	9 Feb 2004 05:51:16 -0000
@@ -52,7 +52,7 @@ tree objc_build_finally_epilogue (void);

  tree is_ivar (tree, tree);
  int is_private (tree);
-int is_public (tree, tree);
+int objc_is_public (tree, tree);
  tree add_instance_variable (tree, int, tree, tree, tree);
  tree objc_add_method (tree, tree, int);
  tree get_super_receiver (void);
@@ -126,7 +126,7 @@ tree build_encode_expr (tree);
  	 ? (TYPE)->type.context : NULL_TREE)
  #define SET_TYPE_PROTOCOL_LIST(TYPE, P) (TYPE_CHECK 
(TYPE)->type.context = (P))

-/* Set by `continue_class' and checked by `is_public'.  */
+/* Set by `continue_class' and checked by `objc_is_public'.  */

  #define TREE_STATIC_TEMPLATE(record_type) (TREE_PUBLIC (record_type))
  #define TYPED_OBJECT(type) \



More information about the Gcc-patches mailing list