Skip to content

Commit cf9b4d1

Browse files
authored
[Clang] Diagnose invalid function types in dependent contexts (llvm#138731)
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 llvm#138657 Fixes llvm#115725 Fixes llvm#68852
1 parent 25af0ae commit cf9b4d1

File tree

3 files changed

+69
-1
lines changed

3 files changed

+69
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,7 @@ Bug Fixes to C++ Support
657657
- Fixed an assertion when trying to constant-fold various builtins when the argument
658658
referred to a reference to an incomplete type. (#GH129397)
659659
- Fixed a crash when a cast involved a parenthesized aggregate initialization in dependent context. (#GH72880)
660+
- Fixed a crash when forming an invalid function type in a dependent context. (#GH138657) (#GH115725) (#GH68852)
660661

661662
Bug Fixes to AST Handling
662663
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaExpr.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6541,6 +6541,15 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
65416541
return Call;
65426542
}
65436543

6544+
// Any type that could be used to form a callable expression
6545+
static bool MayBeFunctionType(const ASTContext &Context, QualType T) {
6546+
return T == Context.BoundMemberTy || T == Context.UnknownAnyTy ||
6547+
T == Context.BuiltinFnTy || T == Context.OverloadTy ||
6548+
T->isFunctionType() || T->isFunctionReferenceType() ||
6549+
T->isMemberFunctionPointerType() || T->isFunctionPointerType() ||
6550+
T->isBlockPointerType() || T->isRecordType();
6551+
}
6552+
65446553
ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
65456554
MultiExprArg ArgExprs, SourceLocation RParenLoc,
65466555
Expr *ExecConfig, bool IsExecConfig,
@@ -6594,6 +6603,15 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
65946603
*this, dyn_cast<UnresolvedMemberExpr>(Fn->IgnoreParens()),
65956604
Fn->getBeginLoc());
65966605

6606+
// If the type of the function itself is not dependent
6607+
// check that it is a reasonable as a function, as type deduction
6608+
// later assume the CallExpr has a sensible TYPE.
6609+
if (!Fn->getType()->isDependentType() &&
6610+
!MayBeFunctionType(Context, Fn->getType()))
6611+
return ExprError(
6612+
Diag(LParenLoc, diag::err_typecheck_call_not_function)
6613+
<< Fn->getType() << Fn->getSourceRange());
6614+
65976615
return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy,
65986616
VK_PRValue, RParenLoc, CurFPFeatureOverrides());
65996617
}

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)