Here we initialize an enumerator with a class prvalue with a conversion
function. When we fold it in build_enumerator, we create a TARGET_EXPR
for the object, and subsequently crash in tsubst_expr, which should not
see such a code.
Normally, we fix similar problems by using an IMPLICIT_CONV_EXPR but here
I may get away with not using the result of fold_non_dependent_expr unless
the result is a constant. A TARGET_EXPR is not constant.
PR c++/115657
gcc/cp/ChangeLog:
* decl.cc (build_enumerator): Call maybe_fold_non_dependent_expr
instead of fold_non_dependent_expr.
gcc/testsuite/ChangeLog:
* g++.dg/cpp1y/constexpr-recursion2.C: New test.
* g++.dg/template/conv21.C: New test.
(cherry picked from commit
53283c3231a7b94e728619cccbf21170fb36b2a8)
tree type;
/* scalar_constant_value will pull out this expression, so make sure
- it's folded as appropriate. */
+ it's folded as appropriate.
+
+ Creating a TARGET_EXPR in a template breaks when substituting, and
+ here we would create it for instance when using a class prvalue with
+ a user-defined conversion function. So don't use such a tree. We
+ instantiate VALUE here to get errors about bad enumerators even in
+ a template that does not get instantiated. */
if (processing_template_decl)
- value = fold_non_dependent_expr (value);
+ value = maybe_fold_non_dependent_expr (value);
/* If the VALUE was erroneous, pretend it wasn't there; that will
result in the enum being assigned the next value in sequence. */
--- /dev/null
+// PR c++/115657
+// { dg-do compile { target c++14 } }
+// { dg-options "-Wall" }
+
+// Like constexpr-recursion1.C but use a class with a conversion function.
+
+struct X {
+ constexpr operator int() { return 0; }
+};
+
+template <int N>
+constexpr X f1 ()
+{
+ enum E { a = f1<0> () }; // { dg-error "called in a constant expression before its definition is complete|is not an integer constant" }
+ return {};
+}
+
+constexpr X f3 ()
+{
+ enum E { a = f3 () }; // { dg-error "called in a constant expression before its definition is complete|is not an integer constant" }
+ return {};
+}
--- /dev/null
+// PR c++/115657
+// { dg-do compile { target c++11 } }
+
+struct NonIntegral
+{
+ constexpr operator int() { return 0; }
+};
+
+template<typename T> struct TemplatedStructural
+{
+ enum { e = NonIntegral{} };
+};
+
+template struct TemplatedStructural<void>;