Skip to content

Commit af80b8c

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 '+').
1 parent 6f07f30 commit af80b8c

File tree

4 files changed

+34
-33
lines changed

4 files changed

+34
-33
lines changed

clang/lib/AST/Expr.cpp

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

1446-
while (SubstNonTypeTemplateParmExpr *NTTP
1447-
= dyn_cast<SubstNonTypeTemplateParmExpr>(CEE)) {
1448-
CEE = NTTP->getReplacement()->IgnoreParenCasts();
1446+
while (SubstNonTypeTemplateParmExpr *NTTP =
1447+
dyn_cast<SubstNonTypeTemplateParmExpr>(CEE)) {
1448+
CEE = NTTP->getReplacement()->IgnoreParenImpCasts();
14491449
}
14501450

14511451
// If we're calling a dereference, look at the pointer instead.
1452-
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) {
1453-
if (BO->isPtrMemOp())
1454-
CEE = BO->getRHS()->IgnoreParenCasts();
1455-
} else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(CEE)) {
1456-
if (UO->getOpcode() == UO_Deref)
1457-
CEE = UO->getSubExpr()->IgnoreParenCasts();
1452+
while (true) {
1453+
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) {
1454+
if (BO->isPtrMemOp()) {
1455+
CEE = BO->getRHS()->IgnoreParenImpCasts();
1456+
continue;
1457+
}
1458+
} else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(CEE)) {
1459+
if (UO->getOpcode() == UO_Deref || UO->getOpcode() == UO_AddrOf ||
1460+
UO->getOpcode() == UO_Plus) {
1461+
CEE = UO->getSubExpr()->IgnoreParenImpCasts();
1462+
continue;
1463+
}
1464+
}
1465+
break;
14581466
}
1467+
14591468
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE))
14601469
return DRE->getDecl();
14611470
if (MemberExpr *ME = dyn_cast<MemberExpr>(CEE))
@@ -1466,28 +1475,11 @@ Decl *Expr::getReferencedDeclOfCallee() {
14661475
return nullptr;
14671476
}
14681477

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

14931485
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
@@ -10660,7 +10660,7 @@ static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info,
1066010660

1066110661
bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
1066210662
unsigned BuiltinOp) {
10663-
switch (unsigned BuiltinOp = E->getBuiltinCallee()) {
10663+
switch (BuiltinOp) {
1066410664
default:
1066510665
return ExprEvaluatorBaseTy::VisitCallExpr(E);
1066610666

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)