Index: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -17,6 +17,7 @@ #include "BranchCloneCheck.h" #include "CopyConstructorInitCheck.h" #include "DanglingHandleCheck.h" +#include "DoNotReferAtomicTwiceCheck.h" #include "DynamicStaticInitializersCheck.h" #include "ExceptionEscapeCheck.h" #include "FoldInitTypeCheck.h" @@ -84,6 +85,8 @@ "bugprone-copy-constructor-init"); CheckFactories.registerCheck( "bugprone-dangling-handle"); + CheckFactories.registerCheck( + "bugprone-do-not-refer-atomic-twice"); CheckFactories.registerCheck( "bugprone-dynamic-static-initializers"); CheckFactories.registerCheck( Index: clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -9,6 +9,7 @@ BugproneTidyModule.cpp CopyConstructorInitCheck.cpp DanglingHandleCheck.cpp + DoNotReferAtomicTwiceCheck.cpp DynamicStaticInitializersCheck.cpp ExceptionEscapeCheck.cpp FoldInitTypeCheck.cpp Index: clang-tools-extra/clang-tidy/bugprone/DoNotReferAtomicTwiceCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/DoNotReferAtomicTwiceCheck.h @@ -0,0 +1,34 @@ +//===--- DoNotReferAtomicTwiceCheck.h - clang-tidy --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DONOTREFERATOMICTWICECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DONOTREFERATOMICTWICECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Finds atomic variable which is referred twice in an expression. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-do-not-refer-atomic-twice.html +class DoNotReferAtomicTwiceCheck : public ClangTidyCheck { +public: + DoNotReferAtomicTwiceCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace bugprone +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DONOTREFERATOMICTWICECHECK_H Index: clang-tools-extra/clang-tidy/bugprone/DoNotReferAtomicTwiceCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/DoNotReferAtomicTwiceCheck.cpp @@ -0,0 +1,44 @@ +//===--- DoNotReferAtomicTwiceCheck.cpp - clang-tidy ----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DoNotReferAtomicTwiceCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bugprone { + +void DoNotReferAtomicTwiceCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + declRefExpr(hasType(hasUnqualifiedDesugaredType(atomicType())), + to(varDecl().bind("atomic")), + hasAncestor(binaryOperator( + unless(hasDescendant(atomicExpr())), + hasRHS(hasDescendant( + declRefExpr(to(varDecl(equalsBoundNode("atomic")))) + .bind("rhs"))))), + unless(equalsBoundNode("rhs"))), + this); +} + +void DoNotReferAtomicTwiceCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedVar = Result.Nodes.getNodeAs("atomic"); + const auto *MatchedRef = Result.Nodes.getNodeAs("rhs"); + if (!MatchedRef || !MatchedVar) + return; + diag(MatchedRef->getExprLoc(), + "Do not refer to '%0' atomic variable twice in an expression") + << MatchedVar->getName(); +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp +++ clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp @@ -10,6 +10,7 @@ #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" #include "../bugprone/BadSignalToKillThreadCheck.h" +#include "../bugprone/DoNotReferAtomicTwiceCheck.h" #include "../bugprone/ReservedIdentifierCheck.h" #include "../bugprone/SpuriouslyWakeUpFunctionsCheck.h" #include "../bugprone/UnhandledSelfAssignmentCheck.h" @@ -85,6 +86,8 @@ // C checkers // CON + CheckFactories.registerCheck( + "cert-con40-c"); CheckFactories.registerCheck( "cert-con36-c"); // DCL Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -75,6 +75,11 @@ New checks ^^^^^^^^^^ +- New :doc:`bugprone-do-not-refer-atomic-twice + ` check. + + Finds atomic variable which is referred twice in an expression. + - New :doc:`cppcoreguidelines-avoid-non-const-global-variables ` check. Finds non-const global variables as described in check I.2 of C++ Core @@ -137,6 +142,11 @@ :doc:`bugprone-spuriously-wake-up-functions ` was added. +- New alias :doc:`cert-con40-c + ` to + :doc:`bugprone-do-not-refer-atomic-twice + ` was added. + - New alias :doc:`cert-con54-cpp ` to :doc:`bugprone-spuriously-wake-up-functions Index: clang-tools-extra/docs/clang-tidy/checks/bugprone-do-not-refer-atomic-twice.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/bugprone-do-not-refer-atomic-twice.rst @@ -0,0 +1,17 @@ +.. title:: clang-tidy - bugprone-do-not-refer-atomic-twice + +bugprone-do-not-refer-atomic-twice +================================== + +Finds atomic variable which is referred twice in an expression. + +.. code-block: c + + atomic_int n = ATOMIC_VAR_INIT(0); + int compute_sum(void) { + return n * (n + 1) / 2; + } + +This check corresponds to the CERT C Coding Standard rule +`CON40-C. Do not refer to an atomic variable twice in an expression +`_. Index: clang-tools-extra/docs/clang-tidy/checks/cert-con40-c.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/cert-con40-c.rst @@ -0,0 +1,10 @@ +.. title:: clang-tidy - cert-con40-c +.. meta:: + :http-equiv=refresh: 5;URL=bugprone-do-not-refer-atomic-twice.html + +cert-con40-c +============ + +The cert-con40-c check is an alias, please see +`bugprone-do-not-refer-atomic-twice `_ +for more information. Index: clang-tools-extra/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -52,6 +52,7 @@ `bugprone-branch-clone `_, `bugprone-copy-constructor-init `_, "Yes" `bugprone-dangling-handle `_, + `bugprone-do-not-refer-atomic-twice `_, `bugprone-dynamic-static-initializers `_, `bugprone-exception-escape `_, `bugprone-fold-init-type `_, @@ -97,6 +98,7 @@ `bugprone-unused-return-value `_, `bugprone-use-after-move `_, `bugprone-virtual-near-miss `_, "Yes" + `cert-con40-c `_, `cert-dcl21-cpp `_, `cert-dcl50-cpp `_, `cert-dcl58-cpp `_, @@ -132,6 +134,7 @@ `clang-analyzer-valist.Uninitialized `_, `clang-analyzer-valist.Unterminated `_, `cppcoreguidelines-avoid-goto `_, + `cppcoreguidelines-avoid-non-const-global-variables `_, `cppcoreguidelines-init-variables `_, "Yes" `cppcoreguidelines-interfaces-global-init `_, `cppcoreguidelines-macro-usage `_, @@ -188,7 +191,7 @@ `llvm-prefer-isa-or-dyn-cast-in-conditionals `_, "Yes" `llvm-prefer-register-over-unsigned `_, "Yes" `llvm-twine-local `_, "Yes" - `llvmlibc-restrict-system-libc-headers `_, "Yes" + `llvmlibc-restrict-system-libc-headers `_, `misc-definitions-in-headers `_, "Yes" `misc-misplaced-const `_, `misc-new-delete-overloads `_, @@ -209,7 +212,7 @@ `modernize-deprecated-headers `_, "Yes" `modernize-deprecated-ios-base-aliases `_, "Yes" `modernize-loop-convert `_, "Yes" - `modernize-make-shared `_, "Yes" + `modernize-make-shared `_, `modernize-make-unique `_, "Yes" `modernize-pass-by-value `_, "Yes" `modernize-raw-string-literal `_, "Yes" @@ -383,7 +386,6 @@ `clang-analyzer-unix.cstring.NullArg `_, `Clang Static Analyzer `_, `cppcoreguidelines-avoid-c-arrays `_, `modernize-avoid-c-arrays `_, `cppcoreguidelines-avoid-magic-numbers `_, `readability-magic-numbers `_, - `cppcoreguidelines-avoid-non-const-global-variables `_, , , "" `cppcoreguidelines-c-copy-assignment-signature `_, `misc-unconventional-assign-operator `_, `cppcoreguidelines-explicit-virtual-functions `_, `modernize-use-override `_, "Yes" `cppcoreguidelines-non-private-member-variables-in-classes `_, `misc-non-private-member-variables-in-classes `_, @@ -417,4 +419,3 @@ `hicpp-use-override `_, `modernize-use-override `_, "Yes" `hicpp-vararg `_, `cppcoreguidelines-pro-type-vararg `_, `llvm-qualified-auto `_, `readability-qualified-auto `_, "Yes" - Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-do-not-refer-atomic-twice.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-do-not-refer-atomic-twice.cpp @@ -0,0 +1,79 @@ +// RUN: %check_clang_tidy %s bugprone-do-not-refer-atomic-twice %t +#define _Bool bool +typedef _Atomic _Bool atomic_bool; +typedef _Atomic int atomic_int; +#define ATOMIC_VAR_INIT(VALUE) (VALUE) + +atomic_bool b = ATOMIC_VAR_INIT(false); +atomic_int n = ATOMIC_VAR_INIT(0); +_Atomic int n2 = ATOMIC_VAR_INIT(0); +_Atomic(int) n3 = ATOMIC_VAR_INIT(0); + +void warn1() { + n = (n + 1) / 2; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Do not refer to 'n' atomic variable twice in an expression [bugprone-do-not-refer-atomic-twice] + n2 = (n2 + 1) / 2; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Do not refer to 'n2' atomic variable twice in an expression [bugprone-do-not-refer-atomic-twice] + n3 = (n3 + 1) / 2; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Do not refer to 'n3' atomic variable twice in an expression [bugprone-do-not-refer-atomic-twice] + b = b && true; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: Do not refer to 'b' atomic variable twice in an expression [bugprone-do-not-refer-atomic-twice] +} + +int warn2_1() { + return n * (n + 1) / 2; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Do not refer to 'n' atomic variable twice in an expression [bugprone-do-not-refer-atomic-twice] +} + +int warn2_2() { + return n2 * (n2 + 1) / 2; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Do not refer to 'n2' atomic variable twice in an expression [bugprone-do-not-refer-atomic-twice] +} + +int warn2_3() { + return n3 * (n3 + 1) / 2; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Do not refer to 'n3' atomic variable twice in an expression [bugprone-do-not-refer-atomic-twice] +} + +int warn2_4() { + return (b && true) || b; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: Do not refer to 'b' atomic variable twice in an expression [bugprone-do-not-refer-atomic-twice] +} + +void good1() { + n = 12; + n2 = 12; + n3 = 12; + b = true; +} + +int good2_1() { + return n; +} + +int good2_2() { + return n2; +} + +int good2_3() { + return n3; +} + +bool good2_4() { + return b; +} + +void good3() { + n += 12; + n2 += 12; + n3 += 12; + b ^= 1; +} + +void good4() { + n++; + n2++; + n3++; +} + +int main() {}