From d897f7c2662b96117752b1f5c56b547eaa994f5c Mon Sep 17 00:00:00 2001
From: bonzini <bonzini@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Thu, 17 Aug 2006 07:02:55 +0000
Subject: [PATCH] 2006-08-17  Paolo Bonzini <bonzini@gnu.org>

	PR c++/28573
	* c-common.c (fold_offsetof_1): Add an argument and recurse down to it
	or the INTEGER_CST.  Fail on a CALL_EXPR.
	(fold_offsetof): Pass new argument to fold_offsetof_1.
	* c-parser.c (c_parser_postfix_expression): Don't include a NULL
	operand into an INDIRECT_REF.
	* c-typeck.c (build_unary_op): Adjust call to fold_offsetof.

cp:
2006-08-17  Paolo Bonzini  <bonzini@gnu.org>

	PR c++/28573
	* semantics.c (finish_offsetof): Add new argument to fold_offsetof.

testsuite:
2006-08-17  Paolo Bonzini  <bonzini@gnu.org>

	PR c++/28573
	* g++.dg/parse/offsetof6.C: New test.
	* g++.dg/parse/offsetof7.C: New test.



git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@116208 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog                          | 10 ++++++++
 gcc/c-common.c                         | 32 ++++++++++++++++++--------
 gcc/c-common.h                         |  2 +-
 gcc/c-parser.c                         |  4 ++--
 gcc/c-typeck.c                         |  2 +-
 gcc/cp/ChangeLog                       |  7 +++++-
 gcc/cp/semantics.c                     |  2 +-
 gcc/testsuite/ChangeLog                |  9 +++++++-
 gcc/testsuite/g++.dg/parse/offsetof6.C | 19 +++++++++++++++
 gcc/testsuite/g++.dg/parse/offsetof7.C | 18 +++++++++++++++
 10 files changed, 89 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/parse/offsetof6.C
 create mode 100644 gcc/testsuite/g++.dg/parse/offsetof7.C

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f4c0ff4b4794..d2bc8c54cd00 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2006-08-17  Paolo Bonzini <bonzini@gnu.org>
+
+	PR c++/28573
+	* c-common.c (fold_offsetof_1): Add an argument and recurse down to it
+	or the INTEGER_CST.  Fail on a CALL_EXPR. 
+	(fold_offsetof): Pass new argument to fold_offsetof_1.
+	* c-parser.c (c_parser_postfix_expression): Don't include a NULL
+	operand into an INDIRECT_REF. 
+	* c-typeck.c (build_unary_op): Adjust call to fold_offsetof.
+
 2006-08-16  Zdenek Dvorak <dvorakz@suse.cz>
 
 	PR gcov/profile/26570
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 167d04b81ff0..17643f0b5abc 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -5982,16 +5982,19 @@ c_common_to_target_charset (HOST_WIDE_INT c)
 }
 
 /* Build the result of __builtin_offsetof.  EXPR is a nested sequence of
-   component references, with an INDIRECT_REF at the bottom; much like
-   the traditional rendering of offsetof as a macro.  Returns the folded
-   and properly cast result.  */
+   component references, with STOP_REF, or alternatively an INDIRECT_REF of
+   NULL, at the bottom; much like the traditional rendering of offsetof as a
+   macro.  Returns the folded and properly cast result.  */
 
 static tree
-fold_offsetof_1 (tree expr)
+fold_offsetof_1 (tree expr, tree stop_ref)
 {
   enum tree_code code = PLUS_EXPR;
   tree base, off, t;
 
+  if (expr == stop_ref && TREE_CODE (expr) != ERROR_MARK)
+    return size_zero_node;
+
   switch (TREE_CODE (expr))
     {
     case ERROR_MARK:
@@ -6001,11 +6004,22 @@ fold_offsetof_1 (tree expr)
       error ("cannot apply %<offsetof%> to static data member %qD", expr);
       return error_mark_node;
 
-    case INDIRECT_REF:
+    case CALL_EXPR:
+      error ("cannot apply %<offsetof%> when %<operator[]%> is overloaded");
+      return error_mark_node;
+
+    case INTEGER_CST:
+      gcc_assert (integer_zerop (expr));
       return size_zero_node;
 
+    case NOP_EXPR:
+    case INDIRECT_REF:
+      base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref);
+      gcc_assert (base == error_mark_node || base == size_zero_node);
+      return base;
+
     case COMPONENT_REF:
-      base = fold_offsetof_1 (TREE_OPERAND (expr, 0));
+      base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref);
       if (base == error_mark_node)
 	return base;
 
@@ -6022,7 +6036,7 @@ fold_offsetof_1 (tree expr)
       break;
 
     case ARRAY_REF:
-      base = fold_offsetof_1 (TREE_OPERAND (expr, 0));
+      base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref);
       if (base == error_mark_node)
 	return base;
 
@@ -6044,10 +6058,10 @@ fold_offsetof_1 (tree expr)
 }
 
 tree
-fold_offsetof (tree expr)
+fold_offsetof (tree expr, tree stop_ref)
 {
   /* Convert back from the internal sizetype to size_t.  */
-  return convert (size_type_node, fold_offsetof_1 (expr));
+  return convert (size_type_node, fold_offsetof_1 (expr, stop_ref));
 }
 
 /* Print an error message for an invalid lvalue.  USE says
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 4f4919e9b0b7..633990a3a35b 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -830,7 +830,7 @@ extern void c_warn_unused_result (tree *);
 
 extern void verify_sequence_points (tree);
 
-extern tree fold_offsetof (tree);
+extern tree fold_offsetof (tree, tree);
 
 /* Places where an lvalue, or modifiable lvalue, may be required.
    Used to select diagnostic messages in lvalue_error and
diff --git a/gcc/c-parser.c b/gcc/c-parser.c
index 6e243dff58a5..9031e5b4d2f2 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -5203,7 +5203,7 @@ c_parser_postfix_expression (c_parser *parser)
 	    if (type == error_mark_node)
 	      offsetof_ref = error_mark_node;
 	    else
-	      offsetof_ref = build1 (INDIRECT_REF, type, NULL);
+	      offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node);
 	    /* Parse the second argument to __builtin_offsetof.  We
 	       must have one identifier, and beyond that we want to
 	       accept sub structure and sub array references.  */
@@ -5245,7 +5245,7 @@ c_parser_postfix_expression (c_parser *parser)
 	      c_parser_error (parser, "expected identifier");
 	    c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
 				       "expected %<)%>");
-	    expr.value = fold_offsetof (offsetof_ref);
+	    expr.value = fold_offsetof (offsetof_ref, NULL_TREE);
 	    expr.original_code = ERROR_MARK;
 	  }
 	  break;
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index dee7414e43ae..c55bcad89c98 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -3057,7 +3057,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
       if (val && TREE_CODE (val) == INDIRECT_REF
           && TREE_CONSTANT (TREE_OPERAND (val, 0)))
 	{
-	  tree op0 = fold_convert (argtype, fold_offsetof (arg)), op1;
+	  tree op0 = fold_convert (argtype, fold_offsetof (arg, val)), op1;
 
 	  op1 = fold_convert (argtype, TREE_OPERAND (val, 0));
 	  return fold_build2 (PLUS_EXPR, argtype, op0, op1);
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index cde739dbb95a..7048c5f1411e 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,8 +1,13 @@
+2006-08-17  Paolo Bonzini  <bonzini@gnu.org>
+
+	PR c++/28573
+	* semantics.c (finish_offsetof): Add new argument to fold_offsetof.
+
 2006-08-16  Andrew Pinski  <pinskia@physics.uc.edu>
 
 	PR c++/28302
 	* typeck.c (build_unary_op <case BIT_NOT_EXPR:>): Don't call
-	perform_integral_promotions for non integral type
+	perform_integral_promotions for non integral type.
 
 2006-08-16  Jason Merrill  <jason@redhat.com>
 
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index d36eba76e414..fb4ea0a79dfa 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2904,7 +2904,7 @@ finish_offsetof (tree expr)
       error ("cannot apply %<offsetof%> to member function %qD", expr);
       return error_mark_node;
     }
-  return fold_offsetof (expr);
+  return fold_offsetof (expr, NULL_TREE);
 }
 
 /* Called from expand_body via walk_tree.  Replace all AGGR_INIT_EXPRs
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 3da59b8a44e5..624a2f23d73e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2006-08-17  Paolo Bonzini  <bonzini@gnu.org>
+
+	* PR c++/28573
+	* g++.dg/parse/offsetof6.C: New test.
+	* g++.dg/parse/offsetof6.C: New test.
+	* g++.dg/parse/offsetof7.C: New test.
+
 2006-08-16  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>
 
 	PR testsuite/28602
@@ -6,7 +13,7 @@
 
 2006-08-16  Andrew Pinski  <pinskia@physics.uc.edu>
 
-	PR C++/28302
+	PR c++/28302
 	* g++.dg/ext/vector3.C: New test.
 
 2006-08-16  Zdenek Dvorak  <dvorakz@suse.cz>
diff --git a/gcc/testsuite/g++.dg/parse/offsetof6.C b/gcc/testsuite/g++.dg/parse/offsetof6.C
new file mode 100644
index 000000000000..0e07a538009c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/offsetof6.C
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+
+// From PR28573
+
+struct A
+{
+  char d[44];
+  char &operator [] ( int indx ) { return d[indx]; }
+};
+
+struct B
+{
+  A a;
+};
+
+int main()
+{
+  return __builtin_offsetof(B, a[0]); /* { dg-error "cannot apply.*offsetof" } */
+}
diff --git a/gcc/testsuite/g++.dg/parse/offsetof7.C b/gcc/testsuite/g++.dg/parse/offsetof7.C
new file mode 100644
index 000000000000..113a7954726d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/offsetof7.C
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+
+// From PR28573
+
+struct A
+{
+   int operator [] ( int indx ) { return indx; }
+};
+
+struct B
+{
+   A a;
+};
+
+int main()
+{
+   return __builtin_offsetof(B, a[0]);  /* { dg-error "cannot apply.*offsetof" } */
+}
-- 
GitLab