aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog10
-rw-r--r--gcc/cp/call.c12
-rw-r--r--gcc/cp/parser.c4
-rw-r--r--gcc/cp/tree.c15
-rw-r--r--gcc/cp/typeck.c4
-rw-r--r--gcc/testsuite/ChangeLog3
-rw-r--r--gcc/testsuite/g++.dg/pr84231.C29
7 files changed, 68 insertions, 9 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3623405..bd2e104 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,15 @@
2018-03-06 Alexandre Oliva <aoliva@redhat.com>
+ 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.
+
PR c++/84593
* init.c (build_zero_init_1): Zero-initialize references.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 11fe282..f83d51f 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4782,7 +4782,7 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
tree arg3_type;
tree result = NULL_TREE;
tree result_type = NULL_TREE;
- bool is_lvalue = true;
+ bool is_glvalue = true;
struct z_candidate *candidates = 0;
struct z_candidate *cand;
void *p;
@@ -5037,7 +5037,7 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
return error_mark_node;
}
- is_lvalue = false;
+ is_glvalue = false;
goto valid_operands;
}
/* [expr.cond]
@@ -5155,6 +5155,10 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
&& same_type_p (arg2_type, arg3_type))
{
result_type = arg2_type;
+ if (processing_template_decl)
+ /* Let lvalue_kind know this was a glvalue. */
+ result_type = cp_build_reference_type (result_type, xvalue_p (arg2));
+
arg2 = mark_lvalue_use (arg2);
arg3 = mark_lvalue_use (arg3);
goto valid_operands;
@@ -5167,7 +5171,7 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
cv-qualified) class type, overload resolution is used to
determine the conversions (if any) to be applied to the operands
(_over.match.oper_, _over.built_). */
- is_lvalue = false;
+ is_glvalue = false;
if (!same_type_p (arg2_type, arg3_type)
&& (CLASS_TYPE_P (arg2_type) || CLASS_TYPE_P (arg3_type)))
{
@@ -5361,7 +5365,7 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
/* We can't use result_type below, as fold might have returned a
throw_expr. */
- if (!is_lvalue)
+ if (!is_glvalue)
{
/* Expand both sides into the same slot, hopefully the target of
the ?: expression. We used to check for TARGET_EXPRs here,
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 460b5ea..a19bbe1 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -4963,7 +4963,9 @@ cp_parser_fold_expression (cp_parser *parser, tree expr1)
else if (is_binary_op (TREE_CODE (expr1)))
error_at (location_of (expr1),
"binary expression in operand of fold-expression");
- else if (TREE_CODE (expr1) == COND_EXPR)
+ else if (TREE_CODE (expr1) == COND_EXPR
+ || (REFERENCE_REF_P (expr1)
+ && TREE_CODE (TREE_OPERAND (expr1, 0)) == COND_EXPR))
error_at (location_of (expr1),
"conditional expression in operand of fold-expression");
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));
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index f535902..0c2ebd1 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -6567,10 +6567,6 @@ build_x_conditional_expr (location_t loc, tree ifexp, tree op1, tree op2,
{
tree min = build_min_non_dep (COND_EXPR, expr,
orig_ifexp, orig_op1, orig_op2);
- /* Remember that the result is an lvalue or xvalue. */
- if (glvalue_p (expr) && !glvalue_p (min))
- TREE_TYPE (min) = cp_build_reference_type (TREE_TYPE (min),
- !lvalue_p (expr));
expr = convert_from_reference (min);
}
return expr;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 9c94d36..3de87e9 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,8 @@
2018-03-06 Alexandre Oliva <aoliva@redhat.com>
+ PR c++/84231
+ * g++.dg/pr84231.C: New.
+
PR c++/84593
* g++.dg/cpp1y/pr84593.C: New.
diff --git a/gcc/testsuite/g++.dg/pr84231.C b/gcc/testsuite/g++.dg/pr84231.C
new file mode 100644
index 0000000..de7c89a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr84231.C
@@ -0,0 +1,29 @@
+// PR c++/84231 - overload resolution with cond_expr in a template
+
+// { dg-do compile }
+
+struct format {
+ template<typename T> format& operator%(const T&) { return *this; }
+ template<typename T> format& operator%(T&) { return *this; }
+};
+
+format f;
+
+template <typename>
+void function_template(bool b)
+{
+ // Compiles OK with array lvalue:
+ f % (b ? "x" : "x");
+
+ // Used to fails with pointer rvalue:
+ f % (b ? "" : "x");
+}
+
+void normal_function(bool b)
+{
+ // Both cases compile OK in non-template function:
+ f % (b ? "x" : "x");
+ f % (b ? "" : "x");
+
+ function_template<void>(b);
+}