Require lvalues as specified by the standard.
authorJason Merrill <jason@redhat.com>
Mon, 27 Sep 2010 20:05:34 +0000 (16:05 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 27 Sep 2010 20:05:34 +0000 (16:05 -0400)
* 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.

From-SVN: r164666

18 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/except.c
gcc/cp/init.c
gcc/cp/rtti.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/rv-lvalue-req.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/complit11.C
gcc/testsuite/g++.old-deja/g++.law/temps1.C
gcc/testsuite/g++.old-deja/g++.ns/koenig6.C
gcc/testsuite/g++.old-deja/g++.oliva/partord1.C

index 37553c5..42d8b17 100644 (file)
@@ -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:
index c3a5799..2e7083d 100644 (file)
@@ -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
index c594d6a..b093ce0 100644 (file)
@@ -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
index c78beb7..2ff0973 100644 (file)
@@ -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);
index ab2b6bf..00aa44a 100644 (file)
@@ -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);
index 07eddb5..18367b5 100644 (file)
@@ -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;
index 6319770..fcc83fb 100644 (file)
@@ -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);
index 351e685..9d19aa9 100644 (file)
@@ -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);
 
index 189bcbe..5091d4e 100644 (file)
@@ -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);
index c994683..d7a151d 100644 (file)
@@ -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
index ea01d1f..d52387b 100644 (file)
@@ -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);
index 9959e40..c25a177 100644 (file)
@@ -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);
index 4f795dd..f56e709 100644 (file)
@@ -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 (file)
index 0000000..ba1c306
--- /dev/null
@@ -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" }
+}
index 7b41795..2cff6cd 100644 (file)
@@ -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)
index cd0bc87..2e6a419 100644 (file)
@@ -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 }
index f77d975..b5fa9c9 100644 (file)
@@ -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));
 }
index 5559317..34fe92e 100644 (file)
@@ -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() {