C++ PATCH: Fix PR 13275
Mark Mitchell
mark@codesourcery.com
Tue Dec 16 17:35:00 GMT 2003
Once the new parser started correctly checking the requirements on
integral constant-expressions, we realized that it was not possible to
implement the "offsetof" macro (which is supposed to be an integral
constant expression) without a compiler extension. This patch
provides that extension.
Tested on i686-pc-linux-gnu, applied on the mainline.
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
2003-12-16 Mark Mitchell <mark@codesourcery.com>
PR c++/13275
* c-common.h (enum rid): Add RID_OFFSETOF.
* c-parser.in (rid_to_yy): Ignore RID_OFFSETOF.
* ginclude/stddef.h (offsetof): Reimplement for C++, using
__offsetof__.
* doc/extend.texi: Document __offsetof__.
2003-12-16 Mark Mitchell <mark@codesourcery.com>
PR c++/13275
* lex.c (reswords): Add "__offsetof" and "__offsetof__".
* parser.c (cp_parser): Add in_offsetof_p.
(cp_parser_new): Initialize it.
(cp_parser_primary_expression): Handle __offsetof__ (...).
(cp_parser_postfix_expression): Allow casts to pointer type and
uses of "->" in a constant expression if implementing offsetof.
(cp_parser_unary_expression): Allow the use of "&" in a constant
expression if implementing offsetof.
2003-12-16 Mark Mitchell <mark@codesourcery.com>
PR c++/13275
* g++.dg/other/offsetof2.C: Remove XFAIL.
* g++.dg/parse/offsetof1.C: New test.
* g++.gd/parse/offsetof2.C: Likewise.
Index: c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.211
diff -c -5 -p -r1.211 c-common.h
*** c-common.h 15 Dec 2003 06:28:13 -0000 1.211
--- c-common.h 16 Dec 2003 15:41:29 -0000
*************** enum rid
*** 86,98 ****
/* C++ */
RID_BOOL, RID_WCHAR, RID_CLASS,
RID_PUBLIC, RID_PRIVATE, RID_PROTECTED,
RID_TEMPLATE, RID_NULL, RID_CATCH,
RID_DELETE, RID_FALSE, RID_NAMESPACE,
! RID_NEW, RID_OPERATOR, RID_THIS,
! RID_THROW, RID_TRUE, RID_TRY,
! RID_TYPENAME, RID_TYPEID, RID_USING,
/* casts */
RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST,
/* Objective-C */
--- 86,99 ----
/* C++ */
RID_BOOL, RID_WCHAR, RID_CLASS,
RID_PUBLIC, RID_PRIVATE, RID_PROTECTED,
RID_TEMPLATE, RID_NULL, RID_CATCH,
RID_DELETE, RID_FALSE, RID_NAMESPACE,
! RID_NEW, RID_OFFSETOF, RID_OPERATOR,
! RID_THIS, RID_THROW, RID_TRUE,
! RID_TRY, RID_TYPENAME, RID_TYPEID,
! RID_USING,
/* casts */
RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST,
/* Objective-C */
Index: c-parse.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-parse.in,v
retrieving revision 1.192
diff -c -5 -p -r1.192 c-parse.in
*** c-parse.in 15 Dec 2003 06:28:13 -0000 1.192
--- c-parse.in 16 Dec 2003 15:41:30 -0000
*************** static const short rid_to_yy[RID_MAX] =
*** 3482,3491 ****
--- 3482,3492 ----
/* RID_CATCH */ 0,
/* RID_DELETE */ 0,
/* RID_FALSE */ 0,
/* RID_NAMESPACE */ 0,
/* RID_NEW */ 0,
+ /* RID_OFFSETOF */ 0,
/* RID_OPERATOR */ 0,
/* RID_THIS */ 0,
/* RID_THROW */ 0,
/* RID_TRUE */ 0,
/* RID_TRY */ 0,
Index: cp/lex.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/lex.c,v
retrieving revision 1.318
diff -c -5 -p -r1.318 lex.c
*** cp/lex.c 2 Dec 2003 10:11:24 -0000 1.318
--- cp/lex.c 16 Dec 2003 15:41:32 -0000
*************** static const struct resword reswords[] =
*** 264,273 ****
--- 264,275 ----
{ "__imag__", RID_IMAGPART, 0 },
{ "__inline", RID_INLINE, 0 },
{ "__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 },
{ "__restrict__", RID_RESTRICT, 0 },
{ "__signed", RID_SIGNED, 0 },
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.134
diff -c -5 -p -r1.134 parser.c
*** cp/parser.c 16 Dec 2003 02:46:23 -0000 1.134
--- cp/parser.c 16 Dec 2003 15:41:34 -0000
*************** typedef struct cp_parser GTY(())
*** 1228,1237 ****
--- 1228,1240 ----
/* TRUE if ALLOW_NON_CONSTANT_EXPRESSION_P is TRUE and something has
been seen that makes the expression non-constant. */
bool non_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;
/* TRUE if the declaration we are parsing is part of a
*************** cp_parser_new (void)
*** 2223,2232 ****
--- 2226,2238 ----
/* We are not parsing a constant-expression. */
parser->constant_expression_p = false;
parser->allow_non_constant_expression_p = false;
parser->non_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;
/* We are not processing an `extern "C"' declaration. */
parser->in_unbraced_linkage_specification_p = false;
*************** cp_parser_primary_expression (cp_parser
*** 2501,2510 ****
--- 2507,2539 ----
parser->non_constant_expression_p = true;
}
return build_x_va_arg (expression, type);
}
+ 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;
+ }
+
default:
cp_parser_error (parser, "expected primary-expression");
return error_mark_node;
}
*************** cp_parser_postfix_expression (cp_parser
*** 3392,3402 ****
/* Only type conversions to integral or enumeration types
can be used in constant-expressions. */
if (parser->constant_expression_p
&& !dependent_type_p (type)
! && !INTEGRAL_OR_ENUMERATION_TYPE_P (type))
{
if (!parser->allow_non_constant_expression_p)
return (cp_parser_non_constant_expression
("a cast to a type other than an integral or "
"enumeration type"));
--- 3421,3434 ----
/* Only type conversions to integral or enumeration types
can be used in constant-expressions. */
if (parser->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)))
{
if (!parser->allow_non_constant_expression_p)
return (cp_parser_non_constant_expression
("a cast to a type other than an integral or "
"enumeration type"));
*************** cp_parser_postfix_expression (cp_parser
*** 3852,3862 ****
/* 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->constant_expression_p)
{
if (!parser->allow_non_constant_expression_p)
postfix_expression
= (cp_parser_non_constant_expression
(token_type == CPP_DEREF ? "'->'" : "`.'"));
--- 3884,3897 ----
/* 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->constant_expression_p
! /* The "->" operator is allowed in the implementation
! of "offsetof". */
! && !(parser->in_offsetof_p && token_type == CPP_DEREF))
{
if (!parser->allow_non_constant_expression_p)
postfix_expression
= (cp_parser_non_constant_expression
(token_type == CPP_DEREF ? "'->'" : "`.'"));
*************** cp_parser_unary_expression (cp_parser *p
*** 4257,4267 ****
non_constant_p = "`*'";
expression = build_x_indirect_ref (cast_expression, "unary *");
break;
case ADDR_EXPR:
! non_constant_p = "`&'";
/* Fall through. */
case BIT_NOT_EXPR:
expression = build_x_unary_op (unary_operator, cast_expression);
break;
--- 4292,4305 ----
non_constant_p = "`*'";
expression = build_x_indirect_ref (cast_expression, "unary *");
break;
case ADDR_EXPR:
! /* The "&" operator is allowed in the implementation of
! "offsetof". */
! if (!parser->in_offsetof_p)
! non_constant_p = "`&'";
/* Fall through. */
case BIT_NOT_EXPR:
expression = build_x_unary_op (unary_operator, cast_expression);
break;
Index: ginclude/stddef.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ginclude/stddef.h,v
retrieving revision 1.19
diff -c -5 -p -r1.19 stddef.h
*** ginclude/stddef.h 2 Jul 2003 14:30:52 -0000 1.19
--- ginclude/stddef.h 16 Dec 2003 15:41:34 -0000
*************** typedef __WINT_TYPE__ wint_t;
*** 411,435 ****
/* Offset of member MEMBER in a struct of type TYPE. */
#ifndef __cplusplus
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#else
! /* In C++ a POD type can have a user defined address-of operator, and
! that will break offsetof. C++ core defect 273 addresses this and
! claims that reinterpret_casts to char & type are sufficient to
! overcome this problem.
!
! (reinterpret_cast <size_t>
! (&reinterpret_cast <char &>(static_cast <TYPE *> (0)->MEMBER)))
!
! But, such casts are not permitted in integral constant expressions,
! which offsetof is supposed to be.
!
! It appears that offsetof is unimplementable in C++ without a
! compiler extension. */
! #define offsetof(TYPE, MEMBER) (reinterpret_cast <size_t> \
! (&static_cast<TYPE *> (0)->MEMBER))
#endif /* C++ */
#endif /* _STDDEF_H was defined this time */
#endif /* !_STDDEF_H && !_STDDEF_H_ && !_ANSI_STDDEF_H && !__STDDEF_H__
|| __need_XXX was not defined before */
--- 411,426 ----
/* 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++ */
#endif /* _STDDEF_H was defined this time */
#endif /* !_STDDEF_H && !_STDDEF_H_ && !_ANSI_STDDEF_H && !__STDDEF_H__
|| __need_XXX was not defined before */
Index: testsuite/g++.dg/other/offsetof2.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/other/offsetof2.C,v
retrieving revision 1.2
diff -c -5 -p -r1.2 offsetof2.C
*** testsuite/g++.dg/other/offsetof2.C 2 Jul 2003 14:30:53 -0000 1.2
--- testsuite/g++.dg/other/offsetof2.C 16 Dec 2003 15:41:38 -0000
***************
*** 1,14 ****
! // { dg-do run { xfail *-*-* } }
// { dg-options -Wold-style-cast }
// Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 22 Apr 2003 <nathan@codesourcery.com>
// DR273 POD can have an operator&, offsetof is still required to work
-
- // XFAILED - you can't write offsetof without an extension
#include <stddef.h>
struct POD1
{
--- 1,12 ----
! // { dg-do run }
// { dg-options -Wold-style-cast }
// Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 22 Apr 2003 <nathan@codesourcery.com>
// DR273 POD can have an operator&, offsetof is still required to work
#include <stddef.h>
struct POD1
{
Index: testsuite/g++.dg/parse/offsetof1.C
===================================================================
RCS file: testsuite/g++.dg/parse/offsetof1.C
diff -N testsuite/g++.dg/parse/offsetof1.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/parse/offsetof1.C 16 Dec 2003 15:41:38 -0000
***************
*** 0 ****
--- 1,11 ----
+ #include <stddef.h>
+
+ template <bool> struct StaticAssert;
+ template <> struct StaticAssert<true> {};
+
+ struct MyPOD
+ {
+ int a; int b; int c;
+ };
+
+ StaticAssert<(offsetof(MyPOD, a) == 0)> s;
Index: testsuite/g++.dg/parse/offsetof2.C
===================================================================
RCS file: testsuite/g++.dg/parse/offsetof2.C
diff -N testsuite/g++.dg/parse/offsetof2.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/parse/offsetof2.C 16 Dec 2003 15:41:38 -0000
***************
*** 0 ****
--- 1,12 ----
+ #include <cstddef>
+
+ struct choke_me
+ {
+ int size;
+ char storage[1];
+ };
+
+ struct offset_is_broken
+ {
+ static const int offset = offsetof(choke_me, storage);
+ };
Index: doc/extend.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/extend.texi,v
retrieving revision 1.173
diff -c -5 -p -r1.173 extend.texi
*** doc/extend.texi 10 Dec 2003 22:33:47 -0000 1.173
--- doc/extend.texi 16 Dec 2003 16:04:52 -0000
*************** Predefined Macros,cpp,The GNU C Preproce
*** 7654,7663 ****
--- 7654,7664 ----
each needed template instantiation is emitted.
* Bound member functions:: You can extract a function pointer to the
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++.
@end menu
*************** int main()
*** 8292,8301 ****
--- 8293,8321 ----
@{
f (std::A<float>()); // lookup finds std::f
f (std::A<int>());
@}
@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
The Java language uses a slightly different exception handling model
More information about the Gcc-patches
mailing list