PR44684: Look through parens and similar constructs when determining
authorRichard Smith <richard@metafoo.co.uk>
Thu, 6 Feb 2020 03:01:33 +0000 (19:01 -0800)
committerRichard Smith <richard@metafoo.co.uk>
Thu, 6 Feb 2020 20:21:54 +0000 (12:21 -0800)
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 aaae6b1b617378362462c1685e754813ed82b394,
reinstating af80b8ccc5772c14920d4554b7ca7e15f2fad1c4, with a fix to
clang-tidy.

clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp
clang/lib/AST/Expr.cpp
clang/lib/AST/ExprConstant.cpp
clang/test/Parser/builtin_classify_type.c
clang/test/Sema/constant-builtins.c

index cb3f551..a7a0746 100644 (file)
@@ -34,15 +34,18 @@ void UseUncaughtExceptionsCheck::registerMatchers(MatchFinder *Finder) {
           .bind("decl_ref_expr"),
       this);
 
+  auto DirectCallToUncaughtException = callee(expr(ignoringImpCasts(
+      declRefExpr(hasDeclaration(functionDecl(hasName(MatchText)))))));
+
   // CallExpr: warning, fix-it.
-  Finder->addMatcher(callExpr(hasDeclaration(functionDecl(hasName(MatchText))),
+  Finder->addMatcher(callExpr(DirectCallToUncaughtException,
                               unless(hasAncestor(initListExpr())))
                          .bind("call_expr"),
                      this);
   // CallExpr in initialisation list: warning, fix-it with avoiding narrowing
   // conversions.
-  Finder->addMatcher(callExpr(hasAncestor(initListExpr()),
-                              hasDeclaration(functionDecl(hasName(MatchText))))
+  Finder->addMatcher(callExpr(DirectCallToUncaughtException,
+                              hasAncestor(initListExpr()))
                          .bind("init_call_expr"),
                      this);
 }
index ac4fa12..d929161 100644 (file)
@@ -1446,19 +1446,28 @@ void CallExpr::updateDependenciesFromArg(Expr *Arg) {
 Decl *Expr::getReferencedDeclOfCallee() {
   Expr *CEE = IgnoreParenImpCasts();
 
-  while (SubstNonTypeTemplateParmExpr *NTTP
-                                = dyn_cast<SubstNonTypeTemplateParmExpr>(CEE)) {
-    CEE = NTTP->getReplacement()->IgnoreParenCasts();
+  while (SubstNonTypeTemplateParmExpr *NTTP =
+             dyn_cast<SubstNonTypeTemplateParmExpr>(CEE)) {
+    CEE = NTTP->getReplacement()->IgnoreParenImpCasts();
   }
 
   // If we're calling a dereference, look at the pointer instead.
-  if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) {
-    if (BO->isPtrMemOp())
-      CEE = BO->getRHS()->IgnoreParenCasts();
-  } else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(CEE)) {
-    if (UO->getOpcode() == UO_Deref)
-      CEE = UO->getSubExpr()->IgnoreParenCasts();
+  while (true) {
+    if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) {
+      if (BO->isPtrMemOp()) {
+        CEE = BO->getRHS()->IgnoreParenImpCasts();
+        continue;
+      }
+    } 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))
     return DRE->getDecl();
   if (MemberExpr *ME = dyn_cast<MemberExpr>(CEE))
@@ -1469,28 +1478,11 @@ Decl *Expr::getReferencedDeclOfCallee() {
   return nullptr;
 }
 
-/// getBuiltinCallee - If this is a call to a builtin, return the builtin ID. If
-/// not, return 0.
+/// If this is a call to a builtin, return the builtin ID. If not, return 0.
 unsigned CallExpr::getBuiltinCallee() const {
-  // All simple function calls (e.g. func()) are implicitly cast to pointer to
-  // function. As a result, we try and obtain the DeclRefExpr from the
-  // ImplicitCastExpr.
-  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();
+  auto *FDecl =
+      dyn_cast_or_null<FunctionDecl>(getCallee()->getReferencedDeclOfCallee());
+  return FDecl ? FDecl->getBuiltinID() : 0;
 }
 
 bool CallExpr::isUnevaluatedBuiltinCall(const ASTContext &Ctx) const {
index f045e5f..860eeb1 100644 (file)
@@ -10684,7 +10684,7 @@ static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info,
 
 bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
                                             unsigned BuiltinOp) {
-  switch (unsigned BuiltinOp = E->getBuiltinCallee()) {
+  switch (BuiltinOp) {
   default:
     return ExprEvaluatorBaseTy::VisitCallExpr(E);
 
index 63fd8e2..94434e9 100644 (file)
@@ -9,7 +9,7 @@ int main() {
   struct foo s;
 
   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}}
 
   int result;
index c98f62d..ae3b913 100644 (file)
@@ -25,4 +25,13 @@ short 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, "");