// 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 {{.*}}@"??0A@@Q{{AE|EAA}}@XZ"( // CHECK: call {{.*}}%{{.*}}( get_f()(A{}); // CHECK: call {{.*}}@{{.*}}side_effect{{.*}}( // CHECK-ITANIUM: call {{.*}}@_ZN1AC1Ev( // CHECK-WINDOWS: call {{.*}}@"??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 {{.*}}@"??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(); }