PR44684: Look through parens and similar constructs when determining

whether a call is to a builtin.

We already had a general mechanism to do this but for some reason
weren't using it. In passing, check for the other unary operators that
can intervene in a reasonably-direct function call (we already handled
'&' but missed '*' and '+').

This reverts commit aaae6b1b61,
reinstating af80b8ccc5, with a fix to
clang-tidy.
This commit is contained in:
Richard Smith 2020-02-05 19:01:33 -08:00
parent 6f5a159eab
commit da3dc0011e
5 changed files with 39 additions and 35 deletions

View File

@ -34,15 +34,18 @@ void UseUncaughtExceptionsCheck::registerMatchers(MatchFinder *Finder) {
.bind("decl_ref_expr"), .bind("decl_ref_expr"),
this); this);
auto DirectCallToUncaughtException = callee(expr(ignoringImpCasts(
declRefExpr(hasDeclaration(functionDecl(hasName(MatchText)))))));
// CallExpr: warning, fix-it. // CallExpr: warning, fix-it.
Finder->addMatcher(callExpr(hasDeclaration(functionDecl(hasName(MatchText))), Finder->addMatcher(callExpr(DirectCallToUncaughtException,
unless(hasAncestor(initListExpr()))) unless(hasAncestor(initListExpr())))
.bind("call_expr"), .bind("call_expr"),
this); this);
// CallExpr in initialisation list: warning, fix-it with avoiding narrowing // CallExpr in initialisation list: warning, fix-it with avoiding narrowing
// conversions. // conversions.
Finder->addMatcher(callExpr(hasAncestor(initListExpr()), Finder->addMatcher(callExpr(DirectCallToUncaughtException,
hasDeclaration(functionDecl(hasName(MatchText)))) hasAncestor(initListExpr()))
.bind("init_call_expr"), .bind("init_call_expr"),
this); this);
} }

View File

@ -1446,19 +1446,28 @@ void CallExpr::updateDependenciesFromArg(Expr *Arg) {
Decl *Expr::getReferencedDeclOfCallee() { Decl *Expr::getReferencedDeclOfCallee() {
Expr *CEE = IgnoreParenImpCasts(); Expr *CEE = IgnoreParenImpCasts();
while (SubstNonTypeTemplateParmExpr *NTTP while (SubstNonTypeTemplateParmExpr *NTTP =
= dyn_cast<SubstNonTypeTemplateParmExpr>(CEE)) { dyn_cast<SubstNonTypeTemplateParmExpr>(CEE)) {
CEE = NTTP->getReplacement()->IgnoreParenCasts(); CEE = NTTP->getReplacement()->IgnoreParenImpCasts();
} }
// If we're calling a dereference, look at the pointer instead. // If we're calling a dereference, look at the pointer instead.
while (true) {
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) { if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) {
if (BO->isPtrMemOp()) if (BO->isPtrMemOp()) {
CEE = BO->getRHS()->IgnoreParenCasts(); CEE = BO->getRHS()->IgnoreParenImpCasts();
} else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(CEE)) { continue;
if (UO->getOpcode() == UO_Deref)
CEE = UO->getSubExpr()->IgnoreParenCasts();
} }
} else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(CEE)) {
if (UO->getOpcode() == UO_Deref || UO->getOpcode() == UO_AddrOf ||
UO->getOpcode() == UO_Plus) {
CEE = UO->getSubExpr()->IgnoreParenImpCasts();
continue;
}
}
break;
}
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE))
return DRE->getDecl(); return DRE->getDecl();
if (MemberExpr *ME = dyn_cast<MemberExpr>(CEE)) if (MemberExpr *ME = dyn_cast<MemberExpr>(CEE))
@ -1469,28 +1478,11 @@ Decl *Expr::getReferencedDeclOfCallee() {
return nullptr; return nullptr;
} }
/// getBuiltinCallee - If this is a call to a builtin, return the builtin ID. If /// If this is a call to a builtin, return the builtin ID. If not, return 0.
/// not, return 0.
unsigned CallExpr::getBuiltinCallee() const { unsigned CallExpr::getBuiltinCallee() const {
// All simple function calls (e.g. func()) are implicitly cast to pointer to auto *FDecl =
// function. As a result, we try and obtain the DeclRefExpr from the dyn_cast_or_null<FunctionDecl>(getCallee()->getReferencedDeclOfCallee());
// ImplicitCastExpr. return FDecl ? FDecl->getBuiltinID() : 0;
const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(getCallee());
if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()).
return 0;
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr());
if (!DRE)
return 0;
const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl());
if (!FDecl)
return 0;
if (!FDecl->getIdentifier())
return 0;
return FDecl->getBuiltinID();
} }
bool CallExpr::isUnevaluatedBuiltinCall(const ASTContext &Ctx) const { bool CallExpr::isUnevaluatedBuiltinCall(const ASTContext &Ctx) const {

View File

@ -10684,7 +10684,7 @@ static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info,
bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
unsigned BuiltinOp) { unsigned BuiltinOp) {
switch (unsigned BuiltinOp = E->getBuiltinCallee()) { switch (BuiltinOp) {
default: default:
return ExprEvaluatorBaseTy::VisitCallExpr(E); return ExprEvaluatorBaseTy::VisitCallExpr(E);

View File

@ -9,7 +9,7 @@ int main() {
struct foo s; struct foo s;
static int ary[__builtin_classify_type(a)]; static int ary[__builtin_classify_type(a)];
static int ary2[(__builtin_classify_type)(a)]; // expected-error{{variable length array declaration cannot have 'static' storage duration}} static int ary2[(__builtin_classify_type)(a)];
static int ary3[(*__builtin_classify_type)(a)]; // expected-error{{builtin functions must be directly called}} static int ary3[(*__builtin_classify_type)(a)]; // expected-error{{builtin functions must be directly called}}
int result; int result;

View File

@ -25,4 +25,13 @@ short somefunc();
short t = __builtin_constant_p(5353) ? 42 : somefunc(); short t = __builtin_constant_p(5353) ? 42 : somefunc();
// PR44684
_Static_assert((__builtin_clz)(1u) >= 15, "");
_Static_assert((__builtin_popcount)(1u) == 1, "");
_Static_assert((__builtin_ctz)(2u) == 1, "");
_Static_assert(_Generic(1u,unsigned:__builtin_clz)(1u) >= 15, "");
_Static_assert(_Generic(1u,unsigned:__builtin_popcount)(1u) == 1, "");
_Static_assert(_Generic(1u,unsigned:__builtin_ctz)(2u) == 1, "");
__SIZE_TYPE__ strlen(const char*);
_Static_assert((__builtin_constant_p(1) ? (***&strlen)("foo") : 0) == 3, "");