blob: c33bf0eba231ba795514490cf90adb68f4751b0e [file] [log] [blame]
// RUN: %clang_cc1 -std=c++1z -verify %s
// RUN: %clang_cc1 -std=c++1z -verify %s -DUNDEFINED
#ifdef UNDEFINED
// "used but not defined" errors don't get produced if we have more interesting
// errors.
namespace std_example {
template <typename T, typename... Rest> void g(T &&p, Rest &&... rs) {
// use p
if constexpr(sizeof...(rs) > 0)
g(rs...);
}
void use_g() {
g(1, 2, 3);
}
static int x(); // no definition of x required
int f() {
if constexpr (true)
return 0;
else if (x())
return x();
else
return -x();
}
}
namespace odr_use_in_selected_arm {
static int x(); // expected-warning {{is not defined}}
int f() {
if constexpr (false)
return 0;
else if (x()) // expected-note {{here}}
return x();
else
return -x();
}
}
#else
namespace ccce {
void f() {
if (5) {}
if constexpr (5) {} // expected-error {{cannot be narrowed}}
}
template<int N> void g() {
if constexpr (N) {} // expected-error {{cannot be narrowed}}
}
template void g<5>(); // expected-note {{instantiation of}}
void h() {
if constexpr (4.3) {} // expected-error{{conversion from 'double' to 'bool' is not allowed in a converted constant expression}}
constexpr void *p = nullptr;
if constexpr (p) {} // expected-error{{conversion from 'void *const' to 'bool' is not allowed in a converted constant expression}}
}
}
namespace generic_lambda {
// Substituting for T produces a hard error here, even if substituting for
// the type of x would remove the error.
template<typename T> void f() {
[](auto x) {
if constexpr (sizeof(T) == 1 && sizeof(x) == 1)
T::error(); // expected-error 2{{'::'}}
} (0);
}
template<typename T> void g() {
[](auto x) {
if constexpr (sizeof(T) == 1)
if constexpr (sizeof(x) == 1)
T::error(); // expected-error {{'::'}}
} (0);
}
void use() {
f<int>(); // expected-note {{instantiation of}}
f<char>(); // expected-note {{instantiation of}}
g<int>(); // ok
g<char>(); // expected-note {{instantiation of}}
}
}
namespace potentially_discarded_branch_target {
void in_switch(int n) {
switch (n)
case 4: if constexpr(sizeof(n) == 4) return;
if constexpr(sizeof(n) == 4)
switch (n) case 4: return;
switch (n) {
if constexpr (sizeof(n) == 4) // expected-note 2{{constexpr if}}
case 4: return; // expected-error {{cannot jump}}
else
default: break; // expected-error {{cannot jump}}
}
}
template<typename T>
void in_switch_tmpl(int n) {
switch (n) {
if constexpr (sizeof(T) == 4) // expected-note 2{{constexpr if}}
case 4: return; // expected-error {{cannot jump}}
else
default: break; // expected-error {{cannot jump}}
}
}
void goto_scope(int n) {
goto foo; // expected-error {{cannot jump}}
if constexpr(sizeof(n) == 4) // expected-note {{constexpr if}}
foo: return;
bar:
if constexpr(sizeof(n) == 4)
goto bar; // ok
}
template<typename T>
void goto_scope(int n) {
goto foo; // expected-error {{cannot jump}}
if constexpr(sizeof(n) == 4) // expected-note {{constexpr if}}
foo: return;
bar:
if constexpr(sizeof(n) == 4)
goto bar; // ok
}
void goto_redef(int n) {
a: if constexpr(sizeof(n) == 4) // expected-error {{redefinition}} expected-note {{constexpr if}}
a: goto a; // expected-note 2{{previous}}
else
a: goto a; // expected-error {{redefinition}} expected-error {{cannot jump}}
}
void evil_things() {
goto evil_label; // expected-error {{cannot jump}}
if constexpr (true || ({evil_label: false;})) {} // expected-note {{constexpr if}}
if constexpr (true) // expected-note {{constexpr if}}
goto surprise; // expected-error {{cannot jump}}
else
surprise: {}
}
}
#endif