The NOP_EXPR are changing the "visible" types without changing the representation; sometimes it is about lvalueness being thrown away (which I suspect is the case here). I've always grumbled about not having a uniform way of saying "convert this expression to type T to an expression of type U".
On Sat, May 5, 2012 at 5:38 AM, Paolo Carlini <paolo.carl...@oracle.com> wrote: > 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. > > > >