Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk/14? For trunk as a follow-up I can implement the mentionted representation change to use CALL_EXPR instead of MODOP_EXPR for a non-dependent simple assignment expression that resolved to an operator= overload.
-- >8 -- r14-4111 made us check non-dependent assignment expressions ahead of time, as well as give them a type. Unlike for compound assignment expressions however, if a simple assignment resolves to an operator overload we still represent it as a (typed) MODOP_EXPR instead of a CALL_EXPR to the selected overload. This, I reckoned, was just a pessimization (since we'll have to repeat overload resolution at instantiatiation time) but should be harmless. (And it should be easily fixable by giving cp_build_modify_expr an 'overload' parameter). But it breaks the below testcase ultimately because MODOP_EXPR (of non-reference type) is always treated as an lvalue according to lvalue_kind, which is incorrect for the MODOP_EXPR representing x=42. We can fix this by representing such assignment expressions as CALL_EXPRs matching what that of compound assignments, but that turns out to require some tweaking of our -Wparentheses warning logic which seems unsuitable for backporting. So this patch instead more conservatively fixes this by refining lvalue_kind to consider the type of a (simple) MODOP_EXPR as we already do for COND_EXPR. PR c++/114994 gcc/cp/ChangeLog: * tree.cc (lvalue_kind) <case MODOP_EXPR>: Consider the type of a simple assignment expression. gcc/testsuite/ChangeLog: * g++.dg/template/non-dependent32.C: New test. --- gcc/cp/tree.cc | 7 +++++++ .../g++.dg/template/non-dependent32.C | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 gcc/testsuite/g++.dg/template/non-dependent32.C diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index f1a23ffe817..0b97b789aab 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -275,6 +275,13 @@ lvalue_kind (const_tree ref) /* We expect to see unlowered MODOP_EXPRs only during template processing. */ gcc_assert (processing_template_decl); + if (TREE_CODE (TREE_OPERAND (ref, 1)) == NOP_EXPR + && CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0)))) + /* As in the COND_EXPR case, but for non-dependent assignment + expressions created by build_x_modify_expr. */ + goto default_; + /* A non-dependent (simple or compound) assignment expression that + resolved to a built-in assignment function. */ return clk_ordinary; case MODIFY_EXPR: diff --git a/gcc/testsuite/g++.dg/template/non-dependent32.C b/gcc/testsuite/g++.dg/template/non-dependent32.C new file mode 100644 index 00000000000..54252c7dfaf --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent32.C @@ -0,0 +1,18 @@ +// PR c++/114994 +// { dg-do compile { target c++11 } } + +struct udl_arg { + udl_arg operator=(int); +}; + +void f(udl_arg&&); + +template<class> +void g() { + udl_arg x; + f(x=42); // { dg-bogus "cannot bind" } +} + +int main() { + g<int>(); +} -- 2.45.0.119.g0f3415f1f8