c-parse.in (OFFSETOF, [...]): New.
* 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 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/objc-act.h (objc_is_public): Rename from is_public. * ginclude/stddef.h (offsetof): Use __builtin_offsetof. * doc/extend.texi (Offsetof): Move from C++ section to C section and rewrite for __builtin_offsetof. cp/ * lex.c (reswords): Rename "__offsetof" to "__builtin_offsetof". * parser.c (struct cp_parser): Remove in_offsetof. (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_postfix_expression): ... here. (cp_parser_postfix_dot_deref_expression): Likewise. (cp_parser_builtin_offsetof): New. (cp_parser_primary_expression): Use it. testsuite/ * g++.dg/template/dependent-expr4.C: Use __builtin_offsetof. From-SVN: r82549
This commit is contained in:
parent
c4ec6988bc
commit
7a3ea2011b
15 changed files with 429 additions and 239 deletions
|
@ -1,3 +1,22 @@
|
|||
2004-06-01 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 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/objc-act.h (objc_is_public): Rename
|
||||
from is_public.
|
||||
* ginclude/stddef.h (offsetof): Use __builtin_offsetof.
|
||||
* doc/extend.texi (Offsetof): Move from C++ section to C section
|
||||
and rewrite for __builtin_offsetof.
|
||||
|
||||
2004-06-01 Peter Barada <peter@the-baradas.com>
|
||||
Peter Jakubek <peter@laseranimation.com>
|
||||
|
||||
|
|
|
@ -1236,6 +1236,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 *);
|
||||
|
|
|
@ -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 <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_volatile
|
||||
%type <ttype> initdecls notype_initdecls initdcl notype_initdcl init
|
||||
|
@ -674,17 +675,25 @@ primary:
|
|||
| VA_ARG '(' expr_no_commas ',' typename ')'
|
||||
{ $$ = build_va_arg ($3, groktypename ($5)); }
|
||||
|
||||
| CHOOSE_EXPR '(' expr_no_commas ',' expr_no_commas ',' expr_no_commas ')'
|
||||
| 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;
|
||||
|
||||
|
@ -694,27 +703,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); }
|
||||
|
@ -734,6 +732,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:
|
||||
/* empty */
|
||||
| datadecls
|
||||
|
@ -3273,6 +3286,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 },
|
||||
|
@ -3469,7 +3483,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,
|
||||
|
|
|
@ -258,6 +258,7 @@ extern tree build_asm_expr (tree, tree, tree, tree, bool);
|
|||
extern tree build_asm_stmt (tree, tree);
|
||||
extern tree c_convert_parm_for_inlining (tree, tree, tree, int);
|
||||
extern int c_types_compatible_p (tree, tree);
|
||||
extern tree build_offsetof (tree, tree);
|
||||
|
||||
/* Set to 0 at beginning of a function definition, set to 1 if
|
||||
a return statement that specifies a return value is seen. */
|
||||
|
|
|
@ -1347,6 +1347,9 @@ build_component_ref (tree datum, tree component)
|
|||
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
|
||||
|
@ -7114,3 +7117,30 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
|
|||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
2004-06-01 Richard Henderson <rth@redhat.com>
|
||||
Andrew Pinski <pinskia@physics.uc.edu>
|
||||
|
||||
* lex.c (reswords): Rename "__offsetof" to "__builtin_offsetof".
|
||||
* parser.c (struct cp_parser): Remove in_offsetof.
|
||||
(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_postfix_expression): ... here.
|
||||
(cp_parser_postfix_dot_deref_expression): Likewise.
|
||||
(cp_parser_builtin_offsetof): New.
|
||||
(cp_parser_primary_expression): Use it.
|
||||
|
||||
2004-06-01 Giovanni Bajo <giovannibajo@gcc.gnu.org>
|
||||
|
||||
PR c++/14932
|
||||
|
|
|
@ -253,6 +253,7 @@ static const struct resword reswords[] =
|
|||
{ "__asm__", RID_ASM, 0 },
|
||||
{ "__attribute", RID_ATTRIBUTE, 0 },
|
||||
{ "__attribute__", RID_ATTRIBUTE, 0 },
|
||||
{ "__builtin_offsetof", RID_OFFSETOF, 0 },
|
||||
{ "__builtin_va_arg", RID_VA_ARG, 0 },
|
||||
{ "__complex", RID_COMPLEX, 0 },
|
||||
{ "__complex__", RID_COMPLEX, 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 },
|
||||
|
|
466
gcc/cp/parser.c
466
gcc/cp/parser.c
|
@ -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_name
|
|||
(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] */
|
||||
|
||||
|
@ -2324,9 +2327,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;
|
||||
|
||||
|
@ -2603,27 +2603,7 @@ cp_parser_primary_expression (cp_parser *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");
|
||||
|
@ -3520,9 +3500,6 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
|
|||
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))
|
||||
&& (cp_parser_non_integral_constant_expression
|
||||
(parser,
|
||||
"a cast to a type other than an integral or "
|
||||
|
@ -3765,29 +3742,11 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
|
|||
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 (but they are allowed
|
||||
in offsetof). */
|
||||
if (!parser->in_offsetof_p
|
||||
&& cp_parser_non_integral_constant_expression
|
||||
(parser, "an array reference"))
|
||||
postfix_expression = error_mark_node;
|
||||
}
|
||||
postfix_expression
|
||||
= cp_parser_postfix_open_square_expression (parser,
|
||||
postfix_expression,
|
||||
false);
|
||||
idk = CP_ID_KIND_NONE;
|
||||
break;
|
||||
|
||||
case CPP_OPEN_PAREN:
|
||||
|
@ -3891,132 +3850,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
|
|||
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;
|
||||
|
||||
/* Consume the `.' or `->' operator. */
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
if (scope && name && BASELINK_P (name))
|
||||
adjust_result_of_qualified_name_lookup
|
||||
(name, BINFO_TYPE (BASELINK_BINFO (name)), scope);
|
||||
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;
|
||||
/* These operators may not appear in constant-expressions. */
|
||||
if (/* The "->" operator is allowed in the implementation
|
||||
of "offsetof". The "." operator may appear in the
|
||||
name of the member. */
|
||||
!parser->in_offsetof_p
|
||||
&& (cp_parser_non_integral_constant_expression
|
||||
(parser,
|
||||
token_type == CPP_DEREF ? "'->'" : "`.'")))
|
||||
postfix_expression = error_mark_node;
|
||||
}
|
||||
postfix_expression
|
||||
= cp_parser_postfix_dot_deref_expression (parser, token->type,
|
||||
postfix_expression,
|
||||
false, &idk);
|
||||
break;
|
||||
|
||||
case CPP_PLUS_PLUS:
|
||||
|
@ -4059,6 +3900,183 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
|
|||
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
|
||||
&& (cp_parser_non_integral_constant_expression
|
||||
(parser, "an array reference")))
|
||||
postfix_expression = error_mark_node;
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
if (scope && name && BASELINK_P (name))
|
||||
adjust_result_of_qualified_name_lookup
|
||||
(name, BINFO_TYPE (BASELINK_BINFO (name)), scope);
|
||||
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
|
||||
&& (cp_parser_non_integral_constant_expression
|
||||
(parser, token_type == CPP_DEREF ? "'->'" : "`.'")))
|
||||
postfix_expression = error_mark_node;
|
||||
|
||||
return postfix_expression;
|
||||
}
|
||||
|
||||
/* Parse a parenthesized expression-list.
|
||||
|
||||
expression-list:
|
||||
|
@ -4420,10 +4438,7 @@ cp_parser_unary_expression (cp_parser *parser, bool address_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);
|
||||
|
@ -5457,6 +5472,93 @@ cp_parser_constant_expression (cp_parser* parser,
|
|||
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 */
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
expr = cp_parser_postfix_dot_deref_expression (parser, CPP_DOT, expr,
|
||||
true, &dummy);
|
||||
break;
|
||||
|
||||
case CPP_CLOSE_PAREN:
|
||||
/* Consume the ")" token. */
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
goto success;
|
||||
|
||||
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 failure;
|
||||
}
|
||||
}
|
||||
|
||||
success:
|
||||
/* 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);
|
||||
|
||||
failure:
|
||||
parser->integral_constant_expression_p = save_ice_p;
|
||||
parser->non_integral_constant_expression_p = save_non_ice_p;
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
/* Statements [gram.stmt.stmt] */
|
||||
|
||||
/* Parse a statement.
|
||||
|
|
|
@ -469,6 +469,7 @@ extensions, accepted by GCC in C89 mode and in C++.
|
|||
function.
|
||||
* Return Address:: Getting the return or frame address of a function.
|
||||
* Vector Extensions:: Using vector instructions through built-in functions.
|
||||
* Offsetof:: Special syntax for implementing @code{offsetof}.
|
||||
* Other Builtins:: Other built-in functions.
|
||||
* Target Builtins:: Built-in functions specific to particular targets.
|
||||
* Pragmas:: Pragmas accepted by GCC.
|
||||
|
@ -4704,6 +4705,33 @@ v4si f (v4si a, v4si b, v4si c)
|
|||
|
||||
@end smallexample
|
||||
|
||||
@node Offsetof
|
||||
@section Offsetof
|
||||
@findex __builtin_offsetof
|
||||
|
||||
GCC implements for both C and C++ a syntactic extension to implement
|
||||
the @code{offsetof} macro.
|
||||
|
||||
@smallexample
|
||||
primary:
|
||||
"__builtin_offsetof" "(" @code{typename} "," offsetof_member_designator ")"
|
||||
|
||||
offsetof_member_designator:
|
||||
@code{identifier}
|
||||
| offsetof_member_designator "." @code{identifier}
|
||||
| offsetof_member_designator "[" @code{expr} "]"
|
||||
@end smallexample
|
||||
|
||||
This extension is sufficient such that
|
||||
|
||||
@smallexample
|
||||
#define offsetof(@var{type}, @var{member}) __builtin_offsetof (@var{type}, @var{member})
|
||||
@end smallexample
|
||||
|
||||
is a suitable definition of the @code{offsetof} macro. In C++, @var{type}
|
||||
may be dependent. In either case, @var{member} may consist of a single
|
||||
identifier, or a sequence of member accesses and array references.
|
||||
|
||||
@node Other Builtins
|
||||
@section Other built-in functions provided by GCC
|
||||
@cindex built-in functions
|
||||
|
@ -7620,7 +7648,6 @@ Predefined Macros,cpp,The GNU C Preprocessor}).
|
|||
method denoted by a @samp{->*} or @samp{.*} expression.
|
||||
* C++ Attributes:: Variable, function, and type attributes for C++ only.
|
||||
* Strong Using:: Strong using-directives for namespace composition.
|
||||
* Offsetof:: Special syntax for implementing @code{offsetof}.
|
||||
* Java Exceptions:: Tweaking exception handling to work with Java.
|
||||
* Deprecated Features:: Things will disappear from g++.
|
||||
* Backwards Compatibility:: Compatibilities with earlier definitions of C++.
|
||||
|
@ -8265,25 +8292,6 @@ int main()
|
|||
@}
|
||||
@end smallexample
|
||||
|
||||
@node Offsetof
|
||||
@section Offsetof
|
||||
|
||||
G++ uses a syntactic extension to implement the @code{offsetof} macro.
|
||||
|
||||
In particular:
|
||||
|
||||
@smallexample
|
||||
__offsetof__ (expression)
|
||||
@end smallexample
|
||||
|
||||
is equivalent to the parenthesized expression, except that the
|
||||
expression is considered an integral constant expression even if it
|
||||
contains certain operators that are not normally permitted in an
|
||||
integral constant expression. Users should never use
|
||||
@code{__offsetof__} directly; the only valid use of
|
||||
@code{__offsetof__} is to implement the @code{offsetof} macro in
|
||||
@code{<stddef.h>}.
|
||||
|
||||
@node Java Exceptions
|
||||
@section Java Exceptions
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* Copyright (C) 1989, 1997, 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1989, 1997, 1998, 1999, 2000, 2002, 2004
|
||||
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__
|
||||
|
|
|
@ -6475,7 +6475,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);
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -69,3 +69,8 @@ objc_message_selector (void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
objc_is_public (tree expr ATTRIBUTE_UNUSED, tree identifier ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2004-06-01 Richard Hederson <rth@redhat.com>
|
||||
|
||||
* g++.dg/template/dependent-expr4.C: Use __builtin_offsetof.
|
||||
|
||||
2004-06-01 Giovanni Bajo <giovannibajo@gcc.gnu.org>
|
||||
|
||||
PR c++/14932
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// { dg-do compile }
|
||||
// Origin: jbrandmeyer at users dot sourceforge dot net
|
||||
// PR c++/12573: COMPONENT_REFs must be inspected for dependness.
|
||||
// Or, more specifically OFFSETOF.
|
||||
|
||||
template <bool> struct S;
|
||||
|
||||
|
@ -9,6 +10,6 @@ template <typename K> struct Y {
|
|||
};
|
||||
|
||||
template <class T> struct Z {
|
||||
S< (bool)(__offsetof__(&static_cast<Y<T>*>(0)->x) == 0) >
|
||||
S< (bool)(__builtin_offsetof (Y<T>*, x) == 0) >
|
||||
s;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue