Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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")));
Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,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``.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -81,4 +114,3 @@ class B2 {
};
const int B2::I;
const int B2::J;