# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. # All rights reserved. # SPDX-License-Identifier: Apache-2.0 --- Checks: # enable everything first - 'performance-*' - 'modernize-*' - 'readability-*' - 'clang-analyzer-*' - 'clang-diagnostic-*' - 'bugprone-*' - 'misc-*' - 'core-*' - 'mpi-*' - 'cert-*' - 'portability-*' - 'google-*' - 'cppcoreguidelines-*' - 'concurrency-*' # TODO: BEGIN REMOVE ME - '-*' - 'performance-*' - '-performance-enum-size' - '-performance-unnecessary-value-param' - 'modernize-*' - '-modernize-use-integer-sign-comparison' - '-modernize-use-nodiscard' - '-modernize-return-braced-init-list' - '-modernize-use-auto' - 'clang-diagnostic-*' - 'bugprone-*' - '-bugprone-crtp-constructor-accessibility' - '-bugprone-argument-comment' # This is just noise - '-bugprone-signed-char-misuse' - '-bugprone-multi-level-implicit-pointer-conversion' # END REMOVE ME # TODO(jfaibussowit): # # Enable these once we move to C++20. Normally, clang-tidy does not suggest checks for # cpp N+1 if you are compiling with -std=c++N. However some subprojects like c.parallel # actually require cpp N+1 so clang-tidy emits diagnostics for any headers included by # it. - '-modernize-use-designated-initializers' - '-modernize-use-constraints' - '-modernize-use-ranges' # Irrelevant for GPU code - '-modernize-pass-by-value' # HICPP is 99% aliased to other checks (mostly modernize-* and bugprone-*). We don't # want to also enable it because then we need to duplicate the NOLINT. The only 2 checks # that aren't aliases are: # # - hicpp-multiway-paths-covered. This check is useful for detecting degenerate if-else # branches, but the switch cases are IMO better handled by -Wswitch. To make -Wswitch # even stronger, we should ban default: cases entirely, # # - hicpp-signed-bitwise. This check is also covered by # clang.llvm.org/extra/clang-tidy/checks/clang-analyzer/core.BitwiseShift.html # # - 'hicpp-*' # # LLVM checks are extremely specific to the LLVM project and aren't suitable for # downstream users. # # - 'llvm-*' # # then disable the stuff we don't want - '-cert-dcl21-cpp' # returning non-const from operator-- or operator++ - '-cert-dcl50-cpp' # allow c-style variadics # No reserved identifiers, both of these are aliased to bugprone-reserved-identifier, # which we do enable. Leaving these enabled however, leads to needing to specify all # three (bugprone-reserved-identifier, cert-dcl51-cpp, and cert-dcl37-c) in NOLINT lines # which is a hassle. Since bugprone-reserved-identifier is enabled, the check still # fires. - '-cert-dcl51-cpp,-cert-dcl37-c,-cert-oop54-cpp' # Covered by bugprone-throwing-static-initialization - '-cert-err58-cpp' - '-modernize-use-trailing-return-type' - '-readability-function-cognitive-complexity' - '-readability-implicit-bool-conversion' - '-readability-braces-around-statements' - '-readability-qualified-auto' - '-readability-isolate-declaration' - '-modernize-avoid-c-arrays' - '-cppcoreguidelines-avoid-c-arrays' - '-readability-named-parameter' - '-readability-identifier-length' - '-misc-non-private-member-variables-in-classes' - '-bugprone-easily-swappable-parameters' - '-bugprone-implicit-widening-of-multiplication-result' - '-misc-include-cleaner' - '-misc-header-include-cycle' - '-modernize-macro-to-enum' - '-cppcoreguidelines-macro-to-enum' - '-misc-no-recursion' - '-bugprone-dynamic-static-initializers' - '-portability-avoid-pragma-once' # Generally speaking if something is static then it has an express reason to be. 99% of # the candidates identified by this check were because they just so happened not to # touch any member variables, not because they are logically static. So we disable the # check. - '-readability-convert-member-functions-to-static' # When running in a conda env, ignore options that may have been added by conda but are unused - '-clang-diagnostic-unused-command-line-argument' # Given # # std::make_pair(...) # # Results in: error: for C++11-compatibility, use pair directly. But we don't care about # C++11, and so we don't care about this warning. - '-google-build-explicit-make-pair' # This check is incredibly expensive for absolutely no reason, and since we a) use # modern google-test and b) don't have clang-tidy enabled on our testing code, we don't # need to enable it! - '-google-upgrade-googletest-case' # This warning will warn if you have redundant default-initializers for class # members. For example: # # class Foo # { # int x_{}; // WARNING: redundant initializer here # # public: # Foo(int x) : x_{x} { } # }; # # Since Foo can only ever be constructed with an explicit value for x_ via its constructor, # the default initializer is technically redundant. However, if we change the definition # of Foo to now allow a default ctor, then the initializer becomes non-redundant # again. It is easier to just follow the rule of "always explicitly default initialize # members" than to remember to change 2 places at once. - '-readability-redundant-member-init' # Alias for readability-enum-initial-value, disable this one because the readability- # name is easier to understand, and we don't want to silence 2 things for the same # warning. - '-cert-int09-c' # This one is potentially controversial. This check warns when iterating over unordered # containers of pointers: # # { # int a = 1, b = 2; # std::unordered_set set = {&a, &b}; # # for (auto *i : set) { // iteration order not deterministic # f(i); # } # } # # On the one hand, this is a clear case of non-determinism. But on the other hand, I # feel it is obvious that a user does not care about the order of iteration # because... they are using unordered containers! - '-bugprone-nondeterministic-pointer-iteration-order' - '-cppcoreguidelines-pro-type-reinterpret-cast' # We don't use GSL - '-cppcoreguidelines-owning-memory' # Covered by modernize-use-override already - '-cppcoreguidelines-explicit-virtual-functions' # Covered by readability-magic-numbers - '-cppcoreguidelines-avoid-magic-numbers' # This check does more harm than good, as it appears to be very rudimentary. For # example, it emits warnings saying that: # # #define DEFINE_OPERATOR(op) \ # _CCCL_HOST_DEVICE custom_numeric operator op() const \ # { \ # return custom_numeric(op value[0]); \ # } # # Should be replaced by a template function, but this is not possible. We instead rely # on best judgment of reviewers to catch macros that can be functions. - '-cppcoreguidelines-macro-usage' # This check does not understand more complex macro usage where brackets are not allowed # # error: macro replacement list should be enclosed in parentheses [bugprone-macro-parentheses] # 36 | #define __THRUST_HOST_SYSTEM_INCLUDE(filename) <__THRUST_HOST_SYSTEM_ROOT/filename> # | ^ # | ( ) # # So better left disabled. - '-bugprone-macro-parentheses' # TODO: Enable for clang-tidy-22 - '-modernize-avoid-c-style-cast' - '-bugprone-signed-bitwise' - '-bugprone-std-namespace-modification' - '-clang-diagnostic-deprecated-attributes' - '-bugprone-throwing-static-initialization' - '-bugprone-unchecked-string-to-number-conversion' - '-bugprone-invalid-enum-default-initialization' - '-bugprone-derived-method-shadowing-base-method' - '-bugprone-unsafe-to-allow-exceptions' - '-bugprone-sizeof-expression' - '-modernize-use-nullptr' - '-bugprone-std-exception-baseclass' - '-modernize-avoid-variadic-functions' - '-modernize-type-traits' - '-bugprone-random-generator-seed' - '-bugprone-command-processor' # TODO: ironically enough, enable this someday - '-google-readability-todo' # Covered by modernize-avoid-c-style-cast, and also is buggier. It seems to fire on # `_v`-style constexpr bools as well sometimes. - '-google-readability-casting' # Covered by performance-noexcept-move-constructor - '-cppcoreguidelines-noexcept-move-operations' # REVIEW ME: This warns about any usage of operator[], suggesting usage of .at() instead. Could - '-cppcoreguidelines-pro-bounds-avoid-unchecked-container-access' - '-cppcoreguidelines-narrowing-conversions' # Covered by misc-unconventional-assign-operator - '-cppcoreguidelines-c-copy-assignment-signature' # Covered by performance-noexcept-swap - '-cppcoreguidelines-noexcept-swap' # Covered by modernize-use-default-member-init - '-cppcoreguidelines-use-default-member-init' # clang-tidy documentation says that for a given file, it matches the closest # .clang-tidy up the directory stack and applies the configuration from it. However, by # "it" `clang-tidy` means the closest `.clang-tidy` to the *source* file, not the file # that was included by the source file. # # So `cuda/std/foo.h` included by `cccl/foo/bar/baz.cpp` will never "match" against # `cccl/libcudacxx/.clang-tidy` because `clang-tidy` finds `cccl/.clang-tidy` instead. # # So we disable this for now. In the future we should add a custom check that bans # reserved identifiers except symbols from libcu++. - '-bugprone-reserved-identifier' WarningsAsErrors: '*' HeaderFileExtensions: - '' - h - hh - hpp - hxx - cuh - inl - ipp ImplementationFileExtensions: - c - cc - cpp - cxx - cu SystemHeaders: false HeaderFilterRegex: '.*/(thrust|cub|cuda|nv|cccl|c2h|cudastf|test)/.*' ExtraArgsBefore: # To match _CCCL_DOXYGEN_INVOKED - '-D_CCCL_CLANG_TIDY_INVOKED=1' - '-ftemplate-backtrace-limit=0' - '-fmacro-backtrace-limit=0' ExtraArgs: # These must come in ExtraArgs not ExtraArgsBefore, because they are overriding the # effects of -Wall and -Werror, where the last flag "wins". - '-Wno-unknown-warning-option' - '-Wno-unknown-cuda-version' - '-Wno-error=unused-command-line-argument' CheckOptions: cert-dcl16-c.NewSuffixes: 'L;LL;LU;LLU' cert-err33-c.CheckedFunctions: '::aligned_alloc;::asctime_s;::at_quick_exit;::atexit;::bsearch;::bsearch_s;::btowc;::c16rtomb;::c32rtomb;::calloc;::clock;::cnd_broadcast;::cnd_init;::cnd_signal;::cnd_timedwait;::cnd_wait;::ctime_s;::fclose;::fflush;::fgetc;::fgetpos;::fgets;::fgetwc;::fopen;::fopen_s;::fprintf;::fprintf_s;::fputc;::fputs;::fputwc;::fputws;::fread;::freopen;::freopen_s;::fscanf;::fscanf_s;::fseek;::fsetpos;::ftell;::fwprintf;::fwprintf_s;::fwrite;::fwscanf;::fwscanf_s;::getc;::getchar;::getenv;::getenv_s;::gets_s;::getwc;::getwchar;::gmtime;::gmtime_s;::localtime;::localtime_s;::malloc;::mbrtoc16;::mbrtoc32;::mbsrtowcs;::mbsrtowcs_s;::mbstowcs;::mbstowcs_s;::memchr;::mktime;::mtx_init;::mtx_lock;::mtx_timedlock;::mtx_trylock;::mtx_unlock;::printf_s;::putc;::putwc;::raise;::realloc;::remove;::rename;::scanf;::scanf_s;::setlocale;::setvbuf;::signal;::snprintf;::snprintf_s;::sprintf;::sprintf_s;::sscanf;::sscanf_s;::strchr;::strerror_s;::strftime;::strpbrk;::strrchr;::strstr;::strtod;::strtof;::strtoimax;::strtok;::strtok_s;::strtol;::strtold;::strtoll;::strtoul;::strtoull;::strtoumax;::strxfrm;::swprintf;::swprintf_s;::swscanf;::swscanf_s;::thrd_create;::thrd_detach;::thrd_join;::thrd_sleep;::time;::timespec_get;::tmpfile;::tmpfile_s;::tmpnam;::tmpnam_s;::tss_create;::tss_get;::tss_set;::ungetc;::ungetwc;::vfprintf;::vfprintf_s;::vfscanf;::vfscanf_s;::vfwprintf;::vfwprintf_s;::vfwscanf;::vfwscanf_s;::vprintf_s;::vscanf;::vscanf_s;::vsnprintf;::vsnprintf_s;::vsprintf;::vsprintf_s;::vsscanf;::vsscanf_s;::vswprintf;::vswprintf_s;::vswscanf;::vswscanf_s;::vwprintf_s;::vwscanf;::vwscanf_s;::wcrtomb;::wcschr;::wcsftime;::wcspbrk;::wcsrchr;::wcsrtombs;::wcsrtombs_s;::wcsstr;::wcstod;::wcstof;::wcstoimax;::wcstok;::wcstok_s;::wcstol;::wcstold;::wcstoll;::wcstombs;::wcstombs_s;::wcstoul;::wcstoull;::wcstoumax;::wcsxfrm;::wctob;::wctrans;::wctype;::wmemchr;::wprintf_s;::wscanf;::wscanf_s;' llvm-else-after-return.WarnOnUnfixable: 'false' cert-str34-c.DiagnoseSignedUnsignedCharComparisons: 'false' cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic: 'true' google-readability-braces-around-statements.ShortStatementLines: '1' llvm-qualified-auto.AddConstToQualified: 'false' llvm-else-after-return.WarnOnConditionVariables: 'false' cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField: 'false' performance-move-const-arg.CheckTriviallyCopyableMove: 'false' performance-inefficient-string-concatenation.StrictMode: 'true' readability-simplify-boolean-expr.ChainedConditionalReturn: 'true' readability-simplify-boolean-expr.ChainedConditionalAssignment: 'true' bugprone-dangling-handle.HandleClasses: '::cuda::std::span;::cuda::std::mdspan' bugprone-unused-return-value.AllowCastToVoid: 'true' readability-enum-initial-value.AllowExplicitZeroFirstInitialValue: 'false' readability-enum-initial-value.AllowExplicitSequentialInitialValues: 'false' readability-redundant-access-specifiers.CheckFirstDeclaration: 'true' bugprone-lambda-function-name.IgnoreMacros: 'true' # readability-identifier-naming.ClassCase: 'lower_case' # readability-identifier-naming.UnionCase: 'lower_case' # readability-identifier-naming.ClassConstantCase: 'UPPER_CASE' # readability-identifier-naming.ClassIgnoredRegexp: 'tuple|has_.*|is_.*|as_.*|.*_tag|tag|.*_of' # readability-identifier-naming.ConstantMemberCase: 'UPPER_CASE' # readability-identifier-naming.ConstantMemberIgnoredRegexp: 'value' # readability-identifier-naming.EnumCase: 'lower_case' # readability-identifier-naming.EnumConstantCase: 'UPPER_CASE' # readability-identifier-naming.FunctionCase: 'lower_case' # readability-identifier-naming.GlobalConstantCase: 'UPPER_CASE' # readability-identifier-naming.GlobalConstantIgnoredRegexp: '.*_v' # readability-identifier-naming.LocalVariableCase: 'lower_case' # # We want to allow constexpr auto MY_VAL1 # readability-identifier-naming.LocalVariableIgnoredRegexp: '[A-Z_0-9]+' # readability-identifier-naming.MacroDefinitionCase: 'UPPER_CASE' # # We want to allow MY_MACRO_PRIVATE_1_ # readability-identifier-naming.MacroDefinitionIgnoredRegexp: '[A-Z_0-9]+' # readability-identifier-naming.NamespaceCase: 'lower_case' # readability-identifier-naming.PrivateMemberCase: 'lower_case' # readability-identifier-naming.PrivateMemberSuffix: '_' # readability-identifier-naming.PrivateMethodCase: 'lower_case' # readability-identifier-naming.PrivateMethodSuffix: '_' # readability-identifier-naming.ProtectedMemberCase: 'lower_case' # readability-identifier-naming.ProtectedMemberSuffix: '_' # readability-identifier-naming.ProtectedMethodCase: 'lower_case' # readability-identifier-naming.ProtectedMethodSuffix: '_' # readability-identifier-naming.PublicMethodCase: 'lower_case' # readability-identifier-naming.ScopedEnumCase: 'lower_case' # readability-identifier-naming.ScopedEnumConstantCase: 'UPPER_CASE' readability-magic-numbers.IgnoredIntegerValues: '0;1;2;3;4;5;6;7;8;9' # There are some single-argument functions that we would not like to ignore # (`to_string(bool provenance = false)` comes to mind), but setting this to false makes # clang-tidy warn on a bunch of "obvious" calls, like `set_dim(1)` or # `with_concurrent(true)`. bugprone-argument-comment.IgnoreSingleArgument: true bugprone-argument-comment.CommentBoolLiterals: true bugprone-argument-comment.CommentIntegerLiterals: true bugprone-argument-comment.CommentFloatLiterals: true bugprone-argument-comment.CommentStringLiterals: true bugprone-argument-comment.CommentCharacterLiterals: true bugprone-argument-comment.CommentUserDefinedLiterals: true bugprone-argument-comment.CommentNullPtrs: true cppcoreguidelines-macro-usage.AllowedRegexp: '^DEBUG_.*|THRUST_PP_.*|_CCCL.*_PP_.*' bugprone-reserved-identifier.AllowedIdentifiers: '^_CCCL.*' performance-enum-size.EnumIgnoreList: '::cuda::std::.*' performance-unnecessary-value-param.AllowedTypes: '.*(_ref(erence)?|_ptr|pointer|(_)?[Ii]t(erator)?|IteratorT|__half(2)?|(__nv_bfloat.*)|_view)$' bugprone-exception-escape.CheckMain: false ...