aboutsummaryrefslogtreecommitdiff
path: root/contrib/gcc/cp
diff options
context:
space:
mode:
authorPedro F. Giffuni <pfg@FreeBSD.org>2013-12-20 16:01:02 +0000
committerPedro F. Giffuni <pfg@FreeBSD.org>2013-12-20 16:01:02 +0000
commita5fd0716f8be33c61c747bb3cca5a501bf127b90 (patch)
treeaaf1024abcd7c55552e09fd22908a6bf93b28ff8 /contrib/gcc/cp
parent008f5a254f69c46e367725b4570fdb097caa7e68 (diff)
downloadsrc-a5fd0716f8be33c61c747bb3cca5a501bf127b90.tar.gz
src-a5fd0716f8be33c61c747bb3cca5a501bf127b90.zip
gcc: merge upstream fix and new feature.
Fix for PR c++/29928 Add support for Rvalue references as described here: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html Obtained from: gcc 4.3 (rev. 124724, 125211; GPLv2) MFC after: 2 weeks
Notes
Notes: svn path=/head/; revision=259655
Diffstat (limited to 'contrib/gcc/cp')
-rw-r--r--contrib/gcc/cp/ChangeLog.gcc4365
-rw-r--r--contrib/gcc/cp/call.c110
-rw-r--r--contrib/gcc/cp/cp-tree.h23
-rw-r--r--contrib/gcc/cp/decl.c107
-rw-r--r--contrib/gcc/cp/error.c10
-rw-r--r--contrib/gcc/cp/except.c15
-rw-r--r--contrib/gcc/cp/mangle.c6
-rw-r--r--contrib/gcc/cp/parser.c98
-rw-r--r--contrib/gcc/cp/pt.c53
-rw-r--r--contrib/gcc/cp/rtti.c4
-rw-r--r--contrib/gcc/cp/tree.c69
-rw-r--r--contrib/gcc/cp/typeck.c53
12 files changed, 506 insertions, 107 deletions
diff --git a/contrib/gcc/cp/ChangeLog.gcc43 b/contrib/gcc/cp/ChangeLog.gcc43
index ed0735f3d9bd..1f1de7689316 100644
--- a/contrib/gcc/cp/ChangeLog.gcc43
+++ b/contrib/gcc/cp/ChangeLog.gcc43
@@ -35,10 +35,75 @@
* typeck.c (build_binary_op): Include types in error.
+2007-05-30 Russell Yanofsky <russ@yanofsky.org> (r125211)
+ Douglas Gregor <doug.gregor@gmail.com>
+ Pedro Lamarao <pedro.lamarao@mndfck.org>
+ Howard Hinnant <howard.hinnant@gmail.com>
+
+ PR c++/7412
+ PR c++/29939
+ * typeck.c (comptypes): Don't consider rvalue and lvalue
+ reference types to be equivalent.
+ (check_return_expr): Move from certain lvalues when returning
+ them.
+ * decl.c (grokdeclarator): Implement reference collapsing.
+ (copy_fn_p): Don't consider constructors taking rvalue references
+ to be copy constructors.
+ (move_fn_p): New.
+ * call.c (conversion): New "rvaluedness_matches_p" member.
+ (convert_class_to_reference): Require reference type as first
+ parameter instead of base type.
+ (reference_binding): Add logic to handle rvalue references.
+ (implicit_conversion): Update inaccurate comment.
+ (convert_like_real): Disable creation of temporaries that are
+ impossible to initialize for types with move constructors.
+ (build_over_call): Elide move constructors when possible.
+ (maybe_handle_implicit_object): Set "rvaluedness_matches_p".
+ (maybe_handle_ref_bind): Return conversion instead of type node.
+ (compare_ics): Add logic to use "rvaluedness_matches_p" values to
+ determine preferred conversion sequences.
+ * cp-tree.h (TYPE_REF_IS_RVALUE): New.
+ (LOOKUP_PREFER_RVALUE): New.
+ (DECL_MOVE_CONSTRUCTOR_P): New.
+ (struct cp_declarator): Add "reference" member for reference
+ types, with new "rvalue_ref" flag.
+ (cp_build_reference_type): Declare.
+ (move_fn_p): Declare.
+ * error.c (dump_type_prefix): Format rvalue reference types
+ correctly in error messages.
+ * except.c (build_throw): Move from certain lvalues when
+ throwing.
+ * mangle.c (write_type): Mangle rvalue references differently
+ than regular references.
+ * parser.c (make_reference_declarator): Add boolean parameter for
+ rvalue references.
+ (cp_parser_make_indirect_declarator): New.
+ (cp_parser_new_declarator_opt): Call
+ cp_parser_make_indirect_declarator.
+ (cp_parser_conversion_declarator_opt): Ditto.
+ (cp_parser_declarator): Ditto.
+ (cp_parser_ptr_operator): Parse "&&" tokens into rvalue reference
+ declarators.
+ * pt.c (tsubst): Implement reference collapsing.
+ (maybe_adjust_types_for_deduction): Implement special template
+ parameter deduction rule for rvalue references.
+ (type_unification_real): Update calls to
+ maybe_adjust_types_for_deduction.
+ (try_one_overload): Ditto.
+ (unify_pack_expansion): Ditto.
+ * tree.c (lvalue_p_1): Handle rvalue reference types.
+ (cp_build_reference_type): New.
+
2007-05-18 Geoffrey Keating <geoffk@apple.com> (r124839)
* mangle.c (write_real_cst): Use 'unsigned long' for %lx.
+2007-05-14 Paolo Carlini <pcarlini@suse.de> (r124724)
+
+ PR c++/29928
+ * rtti.c (get_tinfo_decl_dynamic, get_typeid): Try to complete the
+ type only if is a class type (5.2.8/4).
+
2007-05-05 Geoffrey Keating <geoffk@apple.com> (r124467)
PR 31775
diff --git a/contrib/gcc/cp/call.c b/contrib/gcc/cp/call.c
index 24b5d1fc3ec2..576790ca62f8 100644
--- a/contrib/gcc/cp/call.c
+++ b/contrib/gcc/cp/call.c
@@ -95,6 +95,10 @@ struct conversion {
/* If KIND is ck_ptr or ck_pmem, true to indicate that a conversion
from a pointer-to-derived to pointer-to-base is being performed. */
BOOL_BITFIELD base_p : 1;
+ /* If KIND is ck_ref_bind, true when either an lvalue reference is
+ being bound to an lvalue expression or an rvalue reference is
+ being bound to an rvalue expression. */
+ BOOL_BITFIELD rvaluedness_matches_p: 1;
/* The type of the expression resulting from the conversion. */
tree type;
union {
@@ -174,7 +178,7 @@ static conversion *standard_conversion (tree, tree, tree, bool, int);
static conversion *reference_binding (tree, tree, tree, bool, int);
static conversion *build_conv (conversion_kind, tree, conversion *);
static bool is_subseq (conversion *, conversion *);
-static tree maybe_handle_ref_bind (conversion **);
+static conversion *maybe_handle_ref_bind (conversion **);
static void maybe_handle_implicit_object (conversion **);
static struct z_candidate *add_candidate
(struct z_candidate **, tree, tree, size_t,
@@ -895,12 +899,12 @@ reference_compatible_p (tree t1, tree t2)
converted to T as in [over.match.ref]. */
static conversion *
-convert_class_to_reference (tree t, tree s, tree expr)
+convert_class_to_reference (tree reference_type, tree s, tree expr)
{
tree conversions;
tree arglist;
conversion *conv;
- tree reference_type;
+ tree t;
struct z_candidate *candidates;
struct z_candidate *cand;
bool any_viable_p;
@@ -934,7 +938,7 @@ convert_class_to_reference (tree t, tree s, tree expr)
arglist = build_int_cst (build_pointer_type (s), 0);
arglist = build_tree_list (NULL_TREE, arglist);
- reference_type = build_reference_type (t);
+ t = TREE_TYPE (reference_type);
while (conversions)
{
@@ -997,6 +1001,9 @@ convert_class_to_reference (tree t, tree s, tree expr)
cand->second_conv
= (direct_reference_binding
(reference_type, identity_conv));
+ cand->second_conv->rvaluedness_matches_p
+ = TYPE_REF_IS_RVALUE (TREE_TYPE (TREE_TYPE (cand->fn)))
+ == TYPE_REF_IS_RVALUE (reference_type);
cand->second_conv->bad_p |= cand->convs[0]->bad_p;
}
}
@@ -1123,7 +1130,16 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
to = build_qualified_type (to, cp_type_quals (from));
compatible_p = reference_compatible_p (to, from);
- if (lvalue_p && compatible_p)
+ /* Directly bind reference when target expression's type is compatible with
+ the reference and expression is an lvalue. In C++0x, the wording in
+ [8.5.3/5 dcl.init.ref] is changed to also allow direct bindings for const
+ and rvalue references to rvalues of compatible class type, as part of
+ DR391. */
+ if (compatible_p
+ && (lvalue_p
+ || (flag_cpp0x
+ && (CP_TYPE_CONST_NON_VOLATILE_P(to) || TYPE_REF_IS_RVALUE (rto))
+ && CLASS_TYPE_P (from))))
{
/* [dcl.init.ref]
@@ -1136,6 +1152,15 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
lvalue. */
conv = build_identity_conv (from, expr);
conv = direct_reference_binding (rto, conv);
+
+ if (flags & LOOKUP_PREFER_RVALUE)
+ /* The top-level caller requested that we pretend that the lvalue
+ be treated as an rvalue. */
+ conv->rvaluedness_matches_p = TYPE_REF_IS_RVALUE (rto);
+ else
+ conv->rvaluedness_matches_p
+ = (TYPE_REF_IS_RVALUE (rto) == !lvalue_p);
+
if ((lvalue_p & clk_bitfield) != 0
|| ((lvalue_p & clk_packed) != 0 && !TYPE_PACKED (to)))
/* For the purposes of overload resolution, we ignore the fact
@@ -1168,7 +1193,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
the reference is bound to the lvalue result of the conversion
in the second case. */
- conv = convert_class_to_reference (to, from, expr);
+ conv = convert_class_to_reference (rto, from, expr);
if (conv)
return conv;
}
@@ -1191,8 +1216,10 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
/* [dcl.init.ref]
- Otherwise, the reference shall be to a non-volatile const type. */
- if (!CP_TYPE_CONST_NON_VOLATILE_P (to))
+ Otherwise, the reference shall be to a non-volatile const type.
+
+ Under C++0x, [8.5.3/5 dcl.init.ref] it may also be an rvalue reference */
+ if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto))
return NULL;
/* [dcl.init.ref]
@@ -1215,6 +1242,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
{
conv = build_identity_conv (from, expr);
conv = direct_reference_binding (rto, conv);
+ conv->rvaluedness_matches_p = TYPE_REF_IS_RVALUE (rto);
if (!(flags & LOOKUP_CONSTRUCTOR_CALLABLE))
conv->u.next->check_copy_constructor_p = true;
return conv;
@@ -1239,6 +1267,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
/* This reference binding, unlike those above, requires the
creation of a temporary. */
conv->need_temporary_p = true;
+ conv->rvaluedness_matches_p = TYPE_REF_IS_RVALUE (rto);
return conv;
}
@@ -1280,7 +1309,7 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p,
conv = cand->second_conv;
/* We used to try to bind a reference to a temporary here, but that
- is now handled by the recursive call to this function at the end
+ is now handled after the recursive call to this function at the end
of reference_binding. */
return conv;
}
@@ -4409,13 +4438,22 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
{
tree ref_type = totype;
- /* If necessary, create a temporary. */
- if (convs->need_temporary_p || !lvalue_p (expr))
+ /* If necessary, create a temporary.
+
+ 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 build_unary_op (ADDR_EXPR, expr, ...)
+ doesn't fail. */
+ if (convs->need_temporary_p
+ || TREE_CODE (expr) == CONSTRUCTOR
+ || TREE_CODE (expr) == VA_ARG_EXPR)
{
tree type = convs->u.next->type;
cp_lvalue_kind lvalue = real_lvalue_p (expr);
- if (!CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type)))
+ if (!CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type))
+ && !TYPE_REF_IS_RVALUE (ref_type))
{
/* If the reference is volatile or non-const, we
cannot create a temporary. */
@@ -4938,7 +4976,9 @@ build_over_call (struct z_candidate *cand, int flags)
if (! flag_elide_constructors)
/* Do things the hard way. */;
- else if (cand->num_convs == 1 && DECL_COPY_CONSTRUCTOR_P (fn))
+ else if (cand->num_convs == 1
+ && (DECL_COPY_CONSTRUCTOR_P (fn)
+ || DECL_MOVE_CONSTRUCTOR_P (fn)))
{
tree targ;
arg = skip_artificial_parms_for (fn, converted_args);
@@ -5676,28 +5716,28 @@ maybe_handle_implicit_object (conversion **ics)
t = t->u.next;
t = build_identity_conv (TREE_TYPE (t->type), NULL_TREE);
t = direct_reference_binding (reference_type, t);
+ t->rvaluedness_matches_p = 1;
*ics = t;
}
}
/* If *ICS is a REF_BIND set *ICS to the remainder of the conversion,
- and return the type to which the reference refers. Otherwise,
- leave *ICS unchanged and return NULL_TREE. */
+ and return the initial reference binding conversion. Otherwise,
+ leave *ICS unchanged and return NULL. */
-static tree
+static conversion *
maybe_handle_ref_bind (conversion **ics)
{
if ((*ics)->kind == ck_ref_bind)
{
conversion *old_ics = *ics;
- tree type = TREE_TYPE (old_ics->type);
*ics = old_ics->u.next;
(*ics)->user_conv_p = old_ics->user_conv_p;
(*ics)->bad_p = old_ics->bad_p;
- return type;
+ return old_ics;
}
- return NULL_TREE;
+ return NULL;
}
/* Compare two implicit conversion sequences according to the rules set out in
@@ -5721,18 +5761,18 @@ compare_ics (conversion *ics1, conversion *ics2)
conversion_rank rank1, rank2;
/* REF_BINDING is nonzero if the result of the conversion sequence
- is a reference type. In that case TARGET_TYPE is the
- type referred to by the reference. */
- tree target_type1;
- tree target_type2;
+ is a reference type. In that case REF_CONV is the reference
+ binding conversion. */
+ conversion *ref_conv1;
+ conversion *ref_conv2;
/* Handle implicit object parameters. */
maybe_handle_implicit_object (&ics1);
maybe_handle_implicit_object (&ics2);
/* Handle reference parameters. */
- target_type1 = maybe_handle_ref_bind (&ics1);
- target_type2 = maybe_handle_ref_bind (&ics2);
+ ref_conv1 = maybe_handle_ref_bind (&ics1);
+ ref_conv2 = maybe_handle_ref_bind (&ics2);
/* [over.ics.rank]
@@ -6023,15 +6063,31 @@ compare_ics (conversion *ics1, conversion *ics2)
/* [over.ics.rank]
+ --S1 and S2 are reference bindings (_dcl.init.ref_) and neither refers
+ to an implicit object parameter, and either S1 binds an lvalue reference
+ to an lvalue and S2 binds an rvalue reference or S1 binds an rvalue
+ reference to an rvalue and S2 binds an lvalue reference
+ (C++0x draft standard, 13.3.3.2)
+
--S1 and S2 are reference bindings (_dcl.init.ref_), and the
types to which the references refer are the same type except for
top-level cv-qualifiers, and the type to which the reference
initialized by S2 refers is more cv-qualified than the type to
which the reference initialized by S1 refers */
- if (target_type1 && target_type2
+ if (ref_conv1 && ref_conv2
&& same_type_ignoring_top_level_qualifiers_p (to_type1, to_type2))
- return comp_cv_qualification (target_type2, target_type1);
+ {
+ if (ref_conv1->rvaluedness_matches_p
+ && !ref_conv2->rvaluedness_matches_p)
+ return 1;
+ else if (!ref_conv1->rvaluedness_matches_p
+ && ref_conv2->rvaluedness_matches_p)
+ return -1;
+
+ return comp_cv_qualification (TREE_TYPE (ref_conv2->type),
+ TREE_TYPE (ref_conv1->type));
+ }
/* Neither conversion sequence is better than the other. */
return 0;
diff --git a/contrib/gcc/cp/cp-tree.h b/contrib/gcc/cp/cp-tree.h
index 0b30f38809f3..fc924a2dc547 100644
--- a/contrib/gcc/cp/cp-tree.h
+++ b/contrib/gcc/cp/cp-tree.h
@@ -56,6 +56,7 @@ struct diagnostic_context;
OMP_FOR_GIMPLIFYING_P (in OMP_FOR)
BASELINK_QUALIFIED_P (in BASELINK)
TARGET_EXPR_IMPLICIT_P (in TARGET_EXPR)
+ TYPE_REF_IS_RVALUE (in REFERENCE_TYPE)
1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
@@ -1666,6 +1667,10 @@ struct lang_decl GTY(())
#define DECL_COPY_CONSTRUCTOR_P(NODE) \
(DECL_CONSTRUCTOR_P (NODE) && copy_fn_p (NODE) > 0)
+/* Nonzero if NODE (a FUNCTION_DECL) is a move constructor. */
+#define DECL_MOVE_CONSTRUCTOR_P(NODE) \
+ (DECL_CONSTRUCTOR_P (NODE) && move_fn_p (NODE))
+
/* Nonzero if NODE is a destructor. */
#define DECL_DESTRUCTOR_P(NODE) \
(DECL_LANG_SPECIFIC (NODE)->decl_flags.destructor_attr)
@@ -2561,6 +2566,10 @@ extern void decl_shadowed_for_var_insert (tree, tree);
#define TYPE_REF_OBJ_P(NODE) \
(TREE_CODE (NODE) == REFERENCE_TYPE && TYPE_OBJ_P (TREE_TYPE (NODE)))
+/* True if reference type NODE is an rvalue reference */
+#define TYPE_REF_IS_RVALUE(NODE) \
+ TREE_LANG_FLAG_0 (REFERENCE_TYPE_CHECK (NODE))
+
/* Returns true if NODE is a pointer to an object, or a pointer to
void. Keep these checks in ascending tree code order. */
#define TYPE_PTROBV_P(NODE) \
@@ -3444,6 +3453,8 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG };
(Normally, these entities are registered in the symbol table, but
not found by lookup.) */
#define LOOKUP_HIDDEN (LOOKUP_CONSTRUCTOR_CALLABLE << 1)
+/* Prefer that the lvalue be treated as an rvalue. */
+#define LOOKUP_PREFER_RVALUE (LOOKUP_HIDDEN << 1)
#define LOOKUP_NAMESPACES_ONLY(F) \
(((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
@@ -3750,13 +3761,21 @@ struct cp_declarator {
/* The bounds to the array. */
tree bounds;
} array;
- /* For cdk_pointer, cdk_reference, and cdk_ptrmem. */
+ /* For cdk_pointer and cdk_ptrmem. */
struct {
/* The cv-qualifiers for the pointer. */
cp_cv_quals qualifiers;
/* For cdk_ptrmem, the class type containing the member. */
tree class_type;
} pointer;
+ /* For cdk_reference */
+ struct {
+ /* The cv-qualifiers for the reference. These qualifiers are
+ only used to diagnose ill-formed code. */
+ cp_cv_quals qualifiers;
+ /* Whether this is an rvalue reference */
+ bool rvalue_ref;
+ } reference;
} u;
};
@@ -3917,6 +3936,7 @@ extern tree build_ptrmem_type (tree, tree);
/* the grokdeclarator prototype is in decl.h */
extern tree build_this_parm (tree, cp_cv_quals);
extern int copy_fn_p (tree);
+extern bool move_fn_p (tree);
extern tree get_scope_of_declarator (const cp_declarator *);
extern void grok_special_member_properties (tree);
extern int grok_ctor_properties (tree, tree);
@@ -4416,6 +4436,7 @@ extern int is_dummy_object (tree);
extern const struct attribute_spec cxx_attribute_table[];
extern tree make_ptrmem_cst (tree, tree);
extern tree cp_build_type_attribute_variant (tree, tree);
+extern tree cp_build_reference_type (tree, bool);
extern tree cp_build_qualified_type_real (tree, int, tsubst_flags_t);
#define cp_build_qualified_type(TYPE, QUALS) \
cp_build_qualified_type_real ((TYPE), (QUALS), tf_warning_or_error)
diff --git a/contrib/gcc/cp/decl.c b/contrib/gcc/cp/decl.c
index dcceebaf1fd9..1c468e7d18ad 100644
--- a/contrib/gcc/cp/decl.c
+++ b/contrib/gcc/cp/decl.c
@@ -7823,10 +7823,24 @@ grokdeclarator (const cp_declarator *declarator,
if (TREE_CODE (type) == REFERENCE_TYPE)
{
- error (declarator->kind == cdk_reference
- ? "cannot declare reference to %q#T"
- : "cannot declare pointer to %q#T", type);
- type = TREE_TYPE (type);
+ if (declarator->kind != cdk_reference)
+ {
+ error ("cannot declare pointer to %q#T", type);
+ type = TREE_TYPE (type);
+ }
+
+ /* In C++0x, we allow reference to reference declarations
+ that occur indirectly through typedefs [7.1.3/8 dcl.typedef]
+ and template type arguments [14.3.1/4 temp.arg.type]. The
+ check for direct reference to reference declarations, which
+ are still forbidden, occurs below. Reasoning behind the change
+ can be found in DR106, DR540, and the rvalue reference
+ proposals. */
+ else if (!flag_cpp0x)
+ {
+ error ("cannot declare reference to %q#T", type);
+ type = TREE_TYPE (type);
+ }
}
else if (VOID_TYPE_P (type))
{
@@ -7852,8 +7866,39 @@ grokdeclarator (const cp_declarator *declarator,
if (declarator->kind == cdk_reference)
{
+ /* In C++0x, the type we are creating a reference to might be
+ a typedef which is itself a reference type. In that case,
+ we follow the reference collapsing rules in
+ [7.1.3/8 dcl.typedef] to create the final reference type:
+
+ "If a typedef TD names a type that is a reference to a type
+ T, an attempt to create the type 'lvalue reference to cv TD'
+ creates the type 'lvalue reference to T,' while an attempt
+ to create the type "rvalue reference to cv TD' creates the
+ type TD."
+ */
if (!VOID_TYPE_P (type))
- type = build_reference_type (type);
+ type = cp_build_reference_type
+ ((TREE_CODE (type) == REFERENCE_TYPE
+ ? TREE_TYPE (type) : type),
+ (declarator->u.reference.rvalue_ref
+ && (TREE_CODE(type) != REFERENCE_TYPE
+ || TYPE_REF_IS_RVALUE (type))));
+
+ /* In C++0x, we need this check for direct reference to
+ reference declarations, which are forbidden by
+ [8.3.2/5 dcl.ref]. Reference to reference declarations
+ are only allowed indirectly through typedefs and template
+ type arguments. Example:
+
+ void foo(int & &); // invalid ref-to-ref decl
+
+ typedef int & int_ref;
+ void foo(int_ref &); // valid ref-to-ref decl
+ */
+ if (inner_declarator && inner_declarator->kind == cdk_reference)
+ error ("cannot declare reference to %q#T, which is not "
+ "a typedef or a template type argument", type);
}
else if (TREE_CODE (type) == METHOD_TYPE)
type = build_ptrmemfunc_type (build_pointer_type (type));
@@ -9078,6 +9123,7 @@ copy_fn_p (tree d)
result = -1;
}
else if (TREE_CODE (arg_type) == REFERENCE_TYPE
+ && !TYPE_REF_IS_RVALUE (arg_type)
&& TYPE_MAIN_VARIANT (TREE_TYPE (arg_type)) == DECL_CONTEXT (d))
{
if (CP_TYPE_CONST_P (TREE_TYPE (arg_type)))
@@ -9095,6 +9141,57 @@ copy_fn_p (tree d)
return result;
}
+/* D is a constructor or overloaded `operator='.
+
+ Let T be the class in which D is declared. Then, this function
+ returns true when D is a move constructor or move assignment
+ operator, false otherwise. */
+
+bool
+move_fn_p (tree d)
+{
+ tree args;
+ tree arg_type;
+ bool result = false;
+
+ gcc_assert (DECL_FUNCTION_MEMBER_P (d));
+
+ if (!flag_cpp0x)
+ /* There are no move constructors if we aren't in C++0x mode. */
+ return false;
+
+ if (TREE_CODE (d) == TEMPLATE_DECL
+ || (DECL_TEMPLATE_INFO (d)
+ && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (d))))
+ /* Instantiations of template member functions are never copy
+ functions. Note that member functions of templated classes are
+ represented as template functions internally, and we must
+ accept those as copy functions. */
+ return 0;
+
+ args = FUNCTION_FIRST_USER_PARMTYPE (d);
+ if (!args)
+ return 0;
+
+ arg_type = TREE_VALUE (args);
+ if (arg_type == error_mark_node)
+ return 0;
+
+ if (TREE_CODE (arg_type) == REFERENCE_TYPE
+ && TYPE_REF_IS_RVALUE (arg_type)
+ && same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (arg_type)),
+ DECL_CONTEXT (d)))
+ result = true;
+
+ args = TREE_CHAIN (args);
+
+ if (args && args != void_list_node && !TREE_PURPOSE (args))
+ /* There are more non-optional args. */
+ return false;
+
+ return result;
+}
+
/* Remember any special properties of member function DECL. */
void grok_special_member_properties (tree decl)
diff --git a/contrib/gcc/cp/error.c b/contrib/gcc/cp/error.c
index c169cabedb64..92b042a7f3fa 100644
--- a/contrib/gcc/cp/error.c
+++ b/contrib/gcc/cp/error.c
@@ -507,7 +507,15 @@ dump_type_prefix (tree t, int flags)
pp_cxx_whitespace (cxx_pp);
pp_cxx_left_paren (cxx_pp);
}
- pp_character (cxx_pp, "&*"[TREE_CODE (t) == POINTER_TYPE]);
+ if (TREE_CODE (t) == POINTER_TYPE)
+ pp_character(cxx_pp, '*');
+ else if (TREE_CODE (t) == REFERENCE_TYPE)
+ {
+ if (TYPE_REF_IS_RVALUE (t))
+ pp_string (cxx_pp, "&&");
+ else
+ pp_character (cxx_pp, '&');
+ }
pp_base (cxx_pp)->padding = pp_before;
pp_cxx_cv_qualifier_seq (cxx_pp, t);
}
diff --git a/contrib/gcc/cp/except.c b/contrib/gcc/cp/except.c
index f97ab063dde5..66a3b1635946 100644
--- a/contrib/gcc/cp/except.c
+++ b/contrib/gcc/cp/except.c
@@ -709,12 +709,25 @@ build_throw (tree exp)
/* And initialize the exception object. */
if (CLASS_TYPE_P (temp_type))
{
+ int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING;
+
+ /* Under C++0x [12.8/16 class.copy], a thrown lvalue is sometimes
+ treated as an rvalue for the purposes of overload resolution
+ to favor move constructors over copy constructors. */
+ if (/* Must be a local, automatic variable. */
+ TREE_CODE (exp) == VAR_DECL
+ && DECL_CONTEXT (exp) == current_function_decl
+ && ! TREE_STATIC (exp)
+ /* The variable must not have the `volatile' qualifier. */
+ && !(cp_type_quals (TREE_TYPE (exp)) & TYPE_QUAL_VOLATILE))
+ flags = flags | LOOKUP_PREFER_RVALUE;
+
/* Call the copy constructor. */
exp = (build_special_member_call
(object, complete_ctor_identifier,
build_tree_list (NULL_TREE, exp),
TREE_TYPE (object),
- LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING));
+ flags));
if (exp == error_mark_node)
{
error (" in thrown expression");
diff --git a/contrib/gcc/cp/mangle.c b/contrib/gcc/cp/mangle.c
index 8bfdc20ef7a0..6a49350f99c4 100644
--- a/contrib/gcc/cp/mangle.c
+++ b/contrib/gcc/cp/mangle.c
@@ -1541,6 +1541,10 @@ write_local_name (const tree function, const tree local_entity,
::= G <type> # imaginary (C 2000) [not supported]
::= U <source-name> <type> # vendor extended type qualifier
+ C++0x extensions
+
+ <type> ::= RR <type> # rvalue reference-to
+
TYPE is a type node. */
static void
@@ -1635,6 +1639,8 @@ write_type (tree type)
break;
case REFERENCE_TYPE:
+ if (TYPE_REF_IS_RVALUE (type))
+ write_char('R');
write_char ('R');
write_type (TREE_TYPE (type));
break;
diff --git a/contrib/gcc/cp/parser.c b/contrib/gcc/cp/parser.c
index a021d5bcdfa0..0872c28e4617 100644
--- a/contrib/gcc/cp/parser.c
+++ b/contrib/gcc/cp/parser.c
@@ -843,7 +843,7 @@ static cp_declarator *make_array_declarator
static cp_declarator *make_pointer_declarator
(cp_cv_quals, cp_declarator *);
static cp_declarator *make_reference_declarator
- (cp_cv_quals, cp_declarator *);
+ (cp_cv_quals, cp_declarator *, bool);
static cp_parameter_declarator *make_parameter_declarator
(cp_decl_specifier_seq *, cp_declarator *, tree);
static cp_declarator *make_ptrmem_declarator
@@ -937,14 +937,15 @@ make_pointer_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target)
/* Like make_pointer_declarator -- but for references. */
cp_declarator *
-make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target)
+make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target,
+ bool rvalue_ref)
{
cp_declarator *declarator;
declarator = make_declarator (cdk_reference);
declarator->declarator = target;
- declarator->u.pointer.qualifiers = cv_qualifiers;
- declarator->u.pointer.class_type = NULL_TREE;
+ declarator->u.reference.qualifiers = cv_qualifiers;
+ declarator->u.reference.rvalue_ref = rvalue_ref;
return declarator;
}
@@ -1926,6 +1927,8 @@ static bool cp_parser_is_keyword
(cp_token *, enum rid);
static tree cp_parser_make_typename_type
(cp_parser *, tree, tree);
+static cp_declarator * cp_parser_make_indirect_declarator
+ (enum tree_code, tree, cp_cv_quals, cp_declarator *);
/* Returns nonzero if we are parsing tentatively. */
@@ -2599,6 +2602,27 @@ cp_parser_make_typename_type (cp_parser *parser, tree scope, tree id)
return make_typename_type (scope, id, typename_type, tf_error);
}
+/* This is a wrapper around the
+ make_{pointer,ptrmem,reference}_declarator functions that decides
+ which one to call based on the CODE and CLASS_TYPE arguments. The
+ CODE argument should be one of the values returned by
+ cp_parser_ptr_operator. */
+static cp_declarator *
+cp_parser_make_indirect_declarator (enum tree_code code, tree class_type,
+ cp_cv_quals cv_qualifiers,
+ cp_declarator *target)
+{
+ if (code == INDIRECT_REF)
+ if (class_type == NULL_TREE)
+ return make_pointer_declarator (cv_qualifiers, target);
+ else
+ return make_ptrmem_declarator (cv_qualifiers, class_type, target);
+ else if (code == ADDR_EXPR && class_type == NULL_TREE)
+ return make_reference_declarator (cv_qualifiers, target, false);
+ else if (code == NON_LVALUE_EXPR && class_type == NULL_TREE)
+ return make_reference_declarator (cv_qualifiers, target, true);
+ gcc_unreachable ();
+}
/* Create a new C++ parser. */
@@ -5387,15 +5411,8 @@ cp_parser_new_declarator_opt (cp_parser* parser)
/* Parse another optional declarator. */
declarator = cp_parser_new_declarator_opt (parser);
- /* Create the representation of the declarator. */
- if (type)
- declarator = make_ptrmem_declarator (cv_quals, type, declarator);
- else if (code == INDIRECT_REF)
- declarator = make_pointer_declarator (cv_quals, declarator);
- else
- declarator = make_reference_declarator (cv_quals, declarator);
-
- return declarator;
+ return cp_parser_make_indirect_declarator
+ (code, type, cv_quals, declarator);
}
/* If the next token is a `[', there is a direct-new-declarator. */
@@ -8054,16 +8071,8 @@ cp_parser_conversion_declarator_opt (cp_parser* parser)
/* Parse another optional declarator. */
declarator = cp_parser_conversion_declarator_opt (parser);
- /* Create the representation of the declarator. */
- if (class_type)
- declarator = make_ptrmem_declarator (cv_quals, class_type,
- declarator);
- else if (code == INDIRECT_REF)
- declarator = make_pointer_declarator (cv_quals, declarator);
- else
- declarator = make_reference_declarator (cv_quals, declarator);
-
- return declarator;
+ return cp_parser_make_indirect_declarator
+ (code, class_type, cv_quals, declarator);
}
return NULL;
@@ -11522,15 +11531,8 @@ cp_parser_declarator (cp_parser* parser,
&& !cp_parser_parse_definitely (parser))
declarator = NULL;
- /* Build the representation of the ptr-operator. */
- if (class_type)
- declarator = make_ptrmem_declarator (cv_quals,
- class_type,
- declarator);
- else if (code == INDIRECT_REF)
- declarator = make_pointer_declarator (cv_quals, declarator);
- else
- declarator = make_reference_declarator (cv_quals, declarator);
+ declarator = cp_parser_make_indirect_declarator
+ (code, class_type, cv_quals, declarator);
}
/* Everything else is a direct-declarator. */
else
@@ -11971,12 +11973,15 @@ cp_parser_direct_declarator (cp_parser* parser,
& cv-qualifier-seq [opt]
Returns INDIRECT_REF if a pointer, or pointer-to-member, was used.
- Returns ADDR_EXPR if a reference was used. In the case of a
- pointer-to-member, *TYPE is filled in with the TYPE containing the
- member. *CV_QUALS is filled in with the cv-qualifier-seq, or
- TYPE_UNQUALIFIED, if there are no cv-qualifiers. Returns
- ERROR_MARK if an error occurred. */
-
+ Returns ADDR_EXPR if a reference was used, or NON_LVALUE_EXPR for
+ an rvalue reference. In the case of a pointer-to-member, *TYPE is
+ filled in with the TYPE containing the member. *CV_QUALS is
+ filled in with the cv-qualifier-seq, or TYPE_UNQUALIFIED, if there
+ are no cv-qualifiers. Returns ERROR_MARK if an error occurred.
+ Note that the tree codes returned by this function have nothing
+ to do with the types of trees that will be eventually be created
+ to represent the pointer or reference type being parsed. They are
+ just constants with suggestive names. */
static enum tree_code
cp_parser_ptr_operator (cp_parser* parser,
tree* type,
@@ -11992,13 +11997,18 @@ cp_parser_ptr_operator (cp_parser* parser,
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
- /* If it's a `*' or `&' we have a pointer or reference. */
- if (token->type == CPP_MULT || token->type == CPP_AND)
- {
- /* Remember which ptr-operator we were processing. */
- code = (token->type == CPP_AND ? ADDR_EXPR : INDIRECT_REF);
- /* Consume the `*' or `&'. */
+ /* If it's a `*', `&' or `&&' we have a pointer or reference. */
+ if (token->type == CPP_MULT)
+ code = INDIRECT_REF;
+ else if (token->type == CPP_AND)
+ code = ADDR_EXPR;
+ else if (flag_cpp0x && token->type == CPP_AND_AND) /* C++0x only */
+ code = NON_LVALUE_EXPR;
+
+ if (code != ERROR_MARK)
+ {
+ /* Consume the `*', `&' or `&&'. */
cp_lexer_consume_token (parser->lexer);
/* A `*' can be followed by a cv-qualifier-seq, and so can a
diff --git a/contrib/gcc/cp/pt.c b/contrib/gcc/cp/pt.c
index f12fc7b74d4e..69170d608675 100644
--- a/contrib/gcc/cp/pt.c
+++ b/contrib/gcc/cp/pt.c
@@ -110,7 +110,8 @@ static void tsubst_enum (tree, tree, tree);
static tree add_to_template_args (tree, tree);
static tree add_outermost_template_args (tree, tree);
static bool check_instantiated_args (tree, tree, tsubst_flags_t);
-static int maybe_adjust_types_for_deduction (unification_kind_t, tree*, tree*);
+static int maybe_adjust_types_for_deduction (unification_kind_t, tree*, tree*,
+ tree);
static int type_unification_real (tree, tree, tree, tree,
int, unification_kind_t, int);
static void note_template_header (int);
@@ -7546,8 +7547,13 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
-- Attempting to create a pointer to reference type.
-- Attempting to create a reference to a reference type or
- a reference to void. */
- if (TREE_CODE (type) == REFERENCE_TYPE
+ a reference to void.
+
+ Core issue 106 says that creating a reference to a reference
+ during instantiation is no longer a cause for failure. We
+ only enforce this check in strict C++98 mode. */
+ if ((TREE_CODE (type) == REFERENCE_TYPE
+ && ((!flag_cpp0x && flag_iso) || code != REFERENCE_TYPE))
|| (code == REFERENCE_TYPE && TREE_CODE (type) == VOID_TYPE))
{
static location_t last_loc;
@@ -7581,8 +7587,22 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
if (TREE_CODE (type) == METHOD_TYPE)
r = build_ptrmemfunc_type (r);
}
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
+ /* In C++0x, during template argument substitution, when there is an
+ attempt to create a reference to a reference type, reference
+ collapsing is applied as described in [14.3.1/4 temp.arg.type]:
+
+ "If a template-argument for a template-parameter T names a type
+ that is a reference to a type A, an attempt to create the type
+ 'lvalue reference to cv T' creates the type 'lvalue reference to
+ A,' while an attempt to create the type type rvalue reference to
+ cv T' creates the type T"
+ */
+ r = cp_build_reference_type
+ (TREE_TYPE (type),
+ TYPE_REF_IS_RVALUE (t) && TYPE_REF_IS_RVALUE (type));
else
- r = build_reference_type (type);
+ r = cp_build_reference_type (type, TYPE_REF_IS_RVALUE (t));
r = cp_build_qualified_type_real (r, TYPE_QUALS (t), complain);
if (r != error_mark_node)
@@ -9792,12 +9812,14 @@ fn_type_unification (tree fn,
sections are symmetric. PARM is the type of a function parameter
or the return type of the conversion function. ARG is the type of
the argument passed to the call, or the type of the value
- initialized with the result of the conversion function. */
+ initialized with the result of the conversion function.
+ ARG_EXPR is the original argument expression, which may be null. */
static int
maybe_adjust_types_for_deduction (unification_kind_t strict,
tree* parm,
- tree* arg)
+ tree* arg,
+ tree arg_expr)
{
int result = 0;
@@ -9851,6 +9873,16 @@ maybe_adjust_types_for_deduction (unification_kind_t strict,
*arg = TYPE_MAIN_VARIANT (*arg);
}
+ /* From C++0x [14.8.2.1/3 temp.deduct.call] (after DR606), "If P is
+ of the form T&&, where T is a template parameter, and the argument
+ is an lvalue, T is deduced as A& */
+ if (TREE_CODE (*parm) == REFERENCE_TYPE
+ && TYPE_REF_IS_RVALUE (*parm)
+ && TREE_CODE (TREE_TYPE (*parm)) == TEMPLATE_TYPE_PARM
+ && cp_type_quals (TREE_TYPE (*parm)) == TYPE_UNQUALIFIED
+ && arg_expr && real_lvalue_p (arg_expr))
+ *arg = build_reference_type (*arg);
+
/* [temp.deduct.call]
If P is a cv-qualified type, the top level cv-qualifiers
@@ -9887,7 +9919,7 @@ type_unification_real (tree tparms,
unification_kind_t strict,
int flags)
{
- tree parm, arg;
+ tree parm, arg, arg_expr;
int i;
int ntparms = TREE_VEC_LENGTH (tparms);
int sub_strict;
@@ -9929,6 +9961,7 @@ type_unification_real (tree tparms,
parms = TREE_CHAIN (parms);
arg = TREE_VALUE (args);
args = TREE_CHAIN (args);
+ arg_expr = NULL;
if (arg == error_mark_node)
return 1;
@@ -9978,6 +10011,7 @@ type_unification_real (tree tparms,
return 1;
}
+ arg_expr = arg;
arg = unlowered_expr_type (arg);
if (arg == error_mark_node)
return 1;
@@ -9987,7 +10021,8 @@ type_unification_real (tree tparms,
int arg_strict = sub_strict;
if (!subr)
- arg_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg);
+ arg_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg,
+ arg_expr);
if (unify (tparms, targs, parm, arg, arg_strict))
return 1;
@@ -10164,7 +10199,7 @@ try_one_overload (tree tparms,
else if (addr_p)
arg = build_pointer_type (arg);
- sub_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg);
+ sub_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg, NULL);
/* We don't copy orig_targs for this because if we have already deduced
some template args from previous args, unify would complain when we
diff --git a/contrib/gcc/cp/rtti.c b/contrib/gcc/cp/rtti.c
index 5e58e5c3fe6a..f1a045c6a61a 100644
--- a/contrib/gcc/cp/rtti.c
+++ b/contrib/gcc/cp/rtti.c
@@ -238,7 +238,7 @@ get_tinfo_decl_dynamic (tree exp)
/* Peel off cv qualifiers. */
type = TYPE_MAIN_VARIANT (type);
- if (!VOID_TYPE_P (type))
+ if (CLASS_TYPE_P (type))
type = complete_type_or_else (type, exp);
if (!type)
@@ -430,7 +430,7 @@ get_typeid (tree type)
that is the operand of typeid are always ignored. */
type = TYPE_MAIN_VARIANT (type);
- if (!VOID_TYPE_P (type))
+ if (CLASS_TYPE_P (type))
type = complete_type_or_else (type, NULL_TREE);
if (!type)
diff --git a/contrib/gcc/cp/tree.c b/contrib/gcc/cp/tree.c
index eee91514bf24..4e392f9924e2 100644
--- a/contrib/gcc/cp/tree.c
+++ b/contrib/gcc/cp/tree.c
@@ -64,8 +64,28 @@ lvalue_p_1 (tree ref,
cp_lvalue_kind op1_lvalue_kind = clk_none;
cp_lvalue_kind op2_lvalue_kind = clk_none;
+ /* Expressions of reference type are sometimes wrapped in
+ INDIRECT_REFs. INDIRECT_REFs are just internal compiler
+ representation, not part of the language, so we have to look
+ through them. */
+ if (TREE_CODE (ref) == INDIRECT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0)))
+ == REFERENCE_TYPE)
+ return lvalue_p_1 (TREE_OPERAND (ref, 0),
+ treat_class_rvalues_as_lvalues);
+
if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
- return clk_ordinary;
+ {
+ /* unnamed rvalue references are rvalues */
+ if (TYPE_REF_IS_RVALUE (TREE_TYPE (ref))
+ && TREE_CODE (ref) != PARM_DECL
+ && TREE_CODE (ref) != VAR_DECL
+ && TREE_CODE (ref) != COMPONENT_REF)
+ return clk_none;
+
+ /* lvalue references and named rvalue refences are lvalues */
+ return clk_ordinary;
+ }
if (ref == current_class_ptr)
return clk_none;
@@ -451,6 +471,53 @@ build_cplus_array_type (tree elt_type, tree index_type)
return t;
}
+
+/* Return a reference type node referring to TO_TYPE. If RVAL is
+ true, return an rvalue reference type, otherwise return an lvalue
+ reference type. If a type node exists, reuse it, otherwise create
+ a new one. */
+tree
+cp_build_reference_type (tree to_type, bool rval)
+{
+ tree lvalue_ref, t;
+ lvalue_ref = build_reference_type (to_type);
+ if (!rval)
+ return lvalue_ref;
+
+ /* This code to create rvalue reference types is based on and tied
+ to the code creating lvalue reference types in the middle-end
+ functions build_reference_type_for_mode and build_reference_type.
+
+ It works by putting the rvalue reference type nodes after the
+ lvalue reference nodes in the TYPE_NEXT_REF_TO linked list, so
+ they will effectively be ignored by the middle end. */
+
+ for (t = lvalue_ref; (t = TYPE_NEXT_REF_TO (t)); )
+ if (TYPE_REF_IS_RVALUE (t))
+ return t;
+
+ t = copy_node (lvalue_ref);
+
+ TYPE_REF_IS_RVALUE (t) = true;
+ TYPE_NEXT_REF_TO (t) = TYPE_NEXT_REF_TO (lvalue_ref);
+ TYPE_NEXT_REF_TO (lvalue_ref) = t;
+ TYPE_MAIN_VARIANT (t) = t;
+
+ if (TYPE_STRUCTURAL_EQUALITY_P (to_type))
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ else if (TYPE_CANONICAL (to_type) != to_type)
+ TYPE_CANONICAL (t)
+ = cp_build_reference_type (TYPE_CANONICAL (to_type), rval);
+ else
+ TYPE_CANONICAL (t) = t;
+
+ layout_type (t);
+
+ return t;
+
+}
+
+
/* Make a variant of TYPE, qualified with the TYPE_QUALS. Handles
arrays correctly. In particular, if TYPE is an array of T's, and
diff --git a/contrib/gcc/cp/typeck.c b/contrib/gcc/cp/typeck.c
index 34a301d62fa3..9fd40c741840 100644
--- a/contrib/gcc/cp/typeck.c
+++ b/contrib/gcc/cp/typeck.c
@@ -1039,8 +1039,12 @@ comptypes (tree t1, tree t2, int strict)
return false;
break;
- case POINTER_TYPE:
case REFERENCE_TYPE:
+ if (TYPE_REF_IS_RVALUE (t1) != TYPE_REF_IS_RVALUE (t2))
+ return false;
+ /* fall through to checks for pointer types */
+
+ case POINTER_TYPE:
if (TYPE_MODE (t1) != TYPE_MODE (t2)
|| TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)
|| !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
@@ -6499,6 +6503,7 @@ check_return_expr (tree retval, bool *no_warning)
promotions. */
tree valtype;
int fn_returns_value_p;
+ bool named_return_value_okay_p;
*no_warning = false;
@@ -6646,21 +6651,26 @@ check_return_expr (tree retval, bool *no_warning)
See finish_function and finalize_nrv for the rest of this optimization. */
+ named_return_value_okay_p =
+ (retval != NULL_TREE
+ /* Must be a local, automatic variable. */
+ && TREE_CODE (retval) == VAR_DECL
+ && DECL_CONTEXT (retval) == current_function_decl
+ && ! TREE_STATIC (retval)
+ && (DECL_ALIGN (retval)
+ >= DECL_ALIGN (DECL_RESULT (current_function_decl)))
+ /* The cv-unqualified type of the returned value must be the
+ same as the cv-unqualified return type of the
+ function. */
+ && same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))),
+ (TYPE_MAIN_VARIANT
+ (TREE_TYPE (TREE_TYPE (current_function_decl))))));
+
if (fn_returns_value_p && flag_elide_constructors)
{
- if (retval != NULL_TREE
- && (current_function_return_value == NULL_TREE
- || current_function_return_value == retval)
- && TREE_CODE (retval) == VAR_DECL
- && DECL_CONTEXT (retval) == current_function_decl
- && ! TREE_STATIC (retval)
- && ! DECL_ANON_UNION_VAR_P (retval)
- && (DECL_ALIGN (retval)
- >= DECL_ALIGN (DECL_RESULT (current_function_decl)))
- && same_type_p ((TYPE_MAIN_VARIANT
- (TREE_TYPE (retval))),
- (TYPE_MAIN_VARIANT
- (TREE_TYPE (TREE_TYPE (current_function_decl))))))
+ if (named_return_value_okay_p
+ && (current_function_return_value == NULL_TREE
+ || current_function_return_value == retval))
current_function_return_value = retval;
else
current_function_return_value = error_mark_node;
@@ -6679,18 +6689,29 @@ check_return_expr (tree retval, bool *no_warning)
{
/* The type the function is declared to return. */
tree functype = TREE_TYPE (TREE_TYPE (current_function_decl));
+ int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING;
/* The functype's return type will have been set to void, if it
was an incomplete type. Just treat this as 'return;' */
if (VOID_TYPE_P (functype))
return error_mark_node;
+ /* Under C++0x [12.8/16 class.copy], a returned lvalue is sometimes
+ treated as an rvalue for the purposes of overload resolution to
+ favor move constructors over copy constructors. */
+ if (flag_cpp0x
+ && named_return_value_okay_p
+ /* The variable must not have the `volatile' qualifier. */
+ && !(cp_type_quals (TREE_TYPE (retval)) & TYPE_QUAL_VOLATILE)
+ /* The return type must be a class type. */
+ && CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
+ flags = flags | LOOKUP_PREFER_RVALUE;
+
/* First convert the value to the function's return type, then
to the type of return value's location to handle the
case that functype is smaller than the valtype. */
retval = convert_for_initialization
- (NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
- "return", NULL_TREE, 0);
+ (NULL_TREE, functype, retval, flags, "return", NULL_TREE, 0);
retval = convert (valtype, retval);
/* If the conversion failed, treat this just like `return;'. */