Index: c-common.def =================================================================== RCS file: /cvs/gcc/gcc/gcc/c-common.def,v retrieving revision 1.11.2.4 diff -u -p -r1.11.2.4 c-common.def --- c-common.def 7 May 2003 13:27:31 -0000 1.11.2.4 +++ c-common.def 15 Feb 2004 07:50:37 -0000 @@ -29,6 +29,9 @@ DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", DEFTREECODE (ARROW_EXPR, "arrow_expr", 'e', 1) DEFTREECODE (ALIGNOF_EXPR, "alignof_expr", '1', 1) +/* Used to represent an offsetof expression. */ +DEFTREECODE (OFFSETOF_EXPR, "offsetof_expr", '1', 1) + /* Used to represent an expression statement. Use `EXPR_STMT_EXPR' to obtain the expression. */ DEFTREECODE (EXPR_STMT, "expr_stmt", 'e', 1) Index: c-common.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/c-common.h,v retrieving revision 1.141.2.47 diff -u -p -r1.141.2.47 c-common.h --- c-common.h 13 Feb 2004 13:10:55 -0000 1.141.2.47 +++ c-common.h 15 Feb 2004 07:50:38 -0000 @@ -1282,6 +1282,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.29 diff -u -p -r1.144.2.29 c-parse.in --- c-parse.in 13 Feb 2004 13:10:57 -0000 1.144.2.29 +++ c-parse.in 15 Feb 2004 07:50:38 -0000 @@ -146,7 +146,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 @@ -199,6 +199,7 @@ do { \ %type maybe_type_quals_attrs typespec_nonattr typespec_attr %type typespec_reserved_nonattr typespec_reserved_attr %type typespec_nonreserved_nonattr +%type offsetof_member_designator %type scspec SCSPEC STATIC TYPESPEC TYPE_QUAL maybe_type_qual %type initdecls notype_initdecls initdcl notype_initdcl @@ -262,7 +263,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; @@ -687,18 +687,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; @@ -708,27 +717,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); } @@ -748,6 +746,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 { @@ -3287,6 +3300,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 }, @@ -3483,7 +3497,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.30 diff -u -p -r1.99.2.30 c-tree.h --- c-tree.h 13 Feb 2004 13:10:58 -0000 1.99.2.30 +++ c-tree.h 15 Feb 2004 07:50:39 -0000 @@ -304,6 +304,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.39 diff -u -p -r1.196.2.39 c-typeck.c --- c-typeck.c 13 Feb 2004 13:10:59 -0000 1.196.2.39 +++ c-typeck.c 15 Feb 2004 07:50:41 -0000 @@ -81,6 +81,7 @@ static void add_pending_init (tree, tree static void set_nonincremental_init (void); static void set_nonincremental_init_from_string (tree); static tree find_init_member (tree); +static tree c_offsetof_lower (tree); /* Do `exp = require_complete_type (exp);' to make sure exp does not have an incomplete type. (That includes void types.) */ @@ -1300,6 +1301,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 @@ -2428,12 +2432,12 @@ build_unary_op (enum tree_code code, tre IDENTIFIER_POINTER (DECL_NAME (field))); return error_mark_node; } - +/* addr = fold (build (PLUS_EXPR, argtype, convert (argtype, addr), - convert (argtype, byte_position (field)))); + convert (argtype, byte_position (field))));*/ } - else + /*else*/ addr = build1 (code, argtype, arg); return addr; @@ -7081,3 +7085,76 @@ 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)); + + return convert (size_type_node, c_offsetof_lower (t)); +} + +/* Lower the offsetof expression. */ + +static tree +c_offsetof_lower (tree arg) +{ + /* Lower basically &((type*)(0))->a */ + + switch (TREE_CODE (arg)) + { + /* For &x[y], return (*&x)+y. */ + case ARRAY_REF: + { + tree arg0 = c_offsetof_lower (TREE_OPERAND (arg, 0)); + + if (TREE_CODE (arg0) != INTEGER_CST) + abort(); + + arg0 = fold (build_indirect_ref (arg0, NULL)); + + return fold (build_binary_op (PLUS_EXPR, arg0, + TREE_OPERAND (arg, 1), 1)); + } + /* Lower basically &((type*)(0))->a */ + case COMPONENT_REF: + { + tree field = TREE_OPERAND (arg, 1); + tree addr; + tree argtype = build_pointer_type (TREE_TYPE (arg)); + + addr = c_offsetof_lower (TREE_OPERAND (arg, 0)); + + 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; + } + + return fold (build (PLUS_EXPR, argtype, + convert (argtype, addr), + convert (argtype, byte_position (field)))); + } + case INDIRECT_REF: + return fold (convert (build_pointer_type (TREE_TYPE (arg)), TREE_OPERAND (arg, 0))); + + default: + return build_unary_op (ADDR_EXPR, arg, 0); + } +} 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 15 Feb 2004 07:50:41 -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/cp-tree.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v retrieving revision 1.719.2.51 diff -u -p -r1.719.2.51 cp-tree.h --- cp/cp-tree.h 13 Feb 2004 13:13:29 -0000 1.719.2.51 +++ cp/cp-tree.h 15 Feb 2004 07:50:44 -0000 @@ -4097,6 +4097,8 @@ extern void check_accessibility_of_quali extern tree finish_qualified_id_expr (tree, tree, bool, bool); extern void simplify_aggr_init_expr (tree *); extern void finalize_nrv (tree *, tree, tree); +extern tree finish_offsetof (tree); + /* in tree.c */ extern void lang_check_failed (const char *, int, @@ -4196,6 +4198,7 @@ extern int comp_cv_qual_signature extern tree cxx_sizeof_or_alignof_expr (tree, enum tree_code); extern tree cxx_sizeof_or_alignof_type (tree, enum tree_code, bool); #define cxx_sizeof_nowarn(T) cxx_sizeof_or_alignof_type (T, SIZEOF_EXPR, false) +extern tree cxx_offsetof_expr (tree); extern tree inline_conversion (tree); extern tree decay_conversion (tree); extern tree perform_integral_promotions (tree); Index: cp/lex.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cp/lex.c,v retrieving revision 1.284.2.22 diff -u -p -r1.284.2.22 lex.c --- cp/lex.c 13 Feb 2004 13:13:34 -0000 1.284.2.22 +++ cp/lex.c 15 Feb 2004 07:50:44 -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.20 diff -u -p -r1.32.2.20 parser.c --- cp/parser.c 13 Feb 2004 13:13:35 -0000 1.32.2.20 +++ cp/parser.c 15 Feb 2004 07:50:57 -0000 @@ -1232,9 +1232,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; @@ -1342,6 +1339,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 @@ -1398,6 +1399,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] */ @@ -2314,9 +2317,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; @@ -2599,27 +2599,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"); @@ -3515,10 +3495,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 @@ -3754,31 +3731,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: @@ -3883,133 +3840,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 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: @@ -4060,6 +3899,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 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: @@ -4406,10 +4421,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); @@ -5432,6 +5444,94 @@ 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); + + if (dummy == CP_ID_KIND_UNQUALIFIED + && TREE_CODE (expr) == IDENTIFIER_NODE) + /* It is not a Koenig lookup function call. */ + expr + = unqualified_name_lookup_error (expr); + + 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: + + expr = cxx_offsetof_expr (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: cp/pt.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v retrieving revision 1.591.2.45 diff -u -p -r1.591.2.45 pt.c --- cp/pt.c 13 Feb 2004 13:13:37 -0000 1.591.2.45 +++ cp/pt.c 15 Feb 2004 07:51:34 -0000 @@ -7084,7 +7084,7 @@ tsubst (tree t, tree args, tsubst_flags_ return fold (build (TREE_CODE (t), TREE_TYPE (t), e1, e2)); } - + case NEGATE_EXPR: case NOP_EXPR: { @@ -7502,6 +7502,7 @@ tsubst_copy (tree t, tree args, tsubst_f case TYPEID_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: + case OFFSETOF_EXPR: return build1 (code, tsubst (TREE_TYPE (t), args, complain, in_decl), tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl)); @@ -7715,7 +7716,7 @@ tsubst_copy (tree t, tree args, tsubst_f return build_x_va_arg (tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl), tsubst (TREE_TYPE (t), args, complain, in_decl)); - + default: return t; } @@ -7744,6 +7745,7 @@ tsubst_expr (tree t, tree args, tsubst_f switch (TREE_CODE (t)) { + case CTOR_INITIALIZER: prep_stmt (t); finish_mem_initializers (tsubst_initializer_list @@ -8274,6 +8276,9 @@ tsubst_copy_and_build (tree t, if (DECL_P (op1)) mark_used (op1); return grok_array_decl (op1, RECUR (TREE_OPERAND (t, 1))); + + case OFFSETOF_EXPR: + return cxx_offsetof_expr (RECUR (TREE_OPERAND (t, 0))); case SIZEOF_EXPR: case ALIGNOF_EXPR: Index: cp/semantics.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v retrieving revision 1.264.2.46 diff -u -p -r1.264.2.46 semantics.c --- cp/semantics.c 13 Feb 2004 13:13:38 -0000 1.264.2.46 +++ cp/semantics.c 15 Feb 2004 07:51:35 -0000 @@ -2969,6 +2969,7 @@ finalize_nrv (tree *tp, tree var, tree r htab_delete (data.visited); } + /* Start generating the RTL for FN. */ void Index: cp/typeck.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v retrieving revision 1.408.2.41 diff -u -p -r1.408.2.41 typeck.c --- cp/typeck.c 13 Feb 2004 13:13:39 -0000 1.408.2.41 +++ cp/typeck.c 15 Feb 2004 07:51:37 -0000 @@ -61,6 +61,7 @@ static void casts_away_constness_r (tree static bool casts_away_constness (tree, tree); static void maybe_warn_about_returning_address_of_local (tree); static tree lookup_destructor (tree, tree, tree); +static tree cxx_offsetof_lower (tree); /* Return the target type of TYPE, which means return T for: T*, T&, T[], T (...), and otherwise, just T. */ @@ -1283,7 +1284,73 @@ cxx_sizeof_or_alignof_expr (tree e, enum return cxx_sizeof_or_alignof_type (e, op, true); } + +/* Process a offsetof expression where the operand is an + expression. */ + +tree +cxx_offsetof_expr (tree e) +{ + + if (e == error_mark_node) + return error_mark_node; + + if (processing_template_decl) + { + e = build_min (OFFSETOF_EXPR, size_type_node, e); + TREE_SIDE_EFFECTS (e) = 0; + TREE_READONLY (e) = 1; + + return e; + } + return convert (size_type_node, cxx_offsetof_lower (e)); +} + +/* Lower the offsetof expression. */ + +static tree +cxx_offsetof_lower (tree arg) +{ + + switch (TREE_CODE (arg)) + { + /* For &x[y], return x+y. */ + case ARRAY_REF: + { + tree arg0 = cxx_offsetof_lower (TREE_OPERAND (arg, 0)); + + if (TREE_CODE (arg0) != INTEGER_CST) + abort(); + + arg0 = fold (build_indirect_ref (arg0, NULL)); + + return fold (build_binary_op (PLUS_EXPR, arg0, + TREE_OPERAND (arg, 1), 1)); + } + + /* Lower basically &((type*)(0))->a */ + case COMPONENT_REF: + { + tree argtype = build_pointer_type (TREE_TYPE (arg)); + + tree field = TREE_OPERAND (arg, 1); + tree rval = cxx_offsetof_lower (TREE_OPERAND (arg, 0)); + tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (rval)), + decl_type_context (field), + ba_check, NULL); + + rval = build_base_path (PLUS_EXPR, rval, binfo, 1); + rval = build_nop (argtype, rval); + return fold (build (PLUS_EXPR, argtype, rval, + cp_convert (argtype, byte_position (field)))); + } + case INDIRECT_REF: + return fold (convert (build_pointer_type (TREE_TYPE (arg)), TREE_OPERAND (arg, 0))); + default: + return build_unary_op (ADDR_EXPR, arg, 0); + } +} /* Perform the conversions in [expr] that apply when an lvalue appears in an rvalue context: the lvalue-to-rvalue, array-to-pointer, and @@ -4048,6 +4115,8 @@ build_unary_op (enum tree_code code, tre } else { + return build1 (ADDR_EXPR, argtype, arg); +#if 0 /* Unfortunately we cannot just build an address expression here, because we would not handle address-constant-expressions or offsetof correctly. */ @@ -4061,6 +4130,7 @@ build_unary_op (enum tree_code code, tre rval = build_nop (argtype, rval); addr = fold (build (PLUS_EXPR, argtype, rval, cp_convert (argtype, byte_position (field)))); +#endif } if (TREE_CODE (argtype) == POINTER_TYPE 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 15 Feb 2004 07:51:38 -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 \ - (&reinterpret_cast \ - (static_cast (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.32 diff -u -p -r1.137.2.32 objc-act.c --- objc/objc-act.c 13 Feb 2004 13:13:50 -0000 1.137.2.32 +++ objc/objc-act.c 15 Feb 2004 07:51:41 -0000 @@ -6509,7 +6509,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 15 Feb 2004 07:51:41 -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) \