diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index a8f5f40d8fef7..cd452179a6555 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -680,6 +680,7 @@ Bug Fixes to C++ Support - Improved parser recovery of invalid requirement expressions. In turn, this fixes crashes from follow-on processing of the invalid requirement. (#GH138820) - Fixed the handling of pack indexing types in the constraints of a member function redeclaration. (#GH138255) +- Fixed a crash when forming an invalid function type in a dependent context. (#GH138657) (#GH115725) (#GH68852) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index deb8d2edfc5c9..eed791c7c9bde 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6550,6 +6550,23 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, return Call; } +// Any type that could be used to form a callable expression +static bool MayBeFunctionType(const ASTContext &Context, const Expr *E) { + QualType T = E->getType(); + if (T->isDependentType()) + return true; + + if (T == Context.BoundMemberTy || T == Context.UnknownAnyTy || + T == Context.BuiltinFnTy || T == Context.OverloadTy || + T->isFunctionType() || T->isFunctionReferenceType() || + T->isMemberFunctionPointerType() || T->isFunctionPointerType() || + T->isBlockPointerType() || T->isRecordType()) + return true; + + return isa(E); +} + ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig, bool IsExecConfig, @@ -6603,6 +6620,14 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, *this, dyn_cast(Fn->IgnoreParens()), Fn->getBeginLoc()); + // If the type of the function itself is not dependent + // check that it is a reasonable as a function, as type deduction + // later assume the CallExpr has a sensible TYPE. + if (!MayBeFunctionType(Context, Fn)) + return ExprError( + Diag(LParenLoc, diag::err_typecheck_call_not_function) + << Fn->getType() << Fn->getSourceRange()); + return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy, VK_PRValue, RParenLoc, CurFPFeatureOverrides()); } diff --git a/clang/test/SemaTemplate/fun-template-def.cpp b/clang/test/SemaTemplate/fun-template-def.cpp index de77901b5b601..e21ca624f4d01 100644 --- a/clang/test/SemaTemplate/fun-template-def.cpp +++ b/clang/test/SemaTemplate/fun-template-def.cpp @@ -1,6 +1,8 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s // Tests that dependent expressions are always allowed, whereas non-dependent // are checked as usual. @@ -32,7 +34,7 @@ T f1(T t1, U u1, int i1, T** tpp) i1 = t1[u1]; i1 *= t1; - i1(u1, t1); // error + i1(u1, t1); u1(i1, t1); U u2 = (T)i1; @@ -60,3 +62,99 @@ void f3() { f2(0); f2(0); // expected-error {{no matching function for call to 'f2'}} } + +#if __cplusplus >= 202002L +namespace GH138657 { +template // #gh138657-template-head +class meta {}; +template +class meta {}; // expected-error {{called object type 'int' is not a function or function point}} + +template +class meta {}; // expected-error {{called object type 'int *' is not a function or function point}} + +template +class meta {}; // expected-error {{called object type 'char *' is not a function or function point}} + +struct S {}; +template +class meta {}; // expected-error {{template argument for non-type template parameter is treated as function type 'S ()'}} + // expected-note@#gh138657-template-head {{template parameter is declared here}} + +} + +namespace GH115725 { +template struct X {}; +template struct A { + template + A(X<0(Ps)...>, Ts (*...qs)[Ns]); + // expected-error@-1{{called object type 'int' is not a function or function pointer}} + +}; +} + +namespace GH68852 { +template +struct constexpr_value { + template + constexpr constexpr_value call(Ts...) { + //expected-error@-1 {{called object type 'int' is not a function or function pointer}} + return {}; + } +}; + +template constexpr static inline auto c_ = constexpr_value{}; +// expected-note@-1 {{in instantiation of template}} +auto k = c_<1>; // expected-note {{in instantiation of variable}} + +} + +#endif +#if __cplusplus >= 201702L + +namespace GH138731 { +template +using void_t = void; + +template +T&& declval(); + +struct S { + S(); + static int f(); + static int var; +}; + +namespace invoke_detail { + +template +struct traits { + template + using result = decltype(declval()(declval()...)); +}; + +template +using invoke_result_t = typename traits::template result; + +template +inline constexpr bool is_invocable_v = false; + +template +inline constexpr bool + is_invocable_v>, F, A...> = true; + +} + +template +inline constexpr bool is_invocable_v = + invoke_detail::is_invocable_v; + +static_assert(!is_invocable_v); +static_assert(!is_invocable_v); +static_assert(!is_invocable_v); +static_assert(is_invocable_v); +static_assert(!is_invocable_v); + +} + +#endif