Hi,
I'm analyzing this PR and the various testcases which come with it. It
looks like we have indeed two separate issues: one, which looks simpler,
with decltype, leading to ICEs; a more complex one with constexpr. The
former is about ADDR_EXPR unhandled in the finish_decltype_type switch
for this testcase:
template <typename T, T V>
struct C
{
static constexpr decltype(V) c() { return V; }
};
struct D
{
static constexpr int d() { return 10; }
};
static_assert((C<int(*)(), &D::d>::c())() == 10, "oops");
Would it make sense to just handle ADDR_EXPR too like in the patchlet
below? It seems we are in this case too in the same situation which led
to handling INTEGER_CST and PTRMEM_CST, or we have an issue with
const-ness?
The problems with constexpr look more nasty, are all about testcases
similar to the above, many variants of it, like:
template <typename T, T V>
struct B
{
typedef T type;
static constexpr type b() { return V; }
};
struct D
{
static constexpr int d() { return 10; }
};
static_assert((B<int(*)(), &D::d>::b())() == 10, "oops");
which is rejected like:
52282.C:32:1: error: non-constant condition for static assertion
static_assert((B<int(*)(), &D::d>::b())() == 10, "oops"); // line 30
52282.C:32:38: error: expression āD::dā does not designate a constexpr
function
static_assert((B<int(*)(), &D::d>::b())() == 10, "oops"); // line 30
For this kind of testcase I see a lot of NOP_EXPRs around, which I don't
really understand and *appear* to confuse quite a bit code we have in
the cxx_eval_* functions. For example, for the above, one crops up at
the beginning of cxx_eval_call_expression:
if (TREE_CODE (fun) != FUNCTION_DECL)
{
/* Might be a constexpr function pointer. */
fun = cxx_eval_constant_expression (old_call, fun, allow_non_constant,
/*addr*/false, non_constant_p);
if (TREE_CODE (fun) == ADDR_EXPR)
fun = TREE_OPERAND (fun, 0);
}
as the fun returned by cxx_eval_constant_expression and the logic
handling ADDR_EXPR doesn't seem to work as designed. If I force a
STRIP_NOPS the testcase is "accepted". But really I see something
brittle about all these NOP_EXPRs and I'm looking for comments / hints.
I don't think we just want to add STRIP_NOPS in a ton of places, which,
if I understand correctly, would probably also imply the need to
unshare_expr, but I don't have brilliant ideas right now...
Another kind of weird issue we are facing is for:
template <typename T, T V>
struct W_ { static constexpr T value = V; };
constexpr struct C {
constexpr int c1() const { return 10; }
} c;
static_assert((c.*W_<int(C::*)()const, &C::c1>::value)() == 10, "oops");
which leads to:
ice.cpp:72:1: error: non-constant condition for static assertion
static_assert((c.*W_<int(C::*)()const, &C::c1>::value)() == 10, "oops");
ice.cpp:72:56: error: expression ā0uā does not designate a constexpr
function
static_assert((c.*W_<int(C::*)()const, &C::c1>::value)() == 10, "oops");
note the '0u'! (the error message comes from the beginning of
cxx_eval_call_expression) I guess these issues should not require major
surgeries if a testcase like the latter but using, instead of W_:
template <typename T, T V>
struct W { static constexpr T value() { return V; } };
works fine. In this case too, if I follow the long chain of cxx_eval_* I
see a lot of NOP_EXPRs, but I'm not sure it's all there is to the issue,
maybe we are just doing something wrong with the pointers...
Thanks for any comment!
Paolo.
Index: semantics.c
===================================================================
--- semantics.c (revision 187192)
+++ semantics.c (working copy)
@@ -5268,6 +5268,7 @@ finish_decltype_type (tree expr, bool id_expressio
case INTEGER_CST:
case PTRMEM_CST:
+ case ADDR_EXPR:
/* We can get here when the id-expression refers to an
enumerator or non-type template parameter. */
type = TREE_TYPE (expr);