[clang-tools-extra] r265774 - [clang-tidy] cppcoreguidelines-interfaces-global-init

Alexander Kornienko via cfe-commits cfe-commits at lists.llvm.org
Fri Apr 8 02:51:08 PDT 2016


Author: alexfh
Date: Fri Apr  8 04:51:06 2016
New Revision: 265774

URL: http://llvm.org/viewvc/llvm-project?rev=265774&view=rev
Log:
[clang-tidy] cppcoreguidelines-interfaces-global-init

Summary:
This check flags initializers of globals that access extern objects, and therefore can lead to order-of-initialization problems (this recommandation is part of CPP core guidelines).
Note that this only checks half of the guideline for now (it does not enforce using constexpr functions).

Reviewers: aaron.ballman, alexfh

Subscribers: aaron.ballman, etienneb, Eugene.Zelenko, cfe-commits

Patch by Clement Courbet!

Differential Revision: http://reviews.llvm.org/D18649

Added:
    clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.cpp
    clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.h
    clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-interfaces-global-init.rst
    clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-interfaces-global-init.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt
    clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
    clang-tools-extra/trunk/docs/ReleaseNotes.rst
    clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst

Modified: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt?rev=265774&r1=265773&r2=265774&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt Fri Apr  8 04:51:06 2016
@@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS support)
 
 add_clang_library(clangTidyCppCoreGuidelinesModule
   CppCoreGuidelinesTidyModule.cpp
+  InterfacesGlobalInitCheck.cpp
   ProBoundsArrayToPointerDecayCheck.cpp
   ProBoundsConstantArrayIndexCheck.cpp
   ProBoundsPointerArithmeticCheck.cpp

Modified: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp?rev=265774&r1=265773&r2=265774&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp Fri Apr  8 04:51:06 2016
@@ -11,6 +11,7 @@
 #include "../ClangTidyModule.h"
 #include "../ClangTidyModuleRegistry.h"
 #include "../misc/AssignOperatorSignatureCheck.h"
+#include "InterfacesGlobalInitCheck.h"
 #include "ProBoundsArrayToPointerDecayCheck.h"
 #include "ProBoundsConstantArrayIndexCheck.h"
 #include "ProBoundsPointerArithmeticCheck.h"
@@ -30,6 +31,8 @@ namespace cppcoreguidelines {
 class CppCoreGuidelinesModule : public ClangTidyModule {
 public:
   void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+    CheckFactories.registerCheck<InterfacesGlobalInitCheck>(
+        "cppcoreguidelines-interfaces-global-init");
     CheckFactories.registerCheck<ProBoundsArrayToPointerDecayCheck>(
         "cppcoreguidelines-pro-bounds-array-to-pointer-decay");
     CheckFactories.registerCheck<ProBoundsConstantArrayIndexCheck>(

Added: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.cpp?rev=265774&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.cpp Fri Apr  8 04:51:06 2016
@@ -0,0 +1,59 @@
+//===--- InterfacesGlobalInitCheck.cpp - clang-tidy------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InterfacesGlobalInitCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+void InterfacesGlobalInitCheck::registerMatchers(MatchFinder *Finder) {
+  const auto IsGlobal =
+      allOf(hasGlobalStorage(),
+            hasDeclContext(anyOf(translationUnitDecl(), // Global scope.
+                                 namespaceDecl(),       // Namespace scope.
+                                 recordDecl())),        // Class scope.
+            unless(isConstexpr()));
+
+  const auto ReferencesUndefinedGlobalVar = declRefExpr(hasDeclaration(
+      varDecl(IsGlobal, unless(isDefinition())).bind("referencee")));
+
+  Finder->addMatcher(
+      varDecl(IsGlobal, isDefinition(),
+              hasInitializer(expr(hasDescendant(ReferencesUndefinedGlobalVar))))
+          .bind("var"),
+      this);
+}
+
+void InterfacesGlobalInitCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *const Var = Result.Nodes.getNodeAs<VarDecl>("var");
+  // For now assume that people who write macros know what they're doing.
+  if (Var->getLocation().isMacroID())
+    return;
+  const auto *const Referencee = Result.Nodes.getNodeAs<VarDecl>("referencee");
+  // If the variable has been defined, we're good.
+  const auto *const ReferenceeDef = Referencee->getDefinition();
+  if (ReferenceeDef != nullptr &&
+      Result.SourceManager->isBeforeInTranslationUnit(
+          ReferenceeDef->getLocation(), Var->getLocation())) {
+    return;
+  }
+  diag(Var->getLocation(),
+       "initializing non-local variable with non-const expression depending on "
+       "uninitialized non-local variable %0")
+      << Referencee;
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang

Added: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.h?rev=265774&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.h Fri Apr  8 04:51:06 2016
@@ -0,0 +1,35 @@
+//===--- InterfacesGlobalInitCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_INTERFACES_GLOBAL_INIT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_INTERFACES_GLOBAL_INIT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// Flags possible initialization order issues of static variables.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-interfaces-global-init.html
+class InterfacesGlobalInitCheck : public ClangTidyCheck {
+public:
+  InterfacesGlobalInitCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_INTERFACES_GLOBAL_INIT_H

Modified: clang-tools-extra/trunk/docs/ReleaseNotes.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/ReleaseNotes.rst?rev=265774&r1=265773&r2=265774&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/ReleaseNotes.rst (original)
+++ clang-tools-extra/trunk/docs/ReleaseNotes.rst Fri Apr  8 04:51:06 2016
@@ -164,6 +164,13 @@ identified.  The improvements since the
 
   Finds static function and variable definitions in anonymous namespace.
 
+- New `cppcoreguidelines-interfaces-global-init
+  <http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-interfaces-global-init.html>`_ check
+
+  Flags initializers of globals that access extern objects, and therefore can
+  lead to order-of-initialization problems.
+
+
 Fixed bugs:
 
 - Crash when running on compile database with relative source files paths.

Added: clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-interfaces-global-init.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-interfaces-global-init.rst?rev=265774&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-interfaces-global-init.rst (added)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-interfaces-global-init.rst Fri Apr  8 04:51:06 2016
@@ -0,0 +1,14 @@
+.. title:: clang-tidy - cppcoreguidelines-interfaces-global-init
+
+cppcoreguidelines-interfaces-global-init
+========================================
+
+This check flags initializers of globals that access extern objects,
+and therefore can lead to order-of-initialization problems.
+
+This rule is part of the "Interfaces" profile of the C++ Core Guidelines, see
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Ri-global-init
+
+Note that currently this does not flag calls to non-constexpr functions, and
+therefore globals could still be accessed from functions themselves.
+

Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst?rev=265774&r1=265773&r2=265774&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst (original)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst Fri Apr  8 04:51:06 2016
@@ -16,6 +16,7 @@ Clang-Tidy Checks
    cert-fio38-c (redirects to misc-non-copyable-objects) <cert-fio38-c>
    cert-flp30-c
    cert-oop11-cpp (redirects to misc-move-constructor-init) <cert-oop11-cpp>
+   cppcoreguidelines-interfaces-global-init
    cppcoreguidelines-pro-bounds-array-to-pointer-decay
    cppcoreguidelines-pro-bounds-constant-array-index
    cppcoreguidelines-pro-bounds-pointer-arithmetic

Added: clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-interfaces-global-init.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-interfaces-global-init.cpp?rev=265774&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-interfaces-global-init.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-interfaces-global-init.cpp Fri Apr  8 04:51:06 2016
@@ -0,0 +1,84 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-interfaces-global-init %t
+
+constexpr int makesInt() { return 3; }
+constexpr int takesInt(int i) { return i + 1; }
+constexpr int takesIntPtr(int *i) { return *i; }
+
+extern int ExternGlobal;
+static int GlobalScopeBadInit1 = ExternGlobal;
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
+static int GlobalScopeBadInit2 = takesInt(ExternGlobal);
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
+static int GlobalScopeBadInit3 = takesIntPtr(&ExternGlobal);
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable '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'
+
+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'
+
+struct A {
+  static int ClassScope;
+  static int ClassScopeBadInit;
+};
+
+int A::ClassScopeBadInit = takesInt(ExternGlobal);
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable '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'
+} // namespace ns
+
+// "const int B::I;" is fine, it just ODR-defines B::I. See [9.4.3] Static
+// members [class.static]. However the ODR-definitions are not in the right
+// order (C::I after C::J, see [3.6.2.3]).
+class B1 {
+  static const int I = 0;
+  static const int J = I;
+};
+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;
+
+void f() {
+  // This is fine, it's executed after dynamic initialization occurs.
+  static int G = takesInt(ExternGlobal);
+}
+
+// Declaration then definition then usage is fine.
+extern int ExternGlobal2;
+extern int ExternGlobal2;
+int ExternGlobal2 = 123;
+static int GlobalScopeGoodInit1 = ExternGlobal2;
+
+
+// Defined global variables are fine:
+static int GlobalScope = makesInt();
+static int GlobalScopeGoodInit2 = takesInt(GlobalScope);
+static int GlobalScope2 = takesInt(ns::NamespaceScope);
+// Enums are fine.
+enum Enum { kEnumValue = 1 };
+static int GlobalScopeFromEnum = takesInt(kEnumValue);
+
+// Leave constexprs alone.
+extern constexpr int GlobalScopeConstexpr = makesInt();
+static constexpr int GlobalScopeConstexprOk =
+    takesInt(GlobalScopeConstexpr);
+
+// This is a pretty common instance: People are usually not using constexpr, but
+// this is what they should write:
+static constexpr const char kValue[] = "value";
+constexpr int Fingerprint(const char *value) { return 0; }
+static int kFingerprint = Fingerprint(kValue);
+
+// This is fine because the ODR-definitions are in the right order (C::J after
+// C::I).
+class B2 {
+  static const int I = 0;
+  static const int J = I;
+};
+const int B2::I;
+const int B2::J;
+




More information about the cfe-commits mailing list