summaryrefslogtreecommitdiff
path: root/test/CodeGenCXX/cxx1z-eval-order.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/CodeGenCXX/cxx1z-eval-order.cpp')
-rw-r--r--test/CodeGenCXX/cxx1z-eval-order.cpp271
1 files changed, 271 insertions, 0 deletions
diff --git a/test/CodeGenCXX/cxx1z-eval-order.cpp b/test/CodeGenCXX/cxx1z-eval-order.cpp
new file mode 100644
index 0000000000000..1106719a4748f
--- /dev/null
+++ b/test/CodeGenCXX/cxx1z-eval-order.cpp
@@ -0,0 +1,271 @@
+// RUN: %clang_cc1 -std=c++1z %s -emit-llvm -o - -triple %itanium_abi_triple | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ITANIUM
+// RUN: %clang_cc1 -std=c++1z %s -emit-llvm -o - -triple i686-windows | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-WINDOWS
+// RUN: %clang_cc1 -std=c++1z %s -emit-llvm -o - -triple x86_64-windows | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-WINDOWS
+
+struct B;
+struct A {
+ A();
+ A(const A&);
+
+ void operator[](B b);
+
+ int a_member_f(B);
+};
+struct B {
+ B();
+ ~B();
+};
+
+struct C {
+ operator int *();
+ A *operator->();
+ void operator->*(A);
+ friend void operator->*(C, B);
+
+ friend void operator<<(C, B);
+ friend void operator>>(C, B);
+ void operator<<(A);
+ void operator>>(A);
+
+ void operator=(A);
+ void operator+=(A);
+ friend void operator+=(C, B);
+
+ void operator,(A);
+ friend void operator,(C, B);
+
+ void operator&&(A);
+ void operator||(A);
+ friend void operator&&(C, B);
+ friend void operator||(C, B);
+};
+
+A make_a();
+A *make_a_ptr();
+int A::*make_mem_ptr_a();
+void (A::*make_mem_fn_ptr_a())();
+B make_b();
+C make_c();
+void side_effect();
+
+void callee(A);
+void (*get_f())(A);
+
+
+// CHECK-LABEL: define {{.*}}@{{.*}}postfix_before_args{{.*}}(
+void postfix_before_args() {
+ // CHECK: call {{.*}}@{{.*}}get_f{{.*}}(
+ // CHECK-ITANIUM: call {{.*}}@_ZN1AC1Ev(
+ // CHECK-WINDOWS: call {{.*}}@"\01??0A@@Q{{AE|EAA}}@XZ"(
+ // CHECK: call {{.*}}%{{.*}}(
+ get_f()(A{});
+
+ // CHECK: call {{.*}}@{{.*}}side_effect{{.*}}(
+ // CHECK-ITANIUM: call {{.*}}@_ZN1AC1Ev(
+ // CHECK-WINDOWS: call {{.*}}@"\01??0A@@Q{{AE|EAA}}@XZ"(
+ // CHECK: call {{.*}}@{{.*}}callee{{.*}}(
+ (side_effect(), callee)(A{});
+// CHECK: }
+}
+
+
+// CHECK-LABEL: define {{.*}}@{{.*}}dot_lhs_before_rhs{{.*}}(
+void dot_lhs_before_rhs() {
+ // CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}a_member_f{{.*}}(
+ make_a().a_member_f(make_b());
+
+ // CHECK: call {{.*}}@{{.*}}make_a_ptr{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}a_member_f{{.*}}(
+ make_a_ptr()->a_member_f(make_b());
+
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}a_member_f{{.*}}(
+ make_c()->a_member_f(make_b());
+// CHECK: }
+}
+
+
+// CHECK-LABEL: define {{.*}}@{{.*}}array_lhs_before_rhs{{.*}}(
+void array_lhs_before_rhs() {
+ int (&get_arr())[10];
+ extern int get_index();
+
+ // CHECK: call {{.*}}@{{.*}}get_arr{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}get_index{{.*}}(
+ get_arr()[get_index()] = 0;
+
+ // CHECK: call {{.*}}@{{.*}}get_index{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}get_arr{{.*}}(
+ get_index()[get_arr()] = 0;
+
+ // CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
+ // CHECK: call
+ make_a()[make_b()];
+
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}get_index{{.*}}(
+ // CHECK: call
+ make_c()[get_index()] = 0;
+
+ // CHECK: call {{.*}}@{{.*}}get_index{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call
+ get_index()[make_c()] = 0;
+// CHECK: }
+}
+
+
+void *operator new(decltype(sizeof(0)), C);
+
+// CHECK-LABEL: define {{.*}}@{{.*}}alloc_before_init{{.*}}(
+void alloc_before_init() {
+ struct Q { Q(A) {} };
+ // CHECK-ITANIUM: call {{.*}}@_Znw{{.*}}(
+ // CHECK-WINDOWS: call {{.*}}@"\01??2@YAP{{EAX_K|AXI}}@Z"(
+ // CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
+ delete new Q(make_a());
+
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
+ new (make_c()) Q(make_a());
+// CHECK: }
+}
+
+
+// CHECK-LABEL: define {{.*}}@{{.*}}dotstar_lhs_before_rhs{{.*}}(
+int dotstar_lhs_before_rhs() {
+ // CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_mem_ptr_a{{.*}}(
+ int a = make_a().*make_mem_ptr_a();
+
+ // CHECK: call {{.*}}@{{.*}}make_a_ptr{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_mem_ptr_a{{.*}}(
+ int b = make_a_ptr()->*make_mem_ptr_a();
+
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
+ make_c()->*make_a();
+
+ // FIXME: For MS ABI, the order of destruction of parameters here will not be
+ // reverse construction order (parameters are destroyed left-to-right in the
+ // callee). That sadly seems unavoidable; the rules are not implementable as
+ // specified. If we changed parameter destruction order for these functions
+ // to right-to-left, we could make the destruction order match for all cases
+ // other than indirect calls, but we can't completely avoid the problem.
+ //
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
+ make_c()->*make_b();
+
+ // CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_mem_fn_ptr_a{{.*}}(
+ // CHECK: call
+ (make_a().*make_mem_fn_ptr_a())();
+
+ // CHECK: call {{.*}}@{{.*}}make_a_ptr{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_mem_fn_ptr_a{{.*}}(
+ // CHECK: call
+ (make_a_ptr()->*make_mem_fn_ptr_a())();
+
+ return a + b;
+// CHECK: }
+}
+
+
+// CHECK-LABEL: define {{.*}}@{{.*}}assign_rhs_before_lhs{{.*}}(
+void assign_rhs_before_lhs() {
+ extern int &lhs_ref(), rhs();
+
+ // CHECK: call {{.*}}@{{.*}}rhs{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}lhs_ref{{.*}}(
+ lhs_ref() = rhs();
+
+ // CHECK: call {{.*}}@{{.*}}rhs{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}lhs_ref{{.*}}(
+ lhs_ref() += rhs();
+
+ // CHECK: call {{.*}}@{{.*}}rhs{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}lhs_ref{{.*}}(
+ lhs_ref() %= rhs();
+
+ // CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ make_c() = make_a();
+
+ // CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ make_c() += make_a();
+
+ // CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ make_c() += make_b();
+// CHECK: }
+}
+
+// CHECK-LABEL: define {{.*}}@{{.*}}shift_lhs_before_rhs{{.*}}(
+void shift_lhs_before_rhs() {
+ extern int lhs(), rhs();
+
+ // CHECK: call {{.*}}@{{.*}}lhs{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}rhs{{.*}}(
+ (void)(lhs() << rhs());
+
+ // CHECK: call {{.*}}@{{.*}}lhs{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}rhs{{.*}}(
+ (void)(lhs() >> rhs());
+
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
+ make_c() << make_a();
+
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
+ make_c() >> make_a();
+
+ // FIXME: This is not correct for Windows ABIs, see above.
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
+ make_c() << make_b();
+
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
+ make_c() >> make_b();
+// CHECK: }
+}
+
+// CHECK-LABEL: define {{.*}}@{{.*}}comma_lhs_before_rhs{{.*}}(
+void comma_lhs_before_rhs() {
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
+ make_c() , make_a();
+
+ // FIXME: This is not correct for Windows ABIs, see above.
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
+ make_c() , make_b();
+}
+
+// CHECK-LABEL: define {{.*}}@{{.*}}andor_lhs_before_rhs{{.*}}(
+void andor_lhs_before_rhs() {
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
+ make_c() && make_a();
+
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_a{{.*}}(
+ make_c() || make_a();
+
+ // FIXME: This is not correct for Windows ABIs, see above.
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
+ make_c() && make_b();
+
+ // CHECK: call {{.*}}@{{.*}}make_c{{.*}}(
+ // CHECK: call {{.*}}@{{.*}}make_b{{.*}}(
+ make_c() || make_b();
+}