Skip to content

Commit 3d58d00

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 3d58d00

3 files changed

Lines changed: 89 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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,26 @@ 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().getType().getUnspecifiedType().(ReferenceType).getBaseType()
78+
.getUnspecifiedType() instanceof BoolType and
5979
// Exception 2: Contextual conversion from pointer
6080
not (
6181
isPointerType(conv.getExpr().getType()) and

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

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

0 commit comments

Comments
 (0)