// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM

// Explicit-object member function with no use of `self` in the body.
// The function has two AST parameters (self, x) and no implicit `this`.
struct Functor {
  int operator()(this Functor const& self, int x) { return x + 1; }
};

int call_simple(Functor f) {
  return f(3);
}

// CIR-LABEL: cir.func{{.*}} @_ZNH7FunctorclERKS_i(%arg0: !cir.ptr<!rec_Functor>
// CIR-SAME:                                       %arg1: !s32i

// LLVM-LABEL: define {{.*}}i32 @_ZNH7FunctorclERKS_i(ptr {{.*}}%{{.+}}, i32 {{.*}}%{{.+}})

// Explicit-object member function that uses `self` to access a member.
// Confirms the explicit-object parameter is properly entered into the local
// decl map so `self.base` resolves correctly.
struct Adder {
  int base;
  int operator()(this Adder const& self, int x) { return self.base + x; }
};

int call_with_member(Adder a) {
  return a(7);
}

// CIR-LABEL: cir.func{{.*}} @_ZNH5AdderclERKS_i(%arg0: !cir.ptr<!rec_Adder>
// CIR-SAME:                                     %arg1: !s32i
// CIR:         %[[SELF_SLOT:.+]] = cir.alloca "self" {{.*}} : !cir.ptr<!cir.ptr<!rec_Adder>>
// CIR:         %[[SELF_PTR:.+]] = cir.load{{.*}} %[[SELF_SLOT]] : !cir.ptr<!cir.ptr<!rec_Adder>>, !cir.ptr<!rec_Adder>
// CIR:         %[[BASE_PTR:.+]] = cir.get_member %[[SELF_PTR]][0] {name = "base"} : !cir.ptr<!rec_Adder> -> !cir.ptr<!s32i>
// CIR:         %[[BASE:.+]] = cir.load{{.*}} %[[BASE_PTR]] : !cir.ptr<!s32i>, !s32i

// LLVM-LABEL: define {{.*}}i32 @_ZNH5AdderclERKS_i(ptr {{.*}}%{{.+}}, i32 {{.*}}%{{.+}})
// LLVM:         %[[SELF_PTR:.+]] = load ptr, ptr %{{.+}}
// LLVM:         %[[BASE:.+]] = load i32, ptr %{{.+}}
// LLVM:         %[[X:.+]] = load i32, ptr %{{.+}}
// LLVM:         add nsw i32 %[[BASE]], %[[X]]

// Lambda with deducing-this explicit object parameter.
int call_lambda() {
  auto add5 = [](this auto const&, int x) { return x + 5; };
  return add5(10);
}

// CIR-LABEL: cir.func{{.*}} @_Z11call_lambdav

// LLVM-LABEL: define {{.*}}i32 @_Z11call_lambdav

// Control: ordinary (implicit-`this`) instance member function still gets
// the `this` parameter prepended.
struct WithThis {
  int v;
  int regular(int x) { return v + x; }
};

int call_regular(WithThis w) {
  return w.regular(2);
}

// CIR-LABEL: cir.func{{.*}} @_ZN8WithThis7regularEi(%arg0: !cir.ptr<!rec_WithThis>
// CIR-SAME:                                          %arg1: !s32i

// LLVM-LABEL: define {{.*}}i32 @_ZN8WithThis7regularEi(ptr {{.*}}%{{.+}}, i32 {{.*}}%{{.+}})
