diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 37553c53c58d66a35a1fe69fa353d59d334c7000..42d8b1729b02527763fec6b3dcd09bf755572241 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,25 @@
+2010-09-27  Jason Merrill  <jason@redhat.com>
+
+	Require lvalues as specified by the standard.
+	* typeck.c (lvalue_or_else): Use real_lvalue_p.
+	(cp_build_addr_expr_1): Split out of cp_build_unary_op.
+	(cp_build_addr_expr, cp_build_addr_expr_strict): Interfaces.
+	(decay_conversion, get_member_function_from_ptrfunc): Adjust.
+	(build_x_unary_op, build_reinterpret_cast_1): Adjust.
+	(build_const_cast_1): Adjust.
+	* cp-tree.h: Declare new fns.
+	* call.c (build_this, convert_like_real, build_over_call): Adjust.
+	(initialize_reference): Adjust.
+	* class.c (build_base_path, convert_to_base_statically): Adjust.
+	(build_vfn_ref, resolve_address_of_overloaded_function): Adjust.
+	* cvt.c (build_up_reference, convert_to_reference): Adjust.
+	* decl.c (register_dtor_fn): Adjust.
+	* decl2.c (build_offset_ref_call_from_tree): Adjust.
+	* except.c (initialize_handler_parm): Adjust.
+	* init.c (build_offset_ref, build_delete, build_vec_delete): Adjust.
+	* rtti.c (build_dynamic_cast_1, tinfo_base_init): Adjust.
+	* tree.c (stabilize_expr): Adjust.
+
 2010-09-27  Nicola Pero  <nicola.pero@meta-innovation.com>
 
 	Merge from apple/trunk branch on FSF servers:
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index c3a579929c3c04f95b37e4e7183c3a44dac6d9e4..2e7083d45fd03705b416281a547899eb431c677f 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -2740,7 +2740,7 @@ build_this (tree obj)
   if (processing_template_decl)
     return build_address (obj);
 
-  return cp_build_unary_op (ADDR_EXPR, obj, 0, tf_warning_or_error);
+  return cp_build_addr_expr (obj, tf_warning_or_error);
 }
 
 /* Returns true iff functions are equivalent. Equivalent functions are
@@ -5157,7 +5157,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	  /* We are going to bind a reference directly to a base-class
 	     subobject of EXPR.  */
 	  /* Build an expression for `*((base*) &expr)'.  */
-	  expr = cp_build_unary_op (ADDR_EXPR, expr, 0, complain);
+	  expr = cp_build_addr_expr (expr, complain);
 	  expr = convert_to_base (expr, build_pointer_type (totype),
 				  !c_cast_p, /*nonnull=*/true, complain);
 	  expr = cp_build_indirect_ref (expr, RO_IMPLICIT_CONVERSION, complain);
@@ -5206,8 +5206,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
            VA_ARG_EXPR and CONSTRUCTOR expressions are special cases
            that need temporaries, even when their types are reference
            compatible with the type of reference being bound, so the
-           upcoming call to cp_build_unary_op (ADDR_EXPR, expr, ...)
-           doesn't fail.  */
+           upcoming call to cp_build_addr_expr doesn't fail.  */
 	if (convs->need_temporary_p
 	    || TREE_CODE (expr) == CONSTRUCTOR
 	    || TREE_CODE (expr) == VA_ARG_EXPR)
@@ -5264,7 +5263,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 
 	/* Take the address of the thing to which we will bind the
 	   reference.  */
-	expr = cp_build_unary_op (ADDR_EXPR, expr, 1, complain);
+	expr = cp_build_addr_expr (expr, complain);
 	if (expr == error_mark_node)
 	  return error_mark_node;
 
@@ -6011,7 +6010,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 
 	  arg2 = TYPE_SIZE_UNIT (as_base);
 	  arg1 = arg;
-	  arg0 = cp_build_unary_op (ADDR_EXPR, to, 0, complain);
+	  arg0 = cp_build_addr_expr (to, complain);
 
 	  if (!can_trust_pointer_alignment ())
 	    {
@@ -7994,7 +7993,7 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
 	    }
 	  else
 	    /* Take the address of EXPR.  */
-	    expr = cp_build_unary_op (ADDR_EXPR, expr, 0, tf_warning_or_error);
+	    expr = cp_build_addr_expr (expr, tf_warning_or_error);
 	  /* If a BASE_CONV was required, perform it now.  */
 	  if (base_conv_type)
 	    expr = (perform_implicit_conversion
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index c594d6add336e800d37a967b654dac1039cb1520..b093ce0fcc588ee2d87ee2469422b2b3fdb666be 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -282,7 +282,7 @@ build_base_path (enum tree_code code,
 
   if (!want_pointer)
     /* This must happen before the call to save_expr.  */
-    expr = cp_build_unary_op (ADDR_EXPR, expr, 0, tf_warning_or_error);
+    expr = cp_build_addr_expr (expr, tf_warning_or_error);
   else
     expr = mark_rvalue_use (expr);
 
@@ -557,8 +557,7 @@ convert_to_base_statically (tree expr, tree base)
 	 when processing a template because they do not handle C++-specific
 	 trees.  */
       gcc_assert (!processing_template_decl);
-      expr = cp_build_unary_op (ADDR_EXPR, expr, /*noconvert=*/1, 
-                             tf_warning_or_error);
+      expr = cp_build_addr_expr (expr, tf_warning_or_error);
       if (!integer_zerop (BINFO_OFFSET (base)))
         expr = fold_build2_loc (input_location,
 			    POINTER_PLUS_EXPR, pointer_type, expr,
@@ -661,8 +660,7 @@ build_vfn_ref (tree instance_ptr, tree idx)
      vtable entry is treated as a function pointer.  */
   if (TARGET_VTABLE_USES_DESCRIPTORS)
     aref = build1 (NOP_EXPR, TREE_TYPE (aref),
-		   cp_build_unary_op (ADDR_EXPR, aref, /*noconvert=*/1,
-                                   tf_warning_or_error));
+		   cp_build_addr_expr (aref, tf_warning_or_error));
 
   /* Remember this as a method reference, for later devirtualization.  */
   aref = build3 (OBJ_TYPE_REF, TREE_TYPE (aref), aref, instance_ptr, idx);
@@ -6464,7 +6462,7 @@ resolve_address_of_overloaded_function (tree target_type,
     }
 
   if (TYPE_PTRFN_P (target_type) || TYPE_PTRMEMFUNC_P (target_type))
-    return cp_build_unary_op (ADDR_EXPR, fn, 0, flags);
+    return cp_build_addr_expr (fn, flags);
   else
     {
       /* The target must be a REFERENCE_TYPE.  Above, cp_build_unary_op
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c78beb7c2f1ce92e138e17cc33cf3acf08a9834c..2ff0973d691ff8e630ab0b0941b5f4bd738a8e80 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5472,6 +5472,8 @@ extern tree build_x_binary_op			(enum tree_code, tree,
 extern tree build_x_array_ref			(tree, tree, tsubst_flags_t);
 extern tree build_x_unary_op			(enum tree_code, tree,
                                                  tsubst_flags_t);
+extern tree cp_build_addr_expr			(tree, tsubst_flags_t);
+extern tree cp_build_addr_expr_strict		(tree, tsubst_flags_t);
 extern tree cp_build_unary_op                   (enum tree_code, tree, int, 
                                                  tsubst_flags_t);
 extern tree unary_complex_lvalue		(enum tree_code, tree);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index ab2b6bf2d700cdfd5e5e61005bd563cdb2b29a38..00aa44aaa6082793a0fb37b1143bbc0b63ba3ad2 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -327,7 +327,7 @@ build_up_reference (tree type, tree arg, int flags, tree decl)
   /* If we had a way to wrap this up, and say, if we ever needed its
      address, transform all occurrences of the register, into a memory
      reference we could win better.  */
-  rval = cp_build_unary_op (ADDR_EXPR, arg, 1, tf_warning_or_error);
+  rval = cp_build_addr_expr (arg, tf_warning_or_error);
   if (rval == error_mark_node)
     return error_mark_node;
 
@@ -471,7 +471,7 @@ convert_to_reference (tree reftype, tree expr, int convtype,
 	warning (0, "casting %qT to %qT does not dereference pointer",
 		 intype, reftype);
 
-      rval = cp_build_unary_op (ADDR_EXPR, expr, 0, tf_warning_or_error);
+      rval = cp_build_addr_expr (expr, tf_warning_or_error);
       if (rval != error_mark_node)
 	rval = convert_force (build_pointer_type (TREE_TYPE (reftype)),
 			      rval, 0);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 07eddb551df2c51208b92e8ff43d24a801738b4b..18367b5e9db5e2805017a1ceb7726e7c00385ef0 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6354,8 +6354,8 @@ register_dtor_fn (tree decl)
 	   in, and, in general, it's cheaper to pass NULL than any
 	   other value.  */
 	addr = null_pointer_node;
-      arg2 = cp_build_unary_op (ADDR_EXPR, get_dso_handle_node (), 0,
-                                tf_warning_or_error);
+      arg2 = cp_build_addr_expr (get_dso_handle_node (),
+				 tf_warning_or_error);
       if (targetm.cxx.use_aeabi_atexit ())
 	{
 	  arg1 = cleanup;
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 63197705b3271cacdf9150161615c0255c201fc0..fcc83fb66ba52b16acae6b2f4ef03b8bf86ce51f 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4009,7 +4009,7 @@ build_offset_ref_call_from_tree (tree fn, VEC(tree,gc) **args)
       make_args_non_dependent (*args);
       object = build_non_dependent_expr (object);
       if (TREE_CODE (fn) == DOTSTAR_EXPR)
-	object = cp_build_unary_op (ADDR_EXPR, object, 0, tf_warning_or_error);
+	object = cp_build_addr_expr (object, tf_warning_or_error);
       VEC_safe_insert (tree, gc, *args, 0, object);
       /* Now that the arguments are done, transform FN.  */
       fn = build_non_dependent_expr (fn);
@@ -4023,8 +4023,7 @@ build_offset_ref_call_from_tree (tree fn, VEC(tree,gc) **args)
 	void B::g() { (this->*p)(); }  */
   if (TREE_CODE (fn) == OFFSET_REF)
     {
-      tree object_addr = cp_build_unary_op (ADDR_EXPR, object, 0,
-                                         tf_warning_or_error);
+      tree object_addr = cp_build_addr_expr (object, tf_warning_or_error);
       fn = TREE_OPERAND (fn, 1);
       fn = get_member_function_from_ptrfunc (&object_addr, fn);
       VEC_safe_insert (tree, gc, *args, 0, object_addr);
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 351e685a68702279d902e4d512ae069cec507d50..9d19aa984fd9799062d01b8fef30c61b807ea96e 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -376,7 +376,7 @@ initialize_handler_parm (tree decl, tree exp)
      pointer catch parm with the address of the temporary.  */
   if (TREE_CODE (init_type) == REFERENCE_TYPE
       && TYPE_PTR_P (TREE_TYPE (init_type)))
-    exp = cp_build_unary_op (ADDR_EXPR, exp, 1, tf_warning_or_error);
+    exp = cp_build_addr_expr (exp, tf_warning_or_error);
 
   exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
 
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 189bcbec9a5e30bfa39b65a4829bd93aaace1a12..5091d4e749eaba3806349ddc1a475e3e013c2d35 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1649,8 +1649,7 @@ build_offset_ref (tree type, tree member, bool address_p)
 	  if (flag_ms_extensions)
 	    {
 	      PTRMEM_OK_P (member) = 1;
-	      return cp_build_unary_op (ADDR_EXPR, member, 0, 
-                                        tf_warning_or_error);
+	      return cp_build_addr_expr (member, tf_warning_or_error);
 	    }
 	  error ("invalid use of non-static member function %qD",
 		 TREE_OPERAND (member, 1));
@@ -3246,7 +3245,7 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
       /* Don't check PROTECT here; leave that decision to the
 	 destructor.  If the destructor is accessible, call it,
 	 else report error.  */
-      addr = cp_build_unary_op (ADDR_EXPR, addr, 0, tf_warning_or_error);
+      addr = cp_build_addr_expr (addr, tf_warning_or_error);
       if (TREE_SIDE_EFFECTS (addr))
 	addr = save_expr (addr);
 
@@ -3486,7 +3485,7 @@ build_vec_delete (tree base, tree maxindex,
 	 bad name.  */
       maxindex = array_type_nelts_total (type);
       type = strip_array_types (type);
-      base = cp_build_unary_op (ADDR_EXPR, base, 1, tf_warning_or_error);
+      base = cp_build_addr_expr (base, tf_warning_or_error);
       if (TREE_SIDE_EFFECTS (base))
 	{
 	  base_init = get_target_expr (base);
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index c994683aae8e0e9d46a96db43d3df8661bdeb043..d7a151dec1faae27a7c028fd706e59f842e6e09d 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -693,10 +693,10 @@ build_dynamic_cast_1 (tree type, tree expr, tsubst_flags_t complain)
 	  static_type = TYPE_MAIN_VARIANT (TREE_TYPE (exprtype));
 	  td2 = get_tinfo_decl (target_type);
 	  mark_used (td2);
-	  td2 = cp_build_unary_op (ADDR_EXPR, td2, 0, complain);
+	  td2 = cp_build_addr_expr (td2, complain);
 	  td3 = get_tinfo_decl (static_type);
 	  mark_used (td3);
-	  td3 = cp_build_unary_op (ADDR_EXPR, td3, 0, complain);
+	  td3 = cp_build_addr_expr (td3, complain);
 
 	  /* Determine how T and V are related.  */
 	  boff = dcast_base_hint (static_type, target_type);
@@ -706,7 +706,7 @@ build_dynamic_cast_1 (tree type, tree expr, tsubst_flags_t complain)
 
 	  expr1 = expr;
 	  if (tc == REFERENCE_TYPE)
-	    expr1 = cp_build_unary_op (ADDR_EXPR, expr1, 0, complain);
+	    expr1 = cp_build_addr_expr (expr1, complain);
 
 	  elems[0] = expr1;
 	  elems[1] = td3;
@@ -913,8 +913,7 @@ tinfo_base_init (tinfo_s *ti, tree target)
 	}
 
       vtable_ptr = get_vtable_decl (real_type, /*complete=*/1);
-      vtable_ptr = cp_build_unary_op (ADDR_EXPR, vtable_ptr, 0, 
-                                   tf_warning_or_error);
+      vtable_ptr = cp_build_addr_expr (vtable_ptr, tf_warning_or_error);
 
       /* We need to point into the middle of the vtable.  */
       vtable_ptr = build2
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index ea01d1f4677f7d9abbef36240f262ecee9456967..d52387b3b654ac7b584e870d9388514db7b3dfc3 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -3008,7 +3008,7 @@ stabilize_expr (tree exp, tree* initp)
     }
   else
     {
-      exp = cp_build_unary_op (ADDR_EXPR, exp, 1, tf_warning_or_error);
+      exp = cp_build_addr_expr (exp, tf_warning_or_error);
       init_expr = get_target_expr (exp);
       exp = TARGET_EXPR_SLOT (init_expr);
       exp = cp_build_indirect_ref (exp, RO_NULL, tf_warning_or_error);
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 9959e409f538814e787c28173c52b25f102d5cf0..c25a17708b42ac5875c4cd25f06f684a64b05585 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1942,7 +1942,7 @@ decay_conversion (tree exp)
   if (invalid_nonstatic_memfn_p (exp, tf_warning_or_error))
     return error_mark_node;
   if (code == FUNCTION_TYPE || is_overloaded_fn (exp))
-    return cp_build_unary_op (ADDR_EXPR, exp, 0, tf_warning_or_error);
+    return cp_build_addr_expr (exp, tf_warning_or_error);
   if (code == ARRAY_TYPE)
     {
       tree adr;
@@ -1977,7 +1977,7 @@ decay_conversion (tree exp)
 	}
       /* This way is better for a COMPONENT_REF since it can
 	 simplify the offset for a component.  */
-      adr = cp_build_unary_op (ADDR_EXPR, exp, 1, tf_warning_or_error);
+      adr = cp_build_addr_expr (exp, tf_warning_or_error);
       return cp_convert (ptrtype, adr);
     }
 
@@ -3211,8 +3211,7 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
 	 vtable entry is treated as a function pointer.  */
       if (TARGET_VTABLE_USES_DESCRIPTORS)
 	e2 = build1 (NOP_EXPR, TREE_TYPE (e2),
-		     cp_build_unary_op (ADDR_EXPR, e2, /*noconvert=*/1,
-                                     tf_warning_or_error));
+		     cp_build_addr_expr (e2, tf_warning_or_error));
 
       e2 = fold_convert (TREE_TYPE (e3), e2);
       e1 = build_conditional_expr (e1, e2, e3, tf_warning_or_error);
@@ -4721,9 +4720,8 @@ build_x_unary_op (enum tree_code code, tree xarg, tsubst_flags_t complain)
 	      PTRMEM_OK_P (xarg) = ptrmem;
 	    }
 	}
-      else if (TREE_CODE (xarg) == TARGET_EXPR && (complain & tf_warning))
-	warning (0, "taking address of temporary");
-      exp = cp_build_unary_op (ADDR_EXPR, xarg, 0, complain);
+
+      exp = cp_build_addr_expr_strict (xarg, complain);
     }
 
   if (processing_template_decl && exp != error_mark_node)
@@ -4800,6 +4798,276 @@ build_nop (tree type, tree expr)
   return build1 (NOP_EXPR, type, expr);
 }
 
+/* Take the address of ARG, whatever that means under C++ semantics.
+   If STRICT_LVALUE is true, require an lvalue; otherwise, allow xvalues
+   and class rvalues as well.
+
+   Nothing should call this function directly; instead, callers should use
+   cp_build_addr_expr or cp_build_addr_expr_strict.  */
+
+static tree
+cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain)
+{
+  tree argtype;
+  tree val;
+
+  if (!arg || error_operand_p (arg))
+    return error_mark_node;
+
+  arg = mark_lvalue_use (arg);
+  argtype = lvalue_type (arg);
+
+  gcc_assert (TREE_CODE (arg) != IDENTIFIER_NODE
+	      || !IDENTIFIER_OPNAME_P (arg));
+
+  if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg)
+      && !really_overloaded_fn (TREE_OPERAND (arg, 1)))
+    {
+      /* They're trying to take the address of a unique non-static
+	 member function.  This is ill-formed (except in MS-land),
+	 but let's try to DTRT.
+	 Note: We only handle unique functions here because we don't
+	 want to complain if there's a static overload; non-unique
+	 cases will be handled by instantiate_type.  But we need to
+	 handle this case here to allow casts on the resulting PMF.
+	 We could defer this in non-MS mode, but it's easier to give
+	 a useful error here.  */
+
+      /* Inside constant member functions, the `this' pointer
+	 contains an extra const qualifier.  TYPE_MAIN_VARIANT
+	 is used here to remove this const from the diagnostics
+	 and the created OFFSET_REF.  */
+      tree base = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg, 0)));
+      tree fn = get_first_fn (TREE_OPERAND (arg, 1));
+      mark_used (fn);
+
+      if (! flag_ms_extensions)
+	{
+	  tree name = DECL_NAME (fn);
+	  if (!(complain & tf_error))
+	    return error_mark_node;
+	  else if (current_class_type
+		   && TREE_OPERAND (arg, 0) == current_class_ref)
+	    /* An expression like &memfn.  */
+	    permerror (input_location, "ISO C++ forbids taking the address of an unqualified"
+		       " or parenthesized non-static member function to form"
+		       " a pointer to member function.  Say %<&%T::%D%>",
+		       base, name);
+	  else
+	    permerror (input_location, "ISO C++ forbids taking the address of a bound member"
+		       " function to form a pointer to member function."
+		       "  Say %<&%T::%D%>",
+		       base, name);
+	}
+      arg = build_offset_ref (base, fn, /*address_p=*/true);
+    }
+
+  /* Uninstantiated types are all functions.  Taking the
+     address of a function is a no-op, so just return the
+     argument.  */
+  if (type_unknown_p (arg))
+    return build1 (ADDR_EXPR, unknown_type_node, arg);
+
+  if (TREE_CODE (arg) == OFFSET_REF)
+    /* We want a pointer to member; bypass all the code for actually taking
+       the address of something.  */
+    goto offset_ref;
+
+  /* Anything not already handled and not a true memory reference
+     is an error.  */
+  if (TREE_CODE (argtype) != FUNCTION_TYPE
+      && TREE_CODE (argtype) != METHOD_TYPE)
+    {
+      bool win = strict_lvalue ? real_lvalue_p (arg) : lvalue_p (arg);
+      if (!win)
+	{
+	  if (complain & tf_error)
+	    lvalue_error (lv_addressof);
+	  return error_mark_node;
+	}
+    }
+
+  if (TREE_CODE (argtype) == REFERENCE_TYPE)
+    {
+      tree type = build_pointer_type (TREE_TYPE (argtype));
+      arg = build1 (CONVERT_EXPR, type, arg);
+      return arg;
+    }
+  else if (pedantic && DECL_MAIN_P (arg))
+    {
+      /* ARM $3.4 */
+      /* Apparently a lot of autoconf scripts for C++ packages do this,
+	 so only complain if -pedantic.  */
+      if (complain & (flag_pedantic_errors ? tf_error : tf_warning))
+	pedwarn (input_location, OPT_pedantic,
+		 "ISO C++ forbids taking address of function %<::main%>");
+      else if (flag_pedantic_errors)
+	return error_mark_node;
+    }
+
+  /* Let &* cancel out to simplify resulting code.  */
+  if (TREE_CODE (arg) == INDIRECT_REF)
+    {
+      /* We don't need to have `current_class_ptr' wrapped in a
+	 NON_LVALUE_EXPR node.  */
+      if (arg == current_class_ref)
+	return current_class_ptr;
+
+      arg = TREE_OPERAND (arg, 0);
+      if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
+	{
+	  tree type = build_pointer_type (TREE_TYPE (TREE_TYPE (arg)));
+	  arg = build1 (CONVERT_EXPR, type, arg);
+	}
+      else
+	/* Don't let this be an lvalue.  */
+	arg = rvalue (arg);
+      return arg;
+    }
+
+  /* ??? Cope with user tricks that amount to offsetof.  */
+  if (TREE_CODE (argtype) != FUNCTION_TYPE
+      && TREE_CODE (argtype) != METHOD_TYPE
+      && argtype != unknown_type_node
+      && (val = get_base_address (arg))
+      && TREE_CODE (val) == INDIRECT_REF
+      && TREE_CONSTANT (TREE_OPERAND (val, 0)))
+    {
+      tree type = build_pointer_type (argtype);
+      tree op0 = fold_convert (type, TREE_OPERAND (val, 0));
+      tree op1 = fold_convert (sizetype, fold_offsetof (arg, val));
+      return fold_build2 (POINTER_PLUS_EXPR, type, op0, op1);
+    }
+
+  /* Handle complex lvalues (when permitted)
+     by reduction to simpler cases.  */
+  val = unary_complex_lvalue (ADDR_EXPR, arg);
+  if (val != 0)
+    return val;
+
+  switch (TREE_CODE (arg))
+    {
+    CASE_CONVERT:
+    case FLOAT_EXPR:
+    case FIX_TRUNC_EXPR:
+      /* Even if we're not being pedantic, we cannot allow this
+	 extension when we're instantiating in a SFINAE
+	 context.  */
+      if (! lvalue_p (arg) && complain == tf_none)
+	{
+	  if (complain & tf_error)
+	    permerror (input_location, "ISO C++ forbids taking the address of a cast to a non-lvalue expression");
+	  else
+	    return error_mark_node;
+	}
+      break;
+
+    case BASELINK:
+      arg = BASELINK_FUNCTIONS (arg);
+      /* Fall through.  */
+
+    case OVERLOAD:
+      arg = OVL_CURRENT (arg);
+      break;
+
+    case OFFSET_REF:
+    offset_ref:
+      /* Turn a reference to a non-static data member into a
+	 pointer-to-member.  */
+      {
+	tree type;
+	tree t;
+
+	gcc_assert (PTRMEM_OK_P (arg));
+
+	t = TREE_OPERAND (arg, 1);
+	if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+	  {
+	    if (complain & tf_error)
+	      error ("cannot create pointer to reference member %qD", t);
+	    return error_mark_node;
+	  }
+
+	type = build_ptrmem_type (context_for_name_lookup (t),
+				  TREE_TYPE (t));
+	t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
+	return t;
+      }
+
+    default:
+      break;
+    }
+
+  if (argtype != error_mark_node)
+    argtype = build_pointer_type (argtype);
+
+  /* In a template, we are processing a non-dependent expression
+     so we can just form an ADDR_EXPR with the correct type.  */
+  if (processing_template_decl || TREE_CODE (arg) != COMPONENT_REF)
+    {
+      val = build_address (arg);
+      if (TREE_CODE (arg) == OFFSET_REF)
+	PTRMEM_OK_P (val) = PTRMEM_OK_P (arg);
+    }
+  else if (TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK)
+    {
+      tree fn = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
+
+      /* We can only get here with a single static member
+	 function.  */
+      gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
+		  && DECL_STATIC_FUNCTION_P (fn));
+      mark_used (fn);
+      val = build_address (fn);
+      if (TREE_SIDE_EFFECTS (TREE_OPERAND (arg, 0)))
+	/* Do not lose object's side effects.  */
+	val = build2 (COMPOUND_EXPR, TREE_TYPE (val),
+		      TREE_OPERAND (arg, 0), val);
+    }
+  else if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
+    {
+      if (complain & tf_error)
+	error ("attempt to take address of bit-field structure member %qD",
+	       TREE_OPERAND (arg, 1));
+      return error_mark_node;
+    }
+  else
+    {
+      tree object = TREE_OPERAND (arg, 0);
+      tree field = TREE_OPERAND (arg, 1);
+      gcc_assert (same_type_ignoring_top_level_qualifiers_p
+		  (TREE_TYPE (object), decl_type_context (field)));
+      val = build_address (arg);
+    }
+
+  if (TREE_CODE (argtype) == POINTER_TYPE
+      && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
+    {
+      build_ptrmemfunc_type (argtype);
+      val = build_ptrmemfunc (argtype, val, 0,
+			      /*c_cast_p=*/false,
+			      tf_warning_or_error);
+    }
+
+  return val;
+}
+
+/* Take the address of ARG if it has one, even if it's an rvalue.  */
+
+tree
+cp_build_addr_expr (tree arg, tsubst_flags_t complain)
+{
+  return cp_build_addr_expr_1 (arg, 0, complain);
+}
+
+/* Take the address of ARG, but only if it's an lvalue.  */
+
+tree
+cp_build_addr_expr_strict (tree arg, tsubst_flags_t complain)
+{
+  return cp_build_addr_expr_1 (arg, 1, complain);
+}
+
 /* C++: Must handle pointers to members.
 
    Perhaps type instantiation should be extended to handle conversion
@@ -5066,238 +5334,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
     case ADDR_EXPR:
       /* Note that this operation never does default_conversion
 	 regardless of NOCONVERT.  */
-
-      argtype = lvalue_type (arg);
-
-      arg = mark_lvalue_use (arg);
-
-      if (TREE_CODE (arg) == OFFSET_REF)
-	goto offset_ref;
-
-      if (TREE_CODE (argtype) == REFERENCE_TYPE)
-	{
-	  tree type = build_pointer_type (TREE_TYPE (argtype));
-	  arg = build1 (CONVERT_EXPR, type, arg);
-	  return arg;
-	}
-      else if (pedantic && DECL_MAIN_P (arg))
-        {
-          /* ARM $3.4 */
-	  /* Apparently a lot of autoconf scripts for C++ packages do this,
-	     so only complain if -pedantic.  */
-          if (complain & (flag_pedantic_errors ? tf_error : tf_warning))
-            pedwarn (input_location, OPT_pedantic,
-		     "ISO C++ forbids taking address of function %<::main%>");
-          else if (flag_pedantic_errors)
-            return error_mark_node;
-        }
-
-      /* Let &* cancel out to simplify resulting code.  */
-      if (TREE_CODE (arg) == INDIRECT_REF)
-	{
-	  /* We don't need to have `current_class_ptr' wrapped in a
-	     NON_LVALUE_EXPR node.  */
-	  if (arg == current_class_ref)
-	    return current_class_ptr;
-
-	  arg = TREE_OPERAND (arg, 0);
-	  if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
-	    {
-	      tree type = build_pointer_type (TREE_TYPE (TREE_TYPE (arg)));
-	      arg = build1 (CONVERT_EXPR, type, arg);
-	    }
-	  else
-	    /* Don't let this be an lvalue.  */
-	    arg = rvalue (arg);
-	  return arg;
-	}
-
-      /* ??? Cope with user tricks that amount to offsetof.  */
-      if (TREE_CODE (argtype) != FUNCTION_TYPE
-	  && TREE_CODE (argtype) != METHOD_TYPE
-	  && argtype != unknown_type_node
-	  && (val = get_base_address (arg))
-	  && TREE_CODE (val) == INDIRECT_REF
-	  && TREE_CONSTANT (TREE_OPERAND (val, 0)))
-	{
-	  tree type = build_pointer_type (argtype);
-	  tree op0 = fold_convert (type, TREE_OPERAND (val, 0));
-	  tree op1 = fold_convert (sizetype, fold_offsetof (arg, val));
-	  return fold_build2 (POINTER_PLUS_EXPR, type, op0, op1);
-	}
-
-      /* Uninstantiated types are all functions.  Taking the
-	 address of a function is a no-op, so just return the
-	 argument.  */
-
-      gcc_assert (TREE_CODE (arg) != IDENTIFIER_NODE
-		  || !IDENTIFIER_OPNAME_P (arg));
-
-      if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg)
-	  && !really_overloaded_fn (TREE_OPERAND (arg, 1)))
-	{
-	  /* They're trying to take the address of a unique non-static
-	     member function.  This is ill-formed (except in MS-land),
-	     but let's try to DTRT.
-	     Note: We only handle unique functions here because we don't
-	     want to complain if there's a static overload; non-unique
-	     cases will be handled by instantiate_type.  But we need to
-	     handle this case here to allow casts on the resulting PMF.
-	     We could defer this in non-MS mode, but it's easier to give
-	     a useful error here.  */
-
-	  /* Inside constant member functions, the `this' pointer
-	     contains an extra const qualifier.  TYPE_MAIN_VARIANT
-	     is used here to remove this const from the diagnostics
-	     and the created OFFSET_REF.  */
-	  tree base = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg, 0)));
-	  tree fn = get_first_fn (TREE_OPERAND (arg, 1));
-	  mark_used (fn);
-
-	  if (! flag_ms_extensions)
-	    {
-	      tree name = DECL_NAME (fn);
-              if (!(complain & tf_error))
-                return error_mark_node;
-	      else if (current_class_type
-                       && TREE_OPERAND (arg, 0) == current_class_ref)
-                  /* An expression like &memfn.  */
-                permerror (input_location, "ISO C++ forbids taking the address of an unqualified"
-                           " or parenthesized non-static member function to form"
-                           " a pointer to member function.  Say %<&%T::%D%>",
-                           base, name);
-	      else
-		permerror (input_location, "ISO C++ forbids taking the address of a bound member"
-			   " function to form a pointer to member function."
-			   "  Say %<&%T::%D%>",
-			   base, name);
-	    }
-	  arg = build_offset_ref (base, fn, /*address_p=*/true);
-	}
-
-    offset_ref:
-      if (type_unknown_p (arg))
-	return build1 (ADDR_EXPR, unknown_type_node, arg);
-
-      /* Handle complex lvalues (when permitted)
-	 by reduction to simpler cases.  */
-      val = unary_complex_lvalue (code, arg);
-      if (val != 0)
-	return val;
-
-      switch (TREE_CODE (arg))
-	{
-	CASE_CONVERT:
-	case FLOAT_EXPR:
-	case FIX_TRUNC_EXPR:
-          /* Even if we're not being pedantic, we cannot allow this
-             extension when we're instantiating in a SFINAE
-             context.  */
-	  if (! lvalue_p (arg) && complain == tf_none)
-            {
-              if (complain & tf_error)
-                permerror (input_location, "ISO C++ forbids taking the address of a cast to a non-lvalue expression");
-              else
-                return error_mark_node;
-            }
-	  break;
-
-	case BASELINK:
-	  arg = BASELINK_FUNCTIONS (arg);
-	  /* Fall through.  */
-
-	case OVERLOAD:
-	  arg = OVL_CURRENT (arg);
-	  break;
-
-	case OFFSET_REF:
-	  /* Turn a reference to a non-static data member into a
-	     pointer-to-member.  */
-	  {
-	    tree type;
-	    tree t;
-
-	    if (!PTRMEM_OK_P (arg))
-	      return cp_build_unary_op (code, arg, 0, complain);
-
-	    t = TREE_OPERAND (arg, 1);
-	    if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
-	      {
-                if (complain & tf_error)
-                  error ("cannot create pointer to reference member %qD", t);
-		return error_mark_node;
-	      }
-
-	    type = build_ptrmem_type (context_for_name_lookup (t),
-				      TREE_TYPE (t));
-	    t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
-	    return t;
-	  }
-
-	default:
-	  break;
-	}
-
-      /* Anything not already handled and not a true memory reference
-	 is an error.  */
-      if (TREE_CODE (argtype) != FUNCTION_TYPE
-	  && TREE_CODE (argtype) != METHOD_TYPE
-	  && TREE_CODE (arg) != OFFSET_REF
-	  && !lvalue_or_else (arg, lv_addressof, complain))
-	return error_mark_node;
-
-      if (argtype != error_mark_node)
-	argtype = build_pointer_type (argtype);
-
-      /* In a template, we are processing a non-dependent expression
-	 so we can just form an ADDR_EXPR with the correct type.  */
-      if (processing_template_decl || TREE_CODE (arg) != COMPONENT_REF)
-	{
-	  val = build_address (arg);
-	  if (TREE_CODE (arg) == OFFSET_REF)
-	    PTRMEM_OK_P (val) = PTRMEM_OK_P (arg);
-	}
-      else if (TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK)
-	{
-	  tree fn = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
-
-	  /* We can only get here with a single static member
-	     function.  */
-	  gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
-		      && DECL_STATIC_FUNCTION_P (fn));
-	  mark_used (fn);
-	  val = build_address (fn);
-	  if (TREE_SIDE_EFFECTS (TREE_OPERAND (arg, 0)))
-	    /* Do not lose object's side effects.  */
-	    val = build2 (COMPOUND_EXPR, TREE_TYPE (val),
-			  TREE_OPERAND (arg, 0), val);
-	}
-      else if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
-	{
-          if (complain & tf_error)
-            error ("attempt to take address of bit-field structure member %qD",
-                   TREE_OPERAND (arg, 1));
-	  return error_mark_node;
-	}
-      else
-	{
-	  tree object = TREE_OPERAND (arg, 0);
-	  tree field = TREE_OPERAND (arg, 1);
-	  gcc_assert (same_type_ignoring_top_level_qualifiers_p
-		      (TREE_TYPE (object), decl_type_context (field)));
-	  val = build_address (arg);
-	}
-
-      if (TREE_CODE (argtype) == POINTER_TYPE
-	  && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
-	{
-	  build_ptrmemfunc_type (argtype);
-	  val = build_ptrmemfunc (argtype, val, 0,
-				  /*c_cast_p=*/false,
-				  tf_warning_or_error);
-	}
-
-      return val;
+      return cp_build_addr_expr (arg, complain);
 
     default:
       break;
@@ -6128,7 +6165,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
 	warning (0, "casting %qT to %qT does not dereference pointer",
 		 intype, type);
 
-      expr = cp_build_unary_op (ADDR_EXPR, expr, 0, complain);
+      expr = cp_build_addr_expr (expr, complain);
 
       if (warn_strict_aliasing > 2)
 	strict_aliasing_warning (TREE_TYPE (expr), type, expr);
@@ -6366,8 +6403,8 @@ build_const_cast_1 (tree dst_type, tree expr, bool complain,
 	}
       if (reference_type)
 	{
-	  expr = cp_build_unary_op (ADDR_EXPR, expr, 0, 
-                                    complain? tf_warning_or_error : tf_none);
+	  expr = cp_build_addr_expr (expr,
+				     complain ? tf_warning_or_error : tf_none);
 	  expr = build_nop (reference_type, expr);
 	  return convert_from_reference (expr);
 	}
@@ -8324,7 +8361,7 @@ non_reference (tree t)
 int
 lvalue_or_else (tree ref, enum lvalue_use use, tsubst_flags_t complain)
 {
-  int win = lvalue_p (ref);
+  int win = real_lvalue_p (ref);
 
   if (!win && (complain & tf_error))
     lvalue_error (use);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4f795dddb99e90c881002710c17f6c1a81738c6f..f56e70965e287865d5ab12369087411340cc3aa9 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2010-09-27  Jason Merrill  <jason@redhat.com>
+
+	* g++.dg/cpp0x/rv-lvalue-req.C: New.
+	* g++.dg/ext/complit11.C: Adjust.
+	* g++.old-deja/g++.law/temps1.C: Adjust.
+	* g++.old-deja/g++.ns/koenig6.C: Adjust.
+	* g++.old-deja/g++.oliva/partord1.C: Adjust.
+
 2010-09-27  Ian Lance Taylor  <iant@google.com>
 
 	* lib/target-supports.exp (check_effective_target_split_stack):
diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-lvalue-req.C b/gcc/testsuite/g++.dg/cpp0x/rv-lvalue-req.C
new file mode 100644
index 0000000000000000000000000000000000000000..ba1c306d9dcd262a0364af93e08a385bb0889eaf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/rv-lvalue-req.C
@@ -0,0 +1,12 @@
+// { dg-options -std=c++0x }
+
+template <class T> T&& declval();
+
+int main()
+{
+  &declval<int>();		        // { dg-error "lvalue" }
+  declval<int>() = declval<int>();	// { dg-error "lvalue" }
+  declval<int>()++;			// { dg-error "lvalue" }
+  --declval<int>();			// { dg-error "lvalue" }
+  declval<int>() += 1;			// { dg-error "lvalue" }
+}
diff --git a/gcc/testsuite/g++.dg/ext/complit11.C b/gcc/testsuite/g++.dg/ext/complit11.C
index 7b41795ece3713f3fad91cffae9f7ffa2f8cc900..2cff6cd2eb485f749f0a10767c79324955e33e9e 100644
--- a/gcc/testsuite/g++.dg/ext/complit11.C
+++ b/gcc/testsuite/g++.dg/ext/complit11.C
@@ -6,7 +6,7 @@ struct A { int i; };
 template<int t>
 void foo()
 {
-    ((struct A) { 0 }).i += 1;
+    ((struct A) { 0 }).i += 1;	// { dg-error "lvalue required" }
 }
 
 void g(void)
diff --git a/gcc/testsuite/g++.old-deja/g++.law/temps1.C b/gcc/testsuite/g++.old-deja/g++.law/temps1.C
index cd0bc876e8777e1ecb32304124c4b3e599ccba1c..2e6a41951162d08699db4ce4bc54ef7a7a38c07e 100644
--- a/gcc/testsuite/g++.old-deja/g++.law/temps1.C
+++ b/gcc/testsuite/g++.old-deja/g++.law/temps1.C
@@ -16,4 +16,4 @@ struct cookie
 };
 
 cookie cat(&foo("apabepa"));// { dg-warning "deprecated conversion" "dep" }
-// { dg-warning "taking address of temporary" "add" { target *-*-* } 18 }
+// { dg-error "lvalue required" "lvalue" { target *-*-* } 18 }
diff --git a/gcc/testsuite/g++.old-deja/g++.ns/koenig6.C b/gcc/testsuite/g++.old-deja/g++.ns/koenig6.C
index f77d975300cd981c2eb5136f1ff48e77bda3847b..b5fa9c989963ba6adb3e3f90799354f7f4959815 100644
--- a/gcc/testsuite/g++.old-deja/g++.ns/koenig6.C
+++ b/gcc/testsuite/g++.old-deja/g++.ns/koenig6.C
@@ -2,12 +2,12 @@
 namespace A{
   struct X{};
 
-  X foo(X a){return a;}
+  X* foo(X a);
   void bar(X*){}
 }
 
 int main()
 {
   A::X x;
-  bar(&foo(x));  // { dg-warning "" } address of temporary
+  bar(foo(x));
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.oliva/partord1.C b/gcc/testsuite/g++.old-deja/g++.oliva/partord1.C
index 555931725d2896ff027d44e091eeb7b744c37c8e..34fe92e64076fbeaf5f8412db440eceaf8f20446 100644
--- a/gcc/testsuite/g++.old-deja/g++.oliva/partord1.C
+++ b/gcc/testsuite/g++.old-deja/g++.oliva/partord1.C
@@ -14,10 +14,10 @@ template <typename T> class bar {
 };
 
 template <typename T> void foo(T) {
-  bar<T>().i = 0; // ok, I'm a friend
+  bar<T>().i; // ok, I'm a friend
 }
 template <typename T> void foo(T*) {
-  bar<T*>().i = 1; // { dg-error "" } not a friend
+  bar<T*>().i; // { dg-error "" } not a friend
 }
 
 int main() {