This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Re: [rfc] __builtin_offsetof for c and c++
- From: Andrew Pinski <pinskia at physics dot uc dot edu>
- To: Gcc Patch List <gcc-patches at gcc dot gnu dot org>, Richard Henderson <rth at redhat dot com>, Gabriel Dos Reis <gdr at integrable-solutions dot net>
- Cc: Andrew Pinski <pinskia at physics dot uc dot edu>
- Date: Sun, 8 Feb 2004 22:03:19 -0800
- Subject: [PATCH] Re: [rfc] __builtin_offsetof for c and c++
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) \