Skip to content

Commit da3dc00

Browse files
committed
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 aaae6b1, reinstating af80b8c, with a fix to clang-tidy.
1 parent 6f5a159 commit da3dc00

File tree

5 files changed

+40
-36
lines changed

5 files changed

+40
-36
lines changed

clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,18 @@ void UseUncaughtExceptionsCheck::registerMatchers(MatchFinder *Finder) {
3434
.bind("decl_ref_expr"),
3535
this);
3636

37+
auto DirectCallToUncaughtException = callee(expr(ignoringImpCasts(
38+
declRefExpr(hasDeclaration(functionDecl(hasName(MatchText)))))));
39+
3740
// CallExpr: warning, fix-it.
38-
Finder->addMatcher(callExpr(hasDeclaration(functionDecl(hasName(MatchText))),
41+
Finder->addMatcher(callExpr(DirectCallToUncaughtException,
3942
unless(hasAncestor(initListExpr())))
4043
.bind("call_expr"),
4144
this);
4245
// CallExpr in initialisation list: warning, fix-it with avoiding narrowing
4346
// conversions.
44-
Finder->addMatcher(callExpr(hasAncestor(initListExpr()),
45-
hasDeclaration(functionDecl(hasName(MatchText))))
47+
Finder->addMatcher(callExpr(DirectCallToUncaughtException,
48+
hasAncestor(initListExpr()))
4649
.bind("init_call_expr"),
4750
this);
4851
}

clang/lib/AST/Expr.cpp

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,19 +1446,28 @@ void CallExpr::updateDependenciesFromArg(Expr *Arg) {
14461446
Decl *Expr::getReferencedDeclOfCallee() {
14471447
Expr *CEE = IgnoreParenImpCasts();
14481448

1449-
while (SubstNonTypeTemplateParmExpr *NTTP
1450-
= dyn_cast<SubstNonTypeTemplateParmExpr>(CEE)) {
1451-
CEE = NTTP->getReplacement()->IgnoreParenCasts();
1449+
while (SubstNonTypeTemplateParmExpr *NTTP =
1450+
dyn_cast<SubstNonTypeTemplateParmExpr>(CEE)) {
1451+
CEE = NTTP->getReplacement()->IgnoreParenImpCasts();
14521452
}
14531453

14541454
// If we're calling a dereference, look at the pointer instead.
1455-
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) {
1456-
if (BO->isPtrMemOp())
1457-
CEE = BO->getRHS()->IgnoreParenCasts();
1458-
} else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(CEE)) {
1459-
if (UO->getOpcode() == UO_Deref)
1460-
CEE = UO->getSubExpr()->IgnoreParenCasts();
1455+
while (true) {
1456+
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) {
1457+
if (BO->isPtrMemOp()) {
1458+
CEE = BO->getRHS()->IgnoreParenImpCasts();
1459+
continue;
1460+
}
1461+
} else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(CEE)) {
1462+
if (UO->getOpcode() == UO_Deref || UO->getOpcode() == UO_AddrOf ||
1463+
UO->getOpcode() == UO_Plus) {
1464+
CEE = UO->getSubExpr()->IgnoreParenImpCasts();
1465+
continue;
1466+
}
1467+
}
1468+
break;
14611469
}
1470+
14621471
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE))
14631472
return DRE->getDecl();
14641473
if (MemberExpr *ME = dyn_cast<MemberExpr>(CEE))
@@ -1469,28 +1478,11 @@ Decl *Expr::getReferencedDeclOfCallee() {
14691478
return nullptr;
14701479
}
14711480

1472-
/// getBuiltinCallee - If this is a call to a builtin, return the builtin ID. If
1473-
/// not, return 0.
1481+
/// If this is a call to a builtin, return the builtin ID. If not, return 0.
14741482
unsigned CallExpr::getBuiltinCallee() const {
1475-
// All simple function calls (e.g. func()) are implicitly cast to pointer to
1476-
// function. As a result, we try and obtain the DeclRefExpr from the
1477-
// ImplicitCastExpr.
1478-
const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(getCallee());
1479-
if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()).
1480-
return 0;
1481-
1482-
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr());
1483-
if (!DRE)
1484-
return 0;
1485-
1486-
const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl());
1487-
if (!FDecl)
1488-
return 0;
1489-
1490-
if (!FDecl->getIdentifier())
1491-
return 0;
1492-
1493-
return FDecl->getBuiltinID();
1483+
auto *FDecl =
1484+
dyn_cast_or_null<FunctionDecl>(getCallee()->getReferencedDeclOfCallee());
1485+
return FDecl ? FDecl->getBuiltinID() : 0;
14941486
}
14951487

14961488
bool CallExpr::isUnevaluatedBuiltinCall(const ASTContext &Ctx) const {

clang/lib/AST/ExprConstant.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10684,7 +10684,7 @@ static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info,
1068410684

1068510685
bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
1068610686
unsigned BuiltinOp) {
10687-
switch (unsigned BuiltinOp = E->getBuiltinCallee()) {
10687+
switch (BuiltinOp) {
1068810688
default:
1068910689
return ExprEvaluatorBaseTy::VisitCallExpr(E);
1069010690

clang/test/Parser/builtin_classify_type.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ int main() {
99
struct foo s;
1010

1111
static int ary[__builtin_classify_type(a)];
12-
static int ary2[(__builtin_classify_type)(a)]; // expected-error{{variable length array declaration cannot have 'static' storage duration}}
12+
static int ary2[(__builtin_classify_type)(a)];
1313
static int ary3[(*__builtin_classify_type)(a)]; // expected-error{{builtin functions must be directly called}}
1414

1515
int result;

clang/test/Sema/constant-builtins.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,13 @@ short somefunc();
2525

2626
short t = __builtin_constant_p(5353) ? 42 : somefunc();
2727

28-
28+
// PR44684
29+
_Static_assert((__builtin_clz)(1u) >= 15, "");
30+
_Static_assert((__builtin_popcount)(1u) == 1, "");
31+
_Static_assert((__builtin_ctz)(2u) == 1, "");
32+
_Static_assert(_Generic(1u,unsigned:__builtin_clz)(1u) >= 15, "");
33+
_Static_assert(_Generic(1u,unsigned:__builtin_popcount)(1u) == 1, "");
34+
_Static_assert(_Generic(1u,unsigned:__builtin_ctz)(2u) == 1, "");
35+
36+
__SIZE_TYPE__ strlen(const char*);
37+
_Static_assert((__builtin_constant_p(1) ? (***&strlen)("foo") : 0) == 3, "");

0 commit comments

Comments
 (0)