Skip to content

Commit 1b4ef10

Browse files
committed
Fix C++ ternary operator type checking for bitfield operands
`implicit_conversion_sequence` does not guarantee to produce the exact type requested as bitfields promote to the underlying type. Therefore, add typecasts as needed to ensure type consistency. Fixes: #933
1 parent 4fe3ade commit 1b4ef10

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#include <assert.h>
2+
#include <stdbool.h>
3+
#include <stdint.h>
4+
5+
// Regression test for issue where CBMC incorrectly failed with an
6+
// "equality without matching types" error when using ternary expressions
7+
// with bitfield types. The issue occurred when the third argument of a
8+
// ternary operator was a bitfield type (uint8_t : 1) that needed to be
9+
// implicitly converted to bool. GCC and Clang accept this code without
10+
// warnings, and CBMC should handle the implicit conversion as well.
11+
12+
typedef struct
13+
{
14+
uint32_t value_31_0 : 32;
15+
} signal32_t;
16+
17+
typedef struct
18+
{
19+
uint8_t value_0_0 : 1;
20+
} signal1_t;
21+
22+
static inline bool yosys_simplec_get_bit_25_of_32(const signal32_t *sig)
23+
{
24+
return (sig->value_31_0 >> 25) & 1;
25+
}
26+
27+
typedef struct rvfi_insn_srai_state_t
28+
{
29+
signal32_t rvfi_insn;
30+
signal32_t rvfi_rs1_rdata;
31+
signal1_t _abc_1398_n364;
32+
signal1_t _abc_1398_n363;
33+
} rvfi_insn_srai_state_t;
34+
35+
int main()
36+
{
37+
rvfi_insn_srai_state_t state;
38+
39+
// Test case 1: Both operands are function calls returning bool
40+
state.rvfi_insn.value_31_0 = 0;
41+
state.rvfi_rs1_rdata.value_31_0 = 0;
42+
state._abc_1398_n363.value_0_0 = 1;
43+
44+
// This ternary should work: condition ? bool : uint8_t:1
45+
// The third operand is a bitfield that should be implicitly converted to bool
46+
state._abc_1398_n364.value_0_0 =
47+
yosys_simplec_get_bit_25_of_32(&state.rvfi_insn)
48+
? yosys_simplec_get_bit_25_of_32(&state.rvfi_rs1_rdata)
49+
: state._abc_1398_n363.value_0_0;
50+
51+
// Since bit 25 of rvfi_insn is 0, the condition is false,
52+
// so the result should be _abc_1398_n363.value_0_0, which is 1
53+
assert(state._abc_1398_n364.value_0_0 == 1);
54+
55+
// Test case 2: Condition is true
56+
state.rvfi_insn.value_31_0 = (1u << 25); // Set bit 25
57+
state.rvfi_rs1_rdata.value_31_0 = 0;
58+
59+
state._abc_1398_n364.value_0_0 =
60+
yosys_simplec_get_bit_25_of_32(&state.rvfi_insn)
61+
? yosys_simplec_get_bit_25_of_32(&state.rvfi_rs1_rdata)
62+
: state._abc_1398_n363.value_0_0;
63+
64+
// Since bit 25 of rvfi_insn is 1, the condition is true,
65+
// so the result should be the bit 25 of rvfi_rs1_rdata, which is 0
66+
assert(state._abc_1398_n364.value_0_0 == 0);
67+
68+
return 0;
69+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.cpp
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

src/cpp/cpp_typecheck_expr.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,11 +243,21 @@ void cpp_typecheckt::typecheck_expr_trinary(if_exprt &expr)
243243
{
244244
expr.type()=e1.type();
245245
expr.op1().swap(e1);
246+
if(expr.type() != expr.op2().type())
247+
{
248+
implicit_conversion_sequence(expr.op2(), expr.type(), e2);
249+
expr.op2().swap(e2);
250+
}
246251
}
247252
else if(implicit_conversion_sequence(expr.op2(), expr.op1().type(), e2))
248253
{
249254
expr.type()=e2.type();
250255
expr.op2().swap(e2);
256+
if(expr.type() != expr.op1().type())
257+
{
258+
implicit_conversion_sequence(expr.op1(), expr.type(), e1);
259+
expr.op1().swap(e1);
260+
}
251261
}
252262
else if(
253263
expr.op1().type().id() == ID_array &&

0 commit comments

Comments
 (0)