https://github.com/balazske updated 
https://github.com/llvm/llvm-project/pull/153428

From 95634ba1fa9690f3d95c45005c908e642c1ced79 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.k...@ericsson.com>
Date: Wed, 13 Aug 2025 15:13:13 +0200
Subject: [PATCH 1/2] [clang-tidy] Add check 'bugprone-cast-to-struct'

---
 .../bugprone/BugproneTidyModule.cpp           |  2 +
 .../clang-tidy/bugprone/CMakeLists.txt        |  1 +
 .../clang-tidy/bugprone/CastToStructCheck.cpp | 82 +++++++++++++++++++
 .../clang-tidy/bugprone/CastToStructCheck.h   | 39 +++++++++
 clang-tools-extra/docs/ReleaseNotes.rst       |  5 ++
 .../checks/bugprone/cast-to-struct.rst        | 54 ++++++++++++
 .../docs/clang-tidy/checks/list.rst           |  1 +
 .../checkers/bugprone/cast-to-struct-ignore.c | 40 +++++++++
 .../checkers/bugprone/cast-to-struct.c        | 66 +++++++++++++++
 9 files changed, 290 insertions(+)
 create mode 100644 clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/bugprone/cast-to-struct.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/cast-to-struct-ignore.c
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/cast-to-struct.c

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 824ebdfbd00dc..5a1573eb34ee3 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -18,6 +18,7 @@
 #include "BranchCloneCheck.h"
 #include "CapturingThisInMemberVariableCheck.h"
 #include "CastingThroughVoidCheck.h"
+#include "CastToStructCheck.h"
 #include "ChainedComparisonCheck.h"
 #include "ComparePointerToMemberVirtualFunctionCheck.h"
 #include "CopyConstructorInitCheck.h"
@@ -125,6 +126,7 @@ class BugproneModule : public ClangTidyModule {
         "bugprone-capturing-this-in-member-variable");
     CheckFactories.registerCheck<CastingThroughVoidCheck>(
         "bugprone-casting-through-void");
+    CheckFactories.registerCheck<CastToStructCheck>("bugprone-cast-to-struct");
     CheckFactories.registerCheck<ChainedComparisonCheck>(
         "bugprone-chained-comparison");
     CheckFactories.registerCheck<ComparePointerToMemberVirtualFunctionCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index 59928e5e47a09..c2bd0d1e3456c 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -14,6 +14,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   BugproneTidyModule.cpp
   CapturingThisInMemberVariableCheck.cpp
   CastingThroughVoidCheck.cpp
+  CastToStructCheck.cpp
   ChainedComparisonCheck.cpp
   ComparePointerToMemberVirtualFunctionCheck.cpp
   CopyConstructorInitCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.cpp
new file mode 100644
index 0000000000000..374736d48d1c8
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.cpp
@@ -0,0 +1,82 @@
+//===--- CastToStructCheck.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 "CastToStructCheck.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+CastToStructCheck::CastToStructCheck(StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      IgnoredFunctions(
+          utils::options::parseStringList(Options.get("IgnoredFunctions", 
""))),
+      IgnoredFromTypes(
+          utils::options::parseStringList(Options.get("IgnoredFromTypes", 
""))),
+      IgnoredToTypes(
+          utils::options::parseStringList(Options.get("IgnoredToTypes", ""))) 
{}
+
+void CastToStructCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "IgnoredFunctions",
+                utils::options::serializeStringList(IgnoredFunctions));
+  Options.store(Opts, "IgnoredFromTypes",
+                utils::options::serializeStringList(IgnoredFromTypes));
+  Options.store(Opts, "IgnoredToTypes",
+                utils::options::serializeStringList(IgnoredToTypes));
+}
+
+void CastToStructCheck::registerMatchers(MatchFinder *Finder) {
+  auto FromPointee =
+      qualType(hasUnqualifiedDesugaredType(type().bind("FromType")),
+               unless(qualType(matchers::matchesAnyListedTypeName(
+                   IgnoredFromTypes, false))))
+          .bind("FromPointee");
+  auto ToPointee =
+      qualType(hasUnqualifiedDesugaredType(recordType().bind("ToType")),
+               unless(qualType(
+                   matchers::matchesAnyListedTypeName(IgnoredToTypes, false))))
+          .bind("ToPointee");
+  auto FromPtrType = qualType(pointsTo(FromPointee)).bind("FromPtr");
+  auto ToPtrType = qualType(pointsTo(ToPointee)).bind("ToPtr");
+  Finder->addMatcher(
+      cStyleCastExpr(hasSourceExpression(hasType(FromPtrType)),
+                     hasType(ToPtrType),
+                     unless(hasAncestor(functionDecl(
+                         matchers::matchesAnyListedName(IgnoredFunctions)))))
+          .bind("CastExpr"),
+      this);
+}
+
+void CastToStructCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *const FoundCastExpr =
+      Result.Nodes.getNodeAs<CStyleCastExpr>("CastExpr");
+  const auto *const FromPtr = Result.Nodes.getNodeAs<QualType>("FromPtr");
+  const auto *const ToPtr = Result.Nodes.getNodeAs<QualType>("ToPtr");
+  const auto *const FromPointee =
+      Result.Nodes.getNodeAs<QualType>("FromPointee");
+  const auto *const ToPointee = Result.Nodes.getNodeAs<QualType>("ToPointee");
+  const auto *const FromType = Result.Nodes.getNodeAs<Type>("FromType");
+  const auto *const ToType = Result.Nodes.getNodeAs<RecordType>("ToType");
+  if (!FromPointee || !ToPointee)
+    return;
+  if (FromType->isVoidType() || FromType->isUnionType() ||
+      ToType->isUnionType())
+    return;
+  if (FromType == ToType)
+    return;
+  diag(FoundCastExpr->getExprLoc(),
+       "casting a %0 pointer to a "
+       "%1 pointer and accessing a field can lead to memory "
+       "access errors or data corruption")
+      << *FromPtr << *ToPtr;
+}
+
+} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.h 
b/clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.h
new file mode 100644
index 0000000000000..9e6c868824d23
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.h
@@ -0,0 +1,39 @@
+//===--- CastToStructCheck.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_CASTTOSTRUCTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CASTTOSTRUCTCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// Finds casts from pointers to struct or scalar type to pointers to struct
+/// type.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/cast-to-struct.html
+class CastToStructCheck : public ClangTidyCheck {
+public:
+  CastToStructCheck(StringRef Name, ClangTidyContext *Context);
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.C99;
+  }
+
+private:
+  std::vector<llvm::StringRef> IgnoredFunctions;
+  std::vector<llvm::StringRef> IgnoredFromTypes;
+  std::vector<llvm::StringRef> IgnoredToTypes;
+};
+
+} // namespace clang::tidy::bugprone
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CASTTOSTRUCTCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 187aae2ec8c90..a13072123b9ef 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -112,6 +112,11 @@ Improvements to clang-tidy
 New checks
 ^^^^^^^^^^
 
+- New :doc:`bugprone-cast-to-struct
+  <clang-tidy/checks/bugprone/cast-to-struct>` check.
+
+  Finds casts from pointers to struct or scalar type to pointers to struct 
type.
+
 - New :doc:`bugprone-invalid-enum-default-initialization
   <clang-tidy/checks/bugprone/invalid-enum-default-initialization>` check.
 
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/cast-to-struct.rst 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/cast-to-struct.rst
new file mode 100644
index 0000000000000..79864935d3ea1
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/cast-to-struct.rst
@@ -0,0 +1,54 @@
+.. title:: clang-tidy - bugprone-cast-to-struct
+
+bugprone-cast-to-struct
+=======================
+
+Finds casts from pointers to struct or scalar type to pointers to struct type.
+
+Casts between pointers to different structs can be unsafe because it is 
possible
+to access uninitialized or undefined data after the cast. There may be issues
+with type compatibility or data alignment. Cast from a pointer to a scalar type
+(which points often to an array or memory block) to a `struct` type pointer can
+be unsafe for similar reasons. This check warns at casts from any non-`struct`
+type to a `struct` type. No warning is produced at cast from type `void *` 
(this
+is the usual way of allocating memory with `malloc`-like functions). It is
+possible to specify additional types to ignore by the check. In addition,
+`union` types are completely excluded from the check. The check does not take
+into account type compatibility or data layout, only the names of the types.
+
+.. code-block:: c
+
+   void test1(char *p) {
+     struct S1 *s;
+     s = (struct S1 *)p; // warn: 'char *' is converted to 'struct S1 *'
+   }
+
+   void test2(struct S1 *p) {
+     struct S2 *s;
+     s = (struct S2 *)p; // warn: 'struct S1 *' is converted to 'struct S2 *'
+   }
+
+   void test3(void) {
+     struct S1 *s;
+     s = (struct S1 *)calloc(1, sizeof(struct S1)); // no warning
+   }
+
+Options
+-------
+
+.. option:: IgnoredFromTypes
+
+   Semicolon-separated list of types for which the checker should not warn if
+   encountered at cast source. Can contain regular expressions. The `*`
+   character (for pointer type) is not needed in the type names.
+
+.. option:: IgnoredToTypes
+
+   Semicolon-separated list of types for which the checker should not warn if
+   encountered at cast destination. Can contain regular expressions. The `*`
+   character (for pointer type) is not needed in the type names.
+
+.. option:: IgnoredFunctions
+
+   List of function names from which the checker should produce no warnings. 
Can
+   contain regular expressions.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst 
b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index b6444eb3c9aec..5f8ae4a6eabb7 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -85,6 +85,7 @@ Clang-Tidy Checks
    :doc:`bugprone-bool-pointer-implicit-conversion 
<bugprone/bool-pointer-implicit-conversion>`, "Yes"
    :doc:`bugprone-branch-clone <bugprone/branch-clone>`,
    :doc:`bugprone-capturing-this-in-member-variable 
<bugprone/capturing-this-in-member-variable>`,
+   :doc:`bugprone-cast-to-struct <bugprone/cast-to-struct>`,
    :doc:`bugprone-casting-through-void <bugprone/casting-through-void>`,
    :doc:`bugprone-chained-comparison <bugprone/chained-comparison>`,
    :doc:`bugprone-compare-pointer-to-member-virtual-function 
<bugprone/compare-pointer-to-member-virtual-function>`,
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/cast-to-struct-ignore.c 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/cast-to-struct-ignore.c
new file mode 100644
index 0000000000000..1cc4744220f4a
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/cast-to-struct-ignore.c
@@ -0,0 +1,40 @@
+// RUN: %check_clang_tidy -check-suffixes=FUNC %s bugprone-cast-to-struct %t 
-- \
+// RUN:   -config="{CheckOptions: {bugprone-cast-to-struct.IgnoredFunctions: 
'ignored_f$'}}"
+// RUN: %check_clang_tidy -check-suffixes=FROM-TY %s bugprone-cast-to-struct 
%t -- \
+// RUN:   -config="{CheckOptions: {bugprone-cast-to-struct.IgnoredFromTypes: 
'int'}}"
+// RUN: %check_clang_tidy -check-suffixes=TO-TY %s bugprone-cast-to-struct %t 
-- \
+// RUN:   -config="{CheckOptions: {bugprone-cast-to-struct.IgnoredToTypes: 
'IgnoredType'}}"
+
+struct IgnoredType {
+  int a;
+};
+
+struct OtherType {
+  int a;
+  int b;
+};
+
+void ignored_f(char *p) {
+  struct OtherType *p1;
+  p1 = (struct OtherType *)p;
+  // CHECK-MESSAGES-FROM-TY: :[[@LINE-1]]:8: warning: casting a 'char *' 
pointer to a 'struct OtherType *' pointer and accessing a field can lead to 
memory access errors or data corruption
+  // CHECK-MESSAGES-TO-TY: :[[@LINE-2]]:8: warning: casting a 'char *' pointer 
to a 'struct OtherType *' pointer and accessing a field can lead to memory 
access errors or data corruption
+}
+
+void ignored_from_type(int *p) {
+  struct OtherType *p1;
+  p1 = (struct OtherType *)p;
+  // CHECK-MESSAGES-FUNC: :[[@LINE-1]]:8: warning: casting a 'int *' pointer 
to a 'struct OtherType *' pointer and accessing a field can lead to memory 
access errors or data corruption
+  // CHECK-MESSAGES-TO-TY: :[[@LINE-2]]:8: warning: casting a 'int *' pointer 
to a 'struct OtherType *' pointer and accessing a field can lead to memory 
access errors or data corruption
+}
+
+void ignored_to_type(char *p) {
+  struct IgnoredType *p1;
+  p1 = (struct IgnoredType *)p;
+  // CHECK-MESSAGES-FUNC: :[[@LINE-1]]:8: warning: casting a 'char *' pointer 
to a 'struct IgnoredType *' pointer and accessing a field can lead to memory 
access errors or data corruption
+  // CHECK-MESSAGES-FROM-TY: :[[@LINE-2]]:8: warning: casting a 'char *' 
pointer to a 'struct IgnoredType *' pointer and accessing a field can lead to 
memory access errors or data corruption
+}
+
+struct OtherType *test_void_is_always_ignored(void *p) {
+  return (struct OtherType *)p;
+}
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/cast-to-struct.c 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/cast-to-struct.c
new file mode 100644
index 0000000000000..cfabf69351f39
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/cast-to-struct.c
@@ -0,0 +1,66 @@
+// RUN: %check_clang_tidy %s bugprone-cast-to-struct %t
+
+struct S1 {
+  int a;
+};
+
+struct S2 {
+  char a;
+};
+
+union U1 {
+  int a;
+  char b;
+};
+
+union U2 {
+  struct S1 a;
+  char b;
+};
+
+typedef struct S1 TyS1;
+typedef struct S1 *TyPS1;
+
+typedef union U1 *TyPU1;
+
+typedef int int_t;
+typedef int * int_ptr_t;
+
+struct S1 *test_simple(char *p) {
+  return (struct S1 *)p;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: casting a 'char *' pointer to a 
'struct S1 *' pointer and accessing a field can lead to memory access errors or 
data corruption [bugprone-cast-to-struct]
+  struct S1 *s;
+  int i;
+  s = (struct S1 *)&i;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: casting a 'int *' pointer to a 
'struct S1 *' pointer and accessing a field can lead to memory access errors or 
data corruption [bugprone-cast-to-struct]
+}
+
+struct S1 *test_cast_from_void(void *p) {
+  return (struct S1 *)p;
+}
+
+struct S1 *test_cast_from_struct(struct S2 *p) {
+  return (struct S1 *)p;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: casting a 'struct S2 *' pointer 
to a 'struct S1 *' pointer and accessing a field can lead to memory access 
errors or data corruption [bugprone-cast-to-struct]
+}
+
+TyPS1 test_cast_from_similar(struct S1 *p) {
+  return (TyPS1)p;
+}
+
+void test_typedef(char *p1, int_t *p2, int_ptr_t p3) {
+  TyS1 *a = (TyS1 *)p1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: casting a 'char *' pointer to a 
'TyS1 *' (aka 'struct S1 *') pointer and accessing a field can lead to memory 
access errors or data corruption [bugprone-cast-to-struct]
+  TyPS1 b = (TyPS1)p1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: casting a 'char *' pointer to a 
'TyPS1' (aka 'struct S1 *') pointer and accessing a field can lead to memory 
access errors or data corruption [bugprone-cast-to-struct]
+  struct S1 *c = (struct S1 *)p2;
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: casting a 'int_t *' (aka 'int 
*') pointer to a 'struct S1 *' pointer and accessing a field can lead to memory 
access errors or data corruption [bugprone-cast-to-struct]
+  struct S1 *d = (struct S1 *)p3;
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: casting a 'int_ptr_t' (aka 'int 
*') pointer to a 'struct S1 *' pointer and accessing a field can lead to memory 
access errors or data corruption [bugprone-cast-to-struct]
+}
+
+void test_union(char *p1, union U1 *p2, TyPU1 p3) {
+  union U1 *a = (union U1 *)p1;
+  struct S1 *b = (struct S1 *)p2;
+  struct S1 *c = (struct S1 *)p3;
+}

From f2eb00df8326548801b019450ed36f3ff4d476c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.k...@ericsson.com>
Date: Fri, 15 Aug 2025 16:21:23 +0200
Subject: [PATCH 2/2] updated documentation, changed options

---
 .../clang-tidy/bugprone/CastToStructCheck.cpp | 58 +++++++++----------
 .../clang-tidy/bugprone/CastToStructCheck.h   |  4 +-
 .../checks/bugprone/cast-to-struct.rst        | 54 +++++++++--------
 .../checkers/bugprone/cast-to-struct-ignore.c | 51 +++++++---------
 4 files changed, 82 insertions(+), 85 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.cpp
index 374736d48d1c8..9915d32e1ddbd 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.cpp
@@ -17,42 +17,31 @@ namespace clang::tidy::bugprone {
 
 CastToStructCheck::CastToStructCheck(StringRef Name, ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
-      IgnoredFunctions(
-          utils::options::parseStringList(Options.get("IgnoredFunctions", 
""))),
-      IgnoredFromTypes(
-          utils::options::parseStringList(Options.get("IgnoredFromTypes", 
""))),
-      IgnoredToTypes(
-          utils::options::parseStringList(Options.get("IgnoredToTypes", ""))) 
{}
+      IgnoredCasts(
+          utils::options::parseStringList(Options.get("IgnoredCasts", ""))) {}
 
 void CastToStructCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
-  Options.store(Opts, "IgnoredFunctions",
-                utils::options::serializeStringList(IgnoredFunctions));
-  Options.store(Opts, "IgnoredFromTypes",
-                utils::options::serializeStringList(IgnoredFromTypes));
-  Options.store(Opts, "IgnoredToTypes",
-                utils::options::serializeStringList(IgnoredToTypes));
+  Options.store(Opts, "IgnoredCasts",
+                utils::options::serializeStringList(IgnoredCasts));
 }
 
 void CastToStructCheck::registerMatchers(MatchFinder *Finder) {
   auto FromPointee =
       qualType(hasUnqualifiedDesugaredType(type().bind("FromType")),
-               unless(qualType(matchers::matchesAnyListedTypeName(
-                   IgnoredFromTypes, false))))
+               unless(voidType()),
+               unless(hasDeclaration(recordDecl(isUnion()))))
           .bind("FromPointee");
   auto ToPointee =
-      qualType(hasUnqualifiedDesugaredType(recordType().bind("ToType")),
-               unless(qualType(
-                   matchers::matchesAnyListedTypeName(IgnoredToTypes, false))))
+      qualType(hasUnqualifiedDesugaredType(
+                   recordType(unless(hasDeclaration(recordDecl(isUnion()))))
+                       .bind("ToType")))
           .bind("ToPointee");
   auto FromPtrType = qualType(pointsTo(FromPointee)).bind("FromPtr");
   auto ToPtrType = qualType(pointsTo(ToPointee)).bind("ToPtr");
-  Finder->addMatcher(
-      cStyleCastExpr(hasSourceExpression(hasType(FromPtrType)),
-                     hasType(ToPtrType),
-                     unless(hasAncestor(functionDecl(
-                         matchers::matchesAnyListedName(IgnoredFunctions)))))
-          .bind("CastExpr"),
-      this);
+  Finder->addMatcher(cStyleCastExpr(hasSourceExpression(hasType(FromPtrType)),
+                                    hasType(ToPtrType))
+                         .bind("CastExpr"),
+                     this);
 }
 
 void CastToStructCheck::check(const MatchFinder::MatchResult &Result) {
@@ -65,13 +54,24 @@ void CastToStructCheck::check(const 
MatchFinder::MatchResult &Result) {
   const auto *const ToPointee = Result.Nodes.getNodeAs<QualType>("ToPointee");
   const auto *const FromType = Result.Nodes.getNodeAs<Type>("FromType");
   const auto *const ToType = Result.Nodes.getNodeAs<RecordType>("ToType");
-  if (!FromPointee || !ToPointee)
-    return;
-  if (FromType->isVoidType() || FromType->isUnionType() ||
-      ToType->isUnionType())
-    return;
+
   if (FromType == ToType)
     return;
+
+  const std::string FromName = FromPointee->getAsString();
+  const std::string ToName = ToPointee->getAsString();
+  llvm::Regex FromR;
+  llvm::Regex ToR;
+  for (auto [Idx, Str] : llvm::enumerate(IgnoredCasts)) {
+    if (Idx % 2 == 0) {
+      FromR = llvm::Regex(Str);
+    } else {
+      ToR = llvm::Regex(Str);
+      if (FromR.match(FromName) && ToR.match(ToName))
+        return;
+    }
+  }
+
   diag(FoundCastExpr->getExprLoc(),
        "casting a %0 pointer to a "
        "%1 pointer and accessing a field can lead to memory "
diff --git a/clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.h 
b/clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.h
index 9e6c868824d23..ec89fa8ab6dfc 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.h
@@ -29,9 +29,7 @@ class CastToStructCheck : public ClangTidyCheck {
   }
 
 private:
-  std::vector<llvm::StringRef> IgnoredFunctions;
-  std::vector<llvm::StringRef> IgnoredFromTypes;
-  std::vector<llvm::StringRef> IgnoredToTypes;
+  std::vector<llvm::StringRef> IgnoredCasts;
 };
 
 } // namespace clang::tidy::bugprone
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/cast-to-struct.rst 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/cast-to-struct.rst
index 79864935d3ea1..9b9afa43b6a96 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/cast-to-struct.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/cast-to-struct.rst
@@ -6,15 +6,15 @@ bugprone-cast-to-struct
 Finds casts from pointers to struct or scalar type to pointers to struct type.
 
 Casts between pointers to different structs can be unsafe because it is 
possible
-to access uninitialized or undefined data after the cast. There may be issues
-with type compatibility or data alignment. Cast from a pointer to a scalar type
-(which points often to an array or memory block) to a `struct` type pointer can
-be unsafe for similar reasons. This check warns at casts from any non-`struct`
-type to a `struct` type. No warning is produced at cast from type `void *` 
(this
-is the usual way of allocating memory with `malloc`-like functions). It is
-possible to specify additional types to ignore by the check. In addition,
-`union` types are completely excluded from the check. The check does not take
-into account type compatibility or data layout, only the names of the types.
+to access uninitialized or undefined data after the cast. Cast from a
+scalar-type pointer (which points often to an array or memory block) to a
+``struct`` type pointer can be unsafe for similar reasons. This check warns at
+pointer casts from any non-struct type to a struct type. No warning is produced
+at cast from type ``void *`` (this is the usual way of allocating memory with
+``malloc``-like functions). In addition, ``union`` types are excluded from the
+check. It is possible to specify additional types to ignore. The check does not
+take into account type compatibility or data layout, only the names of the
+types.
 
 .. code-block:: c
 
@@ -33,22 +33,28 @@ into account type compatibility or data layout, only the 
names of the types.
      s = (struct S1 *)calloc(1, sizeof(struct S1)); // no warning
    }
 
-Options
--------
-
-.. option:: IgnoredFromTypes
+Limitations
+-----------
 
-   Semicolon-separated list of types for which the checker should not warn if
-   encountered at cast source. Can contain regular expressions. The `*`
-   character (for pointer type) is not needed in the type names.
+The check does run only on `C` code.
 
-.. option:: IgnoredToTypes
+C-style casts are discouraged in `C++` and should be converted to more 
type-safe
+casts. The ``reinterpreted_cast`` is used for the most unsafe cases and
+indicates by itself a potentially dangerous operation. Additionally, 
inheritance
+and dynamic types would make such a check less useful.
 
-   Semicolon-separated list of types for which the checker should not warn if
-   encountered at cast destination. Can contain regular expressions. The `*`
-   character (for pointer type) is not needed in the type names.
-
-.. option:: IgnoredFunctions
+Options
+-------
 
-   List of function names from which the checker should produce no warnings. 
Can
-   contain regular expressions.
+.. option:: IgnoredCasts
+
+   Can contain a semicolon-separated list of type names that specify cast
+   types to ignore. The list should contain pairs of type names in a way that
+   the first type is the "from" type, the second is the "to" type in a cast
+   expression. The types in a pair and the pairs itself are separated by
+   ``;`` characters. For example ``char;Type1;char;Type2`` specifies that the
+   check does not produce warning for casts from ``char *`` to ``Type1 *`` and
+   casts from ``char *`` to ``Type2 *``. The list entries can be regular
+   expressions. The type name in the cast expression is matched without
+   resolution of type aliases like ``typedef``. Default value is empty list.
+   (Casts from ``void *`` are ignored always regardless of this list.)
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/cast-to-struct-ignore.c 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/cast-to-struct-ignore.c
index 1cc4744220f4a..e64fe177448d9 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/cast-to-struct-ignore.c
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/cast-to-struct-ignore.c
@@ -1,40 +1,33 @@
-// RUN: %check_clang_tidy -check-suffixes=FUNC %s bugprone-cast-to-struct %t 
-- \
-// RUN:   -config="{CheckOptions: {bugprone-cast-to-struct.IgnoredFunctions: 
'ignored_f$'}}"
-// RUN: %check_clang_tidy -check-suffixes=FROM-TY %s bugprone-cast-to-struct 
%t -- \
-// RUN:   -config="{CheckOptions: {bugprone-cast-to-struct.IgnoredFromTypes: 
'int'}}"
-// RUN: %check_clang_tidy -check-suffixes=TO-TY %s bugprone-cast-to-struct %t 
-- \
-// RUN:   -config="{CheckOptions: {bugprone-cast-to-struct.IgnoredToTypes: 
'IgnoredType'}}"
+// RUN: %check_clang_tidy %s bugprone-cast-to-struct %t -- \
+// RUN:   -config="{CheckOptions: {bugprone-cast-to-struct.IgnoredCasts: 
'char;S1;int;Other*'}}"
 
-struct IgnoredType {
+struct S1 {
   int a;
 };
 
-struct OtherType {
+struct S2 {
+  char a;
+};
+
+struct OtherS {
   int a;
   int b;
 };
 
-void ignored_f(char *p) {
-  struct OtherType *p1;
-  p1 = (struct OtherType *)p;
-  // CHECK-MESSAGES-FROM-TY: :[[@LINE-1]]:8: warning: casting a 'char *' 
pointer to a 'struct OtherType *' pointer and accessing a field can lead to 
memory access errors or data corruption
-  // CHECK-MESSAGES-TO-TY: :[[@LINE-2]]:8: warning: casting a 'char *' pointer 
to a 'struct OtherType *' pointer and accessing a field can lead to memory 
access errors or data corruption
-}
-
-void ignored_from_type(int *p) {
-  struct OtherType *p1;
-  p1 = (struct OtherType *)p;
-  // CHECK-MESSAGES-FUNC: :[[@LINE-1]]:8: warning: casting a 'int *' pointer 
to a 'struct OtherType *' pointer and accessing a field can lead to memory 
access errors or data corruption
-  // CHECK-MESSAGES-TO-TY: :[[@LINE-2]]:8: warning: casting a 'int *' pointer 
to a 'struct OtherType *' pointer and accessing a field can lead to memory 
access errors or data corruption
-}
-
-void ignored_to_type(char *p) {
-  struct IgnoredType *p1;
-  p1 = (struct IgnoredType *)p;
-  // CHECK-MESSAGES-FUNC: :[[@LINE-1]]:8: warning: casting a 'char *' pointer 
to a 'struct IgnoredType *' pointer and accessing a field can lead to memory 
access errors or data corruption
-  // CHECK-MESSAGES-FROM-TY: :[[@LINE-2]]:8: warning: casting a 'char *' 
pointer to a 'struct IgnoredType *' pointer and accessing a field can lead to 
memory access errors or data corruption
+void test1(char *p1, int *p2) {
+  struct S1 *s1;
+  s1 = (struct S1 *)p1;
+  struct S2 *s2;
+  s2 = (struct S2 *)p1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: casting a 'char *' pointer to a 
'struct S2 *'
+  s2 = (struct S2 *)p2;
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: casting a 'int *' pointer to a 
'struct S2 *'
+  struct OtherS *s3;
+  s3 = (struct OtherS *)p2;
+  s3 = (struct OtherS *)p1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: casting a 'char *' pointer to a 
'struct OtherS *'
 }
 
-struct OtherType *test_void_is_always_ignored(void *p) {
-  return (struct OtherType *)p;
+struct S2 *test_void_is_always_ignored(void *p) {
+  return (struct S2 *)p;
 }

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to