In C++14 mode the compiler turns (x) into static_cast<X&>(x) in order to prevent decltype(auto) from treating it as plain x. But that also messes with the magic for treating a local variable as an rvalue in a return statement. So we need to mark the obfuscation as coming from (x) so we can undo it in check_return_expr.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit c7543bd112b4c0f7f66b555aed23ddf3c2459f48
Author: Jason Merrill <ja...@redhat.com>
Date:   Wed Oct 8 17:04:56 2014 -0400

    	PR c++/63437
    	* cp-tree.h (REF_PARENTHESIZED_P): Also allow INDIRECT_REF.
    	* semantics.c (force_paren_expr): And set it.
    	* typeck.c (check_return_expr): And handle it.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 857af76..cdc8927 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -101,7 +101,7 @@ c-common.h, not after.
       TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR)
       FNDECL_USED_AUTO (in FUNCTION_DECL)
       DECLTYPE_FOR_LAMBDA_PROXY (in DECLTYPE_TYPE)
-      REF_PARENTHESIZED_P (in COMPONENT_REF, SCOPE_REF)
+      REF_PARENTHESIZED_P (in COMPONENT_REF, INDIRECT_REF)
       AGGR_INIT_ZERO_FIRST (in AGGR_INIT_EXPR)
    3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
       ICS_BAD_FLAG (in _CONV)
@@ -3059,11 +3059,12 @@ extern void decl_shadowed_for_var_insert (tree, tree);
 #define PAREN_STRING_LITERAL_P(NODE) \
   TREE_LANG_FLAG_0 (STRING_CST_CHECK (NODE))
 
-/* Indicates whether a COMPONENT_REF has been parenthesized.  Currently
-   only set some of the time in C++14 mode.  */
+/* Indicates whether a COMPONENT_REF has been parenthesized, or an
+   INDIRECT_REF comes from parenthesizing a VAR_DECL.  Currently only set
+   some of the time in C++14 mode.  */
 
 #define REF_PARENTHESIZED_P(NODE) \
-  TREE_LANG_FLAG_2 (COMPONENT_REF_CHECK (NODE))
+  TREE_LANG_FLAG_2 (TREE_CHECK2 ((NODE), COMPONENT_REF, INDIRECT_REF))
 
 /* Nonzero if this AGGR_INIT_EXPR provides for initialization via a
    constructor call, rather than an ordinary function call.  */
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index b11ec09..ba09e72 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1637,6 +1637,8 @@ force_paren_expr (tree expr)
 	  bool rval = !!(kind & clk_rvalueref);
 	  type = cp_build_reference_type (type, rval);
 	  expr = build_static_cast (type, expr, tf_error);
+	  if (expr != error_mark_node)
+	    REF_PARENTHESIZED_P (expr) = true;
 	}
     }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 6a357bf..b4e6824 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -8671,6 +8671,20 @@ check_return_expr (tree retval, bool *no_warning)
       if (VOID_TYPE_P (functype))
 	return error_mark_node;
 
+      /* If we had an id-expression obfuscated by force_paren_expr, we need
+	 to undo it so we can try to treat it as an rvalue below.  */
+      if (cxx_dialect >= cxx14
+	  && INDIRECT_REF_P (retval)
+	  && REF_PARENTHESIZED_P (retval))
+	{
+	  retval = TREE_OPERAND (retval, 0);
+	  while (TREE_CODE (retval) == NON_LVALUE_EXPR
+		 || TREE_CODE (retval) == NOP_EXPR)
+	    retval = TREE_OPERAND (retval, 0);
+	  gcc_assert (TREE_CODE (retval) == ADDR_EXPR);
+	  retval = TREE_OPERAND (retval, 0);
+	}
+
       /* Under C++11 [12.8/32 class.copy], a returned lvalue is sometimes
 	 treated as an rvalue for the purposes of overload resolution to
 	 favor move constructors over copy constructors.
diff --git a/gcc/testsuite/g++.dg/cpp1y/paren1.C b/gcc/testsuite/g++.dg/cpp1y/paren1.C
new file mode 100644
index 0000000..809f251
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/paren1.C
@@ -0,0 +1,31 @@
+// PR c++/63437
+// { dg-do compile { target c++11 } }
+
+struct X // movable but not copyable
+{
+    X() = default;
+    X(X &&) = default;
+
+    X(const X &) = delete;
+};
+
+X non_parenthesized()
+{
+    X x;
+    return x; // works
+}
+
+X parenthesized()
+{
+    X x;
+    return (x); // error: use of deleted function 'X::X(const X&)'
+}
+
+template <class T>
+T parenthesized_t()
+{
+  T t;
+  return (t);
+}
+
+template X parenthesized_t<X>();

Reply via email to