llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-tools-extra

Author: Donát Nagy (NagyDonat)

<details>
<summary>Changes</summary>

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`.

---
Full diff: https://github.com/llvm/llvm-project/pull/155237.diff


2 Files Affected:

- (modified) clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp 
(+2-2) 
- (modified) 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp (+30) 


``````````diff
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{};
+}
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/155237
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to