https://github.com/yxsamliu updated 
https://github.com/llvm/llvm-project/pull/208062

>From 23911b20d5546495f04d1504bcdb7f0a942a3efb Mon Sep 17 00:00:00 2001
From: "Yaxun (Sam) Liu" <[email protected]>
Date: Tue, 7 Jul 2026 13:58:36 -0400
Subject: [PATCH] [Clang] Treat address-of template substitution as SFINAE

Taking the address of a function template specialization can instantiate
its trailing return type as part of a SFINAE probe:

    struct X {};
    template <class T> void f(T) = delete;
    template <class T> auto probe(T t) -> decltype(f(t), void());
    template <class T, class = decltype(&probe<T>)> int test(int);
    template <class T> char test(...);
    static_assert(sizeof(test<X>(0)) == sizeof(char));

Here, substituting the return type of probe<X> selects the deleted f<X>.
The deleted call is in the immediate context of substitution, so it should
remove test(int) from overload resolution. GCC accepts this example. Clang
instead kept deduction as successful and later replayed the stored
diagnostic as a hard error.

The call-deduction path already checks the SFINAE trap after finishing
template argument deduction. Do the same for the address-of path, so the
stored diagnostic is not replayed after deduction succeeds.

Fixes: LCOMPILER-2423
---
 clang/docs/ReleaseNotes.md                    |  4 ++
 clang/lib/Sema/SemaTemplateDeduction.cpp      |  5 +++
 .../test/SemaTemplate/overload-candidates.cpp | 43 +++++++++++++++++++
 3 files changed, 52 insertions(+)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 0a4bf068c8da4..701956da878cd 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -814,6 +814,10 @@ latest release, please see the [Clang Web 
Site](https://clang.llvm.org) or the
 
 - Fixed a preprocessor assertion failure triggered when parsing an invalid 
template-id starting with `::template operator`. (#GH186582)
 - Fixed a crash when a function template is defined as a non-template friend 
with a global scope qualifier. (#GH185341)
+- Fixed valid C++ code that uses an address-of-function-template expression,
+  such as `decltype(&T::func<Args...>)`, in SFINAE checks when substituting the
+  function template's trailing return type fails, such as when the return type
+  contains a `decltype` probe that calls a deleted function.
 - Clang now rejects constant template parameters with block pointer types, 
since these are not implemented anyway and would lead to crashes. (#GH189247)
 - Fixed a crash on error recovery when dealing with invalid templates. 
(#GH183075)
 - Fixed a crash when instantiating `requires` expressions involving 
substitution failures in C++ concepts. (#GH176402)
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index f57f60eb527ae..654dd09e5d2dc 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -4821,6 +4821,11 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
         /*OriginalCallArgs=*/nullptr, /*PartialOverloading=*/false,
         /*PartialOrdering=*/true, IsAddressOfFunction);
   });
+  if (Trap.hasErrorOccurred()) {
+    if (Specialization)
+      Specialization->setInvalidDecl(true);
+    return TemplateDeductionResult::SubstitutionFailure;
+  }
   if (Result != TemplateDeductionResult::Success)
     return Result;
 
diff --git a/clang/test/SemaTemplate/overload-candidates.cpp 
b/clang/test/SemaTemplate/overload-candidates.cpp
index 3a5bedca938bd..702cdb450de15 100644
--- a/clang/test/SemaTemplate/overload-candidates.cpp
+++ b/clang/test/SemaTemplate/overload-candidates.cpp
@@ -164,3 +164,46 @@ namespace PR15673 {
   void rangesv3(); // expected-note{{candidate template ignored: requirement 
'PR15673::some_trait<int>::value' was not satisfied [with T = int, x = 42]}}
   void test_rangesv3() { rangesv3<int>(); } // expected-error{{no matching 
function for call to 'rangesv3'}}
 }
+
+#if __cplusplus >= 201103L
+namespace AddressOfTemplateSFINAE {
+template <class...> struct tag {};
+
+struct Foo {};
+
+template <class T> struct UniqueIf {
+  using Single = int;
+};
+template <class T, unsigned N> struct UniqueIf<T[N]> {
+  using Bounded = int;
+};
+
+template <class T> typename UniqueIf<T>::Single make_unique() { return {}; }
+template <class T, class... Args>
+typename UniqueIf<T>::Bounded make_unique(Args &&...) = delete;
+
+struct Detector {
+  using Self = Detector;
+
+  template <class, class T, class... Args>
+  static auto well_formed(Args &&...args)
+      -> decltype(void(), make_unique<T>(static_cast<Args &&>(args)...),
+                  void()) {}
+
+  template <class... Args, class = decltype(&Self::well_formed<Args...>)>
+  static constexpr bool test(tag<Args...> *, int) {
+    return true;
+  }
+
+  static constexpr bool test(void *, long) { return false; }
+};
+
+template <class T, class... Args> struct has_make_unique {
+  static constexpr bool value =
+      Detector::test(static_cast<tag<void, T, Args...> *>(nullptr), 0);
+};
+
+static_assert(has_make_unique<int>::value, "");
+static_assert(!has_make_unique<Foo[2], int, int>::value, "");
+} // namespace AddressOfTemplateSFINAE
+#endif

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

Reply via email to