[clang-tools-extra] [clang-tidy] Fix spurious errors from builtin macros in modernize-use-trailing-return-type (PR #184022)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Mar 7 05:47:56 PST 2026
https://github.com/vadikmironov updated https://github.com/llvm/llvm-project/pull/184022
>From a28a1fa5f963a1b35ff264b71169c6411c42b301 Mon Sep 17 00:00:00 2001
From: Vadim Mironov <vadik.mironov at gmail.com>
Date: Sun, 1 Mar 2026 18:15:07 +0000
Subject: [PATCH] [clang-tidy] Fix spurious errors from builtin macros in
modernize-use-trailing-return-type
`classifyTokensBeforeFunctionName()` raw-lexes tokens between a
function's begin location and its name. When it encounters a macro
identifier, it checks `!MI || MI->isFunctionLike()` to bail out for
function-like macros that cannot be safely classified.
Builtin macros like `__has_feature`, `__has_builtin`, `__has_extension`,
etc. are registered via `RegisterBuiltinMacro()` as object-like
(`isFunctionLike() == false`), but they expect function-like syntax
(parenthesized arguments) when expanded by the preprocessor. The
existing filter missed them, allowing them to reach `classifyToken()`
which enters `{Tok, EOF}` into the preprocessor token stream.
`PP.Lex()` then tries to expand the builtin, expects an opening
parenthesis, finds EOF, and emits a spurious diagnostic:
error: missing '(' after '__has_feature'
This was reported as issue #168360, which was closed because LLVM 22+
happens to match fewer system-header functions (reducing the chance of
hitting the buggy path). The underlying defect remained, and any
function whose return-type tokens include a builtin macro can still
trigger it.
The fix adds `MI->isBuiltinMacro()` to the existing bail-out condition.
Fixes #168360
Co-Authored-By: Claude Opus 4.6 <noreply at anthropic.com>
---
.../modernize/UseTrailingReturnTypeCheck.cpp | 3 +--
clang-tools-extra/docs/ReleaseNotes.rst | 5 +++++
.../checkers/modernize/use-trailing-return-type.cpp | 11 +++++++++++
3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp
index a87fb6cff937a..32aec60da58bb 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp
@@ -269,8 +269,7 @@ classifyTokensBeforeFunctionName(const FunctionDecl &F, const ASTContext &Ctx,
if (Info.hasMacroDefinition()) {
const MacroInfo *MI = PP->getMacroInfo(&Info);
- if (!MI || MI->isFunctionLike()) {
- // Cannot handle function style macros.
+ if (!MI || MI->isFunctionLike() || MI->isBuiltinMacro()) {
return std::nullopt;
}
}
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index b0b4cd646c3bd..8a55b55949e54 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -265,6 +265,11 @@ Changes in existing checks
<clang-tidy/checks/modernize/use-std-format>` check by fixing a crash
when an argument is part of a macro expansion.
+- Improved :doc:`modernize-use-trailing-return-type
+ <clang-tidy/checks/modernize/use-trailing-return-type>` check by fixing
+ spurious ``missing '(' after '__has_feature'`` errors caused by builtin
+ macros appearing in the return type of a function.
+
- Improved :doc:`modernize-use-using
<clang-tidy/checks/modernize/use-using>` check by avoiding the generation
of invalid code for function types with redundant parentheses.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-trailing-return-type.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-trailing-return-type.cpp
index 6c919409467d6..3b59860e2f7c8 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-trailing-return-type.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-trailing-return-type.cpp
@@ -487,6 +487,17 @@ decltype(COMMAND_LINE_INT{}) h21();
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
// CHECK-FIXES: auto h21() -> decltype(COMMAND_LINE_INT{});
+// Builtin macros like __has_feature are registered as object-like macros but
+// require function-like syntax when expanded. Ensure the check does not cause
+// spurious "missing '(' after '__has_feature'" errors when they appear in the
+// raw lex span of a function return type.
+const decltype(__has_feature(cxx_constexpr)) h22();
+// CHECK-MESSAGES: :[[@LINE-1]]:46: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
+// CHECK-FIXES: const decltype(__has_feature(cxx_constexpr)) h22();
+const decltype(__has_builtin(__builtin_expect)) h23();
+// CHECK-MESSAGES: :[[@LINE-1]]:49: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
+// CHECK-FIXES: const decltype(__has_builtin(__builtin_expect)) h23();
+
//
// Name collisions
//
More information about the cfe-commits
mailing list