This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] C++: Fix ICE in fold_for_warn on CAST_EXPR (PR c++/83974)
- From: David Malcolm <dmalcolm at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: David Malcolm <dmalcolm at redhat dot com>
- Date: Tue, 23 Jan 2018 09:27:44 -0500
- Subject: [PATCH] C++: Fix ICE in fold_for_warn on CAST_EXPR (PR c++/83974)
- Authentication-results: sourceware.org; auth=none
PR c++/83974 reports an ICE within fold_for_warn when calling
cxx_eval_constant_expression on a CAST_EXPR.
This comes from a pointer-to-member-function. The result of
build_ptrmemfunc (within cp_convert_to_pointer for a null ptr) is
a CONSTRUCTOR containing, amongst other things a CAST_EXPR of a
TREE_LIST containing the zero INTEGER_CST.
After r256804, fold_for_warn within a template calls
fold_non_dependent_expr.
For this tree, is_nondependent_constant_expression returns true.
potential_constant_expression_1 has these cases:
case TREE_LIST:
{
gcc_assert (TREE_PURPOSE (t) == NULL_TREE
|| DECL_P (TREE_PURPOSE (t)));
if (!RECUR (TREE_VALUE (t), want_rval))
return false;
if (TREE_CHAIN (t) == NULL_TREE)
return true;
return RECUR (TREE_CHAIN (t), want_rval);
}
and:
case CAST_EXPR:
case CONST_CAST_EXPR:
case STATIC_CAST_EXPR:
case REINTERPRET_CAST_EXPR:
case IMPLICIT_CONV_EXPR:
if (cxx_dialect < cxx11
&& !dependent_type_p (TREE_TYPE (t))
&& !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (t)))
/* In C++98, a conversion to non-integral type can't be part of a
constant expression. */
{
// reject it
}
// accept it
and thus returns true for the CAST_EXPR and TREE_LIST, and hence for the
CONSTRUCTOR as a whole.
However, cxx_eval_constant_expression does not support these tree codes,
ICEing in the default case with:
internal_error ("unexpected expression %qE of kind %s", t,
It seems that, given potential_constant_expression_1 can return true for
these cases, then cxx_eval_constant_expression ought to handle them, which
this patch implements, fixing the ICE.
Successfully bootstrapped®rtested on x86_64-pc-linux-gnu.
OK for trunk?
gcc/cp/ChangeLog:
PR c++/83974
* constexpr.c (cxx_eval_constant_expression): Handle case
TREE_LIST. Handle CAST_EXPR, CONST_CAST_EXPR, STATIC_CAST_EXPR,
REINTERPRET_CAST_EXPR and IMPLICIT_CONV_EXPR via
cxx_eval_unary_expression.
gcc/testsuite/ChangeLog:
PR c++/83974
* g++.dg/warn/pr83974.C: New test case.
---
gcc/cp/constexpr.c | 27 +++++++++++++++++++++++++++
gcc/testsuite/g++.dg/warn/pr83974.C | 11 +++++++++++
2 files changed, 38 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/warn/pr83974.C
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index ca7f369..a593132 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -4348,6 +4348,24 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
}
break;
+ case TREE_LIST:
+ {
+ tree value, chain;
+ gcc_assert (TREE_PURPOSE (t) == NULL_TREE
+ || DECL_P (TREE_PURPOSE (t)));
+ value = cxx_eval_constant_expression (ctx, TREE_VALUE (t), lval,
+ non_constant_p, overflow_p,
+ jump_target);
+ if (TREE_CHAIN (t))
+ chain = cxx_eval_constant_expression (ctx, TREE_CHAIN (t), lval,
+ non_constant_p, overflow_p,
+ jump_target);
+ else
+ chain = NULL_TREE;
+ r = tree_cons (TREE_PURPOSE (t), value, chain);
+ }
+ break;
+
case POINTER_PLUS_EXPR:
case POINTER_DIFF_EXPR:
case PLUS_EXPR:
@@ -4594,6 +4612,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
return cxx_eval_statement_list (&new_ctx, t,
non_constant_p, overflow_p, jump_target);
+ case CAST_EXPR:
+ case CONST_CAST_EXPR:
+ case STATIC_CAST_EXPR:
+ case REINTERPRET_CAST_EXPR:
+ case IMPLICIT_CONV_EXPR:
+ r = cxx_eval_unary_expression (ctx, t, lval,
+ non_constant_p, overflow_p);
+ break;
+
case BIND_EXPR:
return cxx_eval_constant_expression (ctx, BIND_EXPR_BODY (t),
lval,
diff --git a/gcc/testsuite/g++.dg/warn/pr83974.C b/gcc/testsuite/g++.dg/warn/pr83974.C
new file mode 100644
index 0000000..af12c2d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/pr83974.C
@@ -0,0 +1,11 @@
+// { dg-options "-Wtautological-compare" }
+
+struct A {
+ typedef void (A::*B) ();
+ operator B ();
+};
+template <typename>
+struct C {
+ void foo () { d == 0; }
+ A d;
+};
--
1.8.5.3