https://github.com/kodlan updated 
https://github.com/llvm/llvm-project/pull/220110

>From ab58d1f05df92410590043c4a686069180d9b6f4 Mon Sep 17 00:00:00 2001
From: Stanislav Bardyuk <[email protected]>
Date: Tue, 1 Sep 2026 17:50:54 +0000
Subject: [PATCH] [Clang] Fix crash classifying a dependent call to a
 non-callable value

Clang asserts in Type::castAs<FunctionType> (via
CallExpr::getCallReturnType) when a template argument contains a call
whose callee has already been substituted to a plain value while an
argument is still dependent, e.g.

  template <auto V> struct W {
    static constexpr auto value = V;
    template <class T> auto f(T) -> W<value(T::value)>;
  };
  template struct W<42>;

When W<42> is instantiated, the callee "value" becomes an int but
T::value is still dependent, so BuildCallExpr creates a dependent
CallExpr (the MayBeFunctionType guard from #139246 intentionally lets
DeclRefExpr callees through so the error is deferred to instantiation).
Checking the template argument against the auto NTTP then classifies
the expression, and getCallReturnType has no case for a type-dependent
call whose callee type is not a function, so it hits the castAs
assertion.

Handle it the same way the record-callee (#68078) and dependent-builtin
(#210524) cases already are: return DependentTy. The check goes after
the pointer-stripping branch so a callee of pointer-to-non-function type
(same crash, e.g. p(T::value) with const int *p) is covered too. The
invalid call is still diagnosed when the member actually gets
instantiated (as a substitution failure), and the accepted-and-deferred
behavior matches GCC.

Fixes #218323
---
 clang/docs/ReleaseNotes.md                   |  4 ++
 clang/lib/AST/Expr.cpp                       |  7 ++++
 clang/test/SemaTemplate/fun-template-def.cpp | 39 ++++++++++++++++++++
 3 files changed, 50 insertions(+)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index dd3dfdc5ad8d7..af9952c9d32e9 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -574,6 +574,10 @@ features cannot lower the translation-unit ABI level;
   in a token that was lexed and cached before the first occurrence was parsed.
   (#GH214128)
 
+- Fixed a crash when classifying a dependent call whose callee has already
+  been substituted to a value of non-callable type, such as a call to a
+  non-type template parameter member in a trailing return type. (#GH218323)
+
 #### Bug Fixes to AST Handling
 
 - Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 6ce0a29aa3bd7..ee4858e38fecd 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1656,6 +1656,13 @@ QualType CallExpr::getCallReturnType(const ASTContext 
&Ctx) const {
     return Ctx.DependentTy;
   }
 
+  // The callee may be a value of non-callable type (e.g. a plain int, or a
+  // pointer to one), while the call itself is dependent on its arguments;
+  // whether it is valid is checked when the enclosing template is
+  // instantiated.
+  if (isTypeDependent() && !CalleeType->isFunctionType())
+    return Ctx.DependentTy;
+
   const FunctionType *FnType = CalleeType->castAs<FunctionType>();
   return FnType->getReturnType();
 }
diff --git a/clang/test/SemaTemplate/fun-template-def.cpp 
b/clang/test/SemaTemplate/fun-template-def.cpp
index b0d0580d5ba80..7fb8205d77e24 100644
--- a/clang/test/SemaTemplate/fun-template-def.cpp
+++ b/clang/test/SemaTemplate/fun-template-def.cpp
@@ -121,6 +121,45 @@ template struct S<1>; // expected-note {{in instantiation}}
 
 }
 
+namespace GH218323 {
+template <auto V> struct W {
+  static constexpr auto value = V;
+  template <class T> auto f(T) -> W<value(T::value)>; // #gh218323-f
+};
+template struct W<42>; // ok, the call is dependent; diagnosed on use
+
+template <auto V> struct WPtr {
+  static constexpr int arr[1] = {V};
+  static constexpr const int *p = arr;
+  template <class T> auto f(T) -> WPtr<p(T::value)>;
+};
+template struct WPtr<42>; // ok, pointer-to-non-function callee
+
+struct HasValue { static constexpr int value = 1; };
+void use(W<42> w) {
+  w.f(HasValue{}); // expected-error {{no matching member function for call to 
'f'}}
+                   // expected-note@#gh218323-f {{candidate template ignored: 
substitution failure [with T = HasValue]: called object type 'int' is not a 
function or function pointer}}
+}
+
+template <auto V>
+struct ConstantWrapper {
+  static constexpr auto value = V;
+  template <class... Ts>
+  constexpr auto operator()(Ts... args) const -> 
ConstantWrapper<value(Ts::value...)> {
+    return {};
+  }
+};
+
+struct Plus {
+  template <class T, class U>
+  constexpr auto operator()(T&& t, U&& u) const -> 
decltype(static_cast<T&&>(t) + static_cast<U&&>(u)) {
+    return static_cast<T&&>(t) + static_cast<U&&>(u);
+  }
+};
+
+constexpr auto cwv = ConstantWrapper<Plus{}>{}(ConstantWrapper<42>{}, 
ConstantWrapper<17>{});
+static_assert(cwv.value == 59, "");
+}
 
 #endif
 #if __cplusplus >= 201702L

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

Reply via email to