llvm-project/clang/test/SemaCXX/decomposed-condition.cpp
Younan Zhang f4218753ad
[Clang] Implement P0963R3 "Structured binding declaration as a condition" (#130228)
This implements the R2 semantics of P0963.

The R1 semantics, as outlined in the paper, were introduced in Clang 6.
In addition to that, the paper proposes swapping the evaluation order of
condition expressions and the initialization of binding declarations
(i.e. std::tuple-like decompositions).
2025-03-11 15:41:56 +08:00

107 lines
3.0 KiB
C++

// RUN: %clang_cc1 -std=c++17 -Wno-c++26-extensions -verify %s
// RUN: %clang_cc1 -std=c++17 -Wno-c++26-extensions -verify %s -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 -std=c++2c -Wpre-c++26-compat -verify=cxx26,expected %s
// RUN: %clang_cc1 -std=c++2c -Wpre-c++26-compat -verify=cxx26,expected %s -fexperimental-new-constant-interpreter
struct X {
bool flag;
int data;
constexpr explicit operator bool() const {
return flag;
}
constexpr operator int() const {
return data;
}
};
namespace CondInIf {
constexpr int f(X x) {
if (auto [ok, d] = x) // cxx26-warning {{structured binding declaration in a condition is incompatible with C++ standards before C++2c}}
return d + int(ok);
else
return d * int(ok);
ok = {}; // expected-error {{use of undeclared identifier 'ok'}}
d = {}; // expected-error {{use of undeclared identifier 'd'}}
}
static_assert(f({true, 2}) == 3);
static_assert(f({false, 2}) == 0);
constexpr char g(char const (&x)[2]) {
if (auto &[a, b] = x) // cxx26-warning {{structured binding declaration in a condition is incompatible with C++ standards before C++2c}}
return a;
else
return b;
if (auto [a, b] = x) // expected-error {{an array type is not allowed here}} \
// cxx26-warning {{structured binding declaration in a condition is incompatible with C++ standards before C++2c}}
;
}
static_assert(g("x") == 'x');
} // namespace CondInIf
namespace CondInSwitch {
constexpr int f(int n) {
switch (X s = {true, n}; auto [ok, d] = s) {
// cxx26-warning@-1 {{structured binding declaration in a condition is incompatible with C++ standards before C++2c}}
s = {};
case 0:
return int(ok);
case 1:
return d * 10;
case 2:
return d * 40;
default:
return 0;
}
ok = {}; // expected-error {{use of undeclared identifier 'ok'}}
d = {}; // expected-error {{use of undeclared identifier 'd'}}
s = {}; // expected-error {{use of undeclared identifier 's'}}
}
static_assert(f(0) == 1);
static_assert(f(1) == 10);
static_assert(f(2) == 80);
} // namespace CondInSwitch
namespace CondInWhile {
constexpr int f(int n) {
int m = 1;
while (auto [ok, d] = X{n > 1, n}) {
// cxx26-warning@-1 {{structured binding declaration in a condition is incompatible with C++ standards before C++2c}}
m *= d;
--n;
}
return m;
return ok; // expected-error {{use of undeclared identifier 'ok'}}
}
static_assert(f(0) == 1);
static_assert(f(1) == 1);
static_assert(f(4) == 24);
} // namespace CondInWhile
namespace CondInFor {
constexpr int f(int n) {
int a = 1, b = 1;
for (X x = {true, n}; auto &[ok, d] = x; --d) {
// cxx26-warning@-1 {{structured binding declaration in a condition is incompatible with C++ standards before C++2c}}
if (d < 2)
ok = false;
else {
int x = b;
b += a;
a = x;
}
}
return b;
return d; // expected-error {{use of undeclared identifier 'd'}}
}
static_assert(f(0) == 1);
static_assert(f(1) == 1);
static_assert(f(2) == 2);
static_assert(f(5) == 8);
} // namespace CondInFor