Skip to content

Commit 4c87a81

Browse files
committed
[Clang] Diagnose invalid function types in dependent contexts
When forming an invalid function type, we were not diagnosing it if the call was dependent. However, we later rely on the function type to be sensible during argument deduction. We now diagnose anything that is not a potential function type, to avoid constructing bogus call expressions. Fixes #138657 Fixes #115725 Fixes #68852
1 parent 790ce0e commit 4c87a81

File tree

3 files changed

+70
-1
lines changed

3 files changed

+70
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@ Bug Fixes to C++ Support
680680
- Improved parser recovery of invalid requirement expressions. In turn, this
681681
fixes crashes from follow-on processing of the invalid requirement. (#GH138820)
682682
- Fixed the handling of pack indexing types in the constraints of a member function redeclaration. (#GH138255)
683+
- Fixed a crash when forming an invalid function type in a dependent context. (#GH138657) (#GH115725) (#GH68852)
683684

684685
Bug Fixes to AST Handling
685686
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaExpr.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6550,6 +6550,15 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
65506550
return Call;
65516551
}
65526552

6553+
// Any type that could be used to form a callable expression
6554+
static bool MayBeFunctionType(const ASTContext &Context, QualType T) {
6555+
return T == Context.BoundMemberTy || T == Context.UnknownAnyTy ||
6556+
T == Context.BuiltinFnTy || T == Context.OverloadTy ||
6557+
T->isFunctionType() || T->isFunctionReferenceType() ||
6558+
T->isMemberFunctionPointerType() || T->isFunctionPointerType() ||
6559+
T->isBlockPointerType() || T->isRecordType();
6560+
}
6561+
65536562
ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
65546563
MultiExprArg ArgExprs, SourceLocation RParenLoc,
65556564
Expr *ExecConfig, bool IsExecConfig,
@@ -6603,6 +6612,16 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
66036612
*this, dyn_cast<UnresolvedMemberExpr>(Fn->IgnoreParens()),
66046613
Fn->getBeginLoc());
66056614

6615+
if (!Fn->getType()->isDependentType()) {
6616+
// If the type of the function itself is not dependent
6617+
// check that it is a reasonable as a function, as type deduction
6618+
// later assume the CallExpr has a sensible TYPE.
6619+
if (!MayBeFunctionType(Context, Fn->getType()))
6620+
return ExprError(
6621+
Diag(LParenLoc, diag::err_typecheck_call_not_function)
6622+
<< Fn->getType() << Fn->getSourceRange());
6623+
}
6624+
66066625
return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy,
66076626
VK_PRValue, RParenLoc, CurFPFeatureOverrides());
66086627
}

clang/test/SemaTemplate/fun-template-def.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s
22
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
33
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
4+
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
45

56
// Tests that dependent expressions are always allowed, whereas non-dependent
67
// are checked as usual.
@@ -32,7 +33,7 @@ T f1(T t1, U u1, int i1, T** tpp)
3233
i1 = t1[u1];
3334
i1 *= t1;
3435

35-
i1(u1, t1); // error
36+
i1(u1, t1); // expected-error {{called object type 'int' is not a function or function pointer}}
3637
u1(i1, t1);
3738

3839
U u2 = (T)i1;
@@ -60,3 +61,51 @@ void f3() {
6061
f2<int*>(0);
6162
f2<int>(0); // expected-error {{no matching function for call to 'f2'}}
6263
}
64+
65+
#if __cplusplus >= 202002L
66+
namespace GH138657 {
67+
template <auto V> // #gh138657-template-head
68+
class meta {};
69+
template<int N>
70+
class meta<N()> {}; // expected-error {{called object type 'int' is not a function or function point}}
71+
72+
template<int N[1]>
73+
class meta<N()> {}; // expected-error {{called object type 'int *' is not a function or function point}}
74+
75+
template<char* N>
76+
class meta<N()> {}; // expected-error {{called object type 'char *' is not a function or function point}}
77+
78+
struct S {};
79+
template<S>
80+
class meta<S()> {}; // expected-error {{template argument for non-type template parameter is treated as function type 'S ()'}}
81+
// expected-note@#gh138657-template-head {{template parameter is declared here}}
82+
83+
}
84+
85+
namespace GH115725 {
86+
template<auto ...> struct X {};
87+
template<typename T, typename ...Ts> struct A {
88+
template<Ts ...Ns, T *...Ps>
89+
A(X<0(Ps)...>, Ts (*...qs)[Ns]);
90+
// expected-error@-1{{called object type 'int' is not a function or function pointer}}
91+
92+
};
93+
}
94+
95+
namespace GH68852 {
96+
template <auto v>
97+
struct constexpr_value {
98+
template <class... Ts>
99+
constexpr constexpr_value<v(Ts::value...)> call(Ts...) {
100+
//expected-error@-1 {{called object type 'int' is not a function or function pointer}}
101+
return {};
102+
}
103+
};
104+
105+
template <auto v> constexpr static inline auto c_ = constexpr_value<v>{};
106+
// expected-note@-1 {{in instantiation of template}}
107+
auto k = c_<1>; // expected-note {{in instantiation of variable}}
108+
109+
}
110+
111+
#endif

0 commit comments

Comments
 (0)