Commit d02f620d by Jason Merrill Committed by Jason Merrill

re PR c++/20332 (poor diagnostic when bind non lvalue to a reference for default arguments)

	PR c++/20332
	PR c++/21631
	* call.c (reference_binding): Treat lvalue/rvalue mismatch and
	dropped cv-quals as a bad conversion.
	(convert_like_real) [ck_ref_bind]: Explain them.
	(compare_ics): Check badness before stripping reference
	bindings.  Handle comparing bad reference bindings.
	* typeck.c (comp_cv_qualification): Add overload that just takes
	integers.
	* cp-tree.h: Declare it.

From-SVN: r210436
parent 89606913
2014-05-14 Jason Merrill <jason@redhat.com>
PR c++/20332
PR c++/21631
* call.c (reference_binding): Treat lvalue/rvalue mismatch and
dropped cv-quals as a bad conversion.
(convert_like_real) [ck_ref_bind]: Explain them.
(compare_ics): Check badness before stripping reference
bindings. Handle comparing bad reference bindings.
* typeck.c (comp_cv_qualification): Add overload that just takes
integers.
* cp-tree.h: Declare it.
* call.c (struct conversion_info): Rename 'from_type' to 'from'.
(arg_conversion_rejection, bad_arg_conversion_rejection)
(explicit_conversion_rejection, template_conversion_rejection): Adjust.
......
......@@ -1540,15 +1540,11 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
[8.5.3/5 dcl.init.ref] is changed to also require direct bindings for
const and rvalue references to rvalues of compatible class type.
We should also do direct bindings for non-class xvalues. */
if (compatible_p
&& (is_lvalue
|| (((CP_TYPE_CONST_NON_VOLATILE_P (to)
&& !(flags & LOOKUP_NO_RVAL_BIND))
|| TYPE_REF_IS_RVALUE (rto))
&& (gl_kind
|| (!(flags & LOOKUP_NO_TEMP_BIND)
&& (CLASS_TYPE_P (from)
|| TREE_CODE (from) == ARRAY_TYPE))))))
if (related_p
&& (gl_kind
|| (!(flags & LOOKUP_NO_TEMP_BIND)
&& (CLASS_TYPE_P (from)
|| TREE_CODE (from) == ARRAY_TYPE))))
{
/* [dcl.init.ref]
......@@ -1603,6 +1599,16 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
&& !(flags & LOOKUP_PREFER_RVALUE))
conv->bad_p = true;
/* Nor the reverse. */
if (!is_lvalue && !TYPE_REF_IS_RVALUE (rto)
&& (!CP_TYPE_CONST_NON_VOLATILE_P (to)
|| (flags & LOOKUP_NO_RVAL_BIND))
&& TREE_CODE (to) != FUNCTION_TYPE)
conv->bad_p = true;
if (!compatible_p)
conv->bad_p = true;
return conv;
}
/* [class.conv.fct] A conversion function is never used to convert a
......@@ -1647,24 +1653,6 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
difference in top-level cv-qualification is subsumed by the
initialization itself and does not constitute a conversion. */
/* [dcl.init.ref]
Otherwise, the reference shall be an lvalue reference to a
non-volatile const type, or the reference shall be an rvalue
reference. */
if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto))
return NULL;
/* [dcl.init.ref]
Otherwise, a temporary of type "cv1 T1" is created and
initialized from the initializer expression using the rules for a
non-reference copy initialization. If T1 is reference-related to
T2, cv1 must be the same cv-qualification as, or greater
cv-qualification than, cv2; otherwise, the program is ill-formed. */
if (related_p && !at_least_as_qualified_p (to, from))
return NULL;
/* We're generating a temporary now, but don't bind any more in the
conversion (specifically, don't slice the temporary returned by a
conversion operator). */
......@@ -1710,6 +1698,24 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
conv->need_temporary_p = true;
conv->rvaluedness_matches_p = TYPE_REF_IS_RVALUE (rto);
/* [dcl.init.ref]
Otherwise, the reference shall be an lvalue reference to a
non-volatile const type, or the reference shall be an rvalue
reference. */
if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto))
conv->bad_p = true;
/* [dcl.init.ref]
Otherwise, a temporary of type "cv1 T1" is created and
initialized from the initializer expression using the rules for a
non-reference copy initialization. If T1 is reference-related to
T2, cv1 must be the same cv-qualification as, or greater
cv-qualification than, cv2; otherwise, the program is ill-formed. */
if (related_p && !at_least_as_qualified_p (to, from))
conv->bad_p = true;
return conv;
}
......@@ -6334,12 +6340,20 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
if (convs->bad_p && !next_conversion (convs)->bad_p)
{
gcc_assert (TYPE_REF_IS_RVALUE (ref_type)
&& (real_lvalue_p (expr)
|| next_conversion(convs)->kind == ck_rvalue));
error_at (loc, "cannot bind %qT lvalue to %qT",
TREE_TYPE (expr), totype);
tree extype = TREE_TYPE (expr);
if (TYPE_REF_IS_RVALUE (ref_type)
&& real_lvalue_p (expr))
error_at (loc, "cannot bind %qT lvalue to %qT",
extype, totype);
else if (!TYPE_REF_IS_RVALUE (ref_type) && !real_lvalue_p (expr)
&& !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type)))
error_at (loc, "invalid initialization of non-const reference of "
"type %qT from an rvalue of type %qT", totype, extype);
else if (!reference_compatible_p (TREE_TYPE (totype), extype))
error_at (loc, "binding %qT to reference of type %qT "
"discards qualifiers", extype, totype);
else
gcc_unreachable ();
maybe_print_user_conv_context (convs);
if (fn)
inform (input_location,
......@@ -8230,6 +8244,12 @@ compare_ics (conversion *ics1, conversion *ics2)
conversion *ref_conv1;
conversion *ref_conv2;
/* Compare badness before stripping the reference conversion. */
if (ics1->bad_p > ics2->bad_p)
return -1;
else if (ics1->bad_p < ics2->bad_p)
return 1;
/* Handle implicit object parameters. */
maybe_handle_implicit_object (&ics1);
maybe_handle_implicit_object (&ics2);
......@@ -8258,31 +8278,19 @@ compare_ics (conversion *ics1, conversion *ics2)
--a user-defined conversion sequence (_over.ics.user_) is a
better conversion sequence than an ellipsis conversion sequence
(_over.ics.ellipsis_). */
rank1 = CONVERSION_RANK (ics1);
rank2 = CONVERSION_RANK (ics2);
/* Use BAD_CONVERSION_RANK because we already checked for a badness
mismatch. If both ICS are bad, we try to make a decision based on
what would have happened if they'd been good. This is not an
extension, we'll still give an error when we build up the call; this
just helps us give a more helpful error message. */
rank1 = BAD_CONVERSION_RANK (ics1);
rank2 = BAD_CONVERSION_RANK (ics2);
if (rank1 > rank2)
return -1;
else if (rank1 < rank2)
return 1;
if (rank1 == cr_bad)
{
/* Both ICS are bad. We try to make a decision based on what would
have happened if they'd been good. This is not an extension,
we'll still give an error when we build up the call; this just
helps us give a more helpful error message. */
rank1 = BAD_CONVERSION_RANK (ics1);
rank2 = BAD_CONVERSION_RANK (ics2);
if (rank1 > rank2)
return -1;
else if (rank1 < rank2)
return 1;
/* We couldn't make up our minds; try to figure it out below. */
}
if (ics1->ellipsis_p)
/* Both conversions are ellipsis conversions. */
return 0;
......@@ -8602,13 +8610,30 @@ compare_ics (conversion *ics1, conversion *ics2)
|| (TYPE_REF_IS_RVALUE (ref_conv1->type)
!= TYPE_REF_IS_RVALUE (ref_conv2->type))))
{
if (ref_conv1->bad_p
&& !same_type_p (TREE_TYPE (ref_conv1->type),
TREE_TYPE (ref_conv2->type)))
/* Don't prefer a bad conversion that drops cv-quals to a bad
conversion with the wrong rvalueness. */
return 0;
return (ref_conv1->rvaluedness_matches_p
- ref_conv2->rvaluedness_matches_p);
}
if (same_type_ignoring_top_level_qualifiers_p (to_type1, to_type2))
return comp_cv_qualification (TREE_TYPE (ref_conv2->type),
TREE_TYPE (ref_conv1->type));
{
int q1 = cp_type_quals (TREE_TYPE (ref_conv1->type));
int q2 = cp_type_quals (TREE_TYPE (ref_conv2->type));
if (ref_conv1->bad_p)
{
/* Prefer the one that drops fewer cv-quals. */
tree ftype = next_conversion (ref_conv1)->type;
int fquals = cp_type_quals (ftype);
q1 ^= fquals;
q2 ^= fquals;
}
return comp_cv_qualification (q2, q1);
}
}
/* Neither conversion sequence is better than the other. */
......
......@@ -6034,6 +6034,7 @@ extern bool comptypes (tree, tree, int);
extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree);
extern bool compparms (const_tree, const_tree);
extern int comp_cv_qualification (const_tree, const_tree);
extern int comp_cv_qualification (int, int);
extern int comp_cv_qual_signature (tree, tree);
extern tree cxx_sizeof_or_alignof_expr (tree, enum tree_code, bool);
extern tree cxx_sizeof_or_alignof_type (tree, enum tree_code, bool);
......
......@@ -1452,11 +1452,8 @@ at_least_as_qualified_p (const_tree type1, const_tree type2)
more cv-qualified that TYPE1, and 0 otherwise. */
int
comp_cv_qualification (const_tree type1, const_tree type2)
comp_cv_qualification (int q1, int q2)
{
int q1 = cp_type_quals (type1);
int q2 = cp_type_quals (type2);
if (q1 == q2)
return 0;
......@@ -1468,6 +1465,14 @@ comp_cv_qualification (const_tree type1, const_tree type2)
return 0;
}
int
comp_cv_qualification (const_tree type1, const_tree type2)
{
int q1 = cp_type_quals (type1);
int q2 = cp_type_quals (type2);
return comp_cv_qualification (q1, q2);
}
/* Returns 1 if the cv-qualification signature of TYPE1 is a proper
subset of the cv-qualification signature of TYPE2, and the types
are similar. Returns -1 if the other way 'round, and 0 otherwise. */
......
......@@ -9,11 +9,11 @@ struct X {
}
};
void add_one (X & ref) { /* { dg-message "in passing argument" } */
void add_one (X & ref) { /* { dg-message "argument" } */
++ ref.x;
}
void foo() {
X const a (2);
add_one(a); /* { dg-error "invalid initialization of reference of type" } */
add_one(a); /* { dg-error "discards qualifiers" } */
}
// { dg-do compile { target c++11 } }
struct A {};
// We shouldn't arbitarily choose which of these is better.
void f (A&);
void f (const A&&);
// But do prefer the lvalue overload here.
void g (A&);
void g (A&&);
int main()
{
const A a;
f(a); // { dg-error "no match" }
// { dg-error "qualifiers" "" { target *-*-* } 15 }
// { dg-error "lvalue" "" { target *-*-* } 15 }
g(a); // { dg-error "qualifiers" }
}
......@@ -543,9 +543,9 @@ void ucr1111(const S&&) {}
int main()
{
l0001(l); // { dg-error "lvalue" }
l0010(l); // { dg-error "lvalue" }
l0011(l); // { dg-error "lvalue" }
l0001(l); // { dg-error "" }
l0010(l); // { dg-error "" }
l0011(l); // { dg-error "" }
l0100(l);
l0101(l);
l0110(l);
......@@ -564,8 +564,8 @@ int main()
cl0101(cl);
cl0110(cl);
cl0111(cl);
cl1001(cl); // { dg-error "lvalue" }
cl1011(cl); // { dg-error "lvalue" }
cl1001(cl); // { dg-error "" }
cl1011(cl); // { dg-error "" }
cl1100(cl);
cl1101(cl);
cl1110(cl);
......@@ -617,8 +617,8 @@ int main()
ncl0101(ncl);
ncl0110(ncl);
ncl0111(ncl);
ncl1001(ncl); // { dg-error "lvalue" }
ncl1011(ncl); // { dg-error "lvalue" }
ncl1001(ncl); // { dg-error "" }
ncl1011(ncl); // { dg-error "" }
ncl1100(ncl);
ncl1101(ncl);
ncl1110(ncl);
......@@ -644,8 +644,8 @@ int main()
ncr0101(ncr);
ncr0110(ncr);
ncr0111(ncr);
ncr1001(ncr); // { dg-error "lvalue" }
ncr1011(ncr); // { dg-error "lvalue" }
ncr1001(ncr); // { dg-error "" }
ncr1011(ncr); // { dg-error "" }
ncr1100(ncr);
ncr1101(ncr);
ncr1110(ncr);
......@@ -671,8 +671,8 @@ int main()
ucl0101(ucl());
ucl0110(ucl());
ucl0111(ucl());
ucl1001(ucl()); // { dg-error "lvalue" }
ucl1011(ucl()); // { dg-error "lvalue" }
ucl1001(ucl()); // { dg-error "" }
ucl1011(ucl()); // { dg-error "" }
ucl1100(ucl());
ucl1101(ucl());
ucl1110(ucl());
......
// PR c++/20332
struct bar {};
void foo1() {
bar& b = bar(); // { dg-error "rvalue" }
}
void foo(bar& b = bar()) {} // { dg-error "rvalue" }
// PR c++/21631
int f(int&);
int f();
int g(void)
{
return f(1); // { dg-error "rvalue" }
}
// PR c++/27666
struct A { // { dg-message "A" }
A(int); // { dg-message "A" }
A(int);
};
void foo(volatile A a) {
1 ? a : 0; // { dg-error "match|temporary" }
1 ? 0 : a; // { dg-error "match|temporary" }
1 ? a : 0; // { dg-error "qualifiers|lvalue|no match" }
1 ? 0 : a; // { dg-error "qualifiers|lvalue|no match" }
}
// PR c++/34180
struct G {
G(); // { dg-message "" "candidate" }
G();
G(G&); // { dg-message "" "candidate" }
};
......
......@@ -3,15 +3,15 @@
template<class T> struct wrap {};
template<typename T> bool& operator==(wrap<T>, wrap<T>);
template<typename T> bool operator==(wrap<T>, wrap<T>);
template<typename T>
void g(T, wrap<wrap<int> > x)
{
bool& b = x == x; // { dg-bogus "invalid initialization of reference" "" { xfail *-*-*} }
bool b = x == x; // { dg-bogus "" "" { xfail *-*-* } }
}
template<typename T> int& operator==(wrap<wrap<T> >, wrap<wrap<T> >);
template<typename T> void operator==(wrap<wrap<T> >, wrap<wrap<T> >);
void h()
{
......
......@@ -10,7 +10,7 @@ struct A {};
struct B : A
{
B(int); // { dg-message "B::B|no known conversion" "" }
B(int);
B(B&); // { dg-message "note" "" }
};
......@@ -18,5 +18,5 @@ void foo(B); // { dg-message "initializing" }
void bar()
{
foo(0); // { dg-error "no matching function" "no matching" }
foo(0); // { dg-error "" }
}
......@@ -11,7 +11,7 @@ void f()
{
const int i = 42;
A()(i); // { dg-message "<conversion>" }
// { dg-error "qualifiers" "" { target *-*-* } 13 }
}
// { dg-prune-output "no match" }
// { dg-prune-output "candidate" }
......@@ -4,7 +4,7 @@ struct A;
struct B
{
B (A const &); // { dg-message "note" }
B (A const &);
B (B &); // { dg-message "note" }
};
......@@ -16,5 +16,5 @@ struct A
B
f (B const& b)
{
return b; // { dg-error "matching" "matching" }
return b; // { dg-error "" }
}
// PR c++/48118
// { dg-prune-output "note" }
struct A { };
......@@ -9,6 +8,6 @@ void (*g)(A);
int main()
{
volatile A a;
f(a); // { dg-error "no match" }
g(a); // { dg-error "no match" }
f(a); // { dg-error "" }
g(a); // { dg-error "" }
}
......@@ -38,19 +38,19 @@ void r()
B b;
A& a1 = dynamic_cast<A&>(b);
A& a2 = dynamic_cast<const A&>(b); // { dg-error "invalid" }
A& a3 = dynamic_cast<volatile A&>(b); // { dg-error "invalid" }
A& a4 = dynamic_cast<const volatile A&>(b); // { dg-error "invalid" }
A& a2 = dynamic_cast<const A&>(b); // { dg-error "" }
A& a3 = dynamic_cast<volatile A&>(b); // { dg-error "" }
A& a4 = dynamic_cast<const volatile A&>(b); // { dg-error "" }
const A& ca1 = dynamic_cast<A&>(b);
const A& ca2 = dynamic_cast<const A&>(b);
const A& ca3 = dynamic_cast<volatile A&>(b); // { dg-error "invalid" }
const A& ca4 = dynamic_cast<const volatile A&>(b); // { dg-error "invalid" }
const A& ca3 = dynamic_cast<volatile A&>(b); // { dg-error "" }
const A& ca4 = dynamic_cast<const volatile A&>(b); // { dg-error "" }
volatile A& va1 = dynamic_cast<A&>(b);
volatile A& va2 = dynamic_cast<const A&>(b); // { dg-error "invalid" }
volatile A& va2 = dynamic_cast<const A&>(b); // { dg-error "" }
volatile A& va3 = dynamic_cast<volatile A&>(b);
volatile A& va4 = dynamic_cast<const volatile A&>(b);// { dg-error "invalid" }
volatile A& va4 = dynamic_cast<const volatile A&>(b);// { dg-error "" }
const volatile A& cva1 = dynamic_cast<A&>(b);
const volatile A& cva2 = dynamic_cast<const A&>(b);
......
......@@ -6,9 +6,9 @@
struct A
{
A(A&); // { dg-message "note" }
template <class T> A(T); // { dg-message "note" }
A(A&); // { dg-message "A::A" }
template <class T> A(T); // { dg-message "A::A" }
};
A a = 0; // { dg-error "no matching function" }
A a = 0; // { dg-error "" }
......@@ -12,6 +12,6 @@ extern panama dig();
void foo() {
panama obj;
obj = dig(); // { dg-error "no match" }
obj = dig(); // { dg-error "rvalue" }
}
......@@ -44,5 +44,5 @@ public:
void
foo (bar yylval, bar *yyvsp)
{
nnyacc::assign(yylval.valueList, yyvsp[0].valueList);// { dg-error "no matching" }
nnyacc::assign(yylval.valueList, yyvsp[0].valueList);// { dg-error "no matching|rvalue" }
}
......@@ -71,8 +71,8 @@ void t_1_assignment ()
t_1_st_1 t_1_st_1_obj1;
t_1_st_1 t_1_st_1_obj2;
t_1_st_1_obj0 = t_1_st_0_obj0; // { dg-error "no match" }
t_1_st_1_obj1 = t_1_st_1 (t_1_st_0_obj0); // { dg-error "no match" }
t_1_st_1_obj0 = t_1_st_0_obj0; // { dg-error "no match|conversion" }
t_1_st_1_obj1 = t_1_st_1 (t_1_st_0_obj0); // { dg-error "no match|rvalue" }
}
void t_1_local_init ()
......
// { dg-do assemble }
struct A
{
A(); // { dg-message "A::A|candidate expects" } candidate
A();
A(A&); // { dg-message "A::A|no known conversion" } referenced below
};
......@@ -10,7 +10,7 @@ main ()
{
try
{
throw A(); // { dg-error "no matching" "match" } can't copy
throw A(); // { dg-error "rvalue" "" } can't copy
// { dg-error "thrown expression" "expr" { target *-*-* } 13 }
}
catch (...) { }
......
......@@ -2,7 +2,7 @@
class X // Indentation has been done so to see the similarities.
{
public:
X() {} // { dg-message "note" } referenced below
X() {}
X(X& x) {x.i=7;} // { dg-message "note" } Both functions modify the
void bar(X& x) {x.i=7;} // { dg-message "note" } reference parameter x.
int i;
......@@ -12,6 +12,6 @@ X foo() { X x; return x; }
int main()
{
X x(foo()); // { dg-error "no match" } Compiler doesn't warn about temporary reference.
x.bar(foo()); // { dg-error "no match" } The same mistake is warned about in this case.
X x(foo()); // { dg-error "rvalue" } Compiler doesn't warn about temporary reference.
x.bar(foo()); // { dg-error "rvalue" } The same mistake is warned about in this case.
}
......@@ -9,7 +9,7 @@
// Compiles fine with Sun CC 2.1
void f(char *& x) // { dg-message "passing argument" }
void f(const char *& x) // { dg-message "argument" }
{
x++;
}
......
......@@ -24,6 +24,6 @@ int main()
Enum e = enumerator1;
Struct s;
int x = funct(e+1);// { dg-error "invalid" }
int y = s.getI(e+1);// { dg-error "match|conv" }
int y = s.getI(e+1);// { dg-error "invalid" }
return x+y;
}
......@@ -8,7 +8,7 @@
const int ic = 1;
void f(int& arg) // { dg-message "passing argument 1" }
void f(int& arg) // { dg-message "argument 1" }
{
if (arg) ;
}
......@@ -16,7 +16,7 @@ const int& icr = ic;
int main(void)
{
f(icr); // { dg-error "invalid initialization" }
f(icr); // { dg-error "const" }
return 0;
}
......@@ -16,5 +16,5 @@ public:
void
test(B &b1, const B &b2)
{
b1 = b2;// { dg-error "match" }
b1 = b2;// { dg-error "const" }
}
......@@ -11,14 +11,14 @@ public:
int bar;
};
void func(Base&); // { dg-message "passing argument 1" }
void func(Base&); // { dg-message "argument 1" }
void func2(const Derived& d) {
func(d); // { dg-error "invalid initialization" }
func(d); // { dg-error "" }
}
void
foo (int& a) // { dg-message "in passing argument 1" }
foo (int& a) // { dg-message "argument 1" }
{
}
......@@ -27,6 +27,6 @@ int main ()
int b;
const int*const a = &b;
*a = 10; // { dg-error "read-only location" }
foo (*a); // { dg-error "invalid initialization" }
foo (*a); // { dg-error "qualifiers" }
return 0;
}
......@@ -196,7 +196,7 @@ Pix
List_DLS<T>::search(const T& item) const
{
for (Pix x=this->first(); 0 != x; this->next(x)) {
if (item == this->operator()(x)) // { dg-error "match" } const subversion
if (item == this->operator()(x)) // { dg-error "qualifiers" } const subversion
return x;
}
return 0;
......@@ -485,8 +485,8 @@ class STRLIdentifier {
char buf[10];
};
extern int operator==(vertex<STRLIdentifier*>&, vertex<STRLIdentifier*>&); // { dg-message "note" } const subversion
extern int operator==(STRLIdentifier&, STRLIdentifier&); // { dg-message "note" } fn ref in err msg
extern int operator==(vertex<STRLIdentifier*>&, vertex<STRLIdentifier*>&); // { dg-message "argument 1" } const subversion
extern int operator==(STRLIdentifier&, STRLIdentifier&);
extern int x(List_DLSp<STRLIdentifier *>);
......
......@@ -18,6 +18,6 @@ class C
C()
{
B b;
A a = b;// { dg-error "match" }
A a = b;// { dg-error "rvalue" }
}
};
......@@ -19,5 +19,5 @@ void C::test() const
{
D d;
d.a(*this); // { dg-error "match" } *this is const, so should get error
d.a(*this); // { dg-error "const" } *this is const, so should get error
}
......@@ -7,7 +7,7 @@ extern "C"
}
void Munge(int& x) // { dg-message "passing argument 1" }
void Munge(int& x) // { dg-message "argument 1" }
{
x = 2;
}
......@@ -24,7 +24,7 @@ class A
void
A::Safe() const
{
Munge(i); // { dg-error "invalid initialization" }
Munge(i); // { dg-error "const" }
}
int main()
......
......@@ -12,7 +12,7 @@ class foo {
static void iteratorTest(const foo &x)
{
foo::const_iterator i = x.begin(); // { dg-error "incomplete type" "incomplete type" }
// { dg-error "no matching|const foo" "no matching" { target *-*-* } 14 }
// { dg-error "const foo" "" { target *-*-* } 14 }
for (; i; ++i)
*i;
}
......@@ -15,6 +15,6 @@ ret_v_f_class()
int main(void)
{
volatile f_class vf;
0 ? ret_v_f_class() : vf; // { dg-error "match" } can't copy volatile lvalue
0 ? ret_v_f_class() : vf; // { dg-error "volatile" } can't copy volatile lvalue
return 0;
}
......@@ -11,7 +11,7 @@ template<typename X> struct auto_ptr {
explicit auto_ptr(X* p =0) throw() : px(p) {}
auto_ptr(auto_ptr& r) throw() : px(r.release()) {} // { dg-message "note" } candidate
template<typename Y>
auto_ptr(auto_ptr<Y>& r) throw() : px(r.release()) {}// { dg-message "note" } candidate
auto_ptr(auto_ptr<Y>& r) throw() : px(r.release()) {}
auto_ptr& operator=(auto_ptr& r) throw() {
reset(r.release());
......@@ -30,7 +30,7 @@ template<typename X> struct auto_ptr {
X* release() throw() { X* p=px; px=0; return p; }
void reset(X* p=0) throw() { if (px != p) delete px, px = p; }
auto_ptr(auto_ptr_ref<X> r) throw() : px(r.py) {} // { dg-message "note" }
auto_ptr(auto_ptr_ref<X> r) throw() : px(r.py) {}
template<typename Y> operator auto_ptr_ref<Y>() throw() {
return auto_ptr_ref<Y>(release());
}
......@@ -51,5 +51,5 @@ int main() {
auto_ptr<Derived> y(f());
x = y;
g(f());
h(f()); // { dg-error "match" "match" } no usable copy ctor
h(f()); // { dg-error "rvalue" "" } no usable copy ctor
}
// { dg-do assemble }
template <class A> class B { // { dg-message "note" }
template <class A> class B {
A a;
public:
B(A&aa); // { dg-message "note" }
~B();
};
static B<int> b_int (3); // { dg-error "no matching function" }
static B<int> b_int (3); // { dg-error "no match|rvalue" }
......@@ -28,7 +28,7 @@ template<class T, class A1, class A2>
factory(A1&& a1, A2&& a2)
{
return std::shared_ptr<T>(new T(std::forward<A1>(a1),
std::forward<A2>(a2))); // { dg-error "no matching function" }
std::forward<A2>(a2))); // { dg-error "rvalue" }
}
struct A
......
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