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

via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 23 12:25:25 PST 2024


================
@@ -0,0 +1,232 @@
+// RUN: %check_clang_tidy %s bugprone-unsafe-crtp %t
+
+namespace class_implicit_ctor {
+template <typename T>
+class CRTP {};
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the implicit default constructor of the CRTP is publicly accessible [bugprone-unsafe-crtp]
+// CHECK-MESSAGES: :[[@LINE-2]]:7: note: consider making it private
+// CHECK-FIXES: CRTP() = default;
+
+class A : CRTP<A> {};
+} // namespace class_implicit_ctor
+
+namespace class_uncostructible {
+template <typename T>
+class CRTP {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: the CRTP cannot be constructed from the derived class [bugprone-unsafe-crtp]
+// CHECK-MESSAGES: :[[@LINE-2]]:7: note: consider declaring the derived class as friend
+// CHECK-FIXES: friend T;
----------------
isuckatcs wrote:

Since checking if a public or protected function can construct the class would require path sensitive analysis I'd add this example as a limitation to the docs.

E.g.:
```c++
template <class T>
class CRTP
{
    CRTP(int I) {}

public:
    static void hardToDetect(CRTP* Escape, int X) { 
        if(X > 2) {
            Escape = new CRTP{1};
        }
    }
};
```

Another solution would be to walk the callgraph, but that would just pollute the user with non-meaningful warnings.

E.g.:
```c++
template <class T>
class CRTP
{
    CRTP(int I) {}

public:
    void hardToDetect(CRTP* Escape, int X) { 
        if(CRTP && X > 2) {
            Escape = new CRTP{1};
        }
    }
    
    void warning1() { hardToDetect(nullptr, 3); }
    void warning2() { warning1(); }
    void warning3() { warning2(); }
};
```
In the above `CRTP` we could report a warning for every function, right?

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


More information about the cfe-commits mailing list