This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Fix PR c++/69694 (non-dependent MODOP_EXPR with NULL type)
- From: Patrick Palka <patrick at parcs dot ath dot cx>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Cc: Jason Merrill <jason at redhat dot com>, Patrick Palka <patrick at parcs dot ath dot cx>
- Date: Wed, 2 Mar 2016 13:40:42 -0500
- Subject: Re: [PATCH] Fix PR c++/69694 (non-dependent MODOP_EXPR with NULL type)
- Authentication-results: sourceware.org; auth=none
- References: <1456006974-7430-1-git-send-email-patrick at parcs dot ath dot cx>
On Sat, Feb 20, 2016 at 5:22 PM, Patrick Palka <patrick@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);
~~~^~~~