diff options
author | Marek Polacek <polacek@redhat.com> | 2024-08-15 18:47:29 -0400 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2024-08-19 13:29:30 -0400 |
commit | 53283c3231a7b94e728619cccbf21170fb36b2a8 (patch) | |
tree | 9f00304d88d43edf2d57b55558e2711008272f51 | |
parent | 8191f15022b0ea44fcb549449b0458d07ae02e0a (diff) | |
download | gcc-53283c3231a7b94e728619cccbf21170fb36b2a8.zip gcc-53283c3231a7b94e728619cccbf21170fb36b2a8.tar.gz gcc-53283c3231a7b94e728619cccbf21170fb36b2a8.tar.bz2 |
c++: ICE with enum and conversion fn in template [PR115657]
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.
-rw-r--r-- | gcc/cp/decl.cc | 10 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1y/constexpr-recursion2.C | 22 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/conv21.C | 14 |
3 files changed, 44 insertions, 2 deletions
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index f23b635..12139e1 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -17387,9 +17387,15 @@ build_enumerator (tree name, tree value, tree enumtype, tree attributes, 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. */ diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-recursion2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-recursion2.C new file mode 100644 index 0000000..f268f52 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-recursion2.C @@ -0,0 +1,22 @@ +// 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 {}; +} diff --git a/gcc/testsuite/g++.dg/template/conv21.C b/gcc/testsuite/g++.dg/template/conv21.C new file mode 100644 index 0000000..1dc7b3d --- /dev/null +++ b/gcc/testsuite/g++.dg/template/conv21.C @@ -0,0 +1,14 @@ +// 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>; |