This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for c++/68586 (rejects-valid with enum in C++11)
- From: Marek Polacek <polacek at redhat dot com>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>, Jason Merrill <jason at redhat dot com>
- Date: Mon, 18 Jan 2016 15:53:19 +0100
- Subject: C++ PATCH for c++/68586 (rejects-valid with enum in C++11)
- Authentication-results: sourceware.org; auth=none
In this PR, we find ourselves in a curious situation. When parsing this enum:
enum E { x = 1, y = x << 1 };
we process the LSHIFT_EXPR in cp_build_binary_op and call fold_non_dependent_expr
on each of the operands. Then fold_non_dependent_expr calls maybe_constant_value
which, for CONST_DECL x, sticks 1 of INTEGER_TYPE to the cache. But, as explained
in finish_enum_value_list:
/* [dcl.enum]: Following the closing brace of an enum-specifier,
each enumerator has the type of its enumeration. Prior to the
closing brace, the type of each enumerator is the type of its
initializing value. */
the type of CONST_DECL x will be different after the whole enumerator-specifier
has been parsed. This discrepancy can cause problems down the line, as seen in
the testcase. (It's standard_conversion that says that integer -> unscoped enum
conversion is bad.)
That's why I think we shouldn't put CONST_DECLs into the cache while parsing an
enum. I feel uneasy about the new check, but I couldn't find anything better;
TYPE_BEING_DEFINED is for classes only, and COMPLETE_TYPE_P won't work here.
Bootstrapped/regtested on x86_64-linux, ok for trunk?
2016-01-18 Marek Polacek <polacek@redhat.com>
PR c++/68586
* constexpr.c (maybe_constant_value): Don't put enumerators into the
cv_cache while parsing an enumerator-list.
* g++.dg/cpp0x/enum30.C: New test.
diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 6ab4696..d52005b 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -4022,7 +4022,13 @@ maybe_constant_value (tree t, tree decl)
if (!ret)
{
ret = maybe_constant_value_1 (t, decl);
- cv_cache.put (t, ret);
+ /* While parsing an enumerator-list, the type of each enumerator
+ is the type of its initializing value. After the parsing has
+ been done, it will have the type of its enumeration. And this
+ discrepancy could get us in trouble later. */
+ if (TREE_CODE (t) != CONST_DECL
+ || TREE_TYPE (t) == DECL_CONTEXT (t))
+ cv_cache.put (t, ret);
}
return ret;
}
diff --git gcc/testsuite/g++.dg/cpp0x/enum30.C gcc/testsuite/g++.dg/cpp0x/enum30.C
index e69de29..b9bdfd4 100644
--- gcc/testsuite/g++.dg/cpp0x/enum30.C
+++ gcc/testsuite/g++.dg/cpp0x/enum30.C
@@ -0,0 +1,14 @@
+// PR c++/68586
+// { dg-do compile { target c++11 } }
+
+enum E { x = 1, y = x << 1 };
+template<E> struct A {};
+A<x> a;
+
+enum E2 : int { x2 = 1, y2 = x2 << 1 };
+template<E2> struct A2 {};
+A2<x2> a2;
+
+enum class E3 { x3 = 1, y3 = x3 << 1 };
+template<E3> struct A3 {};
+A3<E3::x3> a3;
Marek