aboutsummaryrefslogtreecommitdiff
path: root/test/SemaCXX/conditional-expr.cpp
diff options
context:
space:
mode:
authorSebastian Redl <sebastian.redl@getdesigned.at>2009-04-16 17:51:27 +0000
committerSebastian Redl <sebastian.redl@getdesigned.at>2009-04-16 17:51:27 +0000
commit3201f6beec688ab9fe8750527e28f52d5420e22d (patch)
treeee806d81273e190e494239c9db4b4b57fafc24e4 /test/SemaCXX/conditional-expr.cpp
parentba79fc2d1b742e34df104aadb2780725c2a882fc (diff)
Fix a crash bug when comparing overload quality of conversion operators with conversion constructors.
Remove an atrocious amount of trailing whitespace in the overloaded operator mangler. Sorry, couldn't help myself. Change the DeclType parameter of Sema::CheckReferenceInit to be passed by value instead of reference. It wasn't changed anywhere. Let the parser handle C++'s irregular grammar around assignment-expression and conditional-expression. And finally, the reason for all this stuff: implement C++ semantics for the conditional operator. The implementation is complete except for determining lvalueness. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69299 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/SemaCXX/conditional-expr.cpp')
-rw-r--r--test/SemaCXX/conditional-expr.cpp144
1 files changed, 144 insertions, 0 deletions
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
new file mode 100644
index 0000000000..cbf396936b
--- /dev/null
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -0,0 +1,144 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+
+// 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;
+struct A { A(); A(const B&); };
+struct B { operator A() const; };
+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;
+};
+struct Derived : Base {};
+struct Convertible { operator Base&(); };
+struct Priv : private Base {};
+struct Mid : Base {};
+struct Fin : Mid, Derived {};
+
+struct BadDerived;
+struct BadBase { operator BadDerived&(); };
+struct BadDerived : BadBase {};
+
+struct Fields {
+ int i1, i2, b1 : 3, b2 : 3;
+};
+
+enum Enum { EVal };
+
+struct Ambig {
+ operator short();
+ operator signed char();
+};
+
+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;
+ // FIXME: lvalueness
+ /*Base &bar1 =*/(void)( i1 ? base : derived);
+ /*Base &bar2 =*/(void)( i1 ? derived : base);
+ /*Base &bar3 =*/(void)( i1 ? base : conv);
+ /*Base &bar4 =*/(void)( i1 ? conv : base);
+ // these are ambiguous
+ BadBase bb;
+ BadDerived bd;
+ (void)(i1 ? bb : bd); // expected-error {{conditional expression is ambiguous; 'struct BadBase' can be converted to 'struct BadDerived' and vice versa}}
+ (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
+ (void)(i1 ? Base() : constder()); // expected-error {{incompatible operand types ('struct Base' and 'struct Derived const')}}
+ (void)(i1 ? constder() : Base()); // expected-error {{incompatible operand types ('struct Derived const' and 'struct Base')}}
+ // should fail: private or ambiguous base
+ (void)(i1 ? Base() : Priv()); // xpected-error private base
+ (void)(i1 ? Priv() : Base()); // xpected-error private base
+ (void)(i1 ? Base() : Fin()); // xpected-error ambiguous base
+ (void)(i1 ? Fin() : Base()); // xpected-error ambiguous base
+
+ // 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();
+ // these are ambiguous - better messages would be nice
+ (void)(i1 ? A() : B()); // expected-error {{incompatible operand types}}
+ (void)(i1 ? B() : A()); // expected-error {{incompatible operand types}}
+ (void)(i1 ? 1 : Ambig()); // expected-error {{incompatible operand types}}
+ (void)(i1 ? Ambig() : 1); // expected-error {{incompatible operand types}}
+
+ // p4 (lvalue, same type)
+ //Fields flds;
+ int &ir1 = i1;
+ //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;
+
+ // p5 (conversion to built-in types)
+ // GCC 4.3 fails these
+ double d1 = i1 ? I() : K();
+ pfn = i1 ? F() : G();
+
+ // p6 (final conversions)
+ i1 = i1 ? i1 : ir1;
+ int *pi1 = i1 ? &i1 : 0;
+ pi1 = i1 ? 0 : &i1;
+ i1 = i1 ? i1 : EVal;
+ i1 = i1 ? EVal : i1;
+ d1 = i1 ? 'c' : 4.0;
+ d1 = i1 ? 4.0 : 'c';
+
+ // 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.
+}