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