diff --git a/change_notes/2026-08-20-fix-fp-rule-7-0-1-bool-reference.md b/change_notes/2026-08-20-fix-fp-rule-7-0-1-bool-reference.md new file mode 100644 index 0000000000..68030fb2c8 --- /dev/null +++ b/change_notes/2026-08-20-fix-fp-rule-7-0-1-bool-reference.md @@ -0,0 +1,9 @@ + - `RULE-7-0-1` - `NoConversionFromBool.ql`: + - Fixed false positives where a `bool` value is bound to a reference whose + referenced type is also `bool` (e.g. `bool&`, `const bool&`), including + when this happens via a generic/forwarding-reference parameter (e.g. + `template void f(T&& t)`, or class template forwarding + constructors such as `std::pair`'s `pair(U1&&, U2&&)`) that happens to be + instantiated with `bool`. Binding a value to a reference of its own type + does not change the type or representation of the value, so this is not + a conversion from `bool` in the sense intended by the rule. diff --git a/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql b/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql index 6baa1ed648..4a9d7b8199 100644 --- a/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql +++ b/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql @@ -23,6 +23,18 @@ where conv = e.getConversion() and conv.getExpr().getType().stripTopLevelSpecifiers() instanceof BoolType and not conv.getType().stripTopLevelSpecifiers() instanceof BoolType and + // Exclude conversions that only bind a `bool` value to a reference to `bool` + // (e.g. `bool&`, `const bool&`). Binding a value to a reference of its own + // type does not change the type or representation of the value, so this is + // not a "conversion from bool" in the sense intended by the rule. This + // commonly occurs when a `bool` argument is forwarded through a generic + // `bool&`/`const bool&` parameter (e.g. logging helpers, `std::pair`-style + // structured bindings/aggregates). + not conv.getType() + .stripTopLevelSpecifiers() + .(ReferenceType) + .getBaseType() + .stripTopLevelSpecifiers() instanceof BoolType and // Exclude cases that are explicitly allowed not ( // Exception: equality operators with both bool operands diff --git a/cpp/misra/test/rules/RULE-7-0-1/test.cpp b/cpp/misra/test/rules/RULE-7-0-1/test.cpp index 29fc311e3f..3534a57f7c 100644 --- a/cpp/misra/test/rules/RULE-7-0-1/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-1/test.cpp @@ -122,4 +122,39 @@ void test_bool_conversion_compliant() { // Bit-field assignment exception - compliant bf.bit = b1; // COMPLIANT +} + +void f3(bool &b) {} +void f4(const bool &b) {} + +template void f5(T &&t) {} + +template struct Pair { + template Pair(U1 &&x, U2 &&y) : a(x), b(y) {} + T1 a; + T2 b; +}; + +void test_bool_reference_conversion_compliant() { + bool b1 = true; + + // Binding a bool lvalue to a bool reference parameter - compliant, no + // actual type conversion takes place. + f3(b1); // COMPLIANT + + // Binding a bool value to a const bool reference parameter - compliant. + f4(b1); // COMPLIANT + f4(true); // COMPLIANT + + // Binding a bool value to a forwarding reference parameter deduced as + // bool - compliant. + f5(b1); // COMPLIANT + f5(true); // COMPLIANT + + // Binding a bool value through a generic forwarding-reference constructor, + // where the second template parameter is deduced as bool - compliant. This + // mirrors idiomatic `return {value, overflow_flag};` and structured-binding + // patterns (e.g. std::pair and std::map::insert()'s return value). + Pair p1{1, true}; // COMPLIANT + Pair p2 = {1, b1}; // COMPLIANT } \ No newline at end of file