[clang-tidy] Teach cppcoreguidelines-interfaces-global-init about constinit (#148334)

This check already understands how `constexpr` makes initialization
order problems impossible, and C++20's `constinit` provides the exact
same guarantees.
This commit is contained in:
Victor Chernyakin 2025-07-14 14:10:10 -07:00 committed by GitHub
parent 2464313eef
commit 92ef8e3419
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 38 additions and 2 deletions

View File

@ -19,7 +19,7 @@ void InterfacesGlobalInitCheck::registerMatchers(MatchFinder *Finder) {
hasDeclContext(anyOf(translationUnitDecl(), // Global scope.
namespaceDecl(), // Namespace scope.
recordDecl())), // Class scope.
unless(isConstexpr()));
unless(isConstexpr()), unless(isConstinit()));
const auto ReferencesUndefinedGlobalVar = declRefExpr(hasDeclaration(
varDecl(GlobalVarDecl, unless(isDefinition())).bind("referencee")));

View File

@ -232,6 +232,10 @@ Changes in existing checks
<clang-tidy/checks/cppcoreguidelines/avoid-goto>` check by adding the option
`IgnoreMacros` to ignore ``goto`` labels defined in macros.
- Improved :doc:`cppcoreguidelines-interfaces-global-init
<clang-tidy/checks/cppcoreguidelines/interfaces-global-init>` check by
fixing false positives on uses of ``constinit`` variables.
- Improved :doc:`cppcoreguidelines-missing-std-forward
<clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check by adding a
flag to specify the function used for forwarding instead of ``std::forward``.

View File

@ -14,11 +14,23 @@ static int GlobalScopeBadInit3 = takesIntPtr(&ExternGlobal);
static int GlobalScopeBadInit4 = 3 * (ExternGlobal + 2);
// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
#if __cplusplus >= 202002L
extern constinit int ExternConstinitGlobal;
static int GlobalScopeConstinit1 = ExternConstinitGlobal;
static int GlobalScopeConstinit2 = takesInt(ExternConstinitGlobal);
static int GlobalScopeConstinit3 = takesIntPtr(&ExternConstinitGlobal);
static int GlobalScopeConstinit4 = 3 * (ExternConstinitGlobal + 2);
#endif
namespace ns {
static int NamespaceScope = makesInt();
static int NamespaceScopeBadInit = takesInt(ExternGlobal);
// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
#if __cplusplus >= 202002L
static int NamespaceScopeConstinit = takesInt(ExternConstinitGlobal);
#endif
struct A {
static int ClassScope;
static int ClassScopeBadInit;
@ -29,6 +41,17 @@ int A::ClassScopeBadInit = takesInt(ExternGlobal);
static int FromClassBadInit = takesInt(A::ClassScope);
// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ClassScope'
#if __cplusplus >= 202002L
struct B {
static constinit int ClassScopeConstinit;
static int ClassScopeFromConstinit;
};
int B::ClassScopeFromConstinit = takesInt(ExternConstinitGlobal);
static int FromClassScopeConstinit = takesInt(B::ClassScopeConstinit);
#endif
} // namespace ns
// "const int B::I;" is fine, it just ODR-defines B::I. See [9.4.3] Static
@ -42,6 +65,16 @@ const int B1::J;
// CHECK-MESSAGES: [[@LINE-1]]:15: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'I'
const int B1::I;
#if __cplusplus >= 202002L
class D {
static const constinit int I = 0;
static const int J = I;
};
const int D::J;
const int D::I;
#endif
void f() {
// This is fine, it's executed after dynamic initialization occurs.
static int G = takesInt(ExternGlobal);
@ -81,4 +114,3 @@ class B2 {
};
const int B2::I;
const int B2::J;