mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 19:16:04 +00:00

This introduces some tablegen helpers for defining compatibility warnings. The main aim of this is to both simplify adding new compatibility warnings as well as to unify the naming of compatibility warnings. I’ve refactored ~half of the compatiblity warnings (that follow the usual scheme) in `DiagnosticSemaKinds.td` for illustration purposes and also to simplify/unify the wording of some of them (I also corrected a typo in one of them as a drive-by fix). I haven’t (yet) migrated *all* warnings even in that one file, and there are some more specialised ones for which the scheme I’ve established here doesn’t work (e.g. because they’re warning+error instead of warning+extwarn; however, warning+extension *is* supported), but the point of this isn’t to implement *all* compatibility-related warnings this way, only to make the common case a bit easier to handle. This currently also only handles C++ compatibility warnings, but it should be fairly straight-forward to extend the tablegen code so it can also be used for C compatibility warnings (if this gets merged, I’m planning to do that in a follow-up pr). The vast majority of compatibility warnings are emitted by writing ```c++ Diag(Loc, getLangOpts().CPlusPlusYZ ? diag::ext_... : diag::warn_...) ``` in accordance with which I’ve chosen the following naming scheme: ```c++ Diag(Loc, getLangOpts().CPlusPlusYZ ? diag::compat_cxxyz_foo : diag::compat_pre_cxxyz_foo) ``` That is, for a warning about a C++20 feature—i.e. C++≤17 compatibility—we get: ```c++ Diag(Loc, getLangOpts().CPlusPlus20 ? diag::compat_cxx20_foo : diag::compat_pre_cxx20_foo) ``` While there is an argument to be made against writing ‘`compat_cxx20`’ here since is technically a case of ‘C++17 compatibility’ and not ‘C++20 compatibility’, I at least find this easier to reason about, because I can just write the same number 3 times instead of having to use `ext_cxx20_foo` but `warn_cxx17_foo`. Instead, I like to read this as a warning about the ‘compatibility *of* a C++20 feature’ rather than ‘*with* C++17’. I also experimented with moving all compatibility warnings to a separate file, but 1. I don’t think it’s worth the effort, and 2. I think it hurts compile times a bit because at least in my testing I felt that I had to recompile more code than if we just keep e.g. Sema-specific compat warnings in the Sema diagnostics file. Instead, I’ve opted to put them all in the same place within any one file; currently this is a the very top but I don’t really have strong opinions about this.
106 lines
2.0 KiB
C++
106 lines
2.0 KiB
C++
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fexperimental-new-constant-interpreter %s -verify=expected,both
|
|
// RUN: %clang_cc1 -std=c++23 -fsyntax-only %s -verify=ref,both
|
|
|
|
namespace ConstEval {
|
|
constexpr int f() {
|
|
int i = 0;
|
|
if consteval {
|
|
i = 1;
|
|
}
|
|
return i;
|
|
}
|
|
static_assert(f() == 1, "");
|
|
|
|
constexpr int f2() {
|
|
int i = 0;
|
|
if !consteval {
|
|
i = 12;
|
|
if consteval {
|
|
i = i + 1;
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
static_assert(f2() == 0, "");
|
|
};
|
|
|
|
namespace InitDecl {
|
|
constexpr bool f() {
|
|
if (int i = 5; i != 10) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
static_assert(f(), "");
|
|
|
|
constexpr bool f2() {
|
|
if (bool b = false; b) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
static_assert(!f2(), "");
|
|
|
|
|
|
constexpr int attrs() {
|
|
if (1) [[likely]] {}
|
|
return 1;
|
|
}
|
|
static_assert(attrs() == 1, "");
|
|
};
|
|
|
|
/// The faulty if statement creates a RecoveryExpr with contains-errors,
|
|
/// but the execution will never reach that.
|
|
constexpr char g(char const (&x)[2]) {
|
|
return 'x';
|
|
if (auto [a, b] = x) // both-error {{an array type is not allowed here}} \
|
|
// both-warning {{structured binding declaration in a condition is a C++2c extension}}
|
|
;
|
|
}
|
|
static_assert(g("x") == 'x');
|
|
|
|
namespace IfScope {
|
|
struct Inc {
|
|
int &a;
|
|
constexpr Inc(int &a) : a(a) {}
|
|
constexpr ~Inc() { ++a; }
|
|
};
|
|
|
|
constexpr int foo() {
|
|
int a= 0;
|
|
int b = 12;
|
|
if (Inc{a}; true) {
|
|
b += a;
|
|
}
|
|
return b;
|
|
}
|
|
static_assert(foo() == 13, "");
|
|
}
|
|
|
|
namespace IfScope2 {
|
|
struct __bit_iterator {
|
|
unsigned __ctz_;
|
|
};
|
|
constexpr void __fill_n_bool(__bit_iterator) {}
|
|
|
|
constexpr void fill_n(__bit_iterator __first) {
|
|
if (false)
|
|
__fill_n_bool(__first);
|
|
else
|
|
__fill_n_bool(__first);
|
|
}
|
|
|
|
struct bitset{
|
|
constexpr void reset() {
|
|
auto m = __bit_iterator(8);
|
|
fill_n(m);
|
|
}
|
|
};
|
|
consteval bool foo() {
|
|
bitset v;
|
|
v.reset();
|
|
return true;
|
|
}
|
|
static_assert(foo());
|
|
}
|