https://github.com/akash-manna-sky created 
https://github.com/llvm/llvm-project/pull/221723

Fixes #189146

A call to a class object that goes through a conversion function to a function 
pointer ("surrogate call") asserted when that conversion function had been 
brought into the class with a using-declaration, e.g. `using M::operator 
auto;`. The surrogate loop in `BuildCallToObjectOfClassType` unwraps the 
`UsingShadowDecl` to get the conversion function but records the shadow as the 
candidate's `FoundDecl`, so the two are not the same pointer and the assertion 
fires. It wasn't only the assertion, though: the line before it passed 
`FoundDecl` to `DiagnoseUseOfDecl`, which skips all of its function checks on a 
shadow decl, and surrogates never go through `OR_Deleted` since they carry no 
`Function`. So with the assertion relaxed, a deleted conversion function 
reached through a using-declaration would have compiled without complaint.

The surrogate branch now diagnoses use of the conversion function itself rather 
than the found declaration, which is what `BuildCXXCastArgument` already does 
for the ordinary user-defined conversion path, and the assertion compares 
against the underlying declaration. Access checking keeps using `FoundDecl`, 
since the using-declaration's access is the one that matters. For conversion 
functions declared directly in the class the two pointers are identical, so 
nothing changes there.


>From 4302e1d4cd05b1aa8822fb7b712816cbb97e659c Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Mon, 7 Sep 2026 18:34:24 +0530
Subject: [PATCH] [clang] Fix surrogate call through a using-declared
 conversion function

Fixes #189146

When a call to a class object is resolved through a conversion function
to a function pointer that was brought into the class by a
using-declaration, the candidate's FoundDecl is the UsingShadowDecl
while the conversion function itself is the shadow's target. The
surrogate branch of BuildCallToObjectOfClassType asserted the two were
pointer-identical and passed FoundDecl to DiagnoseUseOfDecl, which does
nothing useful for a shadow decl, so a deleted conversion function
reached this way was never diagnosed.

Diagnose use of the conversion function itself, matching
BuildCXXCastArgument, and have the assertion compare against the
underlying declaration.
---
 clang/docs/ReleaseNotes.md                 |  5 +++
 clang/lib/Sema/SemaOverload.cpp            |  7 ++--
 clang/test/SemaCXX/conversion-function.cpp | 38 ++++++++++++++++++++++
 3 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index a49971adef86f..b37a16248ab0a 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -646,6 +646,11 @@ features cannot lower the translation-unit ABI level;
 - Fixed a crash when a coroutine keyword appeared inside a mem-initializer on a
   function that is not a constructor. (#GH194298)
 
+- Fixed an assertion when a call to a class object was resolved through a
+  conversion function to a function pointer that was introduced into the class
+  by a using-declaration (e.g. `using Base::operator auto;`). Such a conversion
+  function is now also diagnosed if it is deleted. (#GH189146)
+
 #### Bug Fixes to AST Handling
 
 - Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 106ddb90ed9dc..6e42af3956fe3 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -16812,12 +16812,13 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr 
*Obj,
       = cast<CXXConversionDecl>(
                          Best->Conversions[0].UserDefined.ConversionFunction);
 
+    // FoundDecl may be a UsingShadowDecl naming the conversion function.
+    assert(Conv == Best->FoundDecl.getDecl()->getUnderlyingDecl() &&
+           "Found Decl & conversion-to-functionptr should be same, right?!");
     CheckMemberOperatorAccess(LParenLoc, Object.get(), nullptr,
                               Best->FoundDecl);
-    if (DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc))
+    if (DiagnoseUseOfDecl(Conv, LParenLoc))
       return ExprError();
-    assert(Conv == Best->FoundDecl.getDecl() &&
-             "Found Decl & conversion-to-functionptr should be same, right?!");
     // We selected one of the surrogate functions that converts the
     // object parameter to a function pointer. Perform the conversion
     // on the object argument, then let BuildCallExpr finish the job.
diff --git a/clang/test/SemaCXX/conversion-function.cpp 
b/clang/test/SemaCXX/conversion-function.cpp
index e00553fbb20a3..1a09a527b750c 100644
--- a/clang/test/SemaCXX/conversion-function.cpp
+++ b/clang/test/SemaCXX/conversion-function.cpp
@@ -519,3 +519,41 @@ struct S {
   **operator char(); // expected-error {{cannot specify any part of a return 
type in the declaration of a conversion function; put the complete type after 
'operator'}}
 };
 }
+
+#if __cplusplus >= 201402L
+namespace GH189146 {
+  struct M {
+    template <class T> static constexpr int static_foo(T) { return 5; }
+    template <class T> operator T() { return T{}; }
+    constexpr operator auto() { return &static_foo<int>; }
+  };
+
+  struct N : M {
+    using M::operator auto;
+  };
+
+  template <class T> constexpr int test() {
+    return T{}(3);
+  }
+  static_assert(test<M>() == 5, "");
+  static_assert(test<N>() == 5, "");
+
+  using FP = int (*)(int);
+  constexpr int bar(int) { return 7; }
+  struct P {
+    constexpr operator FP() const { return &bar; }
+  };
+  struct Q : P {
+    using P::operator FP;
+  };
+  static_assert(Q{}(0) == 7, "");
+
+  struct R {
+    operator FP() const = delete; // expected-note {{has been explicitly 
marked deleted here}}
+  };
+  struct S : R {
+    using R::operator FP;
+  };
+  int s = S{}(0); // expected-error {{attempt to use a deleted function}}
+}
+#endif

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

Reply via email to