[clang-tools-extra] [clang-tidy] Unsafe CRTP check (PR #82403)

via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 22 06:49:01 PST 2024


================
@@ -0,0 +1,62 @@
+.. title:: clang-tidy - bugprone-unsafe-crtp
+
+bugprone-unsafe-crtp
+====================
+
+Finds CRTP used in an error-prone way.
+
+If the constructor of a class intended to be used in a CRTP is public, then
+it allows users to construct that class on its own.
+
+Example:
+
+.. code-block:: c++
+
+  template <typename T> class CRTP {
+  public:
+    CRTP() = default;
+  };
+
+  class Good : CRTP<Good> {};
+  Good GoodInstance;
+
+  CRTP<int> BadInstance;
+
+If the constructor is protected, the possibility of an accidental instantiation
+is prevented, however it can fade an error, when a different class is used as
+the template parameter instead of the derived one.
+
+Example:
+
+.. code-block:: c++
+
+  template <typename T> class CRTP {
+  protected:
+    CRTP() = default;
+  };
+
+  class Good : CRTP<Good> {};
+  Good GoodInstance;
+
+  class Bad : CRTP<Good> {};
+  Bad BadInstance;
+
+To ensure that no accidental instantiation happens, the best practice is to make
+the constructor private and declare the derived class as friend.
+
+Example:
+
+.. code-block:: c++
+
+  template <typename T> class CRTP {
+    CRTP() = default;
+    friend T;
+  };
+
+  class Good : CRTP<Good> {};
+  Good GoodInstance;
+
+  class Bad : CRTP<Good> {};
+  Bad CompileTimeError;
+
+  CRTP<int> AlsoCompileTimeError;
----------------
whisperity wrote:

Also, protected constructor might be needed in cases where the class we are currently checking a base class in a hierarchy (while also using a CRTP) and there is no reason to allow its direct instantiation by clients, because clients should instantiate the current class's deriveds to get to useful objects. However, those deriveds might not be using CRTP on their own level.

Contrived example:

```cpp

template <class NodeFamily>
struct ASTNode {
  protected:
    // Users should not construct this base class directly.
    ASTNode(...) { ... }
};

struct Stmt : ASTNode<Stmt> {
  protected:
    // Users should not construct this base class directly, either.
    Stmt(...) : ASTNode(...) { ... }
};

struct IfStmt : Stmt {
  // This should be constructible directly by clients.
  IfStmt(...) : Stmt(...) { ... }
};
```

https://github.com/llvm/llvm-project/pull/82403


More information about the cfe-commits mailing list