https://github.com/kodlan updated https://github.com/llvm/llvm-project/pull/220110
>From 91dfee044494a6eb6996ba708f8fbec457112794 Mon Sep 17 00:00:00 2001 From: Stanislav Bardyuk <[email protected]> Date: Tue, 1 Sep 2026 17:50:54 +0000 Subject: [PATCH 1/4] [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 | 3 ++ clang/test/SemaTemplate/fun-template-def.cpp | 39 ++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index bf295981710ac..32434c258b5f3 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -614,6 +614,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..9ec62537f29f0 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1656,6 +1656,9 @@ QualType CallExpr::getCallReturnType(const ASTContext &Ctx) const { return Ctx.DependentTy; } + 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..7156a8c1b6663 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>; + +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>; + +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 >From 903bafa9cdb8d7a9b4b81585af0bdbcc8c9cf1d2 Mon Sep 17 00:00:00 2001 From: Stanislav Bardyuk <[email protected]> Date: Wed, 2 Sep 2026 20:50:41 +0200 Subject: [PATCH 2/4] Apply suggestion from @TPPPP72 Co-authored-by: Shengxin Pei <[email protected]> --- clang/docs/ReleaseNotes.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 32434c258b5f3..9acab99703883 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -615,8 +615,7 @@ features cannot lower the translation-unit ABI level; (#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) + been substituted to a value of non-callable type. (#GH218323) #### Bug Fixes to AST Handling >From 2377ccbf88a5e3b68138815b33b8dbf67ffc3d20 Mon Sep 17 00:00:00 2001 From: Stanislav Bardyuk <[email protected]> Date: Thu, 3 Sep 2026 11:37:36 +0000 Subject: [PATCH 3/4] [Clang] Add alias-argument test cases for GH218323 --- clang/test/SemaTemplate/fun-template-def.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clang/test/SemaTemplate/fun-template-def.cpp b/clang/test/SemaTemplate/fun-template-def.cpp index 7156a8c1b6663..0940c14360d6d 100644 --- a/clang/test/SemaTemplate/fun-template-def.cpp +++ b/clang/test/SemaTemplate/fun-template-def.cpp @@ -125,6 +125,8 @@ 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 <class T> auto g(T) -> W<int(T::type)>; // #gh218323-g + template <class T> auto h(T) -> W<value(T::type)>; // #gh218323-h }; template struct W<42>; @@ -136,9 +138,14 @@ template <auto V> struct WPtr { template struct WPtr<42>; struct HasValue { static constexpr int value = 1; }; +struct HasAlias { using type = int; }; 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}} + w.g(HasAlias{}); // expected-error {{no matching member function for call to 'g'}} + // expected-note@#gh218323-g {{candidate template ignored: substitution failure [with T = HasAlias]: missing 'typename' prior to dependent type name 'GH218323::HasAlias::type'}} + w.h(HasAlias{}); // expected-error {{no matching member function for call to 'h'}} + // expected-note@#gh218323-h {{candidate template ignored: substitution failure [with T = HasAlias]: missing 'typename' prior to dependent type name 'GH218323::HasAlias::type'}} } template <auto V> >From 6d8cebc4c5470d5e87c14df5ca3c74ed9eebc903 Mon Sep 17 00:00:00 2001 From: Stanislav Bardyuk <[email protected]> Date: Thu, 3 Sep 2026 13:00:07 +0000 Subject: [PATCH 4/4] [Clang] Test typename T::type forms for GH218323 and drop the end-to-end case --- clang/test/SemaTemplate/fun-template-def.cpp | 25 +++++++------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/clang/test/SemaTemplate/fun-template-def.cpp b/clang/test/SemaTemplate/fun-template-def.cpp index 0940c14360d6d..7aed80266ff97 100644 --- a/clang/test/SemaTemplate/fun-template-def.cpp +++ b/clang/test/SemaTemplate/fun-template-def.cpp @@ -127,6 +127,7 @@ template <auto V> struct W { template <class T> auto f(T) -> W<value(T::value)>; // #gh218323-f template <class T> auto g(T) -> W<int(T::type)>; // #gh218323-g template <class T> auto h(T) -> W<value(T::type)>; // #gh218323-h + template <class... Ts> auto p(Ts...) -> W<value(Ts::value...)>; }; template struct W<42>; @@ -148,24 +149,16 @@ void use(W<42> w) { // expected-note@#gh218323-h {{candidate template ignored: substitution failure [with T = HasAlias]: missing 'typename' prior to dependent type name 'GH218323::HasAlias::type'}} } -template <auto V> -struct ConstantWrapper { +template <auto V> struct WTypename { // #gh218323-WTypename 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); - } + template <class T> auto f(T) -> WTypename<int(typename T::type)>; // expected-error {{template argument for non-type template parameter is treated as function type 'int (typename T::type)'}} + // expected-note@#gh218323-WTypename {{template parameter is declared here}} + template <class T> auto g(T) -> WTypename<typename T::type(value)>; }; - -constexpr auto cwv = ConstantWrapper<Plus{}>{}(ConstantWrapper<42>{}, ConstantWrapper<17>{}); -static_assert(cwv.value == 59, ""); +template struct WTypename<42>; +void use_typename(WTypename<42> w) { + w.g(HasAlias{}); +} } #endif _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
