diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index df46ddec5bdf..4af9b48704e7 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7463,6 +7463,7 @@ private: ArrayRef Args); bool CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, const FunctionProtoType *Proto); + bool CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto); void CheckConstructorCall(FunctionDecl *FDecl, ArrayRef Args, const FunctionProtoType *Proto, diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 96d8742b91d6..163d5fe849b1 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -499,11 +499,13 @@ void Sema::checkCall(NamedDecl *FDecl, // Printf and scanf checking. bool HandledFormatString = false; - for (specific_attr_iterator - I = FDecl->specific_attr_begin(), - E = FDecl->specific_attr_end(); I != E ; ++I) - if (CheckFormatArguments(*I, Args, IsMemberFunction, CallType, Loc, Range)) - HandledFormatString = true; + if (FDecl) + for (specific_attr_iterator + I = FDecl->specific_attr_begin(), + E = FDecl->specific_attr_end(); I != E ; ++I) + if (CheckFormatArguments(*I, Args, IsMemberFunction, CallType, Loc, + Range)) + HandledFormatString = true; // Refuse POD arguments that weren't caught by the format string // checks above. @@ -514,16 +516,19 @@ void Sema::checkCall(NamedDecl *FDecl, variadicArgumentPODCheck(Arg, CallType); } - for (specific_attr_iterator - I = FDecl->specific_attr_begin(), - E = FDecl->specific_attr_end(); I != E; ++I) - CheckNonNullArguments(*I, Args.data(), Loc); + if (FDecl) { + for (specific_attr_iterator + I = FDecl->specific_attr_begin(), + E = FDecl->specific_attr_end(); I != E; ++I) + CheckNonNullArguments(*I, Args.data(), Loc); - // Type safety checking. - for (specific_attr_iterator - i = FDecl->specific_attr_begin(), - e = FDecl->specific_attr_end(); i != e; ++i) { - CheckArgumentWithTypeTag(*i, Args.data()); + // Type safety checking. + for (specific_attr_iterator + i = FDecl->specific_attr_begin(), + e = FDecl->specific_attr_end(); + i != e; ++i) { + CheckArgumentWithTypeTag(*i, Args.data()); + } } } @@ -627,6 +632,23 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, return false; } +/// Checks function calls when a FunctionDecl or a NamedDecl is not available, +/// such as function pointers returned from functions. +bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) { + VariadicCallType CallType = getVariadicCallType(/*FDecl=*/0, Proto, + TheCall->getCallee()); + unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0; + + checkCall(/*FDecl=*/0, + llvm::makeArrayRef(TheCall->getArgs(), + TheCall->getNumArgs()), + NumProtoArgs, /*IsMemberFunction=*/false, + TheCall->getRParenLoc(), + TheCall->getCallee()->getSourceRange(), CallType); + + return false; +} + ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op) { CallExpr *TheCall = cast(TheCallResult.get()); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d0debba65e4b..a960a3d80846 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4466,6 +4466,9 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, } else if (NDecl) { if (CheckPointerCall(NDecl, TheCall, Proto)) return ExprError(); + } else { + if (CheckOtherCall(TheCall, Proto)) + return ExprError(); } return MaybeBindToTemporary(TheCall); diff --git a/clang/test/SemaCXX/vararg-non-pod.cpp b/clang/test/SemaCXX/vararg-non-pod.cpp index f1ab9b162ce9..056d23fe3323 100644 --- a/clang/test/SemaCXX/vararg-non-pod.cpp +++ b/clang/test/SemaCXX/vararg-non-pod.cpp @@ -153,3 +153,39 @@ namespace t10 { s(f); } } + +namespace t11 { + typedef void(*function_ptr)(int, ...); + typedef void(C::*member_ptr)(int, ...); + typedef void(^block_ptr)(int, ...); + + function_ptr get_f_ptr(); + member_ptr get_m_ptr(); + block_ptr get_b_ptr(); + + function_ptr arr_f_ptr[5]; + member_ptr arr_m_ptr[5]; + block_ptr arr_b_ptr[5]; + + void test() { + C c(10); + + (get_f_ptr())(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic function; call will abort at runtime}} + (get_f_ptr())(10, version); + + (c.*get_m_ptr())(10, c); // TODO: This should also warn. + (c.*get_m_ptr())(10, version); + + (get_b_ptr())(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic block; call will abort at runtime}} + (get_b_ptr())(10, version); + + (arr_f_ptr[3])(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic function; call will abort at runtime}} + (arr_f_ptr[3])(10, version); + + (c.*arr_m_ptr[3])(10, c); // TODO: This should also warn. + (c.*arr_m_ptr[3])(10, version); + + (arr_b_ptr[3])(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic block; call will abort at runtime}} + (arr_b_ptr[3])(10, version); + } +}