Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
- `RULE-7-0-2` - `NoImplicitBoolConversion.ql`:
- Fixed false positives where a conversion's source expression type could
not be resolved to a concrete type (`UnknownType`), which occurs only in
template-dependent contexts that the extractor cannot resolve, e.g. a
`constexpr bool` variable template whose initializer is itself another
dependent variable template such as `std::conjunction_v<...>`.
- Fixed false positives on reference-dereference conversions (`bool&`/
`bool&&` to `bool`), which occur e.g. via the compiler-synthesized
`std::get<N>(...)` call used to implement structured binding
decomposition (`auto [a, b] = some_pair_or_tuple_expr;` where `b` is
`bool`). Dereferencing a reference to `bool` does not change the type or
representation of the value, so this is not a conversion to `bool` in
the sense intended by the rule.
24 changes: 24 additions & 0 deletions cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,30 @@ where
e = conv and
conv.getType().getUnspecifiedType() instanceof BoolType and
not conv.getExpr().getType().getUnspecifiedType() instanceof BoolType and
// Exclude conversions whose source expression type could not be resolved to a concrete
// type (`UnknownType`). This shape occurs only in template-dependent contexts that the
// extractor has not (and, for uninstantiated templates, cannot) resolve to an actual type
// - e.g. a `constexpr bool` variable template / `noexcept(...)` specifier built from
// another variable template such as `std::conjunction_v<...>`. There is no actual,
// concrete conversion to `bool` that a developer wrote or that the compiler ultimately
// performs; flagging it produces a false positive because the "conversion from 'unknown'"
// is an artifact of incomplete extraction of template-dependent/library code, not a
// genuine violation.
not conv.getExpr().getType() instanceof UnknownType and
// Exclude reference-dereference conversions (`T& -> T` / `T&& -> T`) whose referenced type
// is itself `bool` once its reference-ness is stripped, e.g. the compiler-synthesized
// `std::get<N>(...)` call used to implement structured binding decomposition
// (`auto [a, b] = some_pair_or_tuple_expr;` where `b` is `bool`). `getUnspecifiedType()`
// resolves typedefs/specifiers but does not strip reference qualification, so a `bool&`/
// `bool&&` is not itself recognised as already being `bool` by the check above. But
// dereferencing a reference to `bool` does not represent a conversion from a different
// type to `bool` - the referenced value is already a `bool` - so this is not a violation.
not conv.getExpr()
.getType()
.getUnspecifiedType()
.(ReferenceType)
.getBaseType()
.getUnspecifiedType() instanceof BoolType and
// Exception 2: Contextual conversion from pointer
not (
isPointerType(conv.getExpr().getType()) and
Expand Down
55 changes: 55 additions & 0 deletions cpp/misra/test/rules/RULE-7-0-2/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,59 @@ void test_member_function_pointer_conversion() {
bool l3 = l1; // NON_COMPLIANT
bool l4 = l2; // NON_COMPLIANT
bool l5 = (l1 != nullptr); // COMPLIANT
}

// Regression test for a false positive where the compiler-synthesized
// `get<N>(...)` call used to implement structured binding decomposition (`auto
// [a, b] = ...;`) was incorrectly flagged as a "conversion to bool", even
// though the decomposed member is already `bool` - dereferencing a
// `bool&`/`bool&&` reference is not a conversion from another type to `bool`.
struct BoolPair {
std::int32_t first;
bool second;
};

template <std::size_t I> auto get(const BoolPair &p) {
if constexpr (I == 0) {
return p.first;
} else {
return p.second;
}
}

namespace std {
template <class T> struct tuple_size;
template <std::size_t I, class T> struct tuple_element;

template <> struct tuple_size<BoolPair> {
static constexpr std::size_t value = 2;
};
template <> struct tuple_element<0, BoolPair> { using type = std::int32_t; };
template <> struct tuple_element<1, BoolPair> { using type = bool; };
} // namespace std

BoolPair make_bool_pair();

void test_structured_binding_bool_decomposition() {
auto [l1, l2] =
make_bool_pair(); // COMPLIANT - structured binding decomposition, not a
// real conversion to bool
if (l2) { // COMPLIANT
}
bool l3 = l2; // COMPLIANT - l2 is already bool
}

// Regression test for a false positive where a `constexpr bool` variable
// template, whose initializer is itself a dependent expression built from
// another variable template, was incorrectly flagged as a "conversion from
// 'unknown' to bool". The extractor cannot resolve a concrete type for a
// dependent, uninstantiated template expression, so it should not be treated as
// an actual conversion.
template <typename T> constexpr bool is_something_v = true;

template <typename T>
constexpr bool derived_from_template_v = is_something_v<T>; // COMPLIANT

bool test_dependent_variable_template_instantiation() {
return derived_from_template_v<std::int32_t>; // COMPLIANT
}