Here we were assuming that the type of a POINTER_PLUS_EXPR would reflect
the underlying type of the object, which is not the case with this
testcase. So now we keep looking until we find the ADDR_EXPR.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 482c1bb6a00cdd911df18d2fd3486ee00fc2fad5
Author: Jason Merrill <ja...@redhat.com>
Date: Wed Dec 14 16:38:13 2011 -0500
PR c++/51554
* semantics.c (cxx_eval_indirect_ref): Fix sanity check.
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 7e1a396..ef85e45 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -7329,9 +7329,15 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t,
{
tree sub = op0;
STRIP_NOPS (sub);
- if (TREE_CODE (sub) == ADDR_EXPR
- || TREE_CODE (sub) == POINTER_PLUS_EXPR)
+ if (TREE_CODE (sub) == POINTER_PLUS_EXPR)
{
+ sub = TREE_OPERAND (sub, 0);
+ STRIP_NOPS (sub);
+ }
+ if (TREE_CODE (sub) == ADDR_EXPR)
+ {
+ /* We couldn't fold to a constant value. Make sure it's not
+ something we should have been able to fold. */
gcc_assert (!same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t)));
/* DR 1188 says we don't have to deal with this. */
diff --git a/gcc/testsuite/g++.dg/init/constant1.C b/gcc/testsuite/g++.dg/init/constant1.C
new file mode 100644
index 0000000..386b926
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/constant1.C
@@ -0,0 +1,17 @@
+// PR c++/51554
+
+typedef unsigned char uint8;
+typedef unsigned int uint32;
+
+const uint32 XX[] = { 1, 3, 7 };
+
+const uint8 V[] = {
+ *(((const uint8*)&XX[0]) + 0),
+ *(((const uint8*)&XX[0]) + 1),
+ *(((const uint8*)&XX[0]) + 2),
+ *(((const uint8*)&XX[0]) + 3),
+ *(((const uint8*)&XX[1]) + 0),
+ *(((const uint8*)&XX[1]) + 1),
+ *(((const uint8*)&XX[1]) + 2),
+ *(((const uint8*)&XX[1]) + 3),
+};