Commit af80b8cc authored by Richard Smith's avatar Richard Smith
Browse files

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 '+').
parent 6f07f304
Loading
Loading
Loading
Loading
+22 −30
Original line number Diff line number Diff line
@@ -1443,19 +1443,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.
  while (true) {
    if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) {
    if (BO->isPtrMemOp())
      CEE = BO->getRHS()->IgnoreParenCasts();
      if (BO->isPtrMemOp()) {
        CEE = BO->getRHS()->IgnoreParenImpCasts();
        continue;
      }
    } else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(CEE)) {
    if (UO->getOpcode() == UO_Deref)
      CEE = UO->getSubExpr()->IgnoreParenCasts();
      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))
@@ -1466,28 +1475,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 {
+1 −1
Original line number Diff line number Diff line
@@ -10660,7 +10660,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);
+1 −1
Original line number Diff line number Diff line
@@ -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;
+10 −1
Original line number Diff line number Diff line
@@ -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, "");