Skip to content

Commit d724947

Browse files
committed
Simplify overloaded extraction value tracking
1 parent 50fe3a7 commit d724947

2 files changed

Lines changed: 196 additions & 112 deletions

File tree

‎lib/astutils.cpp‎

Lines changed: 17 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)