https://github.com/NagyDonat created https://github.com/llvm/llvm-project/pull/155237
This commit ensures that the modernize-use-constraints check ignores templates that happen to be named `enable_if` or `enable_if_t` if they are not declared in the namespace `std`. This patch motivated by a crash observed during the analysis of the open source library https://github.com/Neargye/magic_enum/ which declares a template `detail::enable_if_t` with semantics that significantly differ from the standard one. (I was unable to reproduce that crash with the standard `enable_if_t`.) However, there are other projects that use non-standard `enable_if`: even `boost` declares a `boost::enable_if` which excepts different parameters than `std::enable_if`. From 414468ef4dc2a5e3e372079418634b55a33dc7dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Mon, 25 Aug 2025 13:48:51 +0200 Subject: [PATCH] [clang-tidy] Limit modernize-use-constraints to standard enable_if This commit ensures that the modernize-use-constraints check ignores templates that happen to be named `enable_if` or `enable_if_t` if they are not declared in the namespace `std`. This patch motivated by a crash observed during the analysis of the open source library https://github.com/Neargye/magic_enum/ which declares a template `detail::enable_if_t` with semantics that significantly differ from the standard one. (I was unable to reproduce that crash with the standard `enable_if_t`.) However, there are other projects that use non-standard `enable_if`: even `boost` declares a `boost::enable_if` which excepts different parameters than `std::enable_if`. --- .../modernize/UseConstraintsCheck.cpp | 4 +-- .../checkers/modernize/use-constraints.cpp | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp index 07274d0376207..1818e30971c21 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp @@ -77,7 +77,7 @@ matchEnableIfSpecializationImplTypename(TypeLoc TheType) { const TemplateDecl *TD = Specialization->getTemplateName().getAsTemplateDecl(); - if (!TD || TD->getName() != "enable_if") + if (!TD || TD->getName() != "enable_if" || !TD->isInStdNamespace()) return std::nullopt; int NumArgs = SpecializationLoc.getNumArgs(); @@ -101,7 +101,7 @@ matchEnableIfSpecializationImplTrait(TypeLoc TheType) { const TemplateDecl *TD = Specialization->getTemplateName().getAsTemplateDecl(); - if (!TD || TD->getName() != "enable_if_t") + if (!TD || TD->getName() != "enable_if_t" || !TD->isInStdNamespace()) return std::nullopt; if (!Specialization->isTypeAlias()) diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp index 3bcd5cd74024e..8289efe338e3f 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp @@ -756,3 +756,33 @@ abs(const number<T, ExpressionTemplates> &v) { } } + +// NOLINTBEGIN +namespace custom { +template <bool B, class T = void> struct enable_if { }; + +template <class T> struct enable_if<true, T> { typedef T type; }; + +template <bool B, class T = void> +using enable_if_t = typename enable_if<B, T>::type; + +} // namespace custom +// NOLINTEND + +namespace use_custom { +// We cannot assume anything about the behavior of templates that happen to be +// named `enable_if` or `enable_if_t` if they are not declared in the namespace +// `std`. (E.g. the first template parameter of `boost::enable_if` is a class +// and not a boolean and `boost::enable_if<Cond, T>` is equivalent to +// `std::enable_if<Cond::value, T>`.) + +template <typename T> +typename custom::enable_if<T::some_value, Obj>::type custom_basic() { + return Obj{}; +} + +template <typename T> +custom::enable_if_t<T::some_value, Obj> custom_basic_t() { + return Obj{}; +} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits