Commit e7f1930f by Jason Merrill Committed by Jason Merrill

call.c (convert_class_to_reference): Binding an lvalue to an rvalue reference is bad.

	* call.c (convert_class_to_reference): Binding an lvalue to an
	rvalue reference is bad.  If the user-defined conversion is bad,
	set bad_p before merging conversions.
	(maybe_handle_ref_bind): Don't push down bad_p.
	(reference_binding): Binding an lvalue to an rvalue reference is bad.
	(convert_like_real): Give a helpful error about binding lvalue
	to rvalue reference.
	(reference_related_p): No longer static.
	* typeck.c (build_typed_address): New.
	(build_static_cast_1): Add static_cast from lvalue to &&.
	* cp-tree.h: Adjust.

	* include/bits/move.h (forward): Implement as in N2835.
	(move): Implement as in N2831.
	* include/std/istream (rvalue stream operator>>): New.
	* include/std/ostream (rvalue stream operator<<): New.

Co-Authored-By: Douglas Gregor <doug.gregor@gmail.com>

From-SVN: r150327
parent 4c650853
2009-07-31 Jason Merrill <jason@redhat.com>
Douglas Gregor <doug.gregor@gmail.com>
Remove implicit binding of lvalues to rvalue references (N2831)
* call.c (convert_class_to_reference): Binding an lvalue to an
rvalue reference is bad. If the user-defined conversion is bad,
set bad_p before merging conversions.
(maybe_handle_ref_bind): Don't push down bad_p.
(reference_binding): Binding an lvalue to an rvalue reference is bad.
(convert_like_real): Give a helpful error about binding lvalue
to rvalue reference.
(reference_related_p): No longer static.
* typeck.c (build_typed_address): New.
(build_static_cast_1): Add static_cast from lvalue to &&.
* cp-tree.h: Adjust.
2009-07-31 Jason Merrill <jason@redhat.com>
* call.c (reference_binding): Rename lvalue_p to is_lvalue.
Do direct binding of "rvalues" in memory to rvalue references.
......
......@@ -190,7 +190,6 @@ static struct z_candidate *add_candidate
conversion **, tree, tree, int);
static tree source_type (conversion *);
static void add_warning (struct z_candidate *, struct z_candidate *);
static bool reference_related_p (tree, tree);
static bool reference_compatible_p (tree, tree);
static conversion *convert_class_to_reference (tree, tree, tree, int);
static conversion *direct_reference_binding (tree, conversion *);
......@@ -966,7 +965,7 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
/* Returns nonzero if T1 is reference-related to T2. */
static bool
bool
reference_related_p (tree t1, tree t2)
{
t1 = TYPE_MAIN_VARIANT (t1);
......@@ -1110,6 +1109,11 @@ convert_class_to_reference (tree reference_type, tree s, tree expr, int flags)
= 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;
/* Don't allow binding of lvalues to rvalue references. */
if (TYPE_REF_IS_RVALUE (reference_type)
&& !TYPE_REF_IS_RVALUE (TREE_TYPE (TREE_TYPE (cand->fn))))
cand->second_conv->bad_p = true;
}
}
}
......@@ -1137,13 +1141,13 @@ convert_class_to_reference (tree reference_type, tree s, tree expr, int flags)
build_identity_conv (TREE_TYPE (expr), expr));
conv->cand = cand;
if (cand->viable == -1)
conv->bad_p = true;
/* Merge it with the standard conversion sequence from the
conversion function's return type to the desired type. */
cand->second_conv = merge_conversion_sequences (conv, cand->second_conv);
if (cand->viable == -1)
conv->bad_p = true;
return cand->second_conv;
}
......@@ -1308,6 +1312,11 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
actually occurs. */
conv->need_temporary_p = true;
/* Don't allow binding of lvalues to rvalue references. */
if (is_lvalue && TYPE_REF_IS_RVALUE (rto)
&& !(flags & LOOKUP_PREFER_RVALUE))
conv->bad_p = true;
return conv;
}
/* [class.conv.fct] A conversion function is never used to convert a
......@@ -4961,6 +4970,19 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
{
tree ref_type = totype;
if (convs->bad_p && TYPE_REF_IS_RVALUE (ref_type)
&& real_lvalue_p (expr))
{
if (complain & tf_error)
{
error ("cannot bind %qT lvalue to %qT",
TREE_TYPE (expr), totype);
if (fn)
error (" initializing argument %P of %q+D", argnum, fn);
}
return error_mark_node;
}
/* If necessary, create a temporary.
VA_ARG_EXPR and CONSTRUCTOR expressions are special cases
......@@ -6459,7 +6481,6 @@ maybe_handle_ref_bind (conversion **ics)
conversion *old_ics = *ics;
*ics = old_ics->u.next;
(*ics)->user_conv_p = old_ics->user_conv_p;
(*ics)->bad_p = old_ics->bad_p;
return old_ics;
}
......
......@@ -4266,6 +4266,7 @@ extern tree set_up_extended_ref_temp (tree, tree, tree *, tree *);
extern tree initialize_reference (tree, tree, tree, tree *);
extern tree make_temporary_var_for_ref_to_temp (tree, tree);
extern tree strip_top_quals (tree);
extern bool reference_related_p (tree, tree);
extern tree perform_implicit_conversion (tree, tree, tsubst_flags_t);
extern tree perform_implicit_conversion_flags (tree, tree, tsubst_flags_t, int);
extern tree perform_direct_initialization_if_possible (tree, tree, bool,
......@@ -5062,6 +5063,7 @@ extern tree cp_build_binary_op (location_t,
#define cxx_sizeof(T) cxx_sizeof_or_alignof_type (T, SIZEOF_EXPR, true)
extern tree build_ptrmemfunc_access_expr (tree, tree);
extern tree build_address (tree);
extern tree build_typed_address (tree, tree);
extern tree build_nop (tree, tree);
extern tree non_reference (tree);
extern tree lookup_anon_field (tree, tree);
......
......@@ -4290,6 +4290,19 @@ build_address (tree t)
return t;
}
/* Returns the address of T with type TYPE. */
tree
build_typed_address (tree t, tree type)
{
if (error_operand_p (t) || !cxx_mark_addressable (t))
return error_mark_node;
t = build_fold_addr_expr_with_type (t, type);
if (TREE_CODE (t) != ADDR_EXPR)
t = rvalue (t);
return t;
}
/* Return a NOP_EXPR converting EXPR to TYPE. */
tree
......@@ -5313,6 +5326,18 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
return convert_from_reference (cp_fold_convert (type, expr));
}
/* "An lvalue of type cv1 T1 can be cast to type rvalue reference to
cv2 T2 if cv2 T2 is reference-compatible with cv1 T1 (8.5.3)." */
if (TREE_CODE (type) == REFERENCE_TYPE
&& TYPE_REF_IS_RVALUE (type)
&& real_lvalue_p (expr)
&& reference_related_p (TREE_TYPE (type), intype)
&& (c_cast_p || at_least_as_qualified_p (TREE_TYPE (type), intype)))
{
expr = build_typed_address (expr, type);
return convert_from_reference (expr);
}
orig = expr;
/* [expr.static.cast]
......
2009-07-31 Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/initlist22.C: Adjust for new rvalue reference
binding semantics.
* g++.dg/cpp0x/named.C: Likewise.
* g++.dg/cpp0x/overload.C: Likewise.
* g++.dg/cpp0x/rv1n.C: Likewise.
* g++.dg/cpp0x/rv1p.C: Likewise.
* g++.dg/cpp0x/rv2n.C: Likewise.
* g++.dg/cpp0x/rv2p.C: Likewise.
* g++.dg/cpp0x/rv3n.C: Likewise.
* g++.dg/cpp0x/rv3p.C: Likewise.
* g++.dg/cpp0x/rv4n.C: Likewise.
* g++.dg/cpp0x/rv4p.C: Likewise.
* g++.dg/cpp0x/rv5n.C: Likewise.
* g++.dg/cpp0x/rv5p.C: Likewise.
* g++.dg/cpp0x/rv6n.C: Likewise.
* g++.dg/cpp0x/rv6p.C: Likewise.
* g++.dg/cpp0x/rv7n.C: Likewise.
* g++.dg/cpp0x/rv7p.C: Likewise.
* g++.dg/cpp0x/template_deduction.C: Likewise.
* g++.dg/cpp0x/unnamed_refs.C: Likewise.
* g++.dg/cpp0x/overloadn.C: New.
* g++.dg/cpp0x/rv-cast.C: New.
2009-07-31 Adam Nemet <anemet@caviumnetworks.com>
* gcc.target/mips/ext-4.c: New test.
......
......@@ -4,7 +4,7 @@
int i;
int& r1{ i }; // OK, direct binding
int&& r2{ i }; // OK, direct binding
int&& r2{ i }; // { dg-error "" } binding && to lvalue
int& r3{ }; // { dg-error "" } reference to temporary
int&& r4{ }; // OK, reference to temporary
......
// { dg-options "--std=c++0x" }
// { dg-do link }
template<typename _Tp>
inline _Tp&&
movel(_Tp& __t)
{ return static_cast<_Tp&&>(__t); }
struct S {};
struct T
{
T(S && s_) : s(s_) {}
S && get() { return s; }
operator S&&() { return s; }
T(S && s_) : s(movel(s_)) {}
S && get() { return movel(s); }
operator S&&() { return movel(s); }
S && s;
};
......@@ -18,8 +23,8 @@ void unnamed(S&&) {}
void f(S && p)
{
S && s(p);
T t(s);
S && s(movel(p));
T t(movel(s));
named(s); // variable reference
named(p); // parameter reference
......
......@@ -2,6 +2,11 @@
// { dg-do link }
// Generated by overload.py
template<typename _Tp>
inline _Tp&&
movel(_Tp& __t)
{ return static_cast<_Tp&&>(__t); }
struct S{};
S l; // lvalue (l)
......@@ -10,12 +15,12 @@ S r() { return l; } // rvalue (r)
S const cr() { return l; } // const rvalue (cr)
S & nl = l; // named lvalue reference (nl)
S const & ncl = l; // named const lvalue reference (ncl)
S && nr = l; // named rvalue reference (nr)
S const && ncr = l; // named const rvalue reference (ncr)
S && nr = movel(l); // named rvalue reference (nr)
S const && ncr = movel(l); // named const rvalue reference (ncr)
S & ul() { return l; } // unnamed lvalue reference (ul)
S const & ucl() { return l; } // unnamed const lvalue reference (ucl)
S && ur() { return l; } // unnamed rvalue reference (ur)
S const && ucr() { return l; } // unnamed const rvalue reference (ucr)
S && ur() { return movel(l); } // unnamed rvalue reference (ur)
S const && ucr() { return movel(l); } // unnamed const rvalue reference (ucr)
void l0001(const S&&) {}
......@@ -538,9 +543,9 @@ void ucr1111(const S&&) {}
int main()
{
l0001(l);
l0010(l);
l0011(l);
//l0001(l);
//l0010(l);
//l0011(l);
l0100(l);
l0101(l);
l0110(l);
......@@ -553,14 +558,14 @@ int main()
l1101(l);
l1110(l);
l1111(l);
cl0001(cl);
cl0011(cl);
//cl0001(cl);
//cl0011(cl);
cl0100(cl);
cl0101(cl);
cl0110(cl);
cl0111(cl);
cl1001(cl);
cl1011(cl);
//cl1001(cl);
//cl1011(cl);
cl1100(cl);
cl1101(cl);
cl1110(cl);
......@@ -591,9 +596,9 @@ int main()
cr1101(cr());
cr1110(cr());
cr1111(cr());
nl0001(nl);
nl0010(nl);
nl0011(nl);
//nl0001(nl);
//nl0010(nl);
//nl0011(nl);
nl0100(nl);
nl0101(nl);
nl0110(nl);
......@@ -606,21 +611,21 @@ int main()
nl1101(nl);
nl1110(nl);
nl1111(nl);
ncl0001(ncl);
ncl0011(ncl);
//ncl0001(ncl);
//ncl0011(ncl);
ncl0100(ncl);
ncl0101(ncl);
ncl0110(ncl);
ncl0111(ncl);
ncl1001(ncl);
ncl1011(ncl);
//ncl1001(ncl);
//ncl1011(ncl);
ncl1100(ncl);
ncl1101(ncl);
ncl1110(ncl);
ncl1111(ncl);
nr0001(nr);
nr0010(nr);
nr0011(nr);
//nr0001(nr);
//nr0010(nr);
//nr0011(nr);
nr0100(nr);
nr0101(nr);
nr0110(nr);
......@@ -633,21 +638,21 @@ int main()
nr1101(nr);
nr1110(nr);
nr1111(nr);
ncr0001(ncr);
ncr0011(ncr);
//ncr0001(ncr);
//ncr0011(ncr);
ncr0100(ncr);
ncr0101(ncr);
ncr0110(ncr);
ncr0111(ncr);
ncr1001(ncr);
ncr1011(ncr);
//ncr1001(ncr);
//ncr1011(ncr);
ncr1100(ncr);
ncr1101(ncr);
ncr1110(ncr);
ncr1111(ncr);
ul0001(ul());
ul0010(ul());
ul0011(ul());
//ul0001(ul());
//ul0010(ul());
//ul0011(ul());
ul0100(ul());
ul0101(ul());
ul0110(ul());
......@@ -660,14 +665,14 @@ int main()
ul1101(ul());
ul1110(ul());
ul1111(ul());
ucl0001(ucl());
ucl0011(ucl());
//ucl0001(ucl());
//ucl0011(ucl());
ucl0100(ucl());
ucl0101(ucl());
ucl0110(ucl());
ucl0111(ucl());
ucl1001(ucl());
ucl1011(ucl());
//ucl1001(ucl());
//ucl1011(ucl());
ucl1100(ucl());
ucl1101(ucl());
ucl1110(ucl());
......
// { dg-options "-std=c++0x" }
void f(int i)
{
int&& r = static_cast<int&&>(i);
}
// I, Howard Hinnant, hereby place this code in the public domain.
// Test overlaod resolution among referece types
// Test overload resolution among reference types
// { dg-do compile }
// { dg-options "-std=c++0x" }
......@@ -103,6 +103,7 @@ int test1_5()
const A ca = a;
volatile A va;
const volatile A cva = a;
sink_1_5(a); // { dg-error "lvalue" }
sink_1_5(ca); // { dg-error "invalid initialization" }
sink_1_5(va); // { dg-error "invalid initialization" }
sink_1_5(cva); // { dg-error "invalid initialization" }
......@@ -120,6 +121,8 @@ int test1_6()
const A ca = a;
volatile A va;
const volatile A cva = a;
sink_1_6(a); // { dg-error "lvalue" }
sink_1_6(ca); // { dg-error "lvalue" }
sink_1_6(va); // { dg-error "invalid initialization" }
sink_1_6(cva); // { dg-error "invalid initialization" }
sink_1_6(v_source()); // { dg-error "invalid initialization" }
......@@ -135,13 +138,30 @@ int test1_7()
const A ca = a;
volatile A va;
const volatile A cva = a;
sink_1_7(a); // { dg-error "lvalue" }
sink_1_7(ca); // { dg-error "invalid initialization" }
sink_1_7(va); // { dg-error "lvalue" }
sink_1_7(cva); // { dg-error "invalid initialization" }
sink_1_7(c_source()); // { dg-error "invalid initialization" }
sink_1_7(cv_source()); // { dg-error "invalid initialization" }
return 0;
}
eight sink_1_8(const volatile A&&); // { dg-error "" }
int test1_8()
{
A a;
const A ca = a;
volatile A va;
const volatile A cva = a;
sink_1_8(a); // { dg-error "lvalue" }
sink_1_8(ca); // { dg-error "lvalue" }
sink_1_8(va); // { dg-error "lvalue" }
sink_1_8(cva); // { dg-error "lvalue" }
return 0;
}
int main()
{
return test1_1() + test1_2() + test1_3() + test1_5() +
......
// I, Howard Hinnant, hereby place this code in the public domain.
// Test overlaod resolution among referece types
// Test overload resolution among reference types
// { dg-do compile }
// { dg-options "-std=c++0x" }
......@@ -93,7 +93,6 @@ int test1_5()
const A ca = a;
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_1_5(a)) == 5> t1;
sa<sizeof(sink_1_5(source())) == 5> t5;
return 0;
}
......@@ -106,8 +105,6 @@ int test1_6()
const A ca = a;
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_1_6(a)) == 6> t1;
sa<sizeof(sink_1_6(ca)) == 6> t2;
sa<sizeof(sink_1_6(source())) == 6> t5;
sa<sizeof(sink_1_6(c_source())) == 6> t6;
return 0;
......@@ -121,8 +118,6 @@ int test1_7()
const A ca = a;
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_1_7(a)) == 7> t1;
sa<sizeof(sink_1_7(va)) == 7> t3;
sa<sizeof(sink_1_7(source())) == 7> t5;
sa<sizeof(sink_1_7(v_source())) == 7> t7;
return 0;
......@@ -136,10 +131,6 @@ int test1_8()
const A ca = a;
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_1_8(a)) == 8> t1;
sa<sizeof(sink_1_8(ca)) == 8> t2;
sa<sizeof(sink_1_8(va)) == 8> t3;
sa<sizeof(sink_1_8(cva)) == 8> t4;
sa<sizeof(sink_1_8(source())) == 8> t5;
sa<sizeof(sink_1_8(c_source())) == 8> t6;
sa<sizeof(sink_1_8(v_source())) == 8> t7;
......
// I, Howard Hinnant, hereby place this code in the public domain.
// Test overlaod resolution among referece types
// Test overload resolution among reference types
// { dg-do compile }
// { dg-options "-std=c++0x" }
......@@ -100,7 +100,6 @@ int test2_16()
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_2_16(a)) == 1> t1;
sa<sizeof(sink_2_16(ca)) == 6> t2;
sa<sizeof(sink_2_16(source())) == 6> t5;
sa<sizeof(sink_2_16(c_source())) == 6> t6;
return 0;
......@@ -116,7 +115,6 @@ int test2_17()
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_2_17(a)) == 1> t1;
sa<sizeof(sink_2_17(va)) == 7> t3;
sa<sizeof(sink_2_17(source())) == 7> t5;
sa<sizeof(sink_2_17(v_source())) == 7> t7;
return 0;
......@@ -132,9 +130,6 @@ int test2_18()
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_2_18(a)) == 1> t1;
sa<sizeof(sink_2_18(ca)) == 8> t2;
sa<sizeof(sink_2_18(va)) == 8> t3;
sa<sizeof(sink_2_18(cva)) == 8> t4;
sa<sizeof(sink_2_18(source())) == 8> t5;
sa<sizeof(sink_2_18(c_source())) == 8> t6;
sa<sizeof(sink_2_18(v_source())) == 8> t7;
......@@ -221,7 +216,6 @@ int test2_27()
const volatile A cva = a;
sa<sizeof(sink_2_27(a)) == 2> t1;
sa<sizeof(sink_2_27(ca)) == 2> t2;
sa<sizeof(sink_2_27(va)) == 7> t3;
sa<sizeof(sink_2_27(source())) == 7> t5;
sa<sizeof(sink_2_27(c_source())) == 2> t6;
sa<sizeof(sink_2_27(v_source())) == 7> t7;
......@@ -239,8 +233,6 @@ int test2_28()
const volatile A cva = a;
sa<sizeof(sink_2_28(a)) == 2> t1;
sa<sizeof(sink_2_28(ca)) == 2> t2;
sa<sizeof(sink_2_28(va)) == 8> t3;
sa<sizeof(sink_2_28(cva)) == 8> t4;
sa<sizeof(sink_2_28(source())) == 8> t5;
sa<sizeof(sink_2_28(c_source())) == 8> t6;
sa<sizeof(sink_2_28(v_source())) == 8> t7;
......@@ -293,7 +285,6 @@ int test2_36()
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_2_36(a)) == 3> t1;
sa<sizeof(sink_2_36(ca)) == 6> t2;
sa<sizeof(sink_2_36(va)) == 3> t3;
sa<sizeof(sink_2_36(source())) == 6> t5;
sa<sizeof(sink_2_36(c_source())) == 6> t6;
......@@ -326,9 +317,7 @@ int test2_38()
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_2_38(a)) == 3> t1;
sa<sizeof(sink_2_38(ca)) == 8> t2;
sa<sizeof(sink_2_38(va)) == 3> t3;
sa<sizeof(sink_2_38(cva)) == 8> t4;
sa<sizeof(sink_2_38(source())) == 8> t5;
sa<sizeof(sink_2_38(c_source())) == 8> t6;
sa<sizeof(sink_2_38(v_source())) == 8> t7;
......@@ -425,8 +414,6 @@ int test2_56()
const A ca = a;
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_2_56(a)) == 5> t1;
sa<sizeof(sink_2_56(ca)) == 6> t2;
sa<sizeof(sink_2_56(source())) == 5> t5;
sa<sizeof(sink_2_56(c_source())) == 6> t6;
return 0;
......@@ -441,8 +428,6 @@ int test2_57()
const A ca = a;
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_2_57(a)) == 5> t1;
sa<sizeof(sink_2_57(va)) == 7> t3;
sa<sizeof(sink_2_57(source())) == 5> t5;
sa<sizeof(sink_2_57(v_source())) == 7> t7;
return 0;
......@@ -457,10 +442,6 @@ int test2_58()
const A ca = a;
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_2_58(a)) == 5> t1;
sa<sizeof(sink_2_58(ca)) == 8> t2;
sa<sizeof(sink_2_58(va)) == 8> t3;
sa<sizeof(sink_2_58(cva)) == 8> t4;
sa<sizeof(sink_2_58(source())) == 5> t5;
sa<sizeof(sink_2_58(c_source())) == 8> t6;
sa<sizeof(sink_2_58(v_source())) == 8> t7;
......@@ -477,8 +458,6 @@ int test2_67()
const A ca = a;
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_2_67(ca)) == 6> t2;
sa<sizeof(sink_2_67(va)) == 7> t3;
sa<sizeof(sink_2_67(c_source())) == 6> t6;
sa<sizeof(sink_2_67(v_source())) == 7> t7;
return 0;
......@@ -493,10 +472,6 @@ int test2_68()
const A ca = a;
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_2_68(a)) == 6> t1;
sa<sizeof(sink_2_68(ca)) == 6> t2;
sa<sizeof(sink_2_68(va)) == 8> t3;
sa<sizeof(sink_2_68(cva)) == 8> t4;
sa<sizeof(sink_2_68(source())) == 6> t5;
sa<sizeof(sink_2_68(c_source())) == 6> t6;
sa<sizeof(sink_2_68(v_source())) == 8> t7;
......@@ -513,10 +488,6 @@ int test2_78()
const A ca = a;
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_2_78(a)) == 7> t1;
sa<sizeof(sink_2_78(ca)) == 8> t2;
sa<sizeof(sink_2_78(va)) == 7> t3;
sa<sizeof(sink_2_78(cva)) == 8> t4;
sa<sizeof(sink_2_78(source())) == 7> t5;
sa<sizeof(sink_2_78(c_source())) == 8> t6;
sa<sizeof(sink_2_78(v_source())) == 7> t7;
......
// I, Howard Hinnant, hereby place this code in the public domain.
// Test overlaod resolution among referece types
// Test overload resolution among reference types
// { dg-do compile }
// { dg-options "-std=c++0x" }
......@@ -173,7 +173,6 @@ int test5_12358()
sa<sizeof(sink_5_12358(a)) == 1> t1;
sa<sizeof(sink_5_12358(ca)) == 2> t2;
sa<sizeof(sink_5_12358(va)) == 3> t3;
sa<sizeof(sink_5_12358(cva)) == 8> t4;
sa<sizeof(sink_5_12358(source())) == 5> t5;
sa<sizeof(sink_5_12358(c_source())) == 8> t6;
sa<sizeof(sink_5_12358(v_source())) == 8> t7;
......@@ -216,7 +215,6 @@ int test5_12368()
sa<sizeof(sink_5_12368(a)) == 1> t1;
sa<sizeof(sink_5_12368(ca)) == 2> t2;
sa<sizeof(sink_5_12368(va)) == 3> t3;
sa<sizeof(sink_5_12368(cva)) == 8> t4;
sa<sizeof(sink_5_12368(source())) == 6> t5;
sa<sizeof(sink_5_12368(c_source())) == 6> t6;
sa<sizeof(sink_5_12368(v_source())) == 8> t7;
......@@ -239,7 +237,6 @@ int test5_12378()
sa<sizeof(sink_5_12378(a)) == 1> t1;
sa<sizeof(sink_5_12378(ca)) == 2> t2;
sa<sizeof(sink_5_12378(va)) == 3> t3;
sa<sizeof(sink_5_12378(cva)) == 8> t4;
sa<sizeof(sink_5_12378(source())) == 7> t5;
sa<sizeof(sink_5_12378(c_source())) == 8> t6;
sa<sizeof(sink_5_12378(v_source())) == 7> t7;
......@@ -394,7 +391,6 @@ int test5_12567()
const volatile A cva = a;
sa<sizeof(sink_5_12567(a)) == 1> t1;
sa<sizeof(sink_5_12567(ca)) == 2> t2;
sa<sizeof(sink_5_12567(va)) == 7> t3;
sa<sizeof(sink_5_12567(source())) == 5> t5;
sa<sizeof(sink_5_12567(c_source())) == 6> t6;
sa<sizeof(sink_5_12567(v_source())) == 7> t7;
......@@ -415,8 +411,6 @@ int test5_12568()
const volatile A cva = a;
sa<sizeof(sink_5_12568(a)) == 1> t1;
sa<sizeof(sink_5_12568(ca)) == 2> t2;
sa<sizeof(sink_5_12568(va)) == 8> t3;
sa<sizeof(sink_5_12568(cva)) == 8> t4;
sa<sizeof(sink_5_12568(source())) == 5> t5;
sa<sizeof(sink_5_12568(c_source())) == 6> t6;
sa<sizeof(sink_5_12568(v_source())) == 8> t7;
......@@ -438,8 +432,6 @@ int test5_12578()
const volatile A cva = a;
sa<sizeof(sink_5_12578(a)) == 1> t1;
sa<sizeof(sink_5_12578(ca)) == 2> t2;
sa<sizeof(sink_5_12578(va)) == 7> t3;
sa<sizeof(sink_5_12578(cva)) == 8> t4;
sa<sizeof(sink_5_12578(source())) == 5> t5;
sa<sizeof(sink_5_12578(c_source())) == 8> t6;
sa<sizeof(sink_5_12578(v_source())) == 7> t7;
......@@ -461,8 +453,6 @@ int test5_12678()
const volatile A cva = a;
sa<sizeof(sink_5_12678(a)) == 1> t1;
sa<sizeof(sink_5_12678(ca)) == 2> t2;
sa<sizeof(sink_5_12678(va)) == 7> t3;
sa<sizeof(sink_5_12678(cva)) == 8> t4;
sa<sizeof(sink_5_12678(c_source())) == 6> t6;
sa<sizeof(sink_5_12678(v_source())) == 7> t7;
sa<sizeof(sink_5_12678(cv_source())) == 8> t8;
......@@ -614,7 +604,6 @@ int test5_13567()
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_5_13567(a)) == 1> t1;
sa<sizeof(sink_5_13567(ca)) == 6> t2;
sa<sizeof(sink_5_13567(va)) == 3> t3;
sa<sizeof(sink_5_13567(source())) == 5> t5;
sa<sizeof(sink_5_13567(c_source())) == 6> t6;
......@@ -635,9 +624,7 @@ int test5_13568()
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_5_13568(a)) == 1> t1;
sa<sizeof(sink_5_13568(ca)) == 6> t2;
sa<sizeof(sink_5_13568(va)) == 3> t3;
sa<sizeof(sink_5_13568(cva)) == 8> t4;
sa<sizeof(sink_5_13568(source())) == 5> t5;
sa<sizeof(sink_5_13568(c_source())) == 6> t6;
sa<sizeof(sink_5_13568(v_source())) == 8> t7;
......@@ -658,9 +645,7 @@ int test5_13578()
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_5_13578(a)) == 1> t1;
sa<sizeof(sink_5_13578(ca)) == 8> t2;
sa<sizeof(sink_5_13578(va)) == 3> t3;
sa<sizeof(sink_5_13578(cva)) == 8> t4;
sa<sizeof(sink_5_13578(source())) == 5> t5;
sa<sizeof(sink_5_13578(c_source())) == 8> t6;
sa<sizeof(sink_5_13578(v_source())) == 7> t7;
......@@ -681,9 +666,7 @@ int test5_13678()
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_5_13678(a)) == 1> t1;
sa<sizeof(sink_5_13678(ca)) == 6> t2;
sa<sizeof(sink_5_13678(va)) == 3> t3;
sa<sizeof(sink_5_13678(cva)) == 8> t4;
sa<sizeof(sink_5_13678(c_source())) == 6> t6;
sa<sizeof(sink_5_13678(v_source())) == 7> t7;
sa<sizeof(sink_5_13678(cv_source())) == 8> t8;
......@@ -793,9 +776,6 @@ int test5_15678()
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_5_15678(a)) == 1> t1;
sa<sizeof(sink_5_15678(ca)) == 6> t2;
sa<sizeof(sink_5_15678(va)) == 7> t3;
sa<sizeof(sink_5_15678(cva)) == 8> t4;
sa<sizeof(sink_5_15678(source())) == 5> t5;
sa<sizeof(sink_5_15678(c_source())) == 6> t6;
sa<sizeof(sink_5_15678(v_source())) == 7> t7;
......@@ -964,7 +944,6 @@ int test5_23568()
const volatile A cva = a;
sa<sizeof(sink_5_23568(ca)) == 2> t2;
sa<sizeof(sink_5_23568(va)) == 3> t3;
sa<sizeof(sink_5_23568(cva)) == 8> t4;
sa<sizeof(sink_5_23568(source())) == 5> t5;
sa<sizeof(sink_5_23568(c_source())) == 6> t6;
sa<sizeof(sink_5_23568(v_source())) == 8> t7;
......@@ -986,7 +965,6 @@ int test5_23578()
const volatile A cva = a;
sa<sizeof(sink_5_23578(ca)) == 2> t2;
sa<sizeof(sink_5_23578(va)) == 3> t3;
sa<sizeof(sink_5_23578(cva)) == 8> t4;
sa<sizeof(sink_5_23578(source())) == 5> t5;
sa<sizeof(sink_5_23578(c_source())) == 8> t6;
sa<sizeof(sink_5_23578(v_source())) == 7> t7;
......@@ -1008,7 +986,6 @@ int test5_23678()
const volatile A cva = a;
sa<sizeof(sink_5_23678(ca)) == 2> t2;
sa<sizeof(sink_5_23678(va)) == 3> t3;
sa<sizeof(sink_5_23678(cva)) == 8> t4;
sa<sizeof(sink_5_23678(c_source())) == 6> t6;
sa<sizeof(sink_5_23678(v_source())) == 7> t7;
sa<sizeof(sink_5_23678(cv_source())) == 8> t8;
......@@ -1119,8 +1096,6 @@ int test5_25678()
const volatile A cva = a;
sa<sizeof(sink_5_25678(a)) == 2> t1;
sa<sizeof(sink_5_25678(ca)) == 2> t2;
sa<sizeof(sink_5_25678(va)) == 7> t3;
sa<sizeof(sink_5_25678(cva)) == 8> t4;
sa<sizeof(sink_5_25678(source())) == 5> t5;
sa<sizeof(sink_5_25678(c_source())) == 6> t6;
sa<sizeof(sink_5_25678(v_source())) == 7> t7;
......@@ -1231,9 +1206,7 @@ int test5_35678()
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_5_35678(a)) == 3> t1;
sa<sizeof(sink_5_35678(ca)) == 6> t2;
sa<sizeof(sink_5_35678(va)) == 3> t3;
sa<sizeof(sink_5_35678(cva)) == 8> t4;
sa<sizeof(sink_5_35678(source())) == 5> t5;
sa<sizeof(sink_5_35678(c_source())) == 6> t6;
sa<sizeof(sink_5_35678(v_source())) == 7> t7;
......
// I, Howard Hinnant, hereby place this code in the public domain.
// Test overlaod resolution among referece types
// Test overload resolution among reference types
// { dg-do compile }
// { dg-options "-std=c++0x" }
......@@ -70,7 +70,7 @@ three sink_6_235678(volatile A&); // { dg-message "note" }
five sink_6_235678( A&&); // { dg-message "note" }
six sink_6_235678(const A&&); // { dg-message "note" }
seven sink_6_235678(volatile A&&); // { dg-message "note" }
eight sink_6_235678(const volatile A&&); // { dg-message "note" }
eight sink_6_235678(const volatile A&&); // { dg-message "" }
int test6_235678()
{
......@@ -79,6 +79,7 @@ int test6_235678()
volatile A va;
const volatile A cva = a;
sink_6_235678(a); // { dg-error "ambiguous" }
sink_6_235678(cva); // { dg-error "lvalue" }
return 0;
}
......@@ -191,7 +192,7 @@ two sink_6_123678(const A&); // { dg-message "candidates" }
three sink_6_123678(volatile A&);
six sink_6_123678(const A&&); // { dg-message "note" }
seven sink_6_123678(volatile A&&); // { dg-message "note" }
eight sink_6_123678(const volatile A&&); // { dg-message "note" }
eight sink_6_123678(const volatile A&&); // { dg-message "" }
int test6_123678()
{
......@@ -199,6 +200,7 @@ int test6_123678()
const A ca = a;
volatile A va;
const volatile A cva = a;
sink_6_123678(cva); // { dg-error "lvalue" }
sink_6_123678(source()); // { dg-error "ambiguous" }
return 0;
}
......@@ -221,6 +223,40 @@ int test6_123567()
return 0;
}
one sink_6_123568( A&);
two sink_6_123568(const A&);
three sink_6_123568(volatile A&);
five sink_6_123568( A&&);
six sink_6_123568(const A&&);
eight sink_6_123568(const volatile A&&); // { dg-message "" }
int test6_123568()
{
A a;
const A ca = a;
volatile A va;
const volatile A cva = a;
sink_6_123568(cva); // { dg-error "lvalue" }
return 0;
}
one sink_6_123578( A&);
two sink_6_123578(const A&);
three sink_6_123578(volatile A&);
five sink_6_123578( A&&);
seven sink_6_123578(volatile A&&);
eight sink_6_123578(const volatile A&&); // { dg-message "" }
int test6_123578()
{
A a;
const A ca = a;
volatile A va;
const volatile A cva = a;
sink_6_123578(cva); // { dg-error "lvalue" }
return 0;
}
one sink_6_123467( A&); // { dg-message "candidates" }
two sink_6_123467(const A&); // { dg-message "note" }
three sink_6_123467(volatile A&); // { dg-message "note" }
......@@ -256,6 +292,24 @@ int test6_124567()
return 0;
}
one sink_6_125678( A&);
two sink_6_125678(const A&);
five sink_6_125678( A&&);
six sink_6_125678(const A&&);
seven sink_6_125678(volatile A&&); // { dg-message "" }
eight sink_6_125678(const volatile A&&); // { dg-message "" }
int test6_125678()
{
A a;
const A ca = a;
volatile A va;
const volatile A cva = a;
sink_6_125678(va); // { dg-error "lvalue" }
sink_6_125678(cva); // { dg-error "lvalue" }
return 0;
}
one sink_6_134567( A&); // { dg-message "candidates" }
three sink_6_134567(volatile A&); // { dg-message "note" }
four sink_6_134567(const volatile A&); // { dg-message "note" }
......@@ -273,6 +327,24 @@ int test6_134567()
return 0;
}
one sink_6_135678( A&);
three sink_6_135678(volatile A&);
five sink_6_135678( A&&);
six sink_6_135678(const A&&); // { dg-message "" }
seven sink_6_135678(volatile A&&);
eight sink_6_135678(const volatile A&&); // { dg-message "" }
int test6_135678()
{
A a;
const A ca = a;
volatile A va;
const volatile A cva = a;
sink_6_135678(ca); // { dg-error "lvalue" }
sink_6_135678(cva); // { dg-error "lvalue" }
return 0;
}
int main()
{
return test6_235678() + test6_234678() + test6_234578() + test6_234568() +
......
// I, Howard Hinnant, hereby place this code in the public domain.
// Test overlaod resolution among referece types
// Test overload resolution among reference types
// { dg-do compile }
// { dg-options "-std=c++0x" }
......@@ -207,7 +207,6 @@ int test6_123568()
sa<sizeof(sink_6_123568(a)) == 1> t1;
sa<sizeof(sink_6_123568(ca)) == 2> t2;
sa<sizeof(sink_6_123568(va)) == 3> t3;
sa<sizeof(sink_6_123568(cva)) == 8> t4;
sa<sizeof(sink_6_123568(source())) == 5> t5;
sa<sizeof(sink_6_123568(c_source())) == 6> t6;
sa<sizeof(sink_6_123568(v_source())) == 8> t7;
......@@ -231,7 +230,6 @@ int test6_123578()
sa<sizeof(sink_6_123578(a)) == 1> t1;
sa<sizeof(sink_6_123578(ca)) == 2> t2;
sa<sizeof(sink_6_123578(va)) == 3> t3;
sa<sizeof(sink_6_123578(cva)) == 8> t4;
sa<sizeof(sink_6_123578(source())) == 5> t5;
sa<sizeof(sink_6_123578(c_source())) == 8> t6;
sa<sizeof(sink_6_123578(v_source())) == 7> t7;
......@@ -255,7 +253,6 @@ int test6_123678()
sa<sizeof(sink_6_123678(a)) == 1> t1;
sa<sizeof(sink_6_123678(ca)) == 2> t2;
sa<sizeof(sink_6_123678(va)) == 3> t3;
sa<sizeof(sink_6_123678(cva)) == 8> t4;
sa<sizeof(sink_6_123678(c_source())) == 6> t6;
sa<sizeof(sink_6_123678(v_source())) == 7> t7;
sa<sizeof(sink_6_123678(cv_source())) == 8> t8;
......@@ -371,8 +368,6 @@ int test6_125678()
const volatile A cva = a;
sa<sizeof(sink_6_125678(a)) == 1> t1;
sa<sizeof(sink_6_125678(ca)) == 2> t2;
sa<sizeof(sink_6_125678(va)) == 7> t3;
sa<sizeof(sink_6_125678(cva)) == 8> t4;
sa<sizeof(sink_6_125678(source())) == 5> t5;
sa<sizeof(sink_6_125678(c_source())) == 6> t6;
sa<sizeof(sink_6_125678(v_source())) == 7> t7;
......@@ -488,9 +483,7 @@ int test6_135678()
volatile A va;
const volatile A cva = a;
sa<sizeof(sink_6_135678(a)) == 1> t1;
sa<sizeof(sink_6_135678(ca)) == 6> t2;
sa<sizeof(sink_6_135678(va)) == 3> t3;
sa<sizeof(sink_6_135678(cva)) == 8> t4;
sa<sizeof(sink_6_135678(source())) == 5> t5;
sa<sizeof(sink_6_135678(c_source())) == 6> t6;
sa<sizeof(sink_6_135678(v_source())) == 7> t7;
......@@ -627,7 +620,6 @@ int test6_235678()
const volatile A cva = a;
sa<sizeof(sink_6_235678(ca)) == 2> t2;
sa<sizeof(sink_6_235678(va)) == 3> t3;
sa<sizeof(sink_6_235678(cva)) == 8> t4;
sa<sizeof(sink_6_235678(source())) == 5> t5;
sa<sizeof(sink_6_235678(c_source())) == 6> t6;
sa<sizeof(sink_6_235678(v_source())) == 7> t7;
......
......@@ -48,6 +48,24 @@ int test7_1234567()
return 0;
}
one sink_7_1235678( A&);
two sink_7_1235678(const A&);
three sink_7_1235678(volatile A&);
five sink_7_1235678( A&&);
six sink_7_1235678(const A&&);
seven sink_7_1235678(volatile A&&);
eight sink_7_1235678(const volatile A&&); // { dg-message "" }
int test7_1235678()
{
A a;
const A ca = a;
volatile A va;
const volatile A cva = a;
sink_7_1235678(cva); // { dg-error "lvalue" }
return 0;
}
two sink_7_2345678(const A&); // { dg-message "candidates" }
three sink_7_2345678(volatile A&); // { dg-message "note" }
four sink_7_2345678(const volatile A&); // { dg-message "note" }
......
// I, Howard Hinnant, hereby place this code in the public domain.
// Test overlaod resolution among referece types
// Test overload resolution among reference types
// { dg-do compile }
// { dg-options "-std=c++0x" }
......@@ -145,7 +145,6 @@ int test7_1235678()
sa<sizeof(sink_7_1235678(a)) == 1> t1;
sa<sizeof(sink_7_1235678(ca)) == 2> t2;
sa<sizeof(sink_7_1235678(va)) == 3> t3;
sa<sizeof(sink_7_1235678(cva)) == 8> t4;
sa<sizeof(sink_7_1235678(source())) == 5> t5;
sa<sizeof(sink_7_1235678(c_source())) == 6> t6;
sa<sizeof(sink_7_1235678(v_source())) == 7> t7;
......
// I, Howard Hinnant, hereby place this code in the public domain.
// Test overlaod resolution among referece types
// Test overload resolution among reference types
// { dg-do compile }
// { dg-options "-std=c++0x" }
......
......@@ -35,7 +35,7 @@ test1(T&&)
template <bool is_lvalue_ref, bool is_rvalue_ref, class T>
void
test2(const T&&)
test2(const T&&) // { dg-error "argument" }
{
sa<is_lvalue_reference<const T&&>::value == is_lvalue_ref> t1;
sa<is_rvalue_reference<const T&&>::value == is_rvalue_ref> t2;
......@@ -60,7 +60,7 @@ int main()
{
test1<true, false>(a);
test1<false, true>(source());
test2<false, true>(a);
test2<false, true>(a); // { dg-error "lvalue" }
test2<false, true>(source());
test3<false, true>(&a);
test3<false, true>(sourcep());
......
......@@ -16,7 +16,12 @@ struct A {};
one foo(const A&) {return one();}
two foo(A&&) {return two();}
A&& source() {static A a; return a;}
template<typename _Tp>
inline _Tp&&
movel(_Tp& __t)
{ return static_cast<_Tp&&>(__t); }
A&& source() {static A a; return movel(a);}
int test1()
{
......
2009-07-31 Jason Merrill <jason@redhat.com>
Douglas Gregor <doug.gregor@gmail.com>
* include/bits/move.h (forward): Implement as in N2835.
(move): Implement as in N2831.
* include/std/istream (rvalue stream operator>>): New.
* include/std/ostream (rvalue stream operator<<): New.
* testsuite/27_io/rvalue_streams.cc: New.
2009-07-31 Jason Merrill <jason@redhat.com>
* include/bits/forward_list.h (splice_after): Use forward.
(merge): Likewise.
......
......@@ -46,12 +46,31 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
typedef _Tp type;
};
/// forward
template<typename _Tp>
inline _Tp&&
/// forward (as per N2835)
/// Forward lvalues as rvalues.
template <class _Tp>
inline typename enable_if<!is_lvalue_reference<_Tp>::value, _Tp&&>::type
forward(typename std::identity<_Tp>::type& __t)
{ return static_cast<_Tp&&>(__t); }
/// Forward rvalues as rvalues.
template <class _Tp>
inline typename enable_if<!is_lvalue_reference<_Tp>::value, _Tp&&>::type
forward(typename std::identity<_Tp>::type&& __t)
{ return static_cast<_Tp&&>(__t); }
// Forward lvalues as lvalues.
template <class _Tp>
inline typename enable_if<is_lvalue_reference<_Tp>::value, _Tp>::type
forward(typename std::identity<_Tp>::type __t)
{ return __t; }
// Prevent forwarding rvalues as const lvalues.
template <class _Tp>
inline typename enable_if<is_lvalue_reference<_Tp>::value, _Tp>::type
forward(typename std::remove_reference<_Tp>::type&& __t)
= delete;
/**
* @brief Move a value.
* @ingroup mutating_algorithms
......@@ -61,7 +80,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
template<typename _Tp>
inline typename std::remove_reference<_Tp>::type&&
move(_Tp&& __t)
{ return __t; }
{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
_GLIBCXX_END_NAMESPACE
......
......@@ -827,6 +827,27 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
basic_istream<_CharT, _Traits>&
ws(basic_istream<_CharT, _Traits>& __is);
#ifdef __GXX_EXPERIMENTAL_CXX0X__
// [27.7.1.6] Rvalue stream extraction
/**
* @brief Generic extractor for rvalue stream
* @param is An input stream.
* @param x A reference to the extraction target.
* @return is
*
* This is just a forwarding function to allow extraction from
* rvalue streams since they won't bind to the extractor functions
* that take an lvalue reference.
*/
template<typename _CharT, typename _Traits, typename _Tp>
basic_istream<_CharT, _Traits>&
operator>>(basic_istream<_CharT, _Traits>&& __is, _Tp& __x)
{
__is >> __x;
return __is;
}
#endif // __GXX_EXPERIMENTAL_CXX0X__
_GLIBCXX_END_NAMESPACE
#ifndef _GLIBCXX_EXPORT_TEMPLATE
......
......@@ -562,6 +562,27 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
flush(basic_ostream<_CharT, _Traits>& __os)
{ return __os.flush(); }
#ifdef __GXX_EXPERIMENTAL_CXX0X__
// [27.7.2.9] Rvalue stream insertion
/**
* @brief Generic inserter for rvalue stream
* @param os An input stream.
* @param x A reference to the object being inserted.
* @return os
*
* This is just a forwarding function to allow insertion to
* rvalue streams since they won't bind to the inserter functions
* that take an lvalue reference.
*/
template<typename _CharT, typename _Traits, typename _Tp>
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
{
__os << __x;
return __os;
}
#endif // __GXX_EXPERIMENTAL_CXX0X__
_GLIBCXX_END_NAMESPACE
#ifndef _GLIBCXX_EXPORT_TEMPLATE
......
// Copyright (C) 2008 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING. If not, write to the Free
// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
// USA.
// { dg-do run }
#include <sstream>
#include <string>
#include <testsuite_hooks.h>
void
test01()
{
int i = 1742;
// This usage isn't supported by the current draft.
// std::string result = (std::ostringstream() << i).str();
std::ostringstream() << i;
std::string result ("1742");
int i2;
std::istringstream(result) >> i2;
VERIFY (i == i2);
}
int
main()
{
test01();
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment