The parantheses are unnecessary IMO because they should have been handled in the parents of such expressions, e.g. in CXXFunctionalCastExpr. Moreover, we shouldn't join CXXDefaultInitExpr either because they are not printed at all.
210 lines
5.0 KiB
C++
210 lines
5.0 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 -fsyntax-only -fexperimental-new-constant-interpreter -triple=x86_64-pc-linux-gnu %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
|