void UseNodiscardCheck::registerMatchers(MatchFinder *Finder) { // If we use ``[[nodiscard]]`` attribute, we require at least C++17. Use a // macro or ``__attribute__`` with pre c++17 compilers by using // ReplacementString option. if ((NoDiscardMacro == "[[nodiscard]]" && !getLangOpts().CPlusPlus17) || !getLangOpts().CPlusPlus) return; auto FunctionObj = cxxRecordDecl(hasAnyName("::std::function", "::boost::function")); // Find all non-void const methods which have not already been marked to // warn on unused result. Finder->addMatcher( cxxMethodDecl( allOf(isConst(), isDefinitionOrInline(), unless(anyOf( returns(voidType()), isNoReturn(), isOverloadedOperator(), isVariadic(), hasTemplateReturnType(), hasClassMutableFields(), isConversionOperator(), hasAttr(clang::attr::WarnUnusedResult), hasType(isInstantiationDependentType()), hasAnyParameter(anyOf( parmVarDecl(anyOf(hasType(FunctionObj), hasType(references(FunctionObj)))), hasType(isNonConstReferenceOrPointer()), hasParameterPack())))))) .bind("no_discard"), this); }
void cacheable_function::useLegacyCache(XQueryDiagnostics* aDiag) { if (isUpdating() || isVariadic()) { if (aDiag) { aDiag->add_warning( NEW_XQUERY_WARNING(zwarn::ZWST0005_CACHING_NOT_POSSIBLE, WARN_PARAMS(getName()->getStringValue(), isUpdating() ? ZED(ZWST0005_UPDATING) : ZED(ZWST0005_VARIADIC)), WARN_LOC(theLoc))); } theHasCache = false; return; } if (isSequential() || !isDeterministic()) { if (aDiag) { aDiag->add_warning( NEW_XQUERY_WARNING(zwarn::ZWST0006_CACHING_MIGHT_NOT_BE_INTENDED, WARN_PARAMS(getName()->getStringValue(), (isSequential() ? "sequential" : "non-deterministic")), WARN_LOC(theLoc))); } } parseCachingAnnotations(aDiag); theHasCache = true; theIsCacheAutomatic = false; theCacheAcrossSnapshots = true; }
void cacheable_function::useDefaultCachingSettings() { if (isVariadic() || isUpdating() || isSequential() || !isDeterministic()) { theHasCache = false; } else { if (!haveAtomicArgumentsAndReturnType()) { theHasCache = false; } else { theHasCache = true; theIsCacheAutomatic = true; theCacheAcrossSnapshots = false; } } }
void cacheable_function::useStrictlyDeterministicCache(XQueryDiagnostics* aDiag) { if (isUpdating() || isSequential() || isVariadic()) { if (aDiag) { aDiag->add_warning( NEW_XQUERY_WARNING(zwarn::ZWST0005_CACHING_NOT_POSSIBLE, WARN_PARAMS(getName()->getStringValue(), isUpdating() ? ZED(ZWST0005_UPDATING) : (isSequential() ? ZED(ZWST0005_SEQUENTIAL) : ZED(ZWST0005_VARIADIC))), WARN_LOC(theLoc))); } theHasCache = false; } else { parseCachingAnnotations(aDiag); theHasCache = true; theIsCacheAutomatic = false; theCacheAcrossSnapshots = false; } }
Func* FuncEmitter::create(Unit& unit, PreClass* preClass /* = NULL */) const { bool isGenerated = isdigit(name->data()[0]) || ParserBase::IsClosureName(name->toCppString()); Attr attrs = this->attrs; if (preClass && preClass->attrs() & AttrInterface) { attrs |= AttrAbstract; } if (attrs & AttrPersistent && ((RuntimeOption::EvalJitEnableRenameFunction && !isGenerated) || (!RuntimeOption::RepoAuthoritative && SystemLib::s_inited) || attrs & AttrInterceptable)) { if (attrs & AttrBuiltin) { SystemLib::s_anyNonPersistentBuiltins = true; } attrs = Attr(attrs & ~AttrPersistent); } if (RuntimeOption::EvalJitEnableRenameFunction && !name->empty() && !Func::isSpecial(name) && !isClosureBody) { // intercepted functions need to pass all args through // to the interceptee attrs |= AttrMayUseVV; } if (isVariadic()) { attrs |= AttrVariadicParam; } if (!containsCalls) { attrs |= AttrPhpLeafFn; } assert(!m_pce == !preClass); Func* f = m_ue.newFunc(this, unit, preClass, line1, line2, base, past, name, attrs, top, docComment, params.size(), isClosureBody); f->shared()->m_info = m_info; f->shared()->m_returnType = returnType; std::vector<Func::ParamInfo> fParams; for (unsigned i = 0; i < params.size(); ++i) { Func::ParamInfo pi = params[i]; f->appendParam(params[i].byRef, pi, fParams); } f->shared()->m_localNames.create(m_localNames); f->shared()->m_numLocals = m_numLocals; f->shared()->m_numIterators = m_numIterators; f->m_maxStackCells = maxStackCells; f->shared()->m_staticVars = staticVars; f->shared()->m_ehtab = ehtab; f->shared()->m_fpitab = fpitab; f->shared()->m_isClosureBody = isClosureBody; f->shared()->m_isAsync = isAsync; f->shared()->m_isGenerator = isGenerator; f->shared()->m_isPairGenerator = isPairGenerator; f->shared()->m_userAttributes = userAttributes; f->shared()->m_builtinFuncPtr = m_builtinFuncPtr; f->shared()->m_nativeFuncPtr = m_nativeFuncPtr; f->shared()->m_retTypeConstraint = retTypeConstraint; f->shared()->m_retUserType = retUserType; f->shared()->m_originalFilename = originalFilename; f->shared()->m_isGenerated = isGenerated; f->finishedEmittingParams(fParams); if (attrs & AttrNative) { auto nif = Native::GetBuiltinFunction(name, m_pce ? m_pce->name() : nullptr, f->isStatic()); if (nif) { Attr dummy = AttrNone; int nativeAttrs = parseNativeAttributes(dummy); if (nativeAttrs & Native::AttrZendCompat) { f->shared()->m_nativeFuncPtr = nif; f->shared()->m_builtinFuncPtr = zend_wrap_func; } else { if (parseNativeAttributes(dummy) & Native::AttrActRec) { f->shared()->m_builtinFuncPtr = nif; f->shared()->m_nativeFuncPtr = nullptr; } else { f->shared()->m_nativeFuncPtr = nif; f->shared()->m_builtinFuncPtr = m_pce ? Native::methodWrapper : Native::functionWrapper; } } } else { f->shared()->m_builtinFuncPtr = Native::unimplementedWrapper; } } return f; }
Func* FuncEmitter::create(Unit& unit, PreClass* preClass /* = NULL */) const { bool isGenerated = isdigit(name->data()[0]) || needsStripInOut(name); Attr attrs = this->attrs; if (preClass && preClass->attrs() & AttrInterface) { attrs |= AttrAbstract; } if (!RuntimeOption::RepoAuthoritative) { if (RuntimeOption::EvalJitEnableRenameFunction) { attrs |= AttrInterceptable; } else { attrs = Attr(attrs & ~AttrInterceptable); } } if (attrs & AttrPersistent && !preClass) { if ((RuntimeOption::EvalJitEnableRenameFunction || attrs & AttrInterceptable || (!RuntimeOption::RepoAuthoritative && SystemLib::s_inited))) { if (attrs & AttrBuiltin) { SystemLib::s_anyNonPersistentBuiltins = true; } attrs = Attr(attrs & ~AttrPersistent); } } else { assertx(preClass || !(attrs & AttrBuiltin)); } if (!RuntimeOption::RepoAuthoritative) { // In non-RepoAuthoritative mode, any function could get a VarEnv because // of evalPHPDebugger. attrs |= AttrMayUseVV; } else if ((attrs & AttrInterceptable) && !name->empty() && !Func::isSpecial(name) && !isClosureBody) { // intercepted functions need to pass all args through // to the interceptee attrs |= AttrMayUseVV; } if (isVariadic()) { attrs |= AttrVariadicParam; if (isVariadicByRef()) { attrs |= AttrVariadicByRef; } } assertx(!m_pce == !preClass); auto f = m_ue.newFunc(this, unit, name, attrs, params.size()); f->m_isPreFunc = !!preClass; bool const needsExtendedSharedData = isNative || line2 - line1 >= Func::kSmallDeltaLimit || past - base >= Func::kSmallDeltaLimit || m_numClsRefSlots > 3; f->m_shared.reset( needsExtendedSharedData ? new Func::ExtendedSharedData(preClass, base, past, line1, line2, top, !containsCalls, docComment) : new Func::SharedData(preClass, base, past, line1, line2, top, !containsCalls, docComment) ); f->init(params.size()); if (auto const ex = f->extShared()) { ex->m_hasExtendedSharedData = true; ex->m_arFuncPtr = nullptr; ex->m_nativeFuncPtr = nullptr; ex->m_line2 = line2; ex->m_past = past; ex->m_returnByValue = false; ex->m_isMemoizeWrapper = false; ex->m_isMemoizeWrapperLSB = false; ex->m_actualNumClsRefSlots = m_numClsRefSlots; } std::vector<Func::ParamInfo> fParams; for (unsigned i = 0; i < params.size(); ++i) { Func::ParamInfo pi = params[i]; if (pi.isVariadic()) { pi.builtinType = RuntimeOption::EvalHackArrDVArrs ? KindOfVec : KindOfArray; } f->appendParam(params[i].byRef, pi, fParams); } auto const originalFullName = (!originalFilename || !RuntimeOption::RepoAuthoritative || FileUtil::isAbsolutePath(originalFilename->slice())) ? originalFilename : makeStaticString(RuntimeOption::SourceRoot + originalFilename->toCppString()); f->shared()->m_localNames.create(m_localNames); f->shared()->m_numLocals = m_numLocals; f->shared()->m_numIterators = m_numIterators; f->m_maxStackCells = maxStackCells; f->shared()->m_staticVars = staticVars; f->shared()->m_ehtab = ehtab; f->shared()->m_fpitab = fpitab; f->shared()->m_isClosureBody = isClosureBody; f->shared()->m_isAsync = isAsync; f->shared()->m_isGenerator = isGenerator; f->shared()->m_isPairGenerator = isPairGenerator; f->shared()->m_userAttributes = userAttributes; f->shared()->m_retTypeConstraint = retTypeConstraint; f->shared()->m_retUserType = retUserType; f->shared()->m_originalFilename = originalFullName; f->shared()->m_isGenerated = isGenerated; f->shared()->m_repoReturnType = repoReturnType; f->shared()->m_repoAwaitedReturnType = repoAwaitedReturnType; f->shared()->m_isMemoizeWrapper = isMemoizeWrapper; f->shared()->m_isMemoizeWrapperLSB = isMemoizeWrapperLSB; f->shared()->m_numClsRefSlots = m_numClsRefSlots; if (isNative) { auto const ex = f->extShared(); ex->m_hniReturnType = hniReturnType; auto const info = getNativeInfo(); Attr dummy = AttrNone; auto nativeAttributes = parseNativeAttributes(dummy); Native::getFunctionPointers( info, nativeAttributes, ex->m_arFuncPtr, ex->m_nativeFuncPtr ); ex->m_takesNumArgs = !!(nativeAttributes & Native::AttrTakesNumArgs); if (ex->m_nativeFuncPtr) { if (info.sig.ret == Native::NativeSig::Type::MixedTV) { ex->m_returnByValue = true; } int extra = (nativeAttributes & Native::AttrTakesNumArgs ? 1 : 0) + (isMethod() ? 1 : 0); assertx(info.sig.args.size() == params.size() + extra); for (auto i = params.size(); i--; ) { switch (info.sig.args[extra + i]) { case Native::NativeSig::Type::ObjectArg: case Native::NativeSig::Type::StringArg: case Native::NativeSig::Type::ArrayArg: case Native::NativeSig::Type::ResourceArg: case Native::NativeSig::Type::OutputArg: case Native::NativeSig::Type::MixedTV: fParams[i].nativeArg = true; break; default: break; } } } } f->finishedEmittingParams(fParams); return f; }
Func* FuncEmitter::create(Unit& unit, PreClass* preClass /* = NULL */) const { bool isGenerated = isdigit(name->data()[0]) || ParserBase::IsClosureName(name->toCppString()); Attr attrs = this->attrs; if (preClass && preClass->attrs() & AttrInterface) { attrs |= AttrAbstract; } if (attrs & AttrPersistent && ((RuntimeOption::EvalJitEnableRenameFunction && !isGenerated) || (!RuntimeOption::RepoAuthoritative && SystemLib::s_inited) || attrs & AttrInterceptable)) { if (attrs & AttrBuiltin) { SystemLib::s_anyNonPersistentBuiltins = true; } attrs = Attr(attrs & ~AttrPersistent); } if (!RuntimeOption::RepoAuthoritative) { // In non-RepoAuthoritative mode, any function could get a VarEnv because // of evalPHPDebugger. attrs |= AttrMayUseVV; } else if (RuntimeOption::EvalJitEnableRenameFunction && !name->empty() && !Func::isSpecial(name) && !isClosureBody) { // intercepted functions need to pass all args through // to the interceptee attrs |= AttrMayUseVV; } if (isVariadic()) { attrs |= AttrVariadicParam; } if (!containsCalls) { attrs |= AttrPhpLeafFn; } assert(!m_pce == !preClass); auto f = m_ue.newFunc(this, unit, name, attrs, params.size()); f->m_isPreFunc = !!preClass; bool const needsExtendedSharedData = m_info || m_builtinFuncPtr || m_nativeFuncPtr || (attrs & AttrNative) || line2 - line1 >= Func::kSmallDeltaLimit || past - base >= Func::kSmallDeltaLimit; f->m_shared.reset( needsExtendedSharedData ? new Func::ExtendedSharedData(preClass, base, past, line1, line2, top, docComment) : new Func::SharedData(preClass, base, past, line1, line2, top, docComment) ); f->init(params.size()); if (auto const ex = f->extShared()) { ex->m_hasExtendedSharedData = true; ex->m_builtinFuncPtr = m_builtinFuncPtr; ex->m_nativeFuncPtr = m_nativeFuncPtr; ex->m_info = m_info; ex->m_line2 = line2; ex->m_past = past; ex->m_returnByValue = false; } std::vector<Func::ParamInfo> fParams; for (unsigned i = 0; i < params.size(); ++i) { Func::ParamInfo pi = params[i]; if (pi.isVariadic()) { pi.builtinType = KindOfArray; } f->appendParam(params[i].byRef, pi, fParams); } f->shared()->m_returnType = returnType; f->shared()->m_localNames.create(m_localNames); f->shared()->m_numLocals = m_numLocals; f->shared()->m_numIterators = m_numIterators; f->m_maxStackCells = maxStackCells; f->shared()->m_staticVars = staticVars; f->shared()->m_ehtab = toFixed(ehtab); f->shared()->m_fpitab = fpitab; f->shared()->m_isClosureBody = isClosureBody; f->shared()->m_isAsync = isAsync; f->shared()->m_isGenerator = isGenerator; f->shared()->m_isPairGenerator = isPairGenerator; f->shared()->m_userAttributes = userAttributes; f->shared()->m_retTypeConstraint = retTypeConstraint; f->shared()->m_retUserType = retUserType; f->shared()->m_originalFilename = originalFilename; f->shared()->m_isGenerated = isGenerated; if (attrs & AttrNative) { auto const ex = f->extShared(); auto const& info = Native::GetBuiltinFunction( name, m_pce ? m_pce->name() : nullptr, f->isStatic() ); Attr dummy = AttrNone; auto nativeAttributes = parseNativeAttributes(dummy); Native::getFunctionPointers( info, nativeAttributes, ex->m_builtinFuncPtr, ex->m_nativeFuncPtr ); if (ex->m_nativeFuncPtr && !(nativeAttributes & Native::AttrZendCompat)) { if (info.sig.ret == Native::NativeSig::Type::MixedTV) { ex->m_returnByValue = true; } int extra = (attrs & AttrNumArgs ? 1 : 0) + (isMethod() ? 1 : 0); assert(info.sig.args.size() == params.size() + extra); for (auto i = params.size(); i--; ) { switch (info.sig.args[extra + i]) { case Native::NativeSig::Type::ObjectArg: case Native::NativeSig::Type::StringArg: case Native::NativeSig::Type::ArrayArg: case Native::NativeSig::Type::ResourceArg: case Native::NativeSig::Type::OutputArg: case Native::NativeSig::Type::MixedTV: fParams[i].nativeArg = true; break; default: break; } } } } f->finishedEmittingParams(fParams); return f; }
ir::Type* TypeParser::_parseType() { std::string nextToken = _lexer->peek(); ir::Type* type = nullptr; if(isFunction(nextToken)) { type = _parseFunction(); } else if(isStructure(nextToken)) { type = _parseStructure(); } else if(isPrimitive(_compiler, nextToken)) { type = _parsePrimitive(); nextToken = _lexer->peek(); if(isFunction(nextToken)) { type = _parseFunction(type); } } else if(isArray(nextToken)) { type = _parseArray(); } else if(isVariadic(nextToken)) { _lexer->scan("..."); type = *_compiler->getOrInsertType(ir::VariadicType(_compiler)); } else if(isTypeAlias(nextToken)) { type = _parseTypeAlias(); } else if(isOpaqueType(nextToken)) { _lexer->scan("opaque"); type = *_compiler->getOrInsertType(ir::OpaqueType(_compiler)); } nextToken = _lexer->peek(); while(isPointer(nextToken)) { _lexer->scan("*"); type = *_compiler->getOrInsertType(ir::PointerType(_compiler, type)); nextToken = _lexer->peek(); } if(type == nullptr) { throw std::runtime_error("Failed to parse type."); } hydrazine::log("TypeParser::Parser") << "Parsed type " << type->name << ".\n"; return type; }
Func* FuncEmitter::create(Unit& unit, PreClass* preClass /* = NULL */) const { bool isGenerated = isdigit(name->data()[0]) || ParserBase::IsClosureName(name->toCppString()); Attr attrs = this->attrs; if (preClass && preClass->attrs() & AttrInterface) { attrs |= AttrAbstract; } if (attrs & AttrPersistent && ((RuntimeOption::EvalJitEnableRenameFunction && !isGenerated) || (!RuntimeOption::RepoAuthoritative && SystemLib::s_inited) || attrs & AttrInterceptable)) { if (attrs & AttrBuiltin) { SystemLib::s_anyNonPersistentBuiltins = true; } attrs = Attr(attrs & ~AttrPersistent); } if (!RuntimeOption::RepoAuthoritative) { // In non-RepoAuthoritative mode, any function could get a VarEnv because // of evalPHPDebugger. attrs |= AttrMayUseVV; } else if (RuntimeOption::EvalJitEnableRenameFunction && !name->empty() && !Func::isSpecial(name) && !isClosureBody) { // intercepted functions need to pass all args through // to the interceptee attrs |= AttrMayUseVV; } if (isVariadic()) { attrs |= AttrVariadicParam; } if (!containsCalls) { attrs |= AttrPhpLeafFn; } assert(!m_pce == !preClass); auto f = m_ue.newFunc(this, unit, name, attrs, params.size()); f->m_isPreFunc = !!preClass; bool const needsExtendedSharedData = m_info || m_builtinFuncPtr || m_nativeFuncPtr || (attrs & AttrNative) || line2 - line1 >= Func::kSmallDeltaLimit || past - base >= Func::kSmallDeltaLimit; f->m_shared.reset( needsExtendedSharedData ? new Func::ExtendedSharedData(preClass, base, past, line1, line2, top, docComment) : new Func::SharedData(preClass, base, past, line1, line2, top, docComment) ); f->init(params.size()); if (auto const ex = f->extShared()) { ex->m_hasExtendedSharedData = true; ex->m_builtinFuncPtr = m_builtinFuncPtr; ex->m_nativeFuncPtr = m_nativeFuncPtr; ex->m_info = m_info; ex->m_line2 = line2; ex->m_past = past; } std::vector<Func::ParamInfo> fParams; bool usesDoubles = false, variadic = false; for (unsigned i = 0; i < params.size(); ++i) { Func::ParamInfo pi = params[i]; if (pi.builtinType == KindOfDouble) usesDoubles = true; if (pi.isVariadic()) variadic = true; f->appendParam(params[i].byRef, pi, fParams); } f->shared()->m_returnType = returnType; f->shared()->m_localNames.create(m_localNames); f->shared()->m_numLocals = m_numLocals; f->shared()->m_numIterators = m_numIterators; f->m_maxStackCells = maxStackCells; f->shared()->m_staticVars = staticVars; f->shared()->m_ehtab = toFixed(ehtab); f->shared()->m_fpitab = fpitab; f->shared()->m_isClosureBody = isClosureBody; f->shared()->m_isAsync = isAsync; f->shared()->m_isGenerator = isGenerator; f->shared()->m_isPairGenerator = isPairGenerator; f->shared()->m_userAttributes = userAttributes; f->shared()->m_retTypeConstraint = retTypeConstraint; f->shared()->m_retUserType = retUserType; f->shared()->m_originalFilename = originalFilename; f->shared()->m_isGenerated = isGenerated; f->finishedEmittingParams(fParams); if (attrs & AttrNative) { auto const ex = f->extShared(); auto const& info = Native::GetBuiltinFunction( name, m_pce ? m_pce->name() : nullptr, f->isStatic() ); auto const nif = info.ptr; if (nif) { Attr dummy = AttrNone; int nativeAttrs = parseNativeAttributes(dummy); if (nativeAttrs & Native::AttrZendCompat) { ex->m_nativeFuncPtr = nif; ex->m_builtinFuncPtr = zend_wrap_func; } else { if (parseNativeAttributes(dummy) & Native::AttrActRec) { ex->m_builtinFuncPtr = nif; ex->m_nativeFuncPtr = nullptr; } else { ex->m_nativeFuncPtr = nif; ex->m_builtinFuncPtr = Native::getWrapper(m_pce, usesDoubles, variadic); } } } else { ex->m_builtinFuncPtr = Native::unimplementedWrapper; } } return f; }