2010-04-10 03:03:51 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -Wsign-compare %s
|
2009-04-17 01:51:27 +08:00
|
|
|
|
|
|
|
// C++ rules for ?: are a lot stricter than C rules, and have to take into
|
|
|
|
// account more conversion options.
|
|
|
|
// This test runs in C++0x mode for the contextual conversion of the condition.
|
|
|
|
|
|
|
|
struct ToBool { explicit operator bool(); };
|
|
|
|
|
|
|
|
struct B;
|
2010-04-25 04:54:38 +08:00
|
|
|
struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}}
|
2010-01-12 08:44:57 +08:00
|
|
|
struct B { operator A() const; }; // expected-note 2 {{candidate function}}
|
2009-04-17 01:51:27 +08:00
|
|
|
struct I { operator int(); };
|
|
|
|
struct J { operator I(); };
|
|
|
|
struct K { operator double(); };
|
|
|
|
typedef void (*vfn)();
|
|
|
|
struct F { operator vfn(); };
|
|
|
|
struct G { operator vfn(); };
|
|
|
|
|
|
|
|
struct Base {
|
|
|
|
int trick();
|
|
|
|
A trick() const;
|
2009-04-18 00:30:52 +08:00
|
|
|
void fn1();
|
|
|
|
};
|
|
|
|
struct Derived : Base {
|
|
|
|
void fn2();
|
2009-04-17 01:51:27 +08:00
|
|
|
};
|
|
|
|
struct Convertible { operator Base&(); };
|
2010-02-10 17:31:12 +08:00
|
|
|
struct Priv : private Base {}; // expected-note 4 {{declared private here}}
|
2009-04-17 01:51:27 +08:00
|
|
|
struct Mid : Base {};
|
|
|
|
struct Fin : Mid, Derived {};
|
2009-04-18 00:30:52 +08:00
|
|
|
typedef void (Derived::*DFnPtr)();
|
|
|
|
struct ToMemPtr { operator DFnPtr(); };
|
2009-04-17 01:51:27 +08:00
|
|
|
|
|
|
|
struct BadDerived;
|
|
|
|
struct BadBase { operator BadDerived&(); };
|
|
|
|
struct BadDerived : BadBase {};
|
|
|
|
|
|
|
|
struct Fields {
|
|
|
|
int i1, i2, b1 : 3, b2 : 3;
|
|
|
|
};
|
2009-04-20 05:15:26 +08:00
|
|
|
struct MixedFields {
|
|
|
|
int i;
|
|
|
|
volatile int vi;
|
|
|
|
const int ci;
|
|
|
|
const volatile int cvi;
|
|
|
|
};
|
|
|
|
struct MixedFieldsDerived : MixedFields {
|
|
|
|
};
|
2009-04-17 01:51:27 +08:00
|
|
|
|
|
|
|
enum Enum { EVal };
|
|
|
|
|
|
|
|
struct Ambig {
|
2010-01-12 08:44:57 +08:00
|
|
|
operator short(); // expected-note 2 {{candidate function}}
|
|
|
|
operator signed char(); // expected-note 2 {{candidate function}}
|
2009-04-17 01:51:27 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
void test()
|
|
|
|
{
|
|
|
|
// This function tests C++0x 5.16
|
|
|
|
|
|
|
|
// p1 (contextually convert to bool)
|
|
|
|
int i1 = ToBool() ? 0 : 1;
|
|
|
|
|
|
|
|
// p2 (one or both void, and throwing)
|
|
|
|
i1 ? throw 0 : throw 1;
|
|
|
|
i1 ? test() : throw 1;
|
|
|
|
i1 ? throw 0 : test();
|
|
|
|
i1 ? test() : test();
|
|
|
|
i1 = i1 ? throw 0 : 0;
|
|
|
|
i1 = i1 ? 0 : throw 0;
|
|
|
|
i1 ? 0 : test(); // expected-error {{right operand to ? is void, but left operand is of type 'int'}}
|
|
|
|
i1 ? test() : 0; // expected-error {{left operand to ? is void, but right operand is of type 'int'}}
|
|
|
|
(i1 ? throw 0 : i1) = 0; // expected-error {{expression is not assignable}}
|
|
|
|
(i1 ? i1 : throw 0) = 0; // expected-error {{expression is not assignable}}
|
|
|
|
|
|
|
|
// p3 (one or both class type, convert to each other)
|
|
|
|
// b1 (lvalues)
|
|
|
|
Base base;
|
|
|
|
Derived derived;
|
|
|
|
Convertible conv;
|
2009-04-18 00:30:52 +08:00
|
|
|
Base &bar1 = i1 ? base : derived;
|
|
|
|
Base &bar2 = i1 ? derived : base;
|
|
|
|
Base &bar3 = i1 ? base : conv;
|
|
|
|
Base &bar4 = i1 ? conv : base;
|
2009-04-17 01:51:27 +08:00
|
|
|
// these are ambiguous
|
|
|
|
BadBase bb;
|
|
|
|
BadDerived bd;
|
2010-03-10 19:27:22 +08:00
|
|
|
(void)(i1 ? bb : bd); // expected-error {{conditional expression is ambiguous; 'BadBase' can be converted to 'BadDerived' and vice versa}}
|
2009-04-17 01:51:27 +08:00
|
|
|
(void)(i1 ? bd : bb); // expected-error {{conditional expression is ambiguous}}
|
|
|
|
// curiously enough (and a defect?), these are not
|
|
|
|
// for rvalues, hierarchy takes precedence over other conversions
|
|
|
|
(void)(i1 ? BadBase() : BadDerived());
|
|
|
|
(void)(i1 ? BadDerived() : BadBase());
|
|
|
|
|
|
|
|
// b2.1 (hierarchy stuff)
|
|
|
|
const Base constret();
|
|
|
|
const Derived constder();
|
|
|
|
// should use const overload
|
|
|
|
A a1((i1 ? constret() : Base()).trick());
|
|
|
|
A a2((i1 ? Base() : constret()).trick());
|
|
|
|
A a3((i1 ? constret() : Derived()).trick());
|
|
|
|
A a4((i1 ? Derived() : constret()).trick());
|
|
|
|
// should use non-const overload
|
|
|
|
i1 = (i1 ? Base() : Base()).trick();
|
|
|
|
i1 = (i1 ? Base() : Base()).trick();
|
|
|
|
i1 = (i1 ? Base() : Derived()).trick();
|
|
|
|
i1 = (i1 ? Derived() : Base()).trick();
|
|
|
|
// should fail: const lost
|
2010-09-05 08:17:29 +08:00
|
|
|
(void)(i1 ? Base() : constder()); // expected-error {{incompatible operand types ('Base' and 'const Derived')}}
|
|
|
|
(void)(i1 ? constder() : Base()); // expected-error {{incompatible operand types ('const Derived' and 'Base')}}
|
2009-04-20 05:53:20 +08:00
|
|
|
|
|
|
|
Priv priv;
|
|
|
|
Fin fin;
|
2010-02-10 17:31:12 +08:00
|
|
|
(void)(i1 ? Base() : Priv()); // expected-error{{private base class}}
|
|
|
|
(void)(i1 ? Priv() : Base()); // expected-error{{private base class}}
|
2010-03-10 19:27:22 +08:00
|
|
|
(void)(i1 ? Base() : Fin()); // expected-error{{ambiguous conversion from derived class 'Fin' to base class 'Base':}}
|
|
|
|
(void)(i1 ? Fin() : Base()); // expected-error{{ambiguous conversion from derived class 'Fin' to base class 'Base':}}
|
2010-02-10 17:31:12 +08:00
|
|
|
(void)(i1 ? base : priv); // expected-error {{private base class}}
|
|
|
|
(void)(i1 ? priv : base); // expected-error {{private base class}}
|
2010-03-10 19:27:22 +08:00
|
|
|
(void)(i1 ? base : fin); // expected-error {{ambiguous conversion from derived class 'Fin' to base class 'Base':}}
|
|
|
|
(void)(i1 ? fin : base); // expected-error {{ambiguous conversion from derived class 'Fin' to base class 'Base':}}
|
2009-04-17 01:51:27 +08:00
|
|
|
|
|
|
|
// b2.2 (non-hierarchy)
|
|
|
|
i1 = i1 ? I() : i1;
|
|
|
|
i1 = i1 ? i1 : I();
|
|
|
|
I i2(i1 ? I() : J());
|
|
|
|
I i3(i1 ? J() : I());
|
|
|
|
// "the type [it] woud have if E2 were converted to an rvalue"
|
|
|
|
vfn pfn = i1 ? F() : test;
|
|
|
|
pfn = i1 ? test : F();
|
2010-03-10 19:27:22 +08:00
|
|
|
(void)(i1 ? A() : B()); // expected-error {{conversion from 'B' to 'A' is ambiguous}}
|
|
|
|
(void)(i1 ? B() : A()); // expected-error {{conversion from 'B' to 'A' is ambiguous}}
|
|
|
|
(void)(i1 ? 1 : Ambig()); // expected-error {{conversion from 'Ambig' to 'int' is ambiguous}}
|
|
|
|
(void)(i1 ? Ambig() : 1); // expected-error {{conversion from 'Ambig' to 'int' is ambiguous}}
|
2009-04-18 00:30:52 +08:00
|
|
|
// By the way, this isn't an lvalue:
|
|
|
|
&(i1 ? i1 : i2); // expected-error {{address expression must be an lvalue or a function designator}}
|
2009-04-17 01:51:27 +08:00
|
|
|
|
|
|
|
// p4 (lvalue, same type)
|
2009-04-18 00:30:52 +08:00
|
|
|
Fields flds;
|
|
|
|
int &ir1 = i1 ? flds.i1 : flds.i2;
|
|
|
|
(i1 ? flds.b1 : flds.i2) = 0;
|
|
|
|
(i1 ? flds.i1 : flds.b2) = 0;
|
|
|
|
(i1 ? flds.b1 : flds.b2) = 0;
|
2009-04-17 01:51:27 +08:00
|
|
|
|
|
|
|
// p5 (conversion to built-in types)
|
|
|
|
// GCC 4.3 fails these
|
|
|
|
double d1 = i1 ? I() : K();
|
|
|
|
pfn = i1 ? F() : G();
|
2009-04-18 00:30:52 +08:00
|
|
|
DFnPtr pfm;
|
2009-04-20 05:53:20 +08:00
|
|
|
pfm = i1 ? DFnPtr() : &Base::fn1;
|
|
|
|
pfm = i1 ? &Base::fn1 : DFnPtr();
|
2009-04-17 01:51:27 +08:00
|
|
|
|
|
|
|
// p6 (final conversions)
|
|
|
|
i1 = i1 ? i1 : ir1;
|
|
|
|
int *pi1 = i1 ? &i1 : 0;
|
|
|
|
pi1 = i1 ? 0 : &i1;
|
2010-03-20 02:53:26 +08:00
|
|
|
i1 = i1 ? i1 : EVal;
|
|
|
|
i1 = i1 ? EVal : i1;
|
2009-04-17 01:51:27 +08:00
|
|
|
d1 = i1 ? 'c' : 4.0;
|
|
|
|
d1 = i1 ? 4.0 : 'c';
|
2009-04-20 03:26:31 +08:00
|
|
|
Base *pb = i1 ? (Base*)0 : (Derived*)0;
|
|
|
|
pb = i1 ? (Derived*)0 : (Base*)0;
|
2009-04-20 05:15:26 +08:00
|
|
|
pfm = i1 ? &Base::fn1 : &Derived::fn2;
|
|
|
|
pfm = i1 ? &Derived::fn2 : &Base::fn1;
|
|
|
|
pfm = i1 ? &Derived::fn2 : 0;
|
|
|
|
pfm = i1 ? 0 : &Derived::fn2;
|
|
|
|
const int (MixedFieldsDerived::*mp1) =
|
|
|
|
i1 ? &MixedFields::ci : &MixedFieldsDerived::i;
|
|
|
|
const volatile int (MixedFields::*mp2) =
|
|
|
|
i1 ? &MixedFields::ci : &MixedFields::cvi;
|
2009-08-25 01:42:35 +08:00
|
|
|
(void)(i1 ? &MixedFields::ci : &MixedFields::vi);
|
2009-04-18 00:30:52 +08:00
|
|
|
// Conversion of primitives does not result in an lvalue.
|
|
|
|
&(i1 ? i1 : d1); // expected-error {{address expression must be an lvalue or a function designator}}
|
|
|
|
|
2009-09-15 07:15:26 +08:00
|
|
|
(void)&(i1 ? flds.b1 : flds.i1); // expected-error {{address of bit-field requested}}
|
|
|
|
(void)&(i1 ? flds.i1 : flds.b1); // expected-error {{address of bit-field requested}}
|
|
|
|
|
2009-11-05 17:23:39 +08:00
|
|
|
|
|
|
|
unsigned long test0 = 5;
|
|
|
|
test0 = test0 ? (long) test0 : test0; // expected-warning {{operands of ? are integers of different signs}}
|
|
|
|
test0 = test0 ? (int) test0 : test0; // expected-warning {{operands of ? are integers of different signs}}
|
|
|
|
test0 = test0 ? (short) test0 : test0; // expected-warning {{operands of ? are integers of different signs}}
|
|
|
|
test0 = test0 ? test0 : (long) test0; // expected-warning {{operands of ? are integers of different signs}}
|
|
|
|
test0 = test0 ? test0 : (int) test0; // expected-warning {{operands of ? are integers of different signs}}
|
|
|
|
test0 = test0 ? test0 : (short) test0; // expected-warning {{operands of ? are integers of different signs}}
|
|
|
|
test0 = test0 ? test0 : (long) 10;
|
|
|
|
test0 = test0 ? test0 : (int) 10;
|
|
|
|
test0 = test0 ? test0 : (short) 10;
|
|
|
|
test0 = test0 ? (long) 10 : test0;
|
|
|
|
test0 = test0 ? (int) 10 : test0;
|
|
|
|
test0 = test0 ? (short) 10 : test0;
|
|
|
|
|
|
|
|
test0 = test0 ? EVal : test0;
|
2010-03-20 02:53:26 +08:00
|
|
|
test0 = test0 ? EVal : (int) test0;
|
2009-11-05 17:23:39 +08:00
|
|
|
|
2009-04-17 01:51:27 +08:00
|
|
|
// Note the thing that this does not test: since DR446, various situations
|
|
|
|
// *must* create a separate temporary copy of class objects. This can only
|
|
|
|
// be properly tested at runtime, though.
|
|
|
|
}
|
2010-03-27 04:59:55 +08:00
|
|
|
|
|
|
|
namespace PR6595 {
|
2010-07-01 11:43:00 +08:00
|
|
|
struct OtherString {
|
|
|
|
OtherString();
|
|
|
|
OtherString(const char*);
|
|
|
|
};
|
|
|
|
|
2010-03-27 04:59:55 +08:00
|
|
|
struct String {
|
|
|
|
String(const char *);
|
2010-07-01 11:43:00 +08:00
|
|
|
String(const OtherString&);
|
2010-03-27 04:59:55 +08:00
|
|
|
operator const char*() const;
|
|
|
|
};
|
|
|
|
|
2010-07-01 11:43:00 +08:00
|
|
|
void f(bool Cond, String S, OtherString OS) {
|
2010-03-27 04:59:55 +08:00
|
|
|
(void)(Cond? S : "");
|
|
|
|
(void)(Cond? "" : S);
|
|
|
|
const char a[1] = {'a'};
|
|
|
|
(void)(Cond? S : a);
|
|
|
|
(void)(Cond? a : S);
|
2010-07-01 11:43:00 +08:00
|
|
|
(void)(Cond? OS : S);
|
2010-03-27 04:59:55 +08:00
|
|
|
}
|
|
|
|
}
|
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to
build a copy and when it can be elided.
The correct implementation is actually simpler than the
approximation. When we only enumerate constructors as part of
initialization (e.g., for direct initialization or when we're copying
from a class type or one of its derived classes), we don't create a
copy. When we enumerate all conversion functions, we do create a
copy. Before, we created some extra copies and missed some
others. The new test copy-initialization.cpp shows a case where we
missed creating a (required, non-elidable) copy as part of a
user-defined conversion, which resulted in a miscompile. This commit
also fixes PR6757, where the missing copy made us reject well-formed
code in the ternary operator.
This commit also cleans up our handling of copy elision in the case
where we create an extra copy of a temporary object, which became
necessary now that we produce the right copies. The code that seeks to
find the temporary object being copied has moved into
Expr::getTemporaryObject(); it used to have two different
not-quite-the-same implementations, one in Sema and one in CodeGen.
Note that we still do not attempt to perform the named return value
optimization, so we miss copy elisions for return values and throw
expressions.
llvm-svn: 100196
2010-04-03 02:24:57 +08:00
|
|
|
|
|
|
|
namespace PR6757 {
|
|
|
|
struct Foo1 {
|
|
|
|
Foo1();
|
|
|
|
Foo1(const Foo1&);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Foo2 { };
|
|
|
|
|
|
|
|
struct Foo3 {
|
|
|
|
Foo3();
|
2010-04-18 06:01:05 +08:00
|
|
|
Foo3(Foo3&); // expected-note{{would lose const qualifier}}
|
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to
build a copy and when it can be elided.
The correct implementation is actually simpler than the
approximation. When we only enumerate constructors as part of
initialization (e.g., for direct initialization or when we're copying
from a class type or one of its derived classes), we don't create a
copy. When we enumerate all conversion functions, we do create a
copy. Before, we created some extra copies and missed some
others. The new test copy-initialization.cpp shows a case where we
missed creating a (required, non-elidable) copy as part of a
user-defined conversion, which resulted in a miscompile. This commit
also fixes PR6757, where the missing copy made us reject well-formed
code in the ternary operator.
This commit also cleans up our handling of copy elision in the case
where we create an extra copy of a temporary object, which became
necessary now that we produce the right copies. The code that seeks to
find the temporary object being copied has moved into
Expr::getTemporaryObject(); it used to have two different
not-quite-the-same implementations, one in Sema and one in CodeGen.
Note that we still do not attempt to perform the named return value
optimization, so we miss copy elisions for return values and throw
expressions.
llvm-svn: 100196
2010-04-03 02:24:57 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Bar {
|
|
|
|
operator const Foo1&() const;
|
|
|
|
operator const Foo2&() const;
|
|
|
|
operator const Foo3&() const;
|
|
|
|
};
|
|
|
|
|
|
|
|
void f() {
|
|
|
|
(void)(true ? Bar() : Foo1()); // okay
|
|
|
|
(void)(true ? Bar() : Foo2()); // okay
|
2010-04-18 06:01:05 +08:00
|
|
|
(void)(true ? Bar() : Foo3()); // expected-error{{no viable constructor copying temporary}}
|
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to
build a copy and when it can be elided.
The correct implementation is actually simpler than the
approximation. When we only enumerate constructors as part of
initialization (e.g., for direct initialization or when we're copying
from a class type or one of its derived classes), we don't create a
copy. When we enumerate all conversion functions, we do create a
copy. Before, we created some extra copies and missed some
others. The new test copy-initialization.cpp shows a case where we
missed creating a (required, non-elidable) copy as part of a
user-defined conversion, which resulted in a miscompile. This commit
also fixes PR6757, where the missing copy made us reject well-formed
code in the ternary operator.
This commit also cleans up our handling of copy elision in the case
where we create an extra copy of a temporary object, which became
necessary now that we produce the right copies. The code that seeks to
find the temporary object being copied has moved into
Expr::getTemporaryObject(); it used to have two different
not-quite-the-same implementations, one in Sema and one in CodeGen.
Note that we still do not attempt to perform the named return value
optimization, so we miss copy elisions for return values and throw
expressions.
llvm-svn: 100196
2010-04-03 02:24:57 +08:00
|
|
|
}
|
|
|
|
}
|
2010-05-06 16:58:33 +08:00
|
|
|
|
|
|
|
// Reduced from selfhost.
|
|
|
|
namespace test1 {
|
|
|
|
struct A {
|
|
|
|
enum Foo {
|
|
|
|
fa, fb, fc, fd, fe, ff
|
|
|
|
};
|
|
|
|
|
|
|
|
Foo x();
|
|
|
|
};
|
|
|
|
|
|
|
|
void foo(int);
|
|
|
|
|
|
|
|
void test(A *a) {
|
|
|
|
foo(a ? a->x() : 0);
|
|
|
|
}
|
|
|
|
}
|
2010-05-20 07:40:50 +08:00
|
|
|
|
|
|
|
namespace rdar7998817 {
|
|
|
|
class X {
|
|
|
|
X(X&); // expected-note{{declared private here}}
|
|
|
|
|
|
|
|
struct ref { };
|
|
|
|
|
|
|
|
public:
|
|
|
|
X();
|
|
|
|
X(ref);
|
|
|
|
|
|
|
|
operator ref();
|
|
|
|
};
|
|
|
|
|
|
|
|
void f(bool B) {
|
|
|
|
X x;
|
|
|
|
(void)(B? x // expected-error{{calling a private constructor of class 'rdar7998817::X'}}
|
|
|
|
: X());
|
|
|
|
}
|
|
|
|
}
|
2010-07-13 16:18:22 +08:00
|
|
|
|
|
|
|
namespace PR7598 {
|
|
|
|
enum Enum {
|
|
|
|
v = 1,
|
|
|
|
};
|
|
|
|
|
2010-07-14 14:36:18 +08:00
|
|
|
const Enum g() {
|
2010-07-13 16:18:22 +08:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2010-07-14 14:36:18 +08:00
|
|
|
const volatile Enum g2() {
|
2010-07-13 16:50:30 +08:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2010-07-13 16:18:22 +08:00
|
|
|
void f() {
|
|
|
|
const Enum v2 = v;
|
|
|
|
Enum e = false ? g() : v;
|
|
|
|
Enum e2 = false ? v2 : v;
|
2010-07-13 16:50:30 +08:00
|
|
|
Enum e3 = false ? g2() : v;
|
2010-07-13 16:18:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|