210 lines
5.1 KiB
C++

// RUN: %clang_cc1 -std=c++2c -verify -emit-llvm -triple=x86_64-pc-linux-gnu %s -o - | FileCheck %s
// RUN: %clang_cc1 -std=c++2c -verify -emit-llvm -triple=x86_64-pc-linux-gnu %s -o - -fexperimental-new-constant-interpreter | FileCheck %s
// expected-no-diagnostics
namespace std {
template <typename T> struct tuple_size;
template <int, typename> struct tuple_element;
} // namespace std
namespace Case1 {
struct S {
int a, b;
bool flag = false;
constexpr explicit operator bool() {
flag = true;
return a != b;
}
constexpr operator int() {
flag = true;
return a * b;
}
constexpr bool operator==(S rhs) const {
return a == rhs.a && b == rhs.b;
}
template <int I>
constexpr int& get() {
if (!flag)
return a = a + b;
return I == 0 ? a : b;
}
};
} // namespace Case1
template <> struct std::tuple_size<Case1::S> {
static const int value = 2;
};
template <int I> struct std::tuple_element<I, Case1::S> {
using type = int;
};
namespace Case1 {
void foo() {
if (S s(1, 2); auto [a, b] = s) {
__builtin_assume(a == 1);
__builtin_assume(b == 2);
}
// CHECK: %[[call:.+]] = call {{.*}} i1 @_ZN5Case11ScvbEv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi0EEERiv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi1EEERiv
// CHECK: br i1 %[[call]], label {{.*}}, label {{.*}}
if (auto [a, b] = S(1, 2)) {
__builtin_assume(a == 1);
__builtin_assume(b == 2);
}
// CHECK: %[[call2:.+]] = call {{.*}} i1 @_ZN5Case11ScvbEv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi0EEERiv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi1EEERiv
// CHECK: br i1 %[[call2]], label {{.*}}, label {{.*}}
if (S s(3, 4); auto& [a, b] = s) {
__builtin_assume(a == 3);
__builtin_assume(b == 4);
}
// CHECK: %[[call3:.+]] = call {{.*}} i1 @_ZN5Case11ScvbEv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi0EEERiv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi1EEERiv
// CHECK: br i1 %[[call3]], label {{.*}}, label {{.*}}
while (auto [i, j] = S(5, 6))
break;
// CHECK: while.cond{{.*}}:
// CHECK: %[[call4:.+]] = call {{.*}} i1 @_ZN5Case11ScvbEv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi0EEERiv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi1EEERiv
// CHECK: br i1 %[[call4]], label {{.*}}, label {{.*}}
S s(7, 8);
while (auto& [i, j] = s)
break;
// CHECK: while.cond{{.*}}:
// CHECK: %[[call5:.+]] = call {{.*}} i1 @_ZN5Case11ScvbEv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi0EEERiv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi1EEERiv
// CHECK: br i1 %[[call5]], label {{.*}}, label {{.*}}
for (int k = 0; auto [i, j] = S(24, 42); ++k)
break;
// CHECK: for.cond{{.*}}:
// CHECK: %[[call6:.+]] = call {{.*}} i1 @_ZN5Case11ScvbEv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi0EEERiv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi1EEERiv
// CHECK: br i1 %[[call6]], label {{.*}}, label {{.*}}
for (S s(114, 514); auto& [i, j] = s; ++i)
break;
// CHECK: for.cond{{.*}}:
// CHECK: %[[call7:.+]] = call {{.*}} i1 @_ZN5Case11ScvbEv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi0EEERiv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi1EEERiv
// CHECK: br i1 %[[call7]], label {{.*}}, label {{.*}}
switch (S s(10, 11); auto& [i, j] = s) {
case 10 * 11:
__builtin_assume(i == 10);
__builtin_assume(j == 11);
break;
default:
break;
}
// CHECK: %[[call8:.+]] = call {{.*}} i32 @_ZN5Case11ScviEv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi0EEERiv
// CHECK: %{{.*}} = call {{.*}} ptr @_ZN5Case11S3getILi1EEERiv
// CHECK: switch i32 %[[call8]], label {{.*}}
}
constexpr int bar(auto) {
constexpr auto value = [] {
if (S s(1, 2); auto [i, j] = s)
return S(i, j);
return S(0, 0);
}();
static_assert(value == S(1, 2));
constexpr auto value2 = [] {
if (auto [a, b] = S(1, 2))
return S(a, b);
return S(0, 0);
}();
static_assert(value2 == S(1, 2));
constexpr auto value3 = [] {
if (auto&& [a, b] = S(3, 4))
return S(a, b);
return S(0, 0);
}();
static_assert(value3 == S(3, 4));
constexpr auto value4 = [] {
S s(7, 8);
int cnt = 0;
while (auto& [i, j] = s) {
s.flag = false;
++i, ++j;
if (++cnt == 10)
break;
}
return s;
}();
static_assert(value4 == S(17, 18));
constexpr auto value5 = [] {
S s(3, 4);
for (int cnt = 0; auto& [x, y] = s; s.flag = false, ++cnt) {
if (cnt == 3)
break;
++x, ++y;
}
return s;
}();
static_assert(value5 == S(6, 7));
constexpr auto value6 = [] {
switch (auto [x, y] = S(3, 4)) {
case 3 * 4:
return S(x, y);
default:
return S(y, x);
}
}();
static_assert(value6 == S(3, 4));
return 42;
}
constexpr int value = bar(1);
#if 0
// FIXME: This causes clang to ICE, though this is not a regression.
constexpr int ice(auto) {
if constexpr (S s(1, 2); auto [i, j] = s) {
static_assert(i == 1);
}
return 42;
}
constexpr int value2 = ice(1);
#endif
} // namespace Case1