llvm/clang/test/Modules/lambda-in-variable.cpp

// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: split-file %s %t
//
// RUN: %clang_cc1 -std=c++20 -fmodules -fmodules-cache-path=%t -fmodule-map-file=%t/module.modulemap %t/use.cpp -emit-llvm -o - -triple x86_64-linux-gnu | FileCheck %s
// RUN: %clang_cc1 -DDEFINE_LOCALLY -std=c++20 -fmodules -fmodules-cache-path=%t -fmodule-map-file=%t/module.modulemap %t/use.cpp -emit-llvm -o - -triple x86_64-linux-gnu | FileCheck %s

//--- module.modulemap
module a { header "a.h" export * }
module b { header "b.h" export * }
module c { header "c.h" export * }

//--- nonmodular.h
void not_constant();

template<typename T> struct A {
  template<T M> static inline T N = [] { not_constant(); return M; } ();
};

template<typename T, T M> inline T N = [] { not_constant(); return M; } ();

template<typename T, T M> inline auto L = [] {};

template<typename T> int Z;

// These lambdas should not be merged, despite having the same context decl and
// mangling number (but different signatures).
inline auto MultipleLambdas = ((void)[](int*) { return 1; }, [] { return 2; });

//--- a.h
#include "nonmodular.h"

//--- b.h
#include "a.h"

int b1() { return A<int>::N<1>; }
int b2() { return N<int, 1>; }

inline auto x1 = L<int, 1>;
inline auto x2 = L<int, 2>;

inline constexpr int *P = &Z<decltype([] { static int n; return &n; }())>;
inline constexpr int *xP = P;

static_assert(!__is_same(decltype(x1), decltype(x2)));

//--- c.h
#include "a.h"

int c1() { return A<int>::N<2>; }
int c2() { return N<int, 2>; }

inline auto y2 = L<int, 2>;
inline auto y1 = L<int, 1>;

inline constexpr int *P = &Z<decltype([] { static int n; return &n; }())>;
inline constexpr int *yP = P;

//--- use.cpp
#ifdef DEFINE_LOCALLY
#include "nonmodular.h"

inline constexpr int *P = &Z<decltype([] { static int n; return &n; }())>;
inline constexpr int *zP = P;

auto z0 = L<int, 0>;
auto z2 = L<int, 2>;
auto z1 = L<int, 1>;
#endif

#include "b.h"
#include "c.h"

int b1v = b1();
int b2v = b2();
int c1v = c1();
int c2v = c2();

// We should merge together matching lambdas.
static_assert(__is_same(decltype(x1), decltype(y1)));
static_assert(__is_same(decltype(x2), decltype(y2)));
static_assert(!__is_same(decltype(x1), decltype(x2)));
static_assert(!__is_same(decltype(y1), decltype(y2)));
static_assert(!__is_same(decltype(x1), decltype(y2)));
static_assert(!__is_same(decltype(x2), decltype(y1)));
static_assert(xP == yP);
#ifdef DEFINE_LOCALLY
static_assert(!__is_same(decltype(x1), decltype(z0)));
static_assert(!__is_same(decltype(x2), decltype(z0)));
static_assert(__is_same(decltype(x1), decltype(z1)));
static_assert(__is_same(decltype(x2), decltype(z2)));
static_assert(xP == zP);
#endif

static_assert(MultipleLambdas() == 2);

// We should not merge the instantiated lambdas from `b.h` and `c.h` together,
// even though they will both have anonymous declaration number #1 within
// A<int> and within the TU, respectively.

// CHECK-LABEL: define {{.*}}global_var_init{{.*}} comdat($_Z1NIiLi1EE) {
// CHECK: load i8, ptr @_ZGV1NIiLi1EE, align 8
// CHECK: call {{.*}} i32 @_ZNK1NIiLi1EEMUlvE_clEv(
// CHECK: store i32 {{.*}}, ptr @_Z1NIiLi1EE

// CHECK-LABEL: define {{.*}}global_var_init{{.*}} comdat($_ZN1AIiE1NILi1EEE) {
// CHECK: load i8, ptr @_ZGVN1AIiE1NILi1EEE, align 8
// CHECK: call {{.*}} i32 @_ZNK1AIiE1NILi1EEMUlvE_clEv(
// CHECK: store i32 {{.*}}, ptr @_ZN1AIiE1NILi1EEE

// CHECK-LABEL: define {{.*}}global_var_init{{.*}} comdat($_Z1NIiLi2EE) {
// CHECK: load i8, ptr @_ZGV1NIiLi2EE, align 8
// CHECK: call {{.*}} i32 @_ZNK1NIiLi2EEMUlvE_clEv(
// CHECK: store i32 {{.*}}, ptr @_Z1NIiLi2EE

// CHECK-LABEL: define {{.*}}global_var_init{{.*}} comdat($_ZN1AIiE1NILi2EEE) {
// CHECK: load i8, ptr @_ZGVN1AIiE1NILi2EEE, align 8
// CHECK: call {{.*}} i32 @_ZNK1AIiE1NILi2EEMUlvE_clEv(
// CHECK: store i32 {{.*}}, ptr @_ZN1AIiE1NILi2EEE