Exemple #1
0
std::vector<CallExpr *> Utils::callListForChain(CallExpr *lastCallExpr)
{
    if (!lastCallExpr)
        return {};

    const bool isOperator = isa<CXXOperatorCallExpr>(lastCallExpr);

    vector<CallExpr *> callexprs = { lastCallExpr };
    Stmt *s = lastCallExpr;
    do {
        const int childCount = std::distance(s->child_begin(), s->child_end());
        if (isOperator && childCount > 1) {
            // for operator case, the chained call childs are in the second child
            s = *(++s->child_begin());
        } else {
            s = childCount > 0 ? *s->child_begin() : nullptr;
        }

        if (s) {
            CallExpr *callExpr = dyn_cast<CallExpr>(s);
            if (callExpr && callExpr->getCalleeDecl()) {
                callexprs.push_back(callExpr);
            } else if (MemberExpr *memberExpr = dyn_cast<MemberExpr>(s)) {
                if (isa<FieldDecl>(memberExpr->getMemberDecl()))
                    break; // accessing a public member via . or -> breaks the chain
            }
        }
    } while (s);

    return callexprs;
}
void ImplicitCasts::VisitStmt(clang::Stmt *stmt)
{
    if (isMacroToIgnore(stmt->getLocStart()))
        return;

    // Lets check only in function calls. Otherwise there are too many false positives, it's common
    // to implicit cast to bool when checking pointers for validity, like if (ptr)

    CallExpr *callExpr = dyn_cast<CallExpr>(stmt);
    CXXConstructExpr *ctorExpr = dyn_cast<CXXConstructExpr>(stmt);
    if (!callExpr && !ctorExpr)
        return;

    FunctionDecl *func = callExpr ? callExpr->getDirectCallee()
                                  : ctorExpr->getConstructor();


    if (isInterestingFunction(func)) {
        // Check pointer->bool implicit casts
        iterateCallExpr<CallExpr>(callExpr, this);
        iterateCallExpr<CXXConstructExpr>(ctorExpr, this);
    } else if (isInterestingFunction2(func)) {
        // Check bool->int implicit casts
        iterateCallExpr2<CallExpr>(callExpr, this, m_parentMap);
        iterateCallExpr2<CXXConstructExpr>(ctorExpr, this, m_parentMap);
    }
}
Exemple #3
0
//
// Determine the index type for a ParamForLoop.
//
// This implementation creates a range with low/high values and then
// asks for its type.
//
Type* ParamForLoop::indexType()
{
  SymExpr*  lse     = lowExprGet();
  SymExpr*  hse     = highExprGet();
  CallExpr* range    = new CallExpr("chpl_build_bounded_range",
                                    lse->copy(), hse->copy());
  Type*     idxType = 0;

  insertBefore(range);

  resolveCall(range);

  if (FnSymbol* sym = range->isResolved())
  {
    resolveFormals(sym);

    DefExpr* formal = toDefExpr(sym->formals.get(1));

    if (toArgSymbol(formal->sym)->typeExpr)
      idxType = toArgSymbol(formal->sym)->typeExpr->body.tail->typeInfo();
    else
      idxType = formal->sym->type;

    range->remove();
  }
  else
  {
    INT_FATAL("unresolved range");
  }

  return idxType;
}
//
// Returns true if 'ref' is only used in the following cases:
//
//   1) Used in 'defCall', usually a PRIM_ADDR_OF or PRIM_SET_REFERENCE
//
//   2) Passed to an initializer in the 'this' slot.
//
//   3) Initialized from a function call, as represented by return-by-ref.
//
// An initializer can thwart detection of a 'const' thing because it takes the
// "this" argument by ref. Normally such a pattern would cause us to assume
// the variable was not const, but in this case we know it is a single def.
//
// defCall: The CallExpr where 'ref' is set from a PRIM_ADDR_OF or
// PRIM_SET_REFERENCE. This call will be ignored while considering uses of
// the 'ref' Symbol.
//
static bool onlyUsedForInitOrRetarg(Symbol* ref, CallExpr* defCall) {
  bool seenInitOrRetarg = false;

  INT_ASSERT(ref->isRef());
  INT_ASSERT(defCall != NULL);

  for_SymbolSymExprs(use, ref) {
    if (use->parentExpr == defCall)
      continue;

    CallExpr* call = toCallExpr(use->parentExpr);

    if (FnSymbol*  fn = call->resolvedFunction()) {
      ArgSymbol* form = actual_to_formal(use);
      if (passedToInitOrRetarg(use, form, fn)) {
        INT_ASSERT(!seenInitOrRetarg); // init/retarg happens just once
        seenInitOrRetarg = true;
      } else {
        return false;  // a use other than what we are looking for
      }
    }
  }

  return true;
}
Exemple #5
0
BlockStmt* DoWhileStmt::build(Expr* cond, BlockStmt* body)
{
  VarSymbol*   condVar       = newTemp();
  CallExpr*    condTest      = new CallExpr("_cond_test", cond);
  LabelSymbol* continueLabel = new LabelSymbol("_continueLabel");
  LabelSymbol* breakLabel    = new LabelSymbol("_breakLabel");
  DoWhileStmt* loop          = 0;
  BlockStmt*   retval        = new BlockStmt();

  // make variables declared in the scope of the body visible to
  // expressions in the condition of a do..while block
  if (body->length() == 1 && toBlockStmt(body->body.only()))
  {
    body = toBlockStmt(body->body.only());
    body->remove();
  }

  body->insertAtTail(new DefExpr(continueLabel));
  body->insertAtTail(new CallExpr(PRIM_MOVE, condVar, condTest->copy()));

  loop = new DoWhileStmt(condVar, body);

  loop->mContinueLabel = continueLabel;
  loop->mBreakLabel    = breakLabel;

  retval->insertAtTail(new DefExpr(condVar));

  retval->insertAtTail(loop);

  retval->insertAtTail(new DefExpr(breakLabel));

  return retval;
}
Exemple #6
0
void IRGenerator::accept(CallExpr& call)
{
    FNTRACE();

    std::vector<Value*> args;

    Value* callee = codegen(call.callee());

    for (Expr* arg: call.args().values()) {
        if (Value* v = codegen(arg)) {
            args.push_back(v);
        } else {
            return;
        }
    }

    if (call.callee()->isFunction()) {
        // builtin function
        result_ = createCallFunction(static_cast<IRBuiltinFunction*>(callee), args);
    } else if (call.callee()->isBuiltin()) {
        // builtin handler
        result_ = createInvokeHandler(args);
    } else {
        // source handler
        result_ = nullptr; // TODO: inline source handler
    }
}
Exemple #7
0
void ReturnByRef::insertAssignmentToFormal(FnSymbol* fn, ArgSymbol* formal)
{
  Expr*     returnPrim  = fn->body->body.tail;

  SET_LINENO(returnPrim);

  CallExpr* returnCall  = toCallExpr(returnPrim);
  Expr*     returnValue = returnCall->get(1)->remove();
  CallExpr* moveExpr    = new CallExpr(PRIM_ASSIGN, formal, returnValue);


  Expr* expr = returnPrim;
  // Walk backwards while the previous element is an autoDestroy call
  while (expr->prev != NULL) {
    bool stop = true;
    if (CallExpr* call = toCallExpr(expr->prev))
      if (FnSymbol* calledFn = call->isResolved())
        if (calledFn->hasFlag(FLAG_AUTO_DESTROY_FN))
          stop = false;

    if (stop) break;

    expr = expr->prev;
  }

  Expr* returnOrFirstAutoDestroy = expr;

  // Add the move to return before the first autoDestroy
  // At this point we could also invoke some other function
  // if that turns out to be necessary. It might well be
  // necessary in order to return array slices by value.
  returnOrFirstAutoDestroy->insertBefore(moveExpr);
}
Exemple #8
0
static void removeVoidReturn(BlockStmt* cloneBody) {
  CallExpr* retexpr = toCallExpr(cloneBody->body.tail);
  INT_ASSERT(retexpr && retexpr->isPrimitive(PRIM_RETURN));
  INT_ASSERT(toSymExpr(retexpr->get(1))->symbol() == gVoid);

  retexpr->remove();
}
Exemple #9
0
void QDeleteAll::VisitStmt(clang::Stmt *stmt)
{
    // Find a call to QMap/QSet/QHash::values
    CXXMemberCallExpr *valuesCall = dyn_cast<CXXMemberCallExpr>(stmt);
    if (valuesCall &&
        valuesCall->getDirectCallee() &&
        valuesCall->getDirectCallee()->getNameAsString() == "values")
    {
        const std::string valuesClassName = valuesCall->getMethodDecl()->getParent()->getNameAsString();
        if (valuesClassName == "QMap" || valuesClassName == "QSet" || valuesClassName == "QHash") { // QMultiHash and QMultiMap automatically supported
            // Once found see if the first parent call is qDeleteAll
            int i = 1;
            Stmt *p = Utils::parent(m_parentMap, stmt, i);
            while (p) {
                CallExpr *pc = dyn_cast<CallExpr>(p);
                if (pc) {
                    if (pc->getDirectCallee() && pc->getDirectCallee()->getNameAsString() == "qDeleteAll") {
                        emitWarning(p->getLocStart(), "Calling qDeleteAll with " + valuesClassName + "::values, call qDeleteAll on the container itself");
                    }
                    break;
                }
                ++i;
                p = Utils::parent(m_parentMap, stmt, i);
            }
        }
    }
}
Exemple #10
0
/*
 * Attempts to replace iteration over simple anonymous ranges with calls to
 * direct iterators that take low, high and stride as arguments. This is to
 * avoid the cost of constructing ranges, and if the stride is known at compile
 * time, provide a more optimized iterator that uses "<, <=, >, or >=" as the
 * relational operator.
 *
 * This is only meant to replace anonymous range iteration for "simple" bounded
 * ranges. Simple means it's a range of the form "low..high" or "low..high by
 * stride". Anything more complex is ignored with the thinking that this should
 * optimize the most common range iterators, but it could be expanded to handle
 * more cases.
 *
 * An alternative is to update scalar replacement of aggregates to work on
 * ranges, which should be able to achieve similar results as this optimization
 * while handling all ranges, including non-anonymous ranges.
 *
 * Will optimize things like:
 * - "for i in 1..10"
 * - "for i in 1..10+1"
 * - "var lo=1, hi=10;for i in lo..hi"
 * - "for i in 1..10 by 2"
 * - "for (i, j) in zip(1..10 by 2, 1..10 by -2)"
 * - "for (i, j) in zip(A, 1..10 by 2)" // will optimize range iter still
 * - "coforall i in 1..10 by 2"         // works for coforalls as well
 *
 * Will not optimize ranges like:
 * - "for in in (1..)"             // doesn't handle unbounded ranges
 * - "for i in 1..10 by 2 by 2"    // doesn't handle more than one by operator
 * - "for i in 1..10 align 2"      // doesn't handle align operator
 * - "for i in 1..#10"             // doesn't handle # operator
 * - "var r = 1..10"; for i in r"  // not an anonymous range
 * - "forall i in 1..10"           // does not get applied to foralls
 *
 * Note that this function is pretty fragile because it relies on names of
 * functions/iterators as well as the arguments and order of those
 * functions/iterators but there's not really a way around it this early in
 * compilation. If the iterator can't be replaced, it is left unchanged.
 */
static void tryToReplaceWithDirectRangeIterator(Expr* iteratorExpr)
{
  CallExpr* range = NULL;
  Expr* stride = NULL;
  if (CallExpr* call = toCallExpr(iteratorExpr))
  {
    // grab the stride if we have a strided range
    if (call->isNamed("chpl_by"))
    {
      range = toCallExpr(call->get(1)->copy());
      stride = toExpr(call->get(2)->copy());
    }
    // assume the call is the range (checked below) and set default stride
    else
    {
      range = call;
      stride = new SymExpr(new_IntSymbol(1));
    }
    // see if we're looking at a builder for a bounded range. the builder is
    // iteratable since range has these() iterators
    if (range && range->isNamed("chpl_build_bounded_range"))
    {
      // replace the range construction with a direct range iterator
      Expr* low = range->get(1)->copy();
      Expr* high = range->get(2)->copy();
      iteratorExpr->replace(new CallExpr("chpl_direct_range_iter", low, high, stride));
    }
  }
}
  forv_Vec(FnSymbol, fn, gFnSymbols)
  {
    if (VarSymbol* ret = toVarSymbol(fn->getReturnSymbol()))
    {
      // The return value of an initCopy function should not be autodestroyed.
      // Normally, the return value of a function is autoCopied, but since
      // autoCopy is typically defined in terms of initCopy, this would lead to
      // infinite recursion.  That is, the return value of initCopy must be
      // handled specially.
      if (fn->hasFlag(FLAG_INIT_COPY_FN))
        ret->removeFlag(FLAG_INSERT_AUTO_DESTROY);

      // This is just a workaround for memory management being handled specially
      // for internally reference-counted types. (sandboxing)
      TypeSymbol* ts = ret->type->symbol;
      if (ts->hasFlag(FLAG_ARRAY) ||
          ts->hasFlag(FLAG_DOMAIN))
        ret->removeFlag(FLAG_INSERT_AUTO_DESTROY);
      // Do we need to add other record-wrapped types here?  Testing will tell.

      // NOTE 1: When the value of a record field is established in a default
      // constructor, it is initialized using a MOVE.  That means that ownership
      // of that value is shared between the formal_tmp and the record field.
      // If the autodestroy flag is left on that formal temp, then it will be
      // destroyed which -- for ref-counted types -- can result in a dangling
      // reference.  So here, we look for that case and remove it.  
      if (fn->hasFlag(FLAG_DEFAULT_CONSTRUCTOR))
      {
        Map<Symbol*,Vec<SymExpr*>*> defMap;
        Map<Symbol*,Vec<SymExpr*>*> useMap;
        buildDefUseMaps(fn, defMap, useMap);

        std::vector<DefExpr*> defs;
        collectDefExprs(fn, defs);

        for_vector(DefExpr, def, defs)
        {
          if (VarSymbol* var = toVarSymbol(def->sym))
          {
            // Examine only those bearing the explicit autodestroy flag.
            if (! var->hasFlag(FLAG_INSERT_AUTO_DESTROY))
              continue;

            // Look for a use in a PRIM_SET_MEMBER where the field is a record
            // type, and remove the flag.
            // (We don't actually check that var is of record type, because
            // chpl__autoDestroy() does nothing when applied to all other types.
            for_uses(se, useMap, var)
            {
              CallExpr* call = toCallExpr(se->parentExpr);
              if (call->isPrimitive(PRIM_SET_MEMBER) &&
                  toSymExpr(call->get(3))->var == var)
                var->removeFlag(FLAG_INSERT_AUTO_DESTROY);
            }
          }
        }

        freeDefUseMaps(defMap, useMap);
      }
  void NetworkDriverRewriteVisitor::InstrumentEntryPoints(FunctionDecl* funcDecl, string fdFile)
  {
    if (funcDecl->getStorageClass() == SC_Static)
      RW.RemoveText(funcDecl->getInnerLocStart(), 7);

    if (DI->getInstance().GetInitFunction() == funcDecl->getNameInfo().getName().getAsString())
      return;

    if (funcDecl->getParamDecl(0)->getOriginalType().getAsString() != "struct device *" &&
      funcDecl->getParamDecl(0)->getOriginalType().getAsString() != "struct pci_dev *")
      return;

    SourceRange sr = funcDecl->getParamDecl(0)->getSourceRange();

    RW.InsertTextBefore(sr.getBegin(), "struct net_device *dev, ");

    Stmt *body = funcDecl->getBody();
    list<DeclStmt*> stmtsToRewrite;

    for (auto i = body->child_begin(), e = body->child_end(); i != e; ++i)
    {
      if (!isa<DeclStmt>(*i))
        continue;

      DeclStmt *declStmt = cast<DeclStmt>(*i);
      if (!declStmt->isSingleDecl() && !isa<VarDecl>(declStmt->getSingleDecl()))
        continue;

      VarDecl *var = cast<VarDecl>(declStmt->getSingleDecl());
      if (!var->hasInit())
        continue;

      Expr *expr = var->getInit();
      if (!isa<ImplicitCastExpr>(expr))
        continue;

      ImplicitCastExpr *implicit = cast<ImplicitCastExpr>(expr);
      if (!isa<CallExpr>(implicit->getSubExpr()))
       continue;

      CallExpr *call = cast<CallExpr>(implicit->getSubExpr());
      DeclRefExpr *callee = cast<DeclRefExpr>(cast<ImplicitCastExpr>(call->getCallee())->getSubExpr());

      if (callee->getNameInfo().getName().getAsString() == "to_pci_dev" ||
          callee->getNameInfo().getName().getAsString() == "pci_get_drvdata")
      {
        stmtsToRewrite.push_back(declStmt);
      }
    }

    while (!stmtsToRewrite.empty())
    {
      DeclStmt *stmt = stmtsToRewrite.back();
      RW.RemoveText(stmt->getSourceRange());
      stmtsToRewrite.pop_back();
    }
  }
Exemple #13
0
void QGetEnv::VisitStmt(clang::Stmt *stmt)
{
    // Lets check only in function calls. Otherwise there are too many false positives, it's common
    // to implicit cast to bool when checking pointers for validity, like if (ptr)

    CXXMemberCallExpr *memberCall = dyn_cast<CXXMemberCallExpr>(stmt);
    if (!memberCall)
        return;

    CXXMethodDecl *method = memberCall->getMethodDecl();
    if (!method)
        return;

    CXXRecordDecl *record = method->getParent();
    if (!record || record->getNameAsString() != "QByteArray") {
        return;
    }

    std::vector<CallExpr *> calls = Utils::callListForChain(memberCall);
    if (calls.size() != 2)
        return;

    CallExpr *qgetEnvCall = calls.back();

    FunctionDecl *func = qgetEnvCall->getDirectCallee();

    if (!func || func->getNameAsString() != "qgetenv")
        return;

    string methodname = method->getNameAsString();
    string errorMsg;
    std::string replacement;
    if (methodname == "isEmpty") {
        errorMsg = "qgetenv().isEmpty() allocates.";
        replacement = "qEnvironmentVariableIsEmpty";
    } else if (methodname == "isNull") {
        errorMsg = "qgetenv().isNull() allocates.";
        replacement = "qEnvironmentVariableIsSet";
    } else if (methodname == "toInt") {
        errorMsg = "qgetenv().toInt() is slow.";
        replacement = "qEnvironmentVariableIntValue";
    }

    if (!errorMsg.empty()) {
        std::vector<FixItHint> fixits;
        if (isFixitEnabled(FixitAll)) {
            const bool success = FixItUtils::transformTwoCallsIntoOne(m_ci, qgetEnvCall, memberCall, replacement, fixits);
            if (!success) {
                queueManualFixitWarning(memberCall->getLocStart(), FixitAll);
            }
        }

        errorMsg += " Use " + replacement + "() instead";
        emitWarning(memberCall->getLocStart(), errorMsg.c_str(), fixits);
    }
}
Exemple #14
0
void FlowCallVisitor::accept(CallExpr& call)
{
    for (const auto& arg: call.args().values()) {
        visit(arg);
    }

    if (call.callee() && call.callee()->isBuiltin()) {
        calls_.push_back(&call);
    }
}
void InstantiationVisitor::visit(CallExpr& c)
{
	std::vector<std::unique_ptr<Expr>> args;

	for (auto& arg : c.arguments())
		args.emplace_back(clone(*arg));

	_expr.reset(new CallExpr(c.sloc(), c.name(), std::move(args), c.type()));
	static_cast<CallExpr&>(*_expr).target(c.target());
}
Exemple #16
0
static
void addNoAliasSetForFormal(ArgSymbol* arg,
                            std::vector<ArgSymbol*> notAliasingThese) {
  SET_LINENO(arg);

  CallExpr* c = new CallExpr(PRIM_NO_ALIAS_SET, new SymExpr(arg));

  for_vector(ArgSymbol, other, notAliasingThese) {
    c->insertAtTail(new SymExpr(other));
  }
void ResolutionCandidate::resolveTypeConstructor(CallInfo& info) {
  SET_LINENO(fn);

  // Ignore tuple constructors; they were generated
  // with their type constructors.
  if (fn->hasFlag(FLAG_PARTIAL_TUPLE) == false) {
    CallExpr* typeConstructorCall = new CallExpr(astr("_type", fn->name));

    for_formals(formal, fn) {
      if (formal->hasFlag(FLAG_IS_MEME) == false) {
        if (fn->_this->type->symbol->hasFlag(FLAG_TUPLE)) {
          if (formal->instantiatedFrom != NULL) {
            typeConstructorCall->insertAtTail(formal->type->symbol);

          } else if (formal->hasFlag(FLAG_INSTANTIATED_PARAM)) {
            typeConstructorCall->insertAtTail(paramMap.get(formal));
          }

        } else {
          if (strcmp(formal->name, "outer") == 0 ||
              formal->type                  == dtMethodToken) {
            typeConstructorCall->insertAtTail(formal);

          } else if (formal->instantiatedFrom != NULL) {
            SymExpr*   se = new SymExpr(formal->type->symbol);
            NamedExpr* ne = new NamedExpr(formal->name, se);

            typeConstructorCall->insertAtTail(ne);

          } else if (formal->hasFlag(FLAG_INSTANTIATED_PARAM)) {
            SymExpr*   se = new SymExpr(paramMap.get(formal));
            NamedExpr* ne = new NamedExpr(formal->name, se);

            typeConstructorCall->insertAtTail(ne);
          }
        }
      }
    }

    info.call->insertBefore(typeConstructorCall);

    // If instead we call resolveCallAndCallee(typeConstructorCall)
    // then the line number reported in an error would change
    // e.g.: domains/deitz/test_generic_class_of_sparse_domain
    // or:   classes/diten/multipledestructor
    resolveCall(typeConstructorCall);

    INT_ASSERT(typeConstructorCall->isResolved());

    resolveFunction(typeConstructorCall->resolvedFunction());

    fn->_this->type = typeConstructorCall->resolvedFunction()->retType;

    typeConstructorCall->remove();
  }
Exemple #18
0
/// Build calls to await_ready, await_suspend, and await_resume for a co_await
/// expression.
static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
                                                  SourceLocation Loc, Expr *E) {
  OpaqueValueExpr *Operand = new (S.Context)
      OpaqueValueExpr(Loc, E->getType(), VK_LValue, E->getObjectKind(), E);

  // Assume invalid until we see otherwise.
  ReadySuspendResumeResult Calls = {{}, Operand, /*IsInvalid=*/true};

  ExprResult CoroHandleRes = buildCoroutineHandle(S, CoroPromise->getType(), Loc);
  if (CoroHandleRes.isInvalid())
    return Calls;
  Expr *CoroHandle = CoroHandleRes.get();

  const StringRef Funcs[] = {"await_ready", "await_suspend", "await_resume"};
  MultiExprArg Args[] = {None, CoroHandle, None};
  for (size_t I = 0, N = llvm::array_lengthof(Funcs); I != N; ++I) {
    ExprResult Result = buildMemberCall(S, Operand, Loc, Funcs[I], Args[I]);
    if (Result.isInvalid())
      return Calls;
    Calls.Results[I] = Result.get();
  }

  // Assume the calls are valid; all further checking should make them invalid.
  Calls.IsInvalid = false;

  using ACT = ReadySuspendResumeResult::AwaitCallType;
  CallExpr *AwaitReady = cast<CallExpr>(Calls.Results[ACT::ACT_Ready]);
  if (!AwaitReady->getType()->isDependentType()) {
    // [expr.await]p3 [...]
    // — await-ready is the expression e.await_ready(), contextually converted
    // to bool.
    ExprResult Conv = S.PerformContextuallyConvertToBool(AwaitReady);
    if (Conv.isInvalid()) {
      S.Diag(AwaitReady->getDirectCallee()->getLocStart(),
             diag::note_await_ready_no_bool_conversion);
      S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
          << AwaitReady->getDirectCallee() << E->getSourceRange();
      Calls.IsInvalid = true;
    }
    Calls.Results[ACT::ACT_Ready] = Conv.get();
  }
  CallExpr *AwaitSuspend = cast<CallExpr>(Calls.Results[ACT::ACT_Suspend]);
  if (!AwaitSuspend->getType()->isDependentType()) {
    // [expr.await]p3 [...]
    //   - await-suspend is the expression e.await_suspend(h), which shall be
    //     a prvalue of type void or bool.
    QualType RetType = AwaitSuspend->getType();
    if (RetType != S.Context.BoolTy && RetType != S.Context.VoidTy) {
      S.Diag(AwaitSuspend->getCalleeDecl()->getLocation(),
             diag::err_await_suspend_invalid_return_type)
          << RetType;
      S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
          << AwaitSuspend->getDirectCallee();
      Calls.IsInvalid = true;
    }
  }

  return Calls;
}
Exemple #19
0
C2::ExprResult C2Sema::ActOnCallExpr(Expr* Fn, Expr** args, unsigned numArgs, SourceLocation RParenLoc) {
#ifdef SEMA_DEBUG
    std::cerr << COL_SEMA"SEMA: call to " << "TODO Fn" << " at " << "TODO Fn";
    //expr2loc(Fn).dump(SourceMgr);
    std::cerr << ANSI_NORMAL"\n";
#endif
    CallExpr* call = new CallExpr(Fn, RParenLoc);
    assert(call);
    for (unsigned i=0; i<numArgs; i++) call->addArg(args[i]);
    return ExprResult(call);
}
Exemple #20
0
void printCallStackCalls() {
  printf("\n" "callStack %d elms\n\n", callStack.n);
  for (int i = 0; i < callStack.n; i++) {
    CallExpr* call = callStack.v[i];
    FnSymbol* cfn = call->isResolved();
    printf("%d  %d %s  <-  %d %s\n", i,
           cfn ? cfn->id : 0, cfn ? cfn->name: "<no callee>",
           call ? call->id : 0, call ? call->stringLoc() : "<no call>");
  }
  printf("\n");
}
void ReturnByRef::insertAssignmentToFormal(FnSymbol* fn, ArgSymbol* formal)
{
  Expr*     returnPrim  = fn->body->body.tail;

  SET_LINENO(returnPrim);

  CallExpr* returnCall  = toCallExpr(returnPrim);
  Expr*     returnValue = returnCall->get(1)->remove();
  CallExpr* moveExpr    = new CallExpr(PRIM_MOVE, formal, returnValue);

  returnPrim->insertBefore(moveExpr);
}
Exemple #22
0
void Inliner::VisitBinaryOperator(BinaryOperator * node) {
    Expr * lhs = node->getLHS(), * rhs = node->getRHS();
    CallExpr * call = dyn_cast<CallExpr>(rhs);
    if (call && call->getDirectCallee()->isThisDeclarationADefinition()) { // replace: x = foo(y); with: /*x = */ { //inlined foo }
        Rewriter &rewriter = (current_func_->isMain()) ? main_rewriter_ : rewriter_;
        rewriter.InsertText(lhs->getLocStart(),"/*");
        rewriter.InsertText(rhs->getLocStart(),"*/"); 
    }
    return_vars_.push_back(Utils::PrintStmt(lhs,contex_));
    VisitChildren(node);
    return_vars_.pop_back();
}
Exemple #23
0
void localizeGlobals() {
  if (fNoGlobalConstOpt) return;
  forv_Vec(FnSymbol, fn, gFnSymbols) {
    Map<Symbol*,VarSymbol*> globals;
    std::vector<BaseAST*> asts;
    collect_asts(fn->body, asts);
    for_vector(BaseAST, ast, asts) {
      if (SymExpr* se = toSymExpr(ast)) {
        Symbol* var = se->symbol();
        ModuleSymbol* parentmod = toModuleSymbol(var->defPoint->parentSymbol);
        CallExpr* parentExpr = toCallExpr(se->parentExpr);
        bool inAddrOf = parentExpr && parentExpr->isPrimitive(PRIM_ADDR_OF);
        bool lhsOfMove = parentExpr && isMoveOrAssign(parentExpr) && (parentExpr->get(1) == se);

        // Is var a global constant?
        // Don't replace the var name in its init function since that's
        //      where we're setting the value. Similarly, dont replace them
        //      inside initStringLiterals
        // If the parentSymbol is the rootModule, the var is 'void,'
        //      'false,' '0,' ...
        // Also don't replace it when it's in an addr of primitive.
        if (parentmod &&
            fn != parentmod->initFn &&
            fn != initStringLiterals &&
            !inAddrOf &&
            !lhsOfMove &&
            var->hasFlag(FLAG_CONST) &&
            var->defPoint->parentSymbol != rootModule) {
          VarSymbol* local_global = globals.get(var);
          SET_LINENO(se); // Set the se line number for output
          if (!local_global) {
            const char * newname = astr("local_", var->cname);
            local_global = newTemp(newname, var->type);
            fn->insertAtHead(new CallExpr(PRIM_MOVE, local_global, var));
            fn->insertAtHead(new DefExpr(local_global));

            // Copy string immediates to localized strings so that
            // we can show the string value in comments next to uses.
            if (!llvmCodegen)
              if (VarSymbol* localVarSym = toVarSymbol(var))
                if (Immediate* immediate = localVarSym->immediate)
                  if (immediate->const_kind == CONST_KIND_STRING)
                    local_global->immediate =
                      new Immediate(immediate->v_string, immediate->string_kind);

            globals.put(var, local_global);
          }
          se->replace(new SymExpr(toSymbol(local_global)));
        }
      }
    }
  }
void QStringAllocations::VisitFromLatin1OrUtf8(Stmt *stmt)
{
    CallExpr *callExpr = dyn_cast<CallExpr>(stmt);
    if (!callExpr)
        return;

    FunctionDecl *functionDecl = callExpr->getDirectCallee();
    if (!StringUtils::functionIsOneOf(functionDecl, {"fromLatin1", "fromUtf8"}))
        return;

    CXXMethodDecl *methodDecl = dyn_cast<CXXMethodDecl>(functionDecl);
    if (!StringUtils::isOfClass(methodDecl, "QString"))
        return;

    if (!Utils::callHasDefaultArguments(callExpr) || !hasCharPtrArgument(functionDecl, 2)) // QString::fromLatin1("foo", 1) is ok
        return;

    if (!containsStringLiteralNoCallExpr(callExpr))
        return;

    if (!isOptionSet("no-msvc-compat")) {
        StringLiteral *lt = stringLiteralForCall(callExpr);
        if (lt && lt->getNumConcatenated() > 1) {
            return; // Nothing to do here, MSVC doesn't like it
        }
    }

    vector<ConditionalOperator*> ternaries;
    HierarchyUtils::getChilds(callExpr, ternaries, 2);
    if (!ternaries.empty()) {
        auto ternary = ternaries[0];
        if (Utils::ternaryOperatorIsOfStringLiteral(ternary)) {
            emitWarning(stmt->getLocStart(), string("QString::fromLatin1() being passed a literal"));
        }

        return;
    }

    std::vector<FixItHint> fixits;

    if (isFixitEnabled(FromLatin1_FromUtf8Allocations)) {
        const FromFunction fromFunction = functionDecl->getNameAsString() == "fromLatin1" ? FromLatin1 : FromUtf8;
        fixits = fixItReplaceFromLatin1OrFromUtf8(callExpr, fromFunction);
    }

    if (functionDecl->getNameAsString() == "fromLatin1") {
        emitWarning(stmt->getLocStart(), string("QString::fromLatin1() being passed a literal"), fixits);
    } else {
        emitWarning(stmt->getLocStart(), string("QString::fromUtf8() being passed a literal"), fixits);
    }
}
Exemple #25
0
static bool
removeIdentityDefs(Symbol* sym) {
  bool change = false;

  for_defs(def, defMap, sym) {
    CallExpr* move = toCallExpr(def->parentExpr);
    if (move && isMoveOrAssign(move)) {
      SymExpr* rhs = toSymExpr(move->get(2));
      if (rhs && def->symbol() == rhs->symbol()) {
        move->remove();
        change = true;
      }
    }
  }
Exemple #26
0
static bool
removeIdentityDefs(Symbol* sym) {
  bool change = false;

  for_defs(def, defMap, sym) {
    CallExpr* move = toCallExpr(def->parentExpr);
    if (move && move->isPrimitive(PRIM_MOVE)) {
      SymExpr* rhs = toSymExpr(move->get(2));
      if (rhs && def->var == rhs->var) {
        move->remove();
        change = true;
      }
    }
  }
//
// Do a breadth first search starting from functions generated for local blocks
// for all function calls in each level of the search, if they directly cause
// communication, add a local temp that isn't wide. If it is a resolved call,
// meaning that it isn't a primitive or external function, clone it and add it
// to the queue of functions to handle at the next iteration of the BFS.
//
static void handleLocalBlocks() {
  Map<FnSymbol*,FnSymbol*> cache; // cache of localized functions
  Vec<BlockStmt*> queue; // queue of blocks to localize

  forv_Vec(BlockStmt, block, gBlockStmts) {
    if (block->parentSymbol) {
      // NOAKES 2014/11/25 Transitional.  Avoid calling blockInfoGet()
      if (block->isLoopStmt() == true) {

      } else if (block->blockInfoGet()) {
        if (block->blockInfoGet()->isPrimitive(PRIM_BLOCK_LOCAL)) {
          queue.add(block);
        }
      }
    }
  }

  forv_Vec(BlockStmt, block, queue) {
    std::vector<CallExpr*> calls;
    collectCallExprs(block, calls);
    for_vector(CallExpr, call, calls) {
      localizeCall(call);
      if (FnSymbol* fn = call->isResolved()) {
        SET_LINENO(fn);
        if (FnSymbol* alreadyLocal = cache.get(fn)) {
          call->baseExpr->replace(new SymExpr(alreadyLocal));
        } else {
          if (!fn->hasFlag(FLAG_EXTERN)) {
            FnSymbol* local = fn->copy();
            local->addFlag(FLAG_LOCAL_FN);
            local->name = astr("_local_", fn->name);
            local->cname = astr("_local_", fn->cname);
            fn->defPoint->insertBefore(new DefExpr(local));
            call->baseExpr->replace(new SymExpr(local));
            queue.add(local->body);
            cache.put(fn, local);
            cache.put(local, local); // to handle recursion
            if (local->retType->symbol->hasFlag(FLAG_WIDE_REF)) {
              CallExpr* ret = toCallExpr(local->body->body.tail);
              INT_ASSERT(ret && ret->isPrimitive(PRIM_RETURN));
              // Capture the return expression in a local temp.
              insertLocalTemp(ret->get(1));
              local->retType = ret->get(1)->typeInfo();
            }
          }
        }
      }
    }
Exemple #28
0
// true for: QString::fromLatin1().arg()
// false for: QString::fromLatin1("")
// true for: QString s = QString::fromLatin1("foo")
// false for: s += QString::fromLatin1("foo"), etc.
static bool isQStringLiteralCandidate(Stmt *s, ParentMap *map, const LangOptions &lo,
                                      const SourceManager &sm , int currentCall = 0)
{
    if (!s)
        return false;

    MemberExpr *memberExpr = dyn_cast<MemberExpr>(s);
    if (memberExpr)
        return true;

    auto constructExpr = dyn_cast<CXXConstructExpr>(s);
    if (StringUtils::isOfClass(constructExpr, "QString"))
        return true;

    if (Utils::isAssignOperator(dyn_cast<CXXOperatorCallExpr>(s), "QString", "QLatin1String", lo))
        return true;

    if (Utils::isAssignOperator(dyn_cast<CXXOperatorCallExpr>(s), "QString", "QString", lo))
        return true;

    CallExpr *callExpr = dyn_cast<CallExpr>(s);
    StringLiteral *literal = stringLiteralForCall(callExpr);
    auto operatorCall = dyn_cast<CXXOperatorCallExpr>(s);
    if (operatorCall && StringUtils::returnTypeName(operatorCall, lo) != "QTestData") {
        // QTest::newRow will static_assert when using QLatin1String
        // Q_STATIC_ASSERT_X(QMetaTypeId2<T>::Defined, "Type is not registered, please use the Q_DECLARE_METATYPE macro to make it known to Qt's meta-object system");

        string className = StringUtils::classNameFor(operatorCall);
        if (className == "QString") {
            return false;
        } else if (className.empty() && StringUtils::hasArgumentOfType(operatorCall->getDirectCallee(), "QString", lo)) {
            return false;
        }
    }

    if (currentCall > 0 && callExpr) {
        auto fDecl = callExpr->getDirectCallee();
        if (fDecl && betterTakeQLatin1String(dyn_cast<CXXMethodDecl>(fDecl), literal))
            return false;

        return true;
    }

    if (currentCall == 0 || dyn_cast<ImplicitCastExpr>(s) || dyn_cast<CXXBindTemporaryExpr>(s) || dyn_cast<MaterializeTemporaryExpr>(s)) // skip this cruft
        return isQStringLiteralCandidate(HierarchyUtils::parent(map, s), map, lo, sm, currentCall + 1);

    return false;
}
//
// Find the _waitEndCount and _endCountFree calls that comes after 'fromHere'.
// Since these two calls come together, it is prettier to insert
// our stuff after the latter.
//
static Expr* findTailInsertionPoint(Expr* fromHere, bool isCoforall) {
  Expr* curr = fromHere;
  if (isCoforall) curr = curr->parentExpr;
  CallExpr* result = NULL;
  while ((curr = curr->next)) {
    if (CallExpr* call = toCallExpr(curr))
      if (call->isNamed("_waitEndCount")) {
        result = call;
        break;
      }
  }
  INT_ASSERT(result);
  CallExpr* freeEC = toCallExpr(result->next);
  // Currently these two calls come together.
  INT_ASSERT(freeEC && freeEC->isNamed("_endCountFree"));
  return freeEC;
}
Exemple #30
0
//
// Print the module name, line number, and function signature of each function
// on the call stack. This can be called from a debugger to to see what the
// call chain looks like e.g. after a resolution error.
//
void printCallStack(bool force, bool shortModule, FILE* out) {
  if (!force) {
    if (!fPrintCallStackOnError || err_print || callStack.n <= 1)
      return;
  }
  if (!developer)
    fprintf(out, "while processing the following Chapel call chain:\n");
  for (int i = callStack.n-1; i >= 0; i--) {
    CallExpr* call = callStack.v[i];
    FnSymbol* fn = call->getFunction();
    ModuleSymbol* module = call->getModule();
    fprintf(out, "  %s:%d: %s%s%s\n",
            (shortModule ? module->name : cleanFilename(fn->fname())),
            call->linenum(), toString(fn),
            (module->modTag == MOD_INTERNAL ? " [internal module]" : ""),
            (fn->hasFlag(FLAG_COMPILER_GENERATED) ? " [compiler-generated]" : ""));
  }
}