diff options
author | Alexandre Oliva <aoliva@redhat.com> | 2018-03-06 06:25:12 +0000 |
---|---|---|
committer | Alexandre Oliva <aoliva@gcc.gnu.org> | 2018-03-06 06:25:12 +0000 |
commit | 23d63b459c032c41f99a7c735a33558e77d6baf7 (patch) | |
tree | 13f3e408fba20d613f4296a5ea55fd51999a632e /gcc/cp/tree.c | |
parent | 2e1a7ecb2d8f1ee3f88fd2906ab16eb30ab525f7 (diff) | |
download | gcc-23d63b459c032c41f99a7c735a33558e77d6baf7.zip gcc-23d63b459c032c41f99a7c735a33558e77d6baf7.tar.gz gcc-23d63b459c032c41f99a7c735a33558e77d6baf7.tar.bz2 |
[C++] [PR84231] overload on cond_expr in template
A non-type-dependent COND_EXPR within a template is reconstructed with
the original operands, after one with non-dependent proxies is built to
determine its result type. This is problematic because the operands of
a COND_EXPR determined to be an rvalue may have been converted to denote
their rvalue nature. The reconstructed one, however, won't have such
conversions, so lvalue_kind may not recognize it as an rvalue, which may
lead to e.g. incorrect overload resolution decisions.
If we mistake such a COND_EXPR for an lvalue, overload resolution might
regard a conversion sequence that binds it to a non-const reference as
viable, and then select that over one that binds it to a const
reference. Only after template substitution would we rebuild the
COND_EXPR, realize it is an rvalue, and conclude the reference binding
is ill-formed, but at that point we'd have long discarded any alternate
candidates we could have used.
This patch modifies the logic that determines whether a
(non-type-dependent) COND_EXPR in a template is an lvalue, to rely on
its type, more specifically, on the presence of a REFERENCE_TYPE
wrapper. In order to avoid a type bootstrapping problem, the
REFERENCE_TYPE that wraps the type of some such COND_EXPRs is
introduced earlier, so that we don't have to test for lvalueness of
the expression using the very code that we wish to change.
for gcc/cp/ChangeLog
PR c++/84231
* tree.c (lvalue_kind): Use presence/absence of REFERENCE_TYPE
only while processing template decls.
* typeck.c (build_x_conditional_expr): Move wrapping of
reference type around type...
* call.c (build_conditional_expr_1): ... here. Rename
is_lvalue to is_glvalue.
* parser.c (cp_parser_fold_expression): Catch REFERENCE_REF_P
INDIRECT_REF of COND_EXPR too.
for gcc/testsuite/ChangeLog
PR c++/84231
* g++.dg/pr84231.C: New.
From-SVN: r258271
Diffstat (limited to 'gcc/cp/tree.c')
-rw-r--r-- | gcc/cp/tree.c | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 19f1c06..4cf2126 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -194,6 +194,21 @@ lvalue_kind (const_tree ref) break; case COND_EXPR: + if (processing_template_decl) + { + /* Within templates, a REFERENCE_TYPE will indicate whether + the COND_EXPR result is an ordinary lvalue or rvalueref. + Since REFERENCE_TYPEs are handled above, if we reach this + point, we know we got a plain rvalue. Unless we have a + type-dependent expr, that is, but we shouldn't be testing + lvalueness if we can't even tell the types yet! */ + gcc_assert (!type_dependent_expression_p (CONST_CAST_TREE (ref))); + if (CLASS_TYPE_P (TREE_TYPE (ref)) + || TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE) + return clk_class; + else + return clk_none; + } op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 1) ? TREE_OPERAND (ref, 1) : TREE_OPERAND (ref, 0)); |