On Sat, Feb 20, 2016 at 5:22 PM, Patrick Palka <patr...@parcs.ath.cx> wrote: > The problem here is that when processing_template_decl, the non-compound > MODOP_EXPRs we build (i.e. a = b and not a += b) are given a NULL > TREE_TYPE even if none of its operands are dependent. This causes > decltypes such as "decltype (a = b)" (where a and b are not dependent) > to fail to get resolved to a concrete type since the MODOP_EXPR within > is considered to be dependent according to > instantiation_dependent_expression_p. > And in the case of decltype65.C this causes partial-specialization > selection to malfunction since the template parameter type > "void_t<decltype (a = b)>" never gets resolved to "void". > > This patch fixes this issue by adjusting build_x_modify_expr to give > non-compound non-dependent MODOP_EXPRs an accurate non-NULL TREE_TYPE. > To do this we have to first process the assignment at template > processing time using cp_build_modify_expr. This means we will now > diagnose invalid assignments at template-processing time, necessitating > some minor adjustments to the testsuite. > > The changes to the test suite are trivial except for the change to > unary2.C. Here, whereas before we were always failing to diagnose at > template processing time the invalid assignment -n = 0 (whose LHS is not > an lvalue), after this patch we now fail to diagnose this invalid > assignment only with c++98. This is because lvalue_kind treats > NON_DEPENDENT_EXPRs differently depending on the cxx_dialect: > > case NON_DEPENDENT_EXPR: > /* We just return clk_ordinary for NON_DEPENDENT_EXPR in C++98, but > in C++11 lvalues don't bind to rvalue references, so we need to > work harder to avoid bogus errors (c++/44870). */ > if (cxx_dialect < cxx11) > return clk_ordinary; > else > return lvalue_kind (TREE_OPERAND (ref, 0)); > > So in c++98 mode any NON_DEPENDENT_EXPR is considered to be a valid LHS > of an assignment even if the underlying expression is not actually an > lvalue. Removing this special case is not completely trivial. > > Bootstrap + regtest in progress on x86_64-pc-linux-gnu, will also test > against Boost. Does this look OK if testing passes? > > gcc/cp/ChangeLog: > > PR c++/69694 > * semantics.c (finish_paranthesized_expr): Set the > TREE_NO_WARNING flag on MODOP_EXPRs that are wrapped in an > implicit INDIRECT_REF. > * typeck.c (build_x_modify_expr): Give the middle operand of > the resulting MODOP_EXPR a dummy non-NULL type. When MODIFYCODE > is NOP_EXPR and the operands are not dependent, don't exit early > and instead process the expression with cp_build_modify_expr. > Assert that the return value of build_new_op is non-NULL. > > gcc/testsuite/ChangeLog: > > PR c++/69694 > * g++.dg/cpp0x/decltype64.C: New test. > * g++.dg/cpp0x/decltype65.C: New test. > * g++.dg/expr/unary2.C: The XFAILs no longer fail > on c++11 or later, only with c++98. > * g++.dg/cpp0x/error2.C: Adjust expected error message. > * g++.dg/ext/fixed1.C: Likewise. > * g++.dg/template/error35.C: Likewise. > * g++.dg/template/init7.C: Likewise.
Just noticed that this patch would cause auto deduction to malfunction when a non-dependent plain assignment resolves to an operator overload. In that case we should be building the assignment using build_min_non_dep_op_overload as well. Test case: struct Foo { int operator=(const Foo &) { return 5; } }; template <typename> void foo (Foo &x, Foo &y) { auto&& a = (x = y); const int &b = a; } void bar () { Foo a; Foo b; foo<int> (a, b); } operator=.cc: In instantiation of ‘void foo(Foo&, Foo&) [with <template-parameter-1-1> = int]’: operator=.cc:23:17: required from here operator=.cc:13:17: error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’ auto&& a = (x = y); ~~~^~~~