[clang-tools-extra] [clang-tidy] Portability Avoid Unprototyped Functions Check (PR #161023)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Sep 27 14:17:50 PDT 2025
https://github.com/isuckatcs updated https://github.com/llvm/llvm-project/pull/161023
>From 51cf252c590d15c7be2ea5a25e7e86ea5e6772c8 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 27 Sep 2025 22:32:15 +0200
Subject: [PATCH] [clang-tidy] Portability Avoid Unprototyped Functions Check
---
.../AvoidUnprototypedFunctionsCheck.cpp | 58 +++++++++++++++
.../AvoidUnprototypedFunctionsCheck.h | 33 +++++++++
.../clang-tidy/portability/CMakeLists.txt | 1 +
.../portability/PortabilityTidyModule.cpp | 3 +
clang-tools-extra/docs/ReleaseNotes.rst | 5 ++
.../docs/clang-tidy/checks/list.rst | 1 +
.../avoid-unprototyped-functions.rst | 73 +++++++++++++++++++
.../avoid-unprototyped-functions.c | 32 ++++++++
8 files changed, 206 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/portability/avoid-unprototyped-functions.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/portability/avoid-unprototyped-functions.c
diff --git a/clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.cpp
new file mode 100644
index 0000000000000..032986471e3e1
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.cpp
@@ -0,0 +1,58 @@
+//===--- AvoidUnprototypedFunctionsCheck.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 "AvoidUnprototypedFunctionsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::portability {
+
+void AvoidUnprototypedFunctionsCheck::registerMatchers(MatchFinder *Finder) {
+ auto FunctionTypeMatcher =
+ forEachDescendant(functionType(unless(functionProtoType())));
+ Finder->addMatcher(declaratorDecl(FunctionTypeMatcher).bind("declaratorDecl"),
+ this);
+ Finder->addMatcher(typedefDecl(FunctionTypeMatcher).bind("typedefDecl"),
+ this);
+}
+
+void AvoidUnprototypedFunctionsCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ if (const auto *MatchedTypedefDecl =
+ Result.Nodes.getNodeAs<TypedefDecl>("typedefDecl")) {
+ diag(MatchedTypedefDecl->getLocation(),
+ "avoid unprototyped functions in typedef; explicitly add a 'void' "
+ "parameter if the function takes no arguments");
+ return;
+ }
+
+ const auto *MatchedDeclaratorDecl =
+ Result.Nodes.getNodeAs<Decl>("declaratorDecl");
+ if (!MatchedDeclaratorDecl) {
+ return;
+ }
+
+ if (const auto *MatchedFunctionDecl =
+ llvm::dyn_cast<FunctionDecl>(MatchedDeclaratorDecl)) {
+ if (MatchedFunctionDecl->isMain() ||
+ MatchedFunctionDecl->hasWrittenPrototype())
+ return;
+
+ diag(MatchedFunctionDecl->getLocation(),
+ "avoid unprototyped function declarations; explicitly spell out a "
+ "single 'void' parameter if the function takes no argument");
+ return;
+ }
+
+ diag(MatchedDeclaratorDecl->getLocation(),
+ "avoid unprototyped functions in type specifiers; explicitly add a "
+ "'void' parameter if the function takes no arguments");
+}
+
+} // namespace clang::tidy::portability
diff --git a/clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.h
new file mode 100644
index 0000000000000..fb89dc6526a24
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.h
@@ -0,0 +1,33 @@
+//===--- AvoidUnprototypedFunctionsCheck.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_PORTABILITY_AVOIDUNPROTOTYPEDFUNCTIONSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDUNPROTOTYPEDFUNCTIONSCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::portability {
+
+/// Checks if unprototyped function types are used in the source code.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/portability/avoid-unprototyped-functions.html
+class AvoidUnprototypedFunctionsCheck : public ClangTidyCheck {
+public:
+ AvoidUnprototypedFunctionsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ 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.CPlusPlus;
+ }
+};
+
+} // namespace clang::tidy::portability
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDUNPROTOTYPEDFUNCTIONSCHECK_H
diff --git a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt
index 73d74a550afc0..7140469ca1515 100644
--- a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangTidyPortabilityModule STATIC
AvoidPragmaOnceCheck.cpp
+ AvoidUnprototypedFunctionsCheck.cpp
PortabilityTidyModule.cpp
RestrictSystemIncludesCheck.cpp
SIMDIntrinsicsCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp
index e73e95455d3a5..ee0c64712bacd 100644
--- a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp
@@ -10,6 +10,7 @@
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
#include "AvoidPragmaOnceCheck.h"
+#include "AvoidUnprototypedFunctionsCheck.h"
#include "RestrictSystemIncludesCheck.h"
#include "SIMDIntrinsicsCheck.h"
#include "StdAllocatorConstCheck.h"
@@ -23,6 +24,8 @@ class PortabilityModule : public ClangTidyModule {
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
CheckFactories.registerCheck<AvoidPragmaOnceCheck>(
"portability-avoid-pragma-once");
+ CheckFactories.registerCheck<AvoidUnprototypedFunctionsCheck>(
+ "portability-avoid-unprototyped-functions");
CheckFactories.registerCheck<RestrictSystemIncludesCheck>(
"portability-restrict-system-includes");
CheckFactories.registerCheck<SIMDIntrinsicsCheck>(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 9257dc6b98ba2..9997bb0ac60a7 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -208,6 +208,11 @@ New checks
Detect redundant parentheses.
+- New :doc:`portability-avoid-unprototyped-functions
+ <clang-tidy/checks/portability/avoid-unprototyped-functions>` check.
+
+ Checks if unprototyped function types are used in the source code.
+
New check aliases
^^^^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index f94696d4ef9c7..57c4321877e9d 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -362,6 +362,7 @@ Clang-Tidy Checks
:doc:`performance-unnecessary-copy-initialization <performance/unnecessary-copy-initialization>`, "Yes"
:doc:`performance-unnecessary-value-param <performance/unnecessary-value-param>`, "Yes"
:doc:`portability-avoid-pragma-once <portability/avoid-pragma-once>`,
+ :doc:`portability-avoid-unprototyped-functions <portability/avoid-unprototyped-functions>`,
:doc:`portability-restrict-system-includes <portability/restrict-system-includes>`, "Yes"
:doc:`portability-simd-intrinsics <portability/simd-intrinsics>`,
:doc:`portability-std-allocator-const <portability/std-allocator-const>`,
diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-unprototyped-functions.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-unprototyped-functions.rst
new file mode 100644
index 0000000000000..3d7ed212b61d9
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-unprototyped-functions.rst
@@ -0,0 +1,73 @@
+.. title:: clang-tidy - portability-avoid-unprototyped-functions
+
+portability-avoid-unprototyped-functions
+========================================
+
+Checks if unprototyped function types are used in the source code.
+
+For example:
+
+.. code-block:: c
+
+ void foo(); // Bad: unprototyped function declaration
+ void foo(void); // Good: a function declaration that takes no parameters
+
+ void (*ptr)(); // Bad: pointer to an unprototyped function
+ void (*ptr)(void); // Good: pointer to a function that takes no parameters
+
+Before C23 ``void foo()`` means a function that takes any number of parameters, so the following snippet is valid.
+
+.. code-block:: c
+
+ // -std=c17
+ void foo();
+
+ int main() {
+ foo(1, 2, 3);
+
+ return 0;
+ }
+
+Starting from C23 however, ``void foo()`` means a function that takes no parameters, so the same snippet is invalid.
+
+.. code-block:: c
+
+ // -std=c23
+ void foo();
+
+ int main() {
+ foo(1, 2, 3);
+ // ^ error: too many arguments to function call, expected 0, have 3
+
+ return 0;
+ }
+
+Similarly a pointer to an unprototyped function binds to any function before C23, so the following snippet is considered valid.
+
+.. code-block:: c
+
+ // -std=c17
+ void foo(int x, int y);
+
+ int main() {
+ void (*ptr)() = &foo;
+
+ return 0;
+ }
+
+From C23 however, the smae pointer will only bind to functions that take no parameters.
+
+.. code-block:: c
+
+ // -std=c23
+ void foo(int x, int y);
+
+ int main() {
+ void (*ptr)() = &foo;
+ // ^ error: incompatible function pointer types initializing 'void (*)(void)' with an expression of type 'void (*)(int, int)'
+
+ return 0;
+ }
+
+Some codebases might explicitly take advantage of the pre-C23 behavior, but these codebases should also be aware that
+their solution might not be fully portable between compilers.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-unprototyped-functions.c b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-unprototyped-functions.c
new file mode 100644
index 0000000000000..0efc029f5c63f
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-unprototyped-functions.c
@@ -0,0 +1,32 @@
+// RUN: %check_clang_tidy %s portability-avoid-unprototyped-functions %t
+struct S {
+ int (*UnprototypedFunctionPtrField)();
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: avoid unprototyped functions in type specifiers; explicitly add a 'void' parameter if the function takes no arguments
+};
+
+void unprototypedFunction();
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid unprototyped function declarations; explicitly spell out a single 'void' parameter if the function takes no argument
+
+void unprototypedParamter(int (*UnprototypedFunctionPtrParameter)());
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: avoid unprototyped functions in type specifiers; explicitly add a 'void' parameter if the function takes no arguments
+
+void unprototypedVariable() {
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid unprototyped function declarations; explicitly spell out a single 'void' parameter if the function takes no argument
+
+ int (*UnprototypedFunctionPtrVariable)();
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: avoid unprototyped functions in type specifiers; explicitly add a 'void' parameter if the function takes no arguments
+}
+
+typedef int (*UnprototypedFunctionPtrArray[13])();
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: avoid unprototyped functions in typedef; explicitly add a 'void' parameter if the function takes no arguments
+
+void unprototypedTypeAliasParameter(UnprototypedFunctionPtrArray);
+
+#define ANYARG
+
+void unprototypedMacroParameter(ANYARG);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid unprototyped function declarations; explicitly spell out a single 'void' parameter if the function takes no argument
+
+void functionWithNoArguments(void);
+
+int main();
More information about the cfe-commits
mailing list