@@ -2715,74 +2715,27 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings &settings,
27152715 // An overloaded >>= can extract into its right-hand operand by reference.
27162716 if (tok2->isCpp () && Token::simpleMatch (tok2->astParent (), " >>=" ) && astIsRHS (tok2) &&
27172717 !astIsIntegral (tok2->astParent ()->astOperand1 (), false )) {
2718- const Token* lhs = tok2->astParent ()->astOperand1 ();
2719- const ValueType* lhsType = lhs->valueType ();
2718+ const ValueType* lhsType = tok2->astParent ()->astOperand1 ()->valueType ();
27202719 if (!lhsType || !lhsType->typeScope )
27212720 return true ;
2722- const ValueType* rhsType = tok2->valueType ();
2723- const auto isKnownType = [](const ValueType* type) {
2724- return type && type->type != ValueType::UNKNOWN_INT &&
2725- (type->isPrimitive () || (type->pointer && (type->type == ValueType::VOID || type->typeScope )));
2726- };
2727- const auto receiverCV = [](const Function* function) {
2728- return (function->isConst () ? 1U : 0U ) | (function->isVolatile () ? 2U : 0U );
2729- };
2730- const unsigned int lhsCV = (lhsType->isConst () ? 1U : 0U ) | (lhsType->isVolatile () ? 2U : 0U );
2731- const auto operators = lhsType->typeScope ->functionMap .equal_range (" operator>>=" );
2721+ const Scope* lhsScope = lhsType->typeScope ;
2722+ const auto operators = lhsScope->functionMap .equal_range (" operator>>=" );
2723+ if (operators.first == operators.second ||
2724+ (lhsScope->definedType && !lhsScope->definedType ->derivedFrom .empty ()) ||
2725+ Token::findsimplematch (lhsScope->bodyStart , " friend" , lhsScope->bodyEnd ))
2726+ return true ;
2727+ // Non-member operators can compete with members. Avoid ranking them.
2728+ for (const Scope& scope : lhsScope->symdb .scopeList ) {
2729+ const auto functions = scope.functionMap .equal_range (" operator>>=" );
2730+ for (auto it = functions.first ; it != functions.second ; ++it) {
2731+ if (!scope.isClassOrStruct () || it->second ->isFriend ())
2732+ return true ;
2733+ }
2734+ }
27322735 for (auto it = operators.first ; it != operators.second ; ++it) {
2733- const Function* function = it->second ;
2734- if ((lhsType->isConst () && !function->isConst ()) ||
2735- (lhsType->isVolatile () && !function->isVolatile ()) ||
2736- (lhs->variable () && function->hasRvalRefQualifier ()))
2737- continue ;
2738- const Variable* arg = function->getArgumentVar (0 );
2739- if (!arg)
2736+ const Variable* arg = it->second ->getArgumentVar (0 );
2737+ if (!arg || (!arg->isConst () && arg->isReference ()))
27402738 return true ;
2741- if (arg->isConst () || !arg->isReference ())
2742- continue ;
2743- // Named variables are lvalues, including named rvalue references.
2744- if (tok2->variable () && arg->isRValueReference () && !function->templateDef )
2745- continue ;
2746- const ValueType* argType = arg->valueType ();
2747- if (isKnownType (rhsType) && isKnownType (argType)) {
2748- // Non-const references cannot bind via arithmetic or pointer conversions.
2749- if (!rhsType->isTypeEqual (argType) ||
2750- (rhsType->sign != ValueType::UNKNOWN_SIGN && argType->sign != ValueType::UNKNOWN_SIGN &&
2751- rhsType->sign != argType->sign ) ||
2752- (rhsType->isVolatile () && !argType->isVolatile ()))
2753- continue ;
2754- // Pointee qualification conversions also create a temporary pointer.
2755- if (rhsType->pointer > 0 && rhsType->pointer < std::numeric_limits<unsigned int >::digits) {
2756- const unsigned int mask = (1U << rhsType->pointer ) - 1 ;
2757- if (((static_cast <unsigned int >(rhsType->constness ) ^ static_cast <unsigned int >(argType->constness )) & mask) ||
2758- ((static_cast <unsigned int >(rhsType->volatileness ) ^ static_cast <unsigned int >(argType->volatileness )) & mask))
2759- continue ;
2760- }
2761- }
2762- // An exact by-value argument can win on the receiver's cv conversion.
2763- // Do not rank user-defined conversions or competing reference bindings.
2764- if (lhs->variable () && isKnownType (rhsType) && isKnownType (argType) &&
2765- rhsType->isTypeEqual (argType) && rhsType->sign == argType->sign &&
2766- rhsType->constness == argType->constness && rhsType->volatileness == argType->volatileness &&
2767- !function->templateDef ) {
2768- const unsigned int cv = receiverCV (function);
2769- const bool hasBetterValueOverload = std::any_of (operators.first , operators.second , [&](const std::pair<const std::string, const Function*>& entry) {
2770- const Function* other = entry.second ;
2771- const unsigned int otherCV = receiverCV (other);
2772- if (otherCV == cv || (otherCV & cv) != otherCV || (otherCV & lhsCV) != lhsCV ||
2773- other->hasLvalRefQualifier () != function->hasLvalRefQualifier () ||
2774- other->hasRvalRefQualifier () != function->hasRvalRefQualifier () || other->templateDef )
2775- return false ;
2776- const Variable* otherArg = other->getArgumentVar (0 );
2777- const ValueType* otherType = otherArg ? otherArg->valueType () : nullptr ;
2778- return otherArg && !otherArg->isReference () && isKnownType (otherType) &&
2779- rhsType->isTypeEqual (otherType) && rhsType->sign == otherType->sign &&
2780- rhsType->constness == otherType->constness && rhsType->volatileness == otherType->volatileness ;
2781- });
2782- if (hasBetterValueOverload)
2783- continue ;
2784- }
2785- return true ;
27862739 }
27872740 }
27882741
0 commit comments