void FunctionScope::outputCPPArguments(ExpressionListPtr params, CodeGenerator &cg, AnalysisResultPtr ar, int extraArg, bool variableArgument, int extraArgArrayId /* = -1 */) { int paramCount = params ? params->getOutputCount() : 0; ASSERT(extraArg <= paramCount); int iMax = paramCount - extraArg; bool extra = false; if (variableArgument) { if (paramCount == 0) { cg.printf("0"); } else { cg.printf("%d, ", paramCount); } } int firstExtra = 0; for (int i = 0; i < paramCount; i++) { ExpressionPtr param = (*params)[i]; cg.setItemIndex(i); if (i > 0) cg.printf(extra ? "." : ", "); if (!extra && (i == iMax || extraArg < 0)) { if (extraArgArrayId != -1) { if (cg.getOutput() == CodeGenerator::SystemCPP) { cg.printf("SystemScalarArrays::%s[%d]", Option::SystemScalarArrayName, extraArgArrayId); } else { cg.printf("ScalarArrays::%s[%d]", Option::ScalarArrayName, extraArgArrayId); } break; } extra = true; // Parameter arrays are always vectors. cg.printf("Array(ArrayInit(%d, true).", paramCount - i); firstExtra = i; } if (extra) { bool needRef = param->hasContext(Expression::RefValue) && !param->hasContext(Expression::NoRefWrapper) && param->isRefable(); cg.printf("set%s(%d, ", needRef ? "Ref" : "", i - firstExtra); if (needRef) { // The parameter itself shouldn't be wrapped with ref() any more. param->setContext(Expression::NoRefWrapper); } param->outputCPP(cg, ar); cg.printf(")"); } else { param->outputCPP(cg, ar); } } if (extra) { cg.printf(".create())"); } }
void ExpressionList::markParam(int p) { ExpressionPtr param = (*this)[p]; if (param->hasContext(Expression::InvokeArgument)) { } else if (!param->hasContext(Expression::RefParameter)) { param->setContext(Expression::InvokeArgument); param->setContext(Expression::RefValue); } param->setArgNum(p); }
void FunctionCall::markRefParams(FunctionScopePtr func, const std::string &fooBarName) { ExpressionList ¶ms = *m_params; if (func) { int mpc = func->getMaxParamCount(); for (int i = params.getCount(); i--; ) { ExpressionPtr p = params[i]; if (i < mpc ? func->isRefParam(i) : func->isReferenceVariableArgument()) { p->setContext(Expression::RefValue); } else if (i < mpc && p->hasContext(RefParameter)) { Symbol *sym = func->getVariables()->addSymbol(func->getParamName(i)); sym->setLvalParam(); sym->setCallTimeRef(); } } } else if (Option::WholeProgram && !m_origName.empty()) { FunctionScope::FunctionInfoPtr info = FunctionScope::GetFunctionInfo(m_origName); if (info) { for (int i = params.getCount(); i--; ) { if (info->isRefParam(i)) { m_params->markParam(i); } } } // If we cannot find information of the so-named function, it might not // exist, or it might go through __call(), either of which cannot have // reference parameters. } else { for (int i = params.getCount(); i--; ) { m_params->markParam(i); } } }
void ExpressionList::markParam(int p, bool noRefWrapper) { ExpressionPtr param = (*this)[p]; if (param->hasContext(Expression::InvokeArgument)) { if (noRefWrapper) { param->setContext(Expression::NoRefWrapper); } else { param->clearContext(Expression::NoRefWrapper); } } else if (!param->hasContext(Expression::RefValue)) { param->setContext(Expression::InvokeArgument); param->setContext(Expression::RefValue); if (noRefWrapper) { param->setContext(Expression::NoRefWrapper); } } }
void DataFlowWalker::process(ExpressionPtr e, bool doAccessChains) { if ((e->getContext() & (Expression::AssignmentLHS|Expression::OprLValue)) || (!doAccessChains && e->hasContext(Expression::AccessContext))) { return; } switch (e->getKindOf()) { case Expression::KindOfListAssignment: processAccessChainLA(static_pointer_cast<ListAssignment>(e)); processAccess(e); break; case Expression::KindOfArrayElementExpression: case Expression::KindOfObjectPropertyExpression: if (!e->hasContext(Expression::AccessContext)) { processAccessChain(e); } // fall through case Expression::KindOfObjectMethodExpression: case Expression::KindOfDynamicFunctionCall: case Expression::KindOfSimpleFunctionCall: case Expression::KindOfNewObjectExpression: case Expression::KindOfIncludeExpression: case Expression::KindOfSimpleVariable: case Expression::KindOfDynamicVariable: case Expression::KindOfStaticMemberExpression: case Expression::KindOfConstantExpression: processAccess(e); break; case Expression::KindOfAssignmentExpression: case Expression::KindOfBinaryOpExpression: case Expression::KindOfUnaryOpExpression: { ExpressionPtr var = e->getStoreVariable(); if (var && var->getContext() & (Expression::AssignmentLHS| Expression::OprLValue)) { processAccessChain(var); processAccess(var); } // fall through } default: processAccess(e); break; } }
void ExpressionList::outputCodeModel(CodeGenerator &cg) { for (unsigned int i = 0; i < m_exps.size(); i++) { ExpressionPtr exp = m_exps[i]; if (exp) { cg.printExpression(exp, exp->hasContext(RefParameter)); } else { cg.printNull(); } } }
Expression::ExprClass Expression::getExprClass() const { assert(m_kindOf > Construct::KindOfExpression); auto const idx = static_cast<int32_t>(m_kindOf) - static_cast<int32_t>(Construct::KindOfExpression); assert(idx > 0); ExprClass cls = Classes[idx]; if (cls == Update) { ExpressionPtr k = getStoreVariable(); if (!k || !(k->hasContext(OprLValue))) cls = Expression::None; } return cls; }
void ExpressionList::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) { for (unsigned int i = 0; i < m_exps.size(); i++) { if (i > 0) cg_printf(", "); ExpressionPtr exp = m_exps[i]; if (exp) { if (exp->hasContext(RefParameter)) { cg_printf("&"); } exp->outputPHP(cg, ar); } } }
bool ExpressionList::hasNonArrayCreateValue( bool arrayElements /* = true */, unsigned int start /* = 0 */) const { for (unsigned int i = start; i < m_exps.size(); i++) { ExpressionPtr value = m_exps[i]; if (arrayElements) { ArrayPairExpressionPtr ap = dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]); value = ap->getValue(); } ASSERT(value); if (value->hasContext(RefValue)) { return true; } } return false; }
void FunctionCall::checkUnpackParams() { if (!m_params) { return; } ExpressionList ¶ms = *m_params; const auto numParams = params.getCount(); // when supporting multiple unpacks at the end of the param list, this // will need to disallow transitions from unpack to non-unpack. for (int i = 0; i < (numParams - 1); ++i) { ExpressionPtr p = params[i]; if (p->hasContext(Expression::UnpackParameter)) { parseTimeFatal( Compiler::NoError, "Only the last parameter in a function call is allowed to use ..."); } } }
static int cloneStmtsForInline(InlineCloneInfo &info, StatementPtr s, const std::string &prefix, AnalysisResultConstPtr ar, FunctionScopePtr scope) { switch (s->getKindOf()) { case Statement::KindOfStatementList: { for (int i = 0, n = s->getKidCount(); i < n; ++i) { if (int ret = cloneStmtsForInline(info, s->getNthStmt(i), prefix, ar, scope)) { return ret; } } return 0; } case Statement::KindOfExpStatement: info.elist->addElement(cloneForInline( info, dynamic_pointer_cast<ExpStatement>(s)-> getExpression(), prefix, ar, scope)); return 0; case Statement::KindOfReturnStatement: { ExpressionPtr exp = dynamic_pointer_cast<ReturnStatement>(s)->getRetExp(); if (exp) { exp = cloneForInline(info, exp, prefix, ar, scope); if (exp->hasContext(Expression::RefValue)) { exp->clearContext(Expression::RefValue); if (exp->isRefable()) exp->setContext(Expression::LValue); } info.elist->addElement(exp); return 1; } return -1; } default: not_reached(); } return 1; }
static void outputStringExpr(CodeGenerator &cg, AnalysisResultPtr ar, ExpressionPtr exp, bool asLitStr) { if (asLitStr && exp->isLiteralString()) { const std::string &s = exp->getLiteralString(); char *enc = string_cplus_escape(s.c_str(), s.size()); cg_printf("\"%s\", %d", enc, s.size()); free(enc); return; } bool close = false; if ((exp->hasContext(Expression::LValue) && (!exp->getActualType()->is(Type::KindOfString) || (exp->getImplementedType() && !exp->getImplementedType()->is(Type::KindOfString)))) || !exp->getType()->is(Type::KindOfString)) { cg_printf("toString("); close = true; } exp->outputCPP(cg, ar); if (close) cg_printf(")"); }
ExpressionPtr FunctionCall::inliner(AnalysisResultConstPtr ar, ExpressionPtr obj, std::string localThis) { FunctionScopePtr fs = getFunctionScope(); if (m_noInline || !fs || fs == m_funcScope || !m_funcScope->getStmt()) { return ExpressionPtr(); } BlockScope::s_jobStateMutex.lock(); if (m_funcScope->getMark() == BlockScope::MarkProcessing) { fs->setForceRerun(true); BlockScope::s_jobStateMutex.unlock(); return ExpressionPtr(); } ReadLock lock(m_funcScope->getInlineMutex()); BlockScope::s_jobStateMutex.unlock(); if (!m_funcScope->getInlineAsExpr()) { return ExpressionPtr(); } if (m_funcScope->getInlineSameContext() && m_funcScope->getContainingClass() && m_funcScope->getContainingClass() != getClassScope()) { /* The function contains a context sensitive construct such as call_user_func (context sensitive because it could call array('parent', 'foo')) so its not safe to inline it into a different context. */ return ExpressionPtr(); } MethodStatementPtr m (dynamic_pointer_cast<MethodStatement>(m_funcScope->getStmt())); VariableTablePtr vt = fs->getVariables(); int nAct = m_params ? m_params->getCount() : 0; int nMax = m_funcScope->getMaxParamCount(); if (nAct < m_funcScope->getMinParamCount() || !m->getStmts()) { return ExpressionPtr(); } InlineCloneInfo info(m_funcScope); info.elist = ExpressionListPtr(new ExpressionList( getScope(), getLocation(), ExpressionList::ListKindWrapped)); std::ostringstream oss; oss << fs->nextInlineIndex() << "_" << m_name << "_"; std::string prefix = oss.str(); if (obj) { info.callWithThis = true; if (!obj->isThis()) { SimpleVariablePtr var (new SimpleVariable(getScope(), obj->getLocation(), prefix + "this")); var->updateSymbol(SimpleVariablePtr()); var->getSymbol()->setHidden(); var->getSymbol()->setUsed(); var->getSymbol()->setReferenced(); AssignmentExpressionPtr ae (new AssignmentExpression(getScope(), obj->getLocation(), var, obj, false)); info.elist->addElement(ae); info.sepm[var->getName()] = var; info.localThis = var->getName(); } } else { if (m_classScope) { if (!m_funcScope->isStatic()) { ClassScopeRawPtr oCls = getOriginalClass(); FunctionScopeRawPtr oFunc = getOriginalFunction(); if (oCls && !oFunc->isStatic() && (oCls == m_classScope || oCls->derivesFrom(ar, m_className, true, false))) { info.callWithThis = true; info.localThis = localThis; } } if (!isSelf() && !isParent() && !isStatic()) { info.staticClass = m_className; } } } ExpressionListPtr plist = m->getParams(); int i; for (i = 0; i < nMax || i < nAct; i++) { ParameterExpressionPtr param (i < nMax ? dynamic_pointer_cast<ParameterExpression>((*plist)[i]) : ParameterExpressionPtr()); ExpressionPtr arg = i < nAct ? (*m_params)[i] : Clone(param->defaultValue(), getScope()); SimpleVariablePtr var (new SimpleVariable(getScope(), (i < nAct ? arg.get() : this)->getLocation(), prefix + (param ? param->getName() : lexical_cast<string>(i)))); var->updateSymbol(SimpleVariablePtr()); var->getSymbol()->setHidden(); var->getSymbol()->setUsed(); var->getSymbol()->setReferenced(); bool ref = (i < nMax && m_funcScope->isRefParam(i)) || arg->hasContext(RefParameter); arg->clearContext(RefParameter); AssignmentExpressionPtr ae (new AssignmentExpression(getScope(), arg->getLocation(), var, arg, ref)); info.elist->addElement(ae); if (i < nAct && (ref || !arg->isScalar())) { info.sepm[var->getName()] = var; } } if (cloneStmtsForInline(info, m->getStmts(), prefix, ar, getFunctionScope()) <= 0) { info.elist->addElement(makeConstant(ar, "null")); } if (info.sepm.size()) { ExpressionListPtr unset_list (new ExpressionList(getScope(), getLocation())); for (StringToExpressionPtrMap::iterator it = info.sepm.begin(), end = info.sepm.end(); it != end; ++it) { ExpressionPtr var = it->second->clone(); var->clearContext((Context)(unsigned)-1); unset_list->addElement(var); } ExpressionPtr unset( new UnaryOpExpression(getScope(), getLocation(), unset_list, T_UNSET, true)); i = info.elist->getCount(); ExpressionPtr ret = (*info.elist)[--i]; if (ret->isScalar()) { info.elist->insertElement(unset, i); } else { ExpressionListPtr result_list (new ExpressionList(getScope(), getLocation(), ExpressionList::ListKindLeft)); if (ret->hasContext(LValue)) { result_list->setContext(LValue); result_list->setContext(ReturnContext); } result_list->addElement(ret); result_list->addElement(unset); (*info.elist)[i] = result_list; } } recomputeEffects(); return replaceValue(info.elist); }
int FunctionScope::inferParamTypes(AnalysisResultPtr ar, ConstructPtr exp, ExpressionListPtr params, bool &valid) { if (!params) { if (m_minParam > 0) { if (exp->getScope()->isFirstPass()) { Compiler::Error(Compiler::TooFewArgument, exp, m_stmt); } valid = false; if (!Option::AllDynamic) setDynamic(); } return 0; } int ret = 0; if (params->getCount() < m_minParam) { if (exp->getScope()->isFirstPass()) { Compiler::Error(Compiler::TooFewArgument, exp, m_stmt); } valid = false; if (!Option::AllDynamic) setDynamic(); } if (params->getCount() > m_maxParam) { if (isVariableArgument()) { ret = params->getCount() - m_maxParam; } else { if (exp->getScope()->isFirstPass()) { Compiler::Error(Compiler::TooManyArgument, exp, m_stmt); } valid = false; if (!Option::AllDynamic) setDynamic(); } } bool canSetParamType = isUserFunction() && !m_overriding && !m_perfectVirtual; for (int i = 0; i < params->getCount(); i++) { ExpressionPtr param = (*params)[i]; if (i < m_maxParam && param->hasContext(Expression::RefParameter)) { /** * This should be very un-likely, since call time pass by ref is a * deprecated, not very widely used (at least in FB codebase) feature. */ TRY_LOCK_THIS(); Symbol *sym = getVariables()->addSymbol(m_paramNames[i]); sym->setLvalParam(); sym->setCallTimeRef(); } if (valid && param->hasContext(Expression::InvokeArgument)) { param->clearContext(Expression::InvokeArgument); param->clearContext(Expression::RefValue); param->clearContext(Expression::NoRefWrapper); } bool isRefVararg = (i >= m_maxParam && isReferenceVariableArgument()); if ((i < m_maxParam && isRefParam(i)) || isRefVararg) { param->setContext(Expression::LValue); param->setContext(Expression::RefValue); param->inferAndCheck(ar, Type::Variant, true); } else if (!(param->getContext() & Expression::RefParameter)) { param->clearContext(Expression::LValue); param->clearContext(Expression::RefValue); param->clearContext(Expression::InvokeArgument); param->clearContext(Expression::NoRefWrapper); } TypePtr expType; /** * Duplicate the logic of getParamType(i), w/o the mutation */ TypePtr paramType(i < m_maxParam && !isZendParamMode() ? m_paramTypes[i] : TypePtr()); if (!paramType) paramType = Type::Some; if (valid && !canSetParamType && i < m_maxParam && (!Option::HardTypeHints || !m_paramTypeSpecs[i])) { /** * What is this magic, you might ask? * * Here, we take advantage of implicit conversion from every type to * Variant. Essentially, we don't really care what type comes out of this * expression since it'll just get converted anyways. Doing it this way * allows us to generate less temporaries along the way. */ TypePtr optParamType(paramType->is(Type::KindOfVariant) ? Type::Some : paramType); expType = param->inferAndCheck(ar, optParamType, false); } else { expType = param->inferAndCheck(ar, Type::Some, false); } if (i < m_maxParam) { if (!Option::HardTypeHints || !m_paramTypeSpecs[i]) { if (canSetParamType) { if (!Type::SameType(paramType, expType) && !paramType->is(Type::KindOfVariant)) { TRY_LOCK_THIS(); paramType = setParamType(ar, i, expType); } else { // do nothing - how is this safe? well, if we ever observe // paramType == expType, then this means at some point in the past, // somebody called setParamType() with expType. thus, by calling // setParamType() again with expType, we contribute no "new" // information. this argument also still applies in the face of // concurrency } } // See note above. If we have an implemented type, however, we // should set the paramType to the implemented type to avoid an // un-necessary cast if (paramType->is(Type::KindOfVariant)) { TypePtr it(param->getImplementedType()); paramType = it ? it : expType; } if (valid) { if (!Type::IsLegalCast(ar, expType, paramType) && paramType->isNonConvertibleType()) { param->inferAndCheck(ar, paramType, true); } param->setExpectedType(paramType); } } } // we do a best-effort check for bad pass-by-reference and do not report // error for some vararg case (e.g., array_multisort can have either ref // or value for the same vararg). if (!isRefVararg || !isMixedVariableArgument()) { Expression::CheckPassByReference(ar, param); } } return ret; }
void ExprDict::updateAccess(ExpressionPtr e) { int cls = e->getExprClass(); int eid = e->getCanonID(); e->clearAnticipated(); e->clearAvailable(); // bail on non-canonical expressions if (!isCanonicalStructure(eid)) { // but record we saw a type assertion belonging to this block m_avlTypeAsserts.push_back(eid); return; } if (m_anticipated && (cls & Expression::Update ? !BitOps::get_bit(eid, m_altered) : !e->getLocalEffects())) { /* Anticipated can be computed bottom up as we go. But note that we only know altered for Load/Store expressions. */ int i = e->getKidCount(); while (true) { if (!i--) { e->setAnticipated(); if (!e->hasContext(Expression::AssignmentLHS)) { setStructureOps(eid, m_anticipated, true); } break; } if (ExpressionPtr k = e->getNthExpr(i)) { if (!isCanonicalStructure(k->getCanonID())) continue; if (!k->isAnticipated()) { break; } } } } if (m_available) { /* Available has to be computed optimistically, because we dont yet know what is going to be altered between here and the end of the block So keep a list of the potentially-available accesses (avlAccess), and for each id, the last potentially-available expression (avlExpr). For each modifying expression that we process, we remove expressions from avlAccess, and at the end, we build up the available expressions bottom up. */ if ((cls & (Expression::Store|Expression::Call)) || (cls & Expression::Load && e->getContext() & (Expression::LValue| Expression::RefValue| Expression::UnsetContext| Expression::DeepReference))) { bool isLoad; int depth = 0, effects = 0; for (int i = 0, n = m_avlAccess.size(); i < n; ) { ExpressionRawPtr a = m_avlAccess[i]; if (m_am.checkAnyInterf(e, a, isLoad, depth, effects) != AliasManager::DisjointAccess) { int aid = a->getCanonID(); assert(isCanonicalStructure(aid)); if (eid != aid || cls == Expression::Load) { BitOps::set_bit(aid, m_altered, true); } if (!(cls & Expression::Store) || a != e->getStoreVariable()) { a->clearAvailable(); m_avlAccess[i] = m_avlAccess[--n]; m_avlAccess.resize(n); continue; } } i++; } } if (cls & Expression::Update || !e->getContainedEffects()) { int i = e->getKidCount(); while (true) { if (!i--) { e->setAvailable(); if (cls & Expression::Update) { m_avlAccess.push_back(e); } m_avlExpr[eid] = e; break; } if (ExpressionPtr k = e->getNthExpr(i)) { if (!isCanonicalStructure(k->getCanonID())) continue; if (!k->isAvailable()) { break; } } } } } if ((cls & (Expression::Store|Expression::Call)) || (cls & Expression::Load && e->getContext() & (Expression::LValue| Expression::RefValue| Expression::UnsetContext| Expression::DeepReference))) { ExpressionPtr cur = m_active, prev; bool isLoad; int depth = 0, effects = 0; while (cur) { ExpressionPtr next = cur->getCanonLVal(); int cid = cur->getCanonID(); assert(isCanonicalStructure(cid)); if ((cid != eid || cls == Expression::Load) && (BitOps::get_bit(cid, m_altered) || m_am.checkAnyInterf(e, cur, isLoad, depth, effects) != AliasManager::DisjointAccess)) { BitOps::set_bit(cid, m_altered, true); if (!prev) { m_active = next; } else { prev->setCanonPtr(next); } } else { prev = cur; } cur = next; } } }
int FunctionScope::inferParamTypes(AnalysisResultPtr ar, ConstructPtr exp, ExpressionListPtr params, bool &valid) { if (!params) { if (m_minParam > 0) { if (ar->isFirstPass()) { ar->getCodeError()->record(CodeError::TooFewArgument, exp, m_stmt); } valid = false; setDynamic(); } return 0; } int ret = 0; if (params->getCount() < m_minParam) { if (ar->isFirstPass()) { ar->getCodeError()->record(CodeError::TooFewArgument, exp, m_stmt); } valid = false; setDynamic(); } if (params->getCount() > m_maxParam) { if (isVariableArgument()) { ret = params->getCount() - m_maxParam; } else { if (ar->isFirstPass()) { ar->getCodeError()->record(CodeError::TooManyArgument, exp, m_stmt); } valid = false; setDynamic(); } } bool canSetParamType = isUserFunction() && !m_overriding; for (int i = 0; i < params->getCount(); i++) { ExpressionPtr param = (*params)[i]; if (valid && param->hasContext(Expression::InvokeArgument)) { param->clearContext(Expression::InvokeArgument); param->clearContext(Expression::RefValue); param->clearContext(Expression::NoRefWrapper); } TypePtr expType; if (!canSetParamType && i < m_maxParam) { expType = param->inferAndCheck(ar, getParamType(i), false); } else { expType = param->inferAndCheck(ar, NEW_TYPE(Some), false); } bool isRefVararg = (i >= m_maxParam && isReferenceVariableArgument()); if ((i < m_maxParam && isRefParam(i)) || isRefVararg) { param->setContext(Expression::LValue); param->setContext(Expression::RefValue); param->inferAndCheck(ar, Type::Variant, true); } else if (!(param->getContext() & Expression::RefParameter)) { param->clearContext(Expression::LValue); param->clearContext(Expression::RefValue); param->clearContext(Expression::InvokeArgument); param->clearContext(Expression::NoRefWrapper); } if (i < m_maxParam) { if (m_paramTypeSpecs[i] && ar->isFirstPass()) { if (!Type::Inferred(ar, expType, m_paramTypeSpecs[i])) { const char *file = m_stmt->getLocation()->file; Logger::Error("%s: parameter %d of %s requires %s, called with %s", file, i, m_name.c_str(), m_paramTypeSpecs[i]->toString().c_str(), expType->toString().c_str()); ar->getCodeError()->record(CodeError::BadArgumentType, m_stmt); } } TypePtr paramType = getParamType(i); if (canSetParamType) { paramType = setParamType(ar, i, expType); } if (!Type::IsLegalCast(ar, expType, paramType) && paramType->isNonConvertibleType()) { param->inferAndCheck(ar, paramType, true); } param->setExpectedType(paramType); } // we do a best-effort check for bad pass-by-reference and do not report // error for some vararg case (e.g., array_multisort can have either ref // or value for the same vararg). if (!isRefVararg || !isMixedVariableArgument()) { Expression::checkPassByReference(ar, param); } } return ret; }
bool ExpressionList::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state) { if (m_kind == ListKindParam && !m_arrayElements) { return Expression::preOutputCPP(cg, ar, state|StashKidVars); } unsigned n = m_exps.size(); bool inExpression = cg.inExpression(); if (!inExpression && (state & FixOrder)) { return true; } cg.setInExpression(false); bool ret = false; if (m_arrayElements) { /* * would like to do: * ret = Expression::preOutputCPP(cg, ar, state); * but icc has problems with the generated code. */ ret = hasEffect(); } else if (n > 1 && m_kind == ListKindLeft) { ret = true; } else { for (unsigned int i = 0; i < n; i++) { if (m_exps[i]->preOutputCPP(cg, ar, 0)) { ret = true; break; } } if (!ret) { ExpressionPtr e = m_exps[n - 1]; if (hasContext(LValue) && !hasAnyContext(RefValue|InvokeArgument) && !(e->hasContext(LValue) && !e->hasAnyContext(RefValue|InvokeArgument))) { ret = true; } else if (hasContext(RefValue) && !e->hasAllContext(LValue|ReturnContext) && !e->hasContext(RefValue)) { ret = true; } } } if (!inExpression) return ret; cg.setInExpression(true); if (!ret) { if (state & FixOrder) { preOutputStash(cg, ar, state); return true; } return false; } cg.wrapExpressionBegin(); if (m_arrayElements) { setCPPTemp(genCPPTemp(cg, ar)); outputCPPInternal(cg, ar, true, true); } else { unsigned ix = isUnused() ? (unsigned)-1 : m_kind == ListKindLeft ? 0 : n - 1; for (unsigned int i = 0; i < n; i++) { ExpressionPtr e = m_exps[i]; e->preOutputCPP(cg, ar, i == ix ? state : 0); if (i != ix) { if (e->outputCPPUnneeded(cg, ar)) { cg_printf(";\n"); } e->setCPPTemp("/**/"); continue; } /* We inlined a by-value function into the rhs of a by-ref assignment. */ bool noRef = hasContext(RefValue) && !e->hasAllContext(LValue|ReturnContext) && !e->hasContext(RefValue) && !e->isTemporary() && Type::IsMappedToVariant(e->getActualType()); /* If we need a non-const reference, but the expression is going to generate a const reference, fix it */ bool lvSwitch = hasContext(LValue) && !hasAnyContext(RefValue|InvokeArgument) && !(e->hasContext(LValue) && !e->hasAnyContext(RefValue|InvokeArgument)); if (e->hasAllContext(LValue|ReturnContext) && i + 1 == n) { e->clearContext(ReturnContext); } if (noRef || lvSwitch || (!i && n > 1)) { e->Expression::preOutputStash(cg, ar, state | FixOrder | StashAll); if (!(state & FixOrder)) { cg_printf("id(%s);\n", e->cppTemp().c_str()); } } if (e->hasCPPTemp() && Type::SameType(e->getGenType(), getGenType())) { string t = e->cppTemp(); if (noRef) { cg_printf("CVarRef %s_nr = wrap_variant(%s);\n", t.c_str(), t.c_str()); t += "_nr"; } if (lvSwitch) { cg_printf("Variant &%s_lv = const_cast<Variant&>(%s);\n", t.c_str(), t.c_str()); t += "_lv"; } setCPPTemp(t); } } } return true; }
void FunctionScope::outputCPPArguments(ExpressionListPtr params, CodeGenerator &cg, AnalysisResultPtr ar, int extraArg, bool variableArgument, int extraArgArrayId /* = -1 */, int extraArgArrayHash /* = -1 */, int extraArgArrayIndex /* = -1 */) { int paramCount = params ? params->getOutputCount() : 0; ASSERT(extraArg <= paramCount); int iMax = paramCount - extraArg; bool extra = false; if (variableArgument) { if (paramCount == 0) { cg_printf("0"); } else { cg_printf("%d, ", paramCount); } } int firstExtra = 0; for (int i = 0; i < paramCount; i++) { ExpressionPtr param = (*params)[i]; cg.setItemIndex(i); if (i > 0) cg_printf(extra ? "." : ", "); if (!extra && (i == iMax || extraArg < 0)) { if (extraArgArrayId != -1) { assert(extraArgArrayHash != -1 && extraArgArrayIndex != -1); ar->outputCPPScalarArrayId(cg, extraArgArrayId, extraArgArrayHash, extraArgArrayIndex); break; } extra = true; // Parameter arrays are always vectors. if (Option::GenArrayCreate && cg.getOutput() != CodeGenerator::SystemCPP) { if (!params->hasNonArrayCreateValue(false, i)) { ar->m_arrayIntegerKeySizes.insert(paramCount - i); cg_printf("Array("); params->outputCPPUniqLitKeyArrayInit(cg, ar, paramCount - i, false, i); cg_printf(")"); return; } } firstExtra = i; cg_printf("Array(ArrayInit(%d, true).", paramCount - i); } if (extra) { bool needRef = param->hasContext(Expression::RefValue) && !param->hasContext(Expression::NoRefWrapper) && param->isRefable(); cg_printf("set%s(", needRef ? "Ref" : ""); if (needRef) { // The parameter itself shouldn't be wrapped with ref() any more. param->setContext(Expression::NoRefWrapper); } param->outputCPP(cg, ar); cg_printf(")"); } else { param->outputCPP(cg, ar); } } if (extra) { cg_printf(".create())"); } }