llvm-project/clang/test/SemaCXX/warn-unused-lambda-capture.cpp
Aaron Ballman 84a3aadf0f Diagnose use of VLAs in C++ by default
Reapplication of 7339c0f782d5c70e0928f8991b0c05338a90c84c with a fix
for a crash involving arrays without a size expression.

Clang supports VLAs in C++ as an extension, but we currently only warn
on their use when you pass -Wvla, -Wvla-extension, or -pedantic.
However, VLAs as they're expressed in C have been considered by WG21
and rejected, are easy to use accidentally to the surprise of users
(e.g., https://ddanilov.me/default-non-standard-features/), and they
have potential security implications beyond constant-size arrays
(https://wiki.sei.cmu.edu/confluence/display/c/ARR32-C.+Ensure+size+arguments+for+variable+length+arrays+are+in+a+valid+range).
C++ users should strongly consider using other functionality such as
std::vector instead.

This seems like sufficiently compelling evidence to warn users about
VLA use by default in C++ modes. This patch enables the -Wvla-extension
diagnostic group in C++ language modes by default, and adds the warning
group to -Wall in GNU++ language modes. The warning is still opt-in in
C language modes, where support for VLAs is somewhat less surprising to
users.

RFC: https://discourse.llvm.org/t/rfc-diagnosing-use-of-vlas-in-c/73109
Fixes https://github.com/llvm/llvm-project/issues/62836
Differential Revision: https://reviews.llvm.org/D156565
2023-10-20 13:10:03 -04:00

204 lines
9.3 KiB
C++

// RUN: %clang_cc1 -fsyntax-only -Wunused-lambda-capture -Wused-but-marked-unused -Wno-uninitialized -verify -std=c++1z %s
class NonTrivialConstructor {
public:
NonTrivialConstructor() {}
};
class NonTrivialCopyConstructor {
public:
NonTrivialCopyConstructor() = default;
NonTrivialCopyConstructor(const NonTrivialCopyConstructor &) {}
};
class NonTrivialDestructor {
public:
~NonTrivialDestructor() {}
};
class Trivial {
public:
Trivial() = default;
Trivial(int a) {}
};
int side_effect() {
return 42;
}
void test() {
int i = 0;
const int k = 0;
auto captures_nothing = [] {};
auto captures_nothing_by_value = [=] {};
auto captures_nothing_by_reference = [&] {};
auto implicit_by_value = [=]() mutable { i++; };
auto implicit_by_reference = [&] { i++; };
auto explicit_by_value_used = [i] { return i + 1; };
auto explicit_by_value_used_void = [i] { (void)i; };
auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
auto explicit_by_value_unused_const = [k] { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
auto explicit_by_reference_used = [&i] { i++; };
auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}}
auto explicit_initialized_reference_used = [&j = i] { return j + 1; };
auto explicit_initialized_reference_unused = [&j = i]{}; // expected-warning{{lambda capture 'j' is not used}}
auto explicit_initialized_value_used = [j = 1] { return j + 1; };
auto explicit_initialized_value_unused = [j = 1] {}; // expected-warning{{lambda capture 'j' is not used}}
auto explicit_initialized_value_non_trivial_constructor = [j = NonTrivialConstructor()]{};
auto explicit_initialized_value_non_trivial_destructor = [j = NonTrivialDestructor()]{};
auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}}
auto explicit_initialized_value_non_trivial_init = [j = Trivial(42)]{};
auto explicit_initialized_value_with_side_effect = [j = side_effect()]{};
auto nested = [&i] {
auto explicit_by_value_used = [i] { return i + 1; };
auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
};
Trivial trivial;
auto explicit_by_value_trivial = [trivial] {}; // expected-warning{{lambda capture 'trivial' is not used}}
NonTrivialConstructor cons;
auto explicit_by_value_non_trivial_constructor = [cons] {}; // expected-warning{{lambda capture 'cons' is not used}}
NonTrivialCopyConstructor copy_cons;
auto explicit_by_value_non_trivial_copy_constructor = [copy_cons] {};
NonTrivialDestructor dest;
auto explicit_by_value_non_trivial_destructor = [dest] {};
volatile int v;
auto explicit_by_value_volatile = [v] {};
}
class TrivialThis : Trivial {
void test() {
auto explicit_this_used = [this] { return i; };
auto explicit_this_used_void = [this] { (void)this; };
auto explicit_this_unused = [this] {}; // expected-warning{{lambda capture 'this' is not used}}
auto explicit_star_this_used = [*this] { return i; };
auto explicit_star_this_used_void = [*this] { (void)this; };
auto explicit_star_this_unused = [*this] {}; // expected-warning{{lambda capture 'this' is not used}}
}
int i;
};
class NonTrivialConstructorThis : NonTrivialConstructor {
void test() {
auto explicit_this_used = [this] { return i; };
auto explicit_this_used_void = [this] { (void)this; };
auto explicit_this_unused = [this] {}; // expected-warning{{lambda capture 'this' is not used}}
auto explicit_star_this_used = [*this] { return i; };
auto explicit_star_this_used_void = [*this] { (void)this; };
auto explicit_star_this_unused = [*this] {}; // expected-warning{{lambda capture 'this' is not used}}
}
int i;
};
class NonTrivialCopyConstructorThis : NonTrivialCopyConstructor {
void test() {
auto explicit_this_used = [this] { return i; };
auto explicit_this_used_void = [this] { (void)this; };
auto explicit_this_unused = [this] {}; // expected-warning{{lambda capture 'this' is not used}}
auto explicit_star_this_used = [*this] { return i; };
auto explicit_star_this_used_void = [*this] { (void)this; };
auto explicit_star_this_unused = [*this] {};
}
int i;
};
class NonTrivialDestructorThis : NonTrivialDestructor {
void test() {
auto explicit_this_used = [this] { return i; };
auto explicit_this_used_void = [this] { (void)this; };
auto explicit_this_unused = [this] {}; // expected-warning{{lambda capture 'this' is not used}}
auto explicit_star_this_used = [*this] { return i; };
auto explicit_star_this_used_void = [*this] { (void)this; };
auto explicit_star_this_unused = [*this] {};
}
int i;
};
template <typename T>
void test_templated() {
int i = 0;
const int k = 0;
auto captures_nothing = [] {};
auto captures_nothing_by_value = [=] {};
auto captures_nothing_by_reference = [&] {};
auto implicit_by_value = [=]() mutable { i++; };
auto implicit_by_reference = [&] { i++; };
auto explicit_by_value_used = [i] { return i + 1; };
auto explicit_by_value_used_generic = [i](auto c) { return i + 1; };
auto explicit_by_value_used_void = [i] { (void)i; };
auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}}
auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}} expected-note {{substituting into a lambda}}
auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}}
auto explicit_by_value_unused_const = [k] { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}} expected-note {{substituting into a lambda}}
auto explicit_by_value_unused_const_generic = [k](auto c) { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}} expected-note {{substituting into a lambda}}
auto explicit_by_reference_used = [&i] { i++; };
auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}}
auto explicit_initialized_reference_used = [&j = i] { return j + 1; };
auto explicit_initialized_reference_unused = [&j = i]{}; // expected-warning{{lambda capture 'j' is not used}} expected-note {{substituting into a lambda}}
auto explicit_initialized_value_used = [j = 1] { return j + 1; };
auto explicit_initialized_value_unused = [j = 1] {}; // expected-warning{{lambda capture 'j' is not used}} expected-note {{substituting into a lambda}}
auto explicit_initialized_value_non_trivial_constructor = [j = NonTrivialConstructor()]{};
auto explicit_initialized_value_non_trivial_destructor = [j = NonTrivialDestructor()]{};
auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}} expected-note {{substituting into a lambda}}
auto explicit_initialized_value_non_trivial_init = [j = Trivial(42)]{};
auto explicit_initialized_value_with_side_effect = [j = side_effect()]{};
auto explicit_initialized_value_generic_used = [i = 1](auto c) mutable { i++; };
auto explicit_initialized_value_generic_unused = [i = 1](auto c) mutable {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}}
auto nested = [&i] { // expected-note {{substituting into a lambda}}
auto explicit_by_value_used = [i] { return i + 1; };
auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}}
};
Trivial trivial;
auto explicit_by_value_trivial = [trivial] {}; // expected-warning{{lambda capture 'trivial' is not used}} expected-note {{substituting into a lambda}}
NonTrivialConstructor cons;
auto explicit_by_value_non_trivial_constructor = [cons] {}; // expected-warning{{lambda capture 'cons' is not used}} expected-note {{substituting into a lambda}}
NonTrivialCopyConstructor copy_cons;
auto explicit_by_value_non_trivial_copy_constructor = [copy_cons] {};
NonTrivialDestructor dest;
auto explicit_by_value_non_trivial_destructor = [dest] {};
volatile int v;
auto explicit_by_value_volatile = [v] {};
}
void test_use_template() {
test_templated<int>(); // expected-note 13{{in instantiation of function template specialization 'test_templated<int>' requested here}}
}
namespace pr35555 {
int a; // expected-note {{declared here}}
void b() {
int c[a]; // expected-warning {{variable length arrays in C++ are a Clang extension}} \
expected-note {{read of non-const variable 'a' is not allowed in a constant expression}}
auto vla_used = [&c] { return c[0]; };
auto vla_unused = [&c] {}; // expected-warning{{lambda capture 'c' is not used}}
}
} // namespace pr35555