Skip to content

Commit 1072944

Browse files
committed
Fix RULE-7-0-2 false positives: UnknownType and reference-to-bool dereference
NoImplicitBoolConversion.ql flagged two systematic false-positive shapes: 1. Conversions whose source expression type could not be resolved to a concrete type (UnknownType). This occurs only in template-dependent contexts the extractor cannot resolve, e.g. a `constexpr bool` variable template initialized from another dependent variable template such as `std::conjunction_v<...>`, or a `noexcept(...)` specifier built the same way. 2. Reference-dereference conversions (`bool&`/`bool&&` -> `bool`). `getUnspecifiedType()` resolves typedefs/specifiers but does not strip reference qualification, so a `bool&`/`bool&&` is not recognised as already being `bool`. This is most commonly synthesized by the compiler for structured binding decomposition (`auto [a, b] = pair_or_tuple_expr;` where `b` is `bool`), which is not a real conversion since the referenced value is already a `bool`. This mirrors the same root-cause pattern already fixed for the sibling rule RULE-7-0-1 in 6f872c7 ("Fix RULE-7-0-1 false positives for bool-to- reference bindings"), applied here to the reverse conversion direction.
1 parent aaac22d commit 1072944

3 files changed

Lines changed: 92 additions & 0 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
- `RULE-7-0-2` - `NoImplicitBoolConversion.ql`:
2+
- Fixed false positives where a conversion's source expression type could
3+
not be resolved to a concrete type (`UnknownType`), which occurs only in
4+
template-dependent contexts that the extractor cannot resolve, e.g. a
5+
`constexpr bool` variable template whose initializer is itself another
6+
dependent variable template such as `std::conjunction_v<...>`.
7+
- Fixed false positives on reference-dereference conversions (`bool&`/
8+
`bool&&` to `bool`), which occur e.g. via the compiler-synthesized
9+
`std::get<N>(...)` call used to implement structured binding
10+
decomposition (`auto [a, b] = some_pair_or_tuple_expr;` where `b` is
11+
`bool`). Dereferencing a reference to `bool` does not change the type or
12+
representation of the value, so this is not a conversion to `bool` in
13+
the sense intended by the rule.

cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,30 @@ where
5656
e = conv and
5757
conv.getType().getUnspecifiedType() instanceof BoolType and
5858
not conv.getExpr().getType().getUnspecifiedType() instanceof BoolType and
59+
// Exclude conversions whose source expression type could not be resolved to a concrete
60+
// type (`UnknownType`). This shape occurs only in template-dependent contexts that the
61+
// extractor has not (and, for uninstantiated templates, cannot) resolve to an actual type
62+
// - e.g. a `constexpr bool` variable template / `noexcept(...)` specifier built from
63+
// another variable template such as `std::conjunction_v<...>`. There is no actual,
64+
// concrete conversion to `bool` that a developer wrote or that the compiler ultimately
65+
// performs; flagging it produces a false positive because the "conversion from 'unknown'"
66+
// is an artifact of incomplete extraction of template-dependent/library code, not a
67+
// genuine violation.
68+
not conv.getExpr().getType() instanceof UnknownType and
69+
// Exclude reference-dereference conversions (`T& -> T` / `T&& -> T`) whose referenced type
70+
// is itself `bool` once its reference-ness is stripped, e.g. the compiler-synthesized
71+
// `std::get<N>(...)` call used to implement structured binding decomposition
72+
// (`auto [a, b] = some_pair_or_tuple_expr;` where `b` is `bool`). `getUnspecifiedType()`
73+
// resolves typedefs/specifiers but does not strip reference qualification, so a `bool&`/
74+
// `bool&&` is not itself recognised as already being `bool` by the check above. But
75+
// dereferencing a reference to `bool` does not represent a conversion from a different
76+
// type to `bool` - the referenced value is already a `bool` - so this is not a violation.
77+
not conv.getExpr()
78+
.getType()
79+
.getUnspecifiedType()
80+
.(ReferenceType)
81+
.getBaseType()
82+
.getUnspecifiedType() instanceof BoolType and
5983
// Exception 2: Contextual conversion from pointer
6084
not (
6185
isPointerType(conv.getExpr().getType()) and

cpp/misra/test/rules/RULE-7-0-2/test.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,59 @@ void test_member_function_pointer_conversion() {
213213
bool l3 = l1; // NON_COMPLIANT
214214
bool l4 = l2; // NON_COMPLIANT
215215
bool l5 = (l1 != nullptr); // COMPLIANT
216+
}
217+
218+
// Regression test for a false positive where the compiler-synthesized
219+
// `get<N>(...)` call used to implement structured binding decomposition (`auto
220+
// [a, b] = ...;`) was incorrectly flagged as a "conversion to bool", even
221+
// though the decomposed member is already `bool` - dereferencing a
222+
// `bool&`/`bool&&` reference is not a conversion from another type to `bool`.
223+
struct BoolPair {
224+
std::int32_t first;
225+
bool second;
226+
};
227+
228+
template <std::size_t I> auto get(const BoolPair &p) {
229+
if constexpr (I == 0) {
230+
return p.first;
231+
} else {
232+
return p.second;
233+
}
234+
}
235+
236+
namespace std {
237+
template <class T> struct tuple_size;
238+
template <std::size_t I, class T> struct tuple_element;
239+
240+
template <> struct tuple_size<BoolPair> {
241+
static constexpr std::size_t value = 2;
242+
};
243+
template <> struct tuple_element<0, BoolPair> { using type = std::int32_t; };
244+
template <> struct tuple_element<1, BoolPair> { using type = bool; };
245+
} // namespace std
246+
247+
BoolPair make_bool_pair();
248+
249+
void test_structured_binding_bool_decomposition() {
250+
auto [l1, l2] =
251+
make_bool_pair(); // COMPLIANT - structured binding decomposition, not a
252+
// real conversion to bool
253+
if (l2) { // COMPLIANT
254+
}
255+
bool l3 = l2; // COMPLIANT - l2 is already bool
256+
}
257+
258+
// Regression test for a false positive where a `constexpr bool` variable
259+
// template, whose initializer is itself a dependent expression built from
260+
// another variable template, was incorrectly flagged as a "conversion from
261+
// 'unknown' to bool". The extractor cannot resolve a concrete type for a
262+
// dependent, uninstantiated template expression, so it should not be treated as
263+
// an actual conversion.
264+
template <typename T> constexpr bool is_something_v = true;
265+
266+
template <typename T>
267+
constexpr bool derived_from_template_v = is_something_v<T>; // COMPLIANT
268+
269+
bool test_dependent_variable_template_instantiation() {
270+
return derived_from_template_v<std::int32_t>; // COMPLIANT
216271
}

0 commit comments

Comments
 (0)