This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH for c++/68586 (rejects-valid with enum in C++11)


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]