Skip to content

Commit 6e17e8e

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 llvm#138657 Fixes llvm#115725 Fixes llvm#68852
1 parent ffc5f79 commit 6e17e8e

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
@@ -655,6 +655,7 @@ Bug Fixes to C++ Support
655655
- Fixed an assertion when trying to constant-fold various builtins when the argument
656656
referred to a reference to an incomplete type. (#GH129397)
657657
- Fixed a crash when a cast involved a parenthesized aggregate initialization in dependent context. (#GH72880)
658+
- Fixed a crash when forming an invalid function type in a dependent context. (#GH138657) (#GH115725) (#GH68852)
658659

659660
Bug Fixes to AST Handling
660661
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaExpr.cpp

Lines changed: 19 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,16 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
65946603
*this, dyn_cast<UnresolvedMemberExpr>(Fn->IgnoreParens()),
65956604
Fn->getBeginLoc());
65966605

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

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)