210 lines
5.1 KiB
C++
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
|