C++ PATCH for c++/50835 (wrong lvalueness with ?: in template)

Message ID 4EB96039.6050104@redhat.com
State New
Headers show

Commit Message

Jason Merrill Nov. 8, 2011, 5 p.m.
In C++98 we can just conservatively assume that everything is an lvalue, 
since the things an lvalue can do are a superset of what an rvalue can 
do.  But that isn't the case in C++11, since an lvalue can't bind to an 
rvalue reference, so I changed lvalue_kind to work harder to figure out 
whether an expression is an lvalue or not.  PR 50835 is about a clash 
between this and our use of build_min_non_dep; for non-dependent 
expressions we first do full processing to figure out what their type is 
and then throw away most of that to build a simple expression with the 
original arguments and the resulting type.  Mostly this works fine, but 
it has problems with the complicated COND_EXPR lvalueness rules.  Fixed 
by representing the lvalueness of a COND_EXPR with a reference type.

Tested x86_64-pc-linux-gnu, applying to trunk.


commit 4bfc3e0d67779234e99e62c6f6ec3d5d56a207b0
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Nov 8 00:26:40 2011 -0500

    	PR c++/50835
    	* typeck.c (build_x_conditional_expr): Preserve lvalue/xvalueness.
    	* tree.c (lvalue_kind) [NON_DEPENDENT_EXPR]: Return clk_ordinary
    	in C++98.

diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index dc9fc95..841029f 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -203,10 +203,13 @@  lvalue_kind (const_tree ref)
       return lvalue_kind (BASELINK_FUNCTIONS (CONST_CAST_TREE (ref)));
-      /* We used to just return clk_ordinary for NON_DEPENDENT_EXPR because
-	 it was safe enough for C++98, but in C++0x lvalues don't bind to
-	 rvalue references, so we get bogus errors (c++/44870).  */
-      return lvalue_kind (TREE_OPERAND (ref, 0));
+      /* 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 < cxx0x)
+	return clk_ordinary;
+      else
+	return lvalue_kind (TREE_OPERAND (ref, 0));
       if (!TREE_TYPE (ref))
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 386f3b8..aed2891 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -5498,8 +5498,16 @@  build_x_conditional_expr (tree ifexp, tree op1, tree op2,
   expr = build_conditional_expr (ifexp, op1, op2, complain);
   if (processing_template_decl && expr != error_mark_node)
-    return build_min_non_dep (COND_EXPR, expr,
-			      orig_ifexp, orig_op1, orig_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 (lvalue_or_rvalue_with_address_p (expr)
+	  && !lvalue_or_rvalue_with_address_p (min))
+	TREE_TYPE (min) = cp_build_reference_type (TREE_TYPE (min),
+						   !real_lvalue_p (expr));
+      expr = convert_from_reference (min);
+    }
   return expr;
diff --git a/gcc/testsuite/g++.dg/template/lvalue2.C b/gcc/testsuite/g++.dg/template/lvalue2.C
new file mode 100644
index 0000000..e9074aa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/lvalue2.C
@@ -0,0 +1,18 @@ 
+// PR c++/50835
+struct A {};
+struct B
+  explicit B(A &);
+  operator A&() const;
+void should_be_lvalue(A&);
+template <typename>
+void f()
+    A v;
+    should_be_lvalue(true ? B(v) : v);