xref: /netbsd-src/tests/usr.bin/xlint/lint1/msg_117.c (revision e6298b924c5ba98f3a22919b56dab04a87cdbb1c)
1 /*	$NetBSD: msg_117.c,v 1.14 2023/07/07 19:45:22 rillig Exp $	*/
2 # 3 "msg_117.c"
3 
4 // Test for message: bitwise '%s' on signed value possibly nonportable [117]
5 
6 /* lint1-extra-flags: -p -X 351 */
7 
8 int
shr(int a,int b)9 shr(int a, int b)
10 {
11 	/* expect+1: warning: bitwise '>>' on signed value possibly nonportable [117] */
12 	return a >> b;
13 }
14 
15 int
shr_lhs_constant_positive(int a)16 shr_lhs_constant_positive(int a)
17 {
18 	return 0x1234 >> a;
19 }
20 
21 int
shr_lhs_constant_negative(int a)22 shr_lhs_constant_negative(int a)
23 {
24 	/* expect+1: warning: bitwise '>>' on signed value nonportable [120] */
25 	return -0x1234 >> a;
26 }
27 
28 int
shr_rhs_constant_positive(int a)29 shr_rhs_constant_positive(int a)
30 {
31 	/* expect+2: warning: bitwise '>>' on signed value possibly nonportable [117] */
32 	/* expect+1: warning: shift amount 4660 is greater than bit-size 32 of 'int' [122] */
33 	return a >> 0x1234;
34 }
35 
36 int
shr_rhs_constant_negative(int a)37 shr_rhs_constant_negative(int a)
38 {
39 	/* expect+2: warning: bitwise '>>' on signed value possibly nonportable [117] */
40 	/* expect+1: warning: negative shift [121] */
41 	return a >> -0x1234;
42 }
43 
44 unsigned int
shr_unsigned_char(unsigned char uc)45 shr_unsigned_char(unsigned char uc)
46 {
47 	/*
48 	 * Even though 'uc' is promoted to 'int', it cannot be negative.
49 	 * Before tree.c 1.335 from 2021-08-15, lint wrongly warned that
50 	 * 'uc >> 4' might be a bitwise '>>' on signed value.
51 	 */
52 	return uc >> 4;
53 }
54 
55 unsigned char
shr_unsigned_char_promoted_signed(unsigned char bit)56 shr_unsigned_char_promoted_signed(unsigned char bit)
57 {
58 	/*
59 	 * The possible values for 'bit' range from 0 to 255.  Subtracting 1
60 	 * from 0 results in a negative expression value.
61 	 */
62 	/* expect+1: warning: bitwise '>>' on signed value possibly nonportable [117] */
63 	return (unsigned char)((bit - 1) >> 5);
64 }
65 
66 unsigned char
shr_unsigned_char_promoted_unsigned(unsigned char bit)67 shr_unsigned_char_promoted_unsigned(unsigned char bit)
68 {
69 	/*
70 	 * To prevent the above warning, the intermediate expression must be
71 	 * cast to 'unsigned char'.
72 	 */
73 	return (unsigned char)((unsigned char)(bit - 1) >> 5);
74 }
75 
76 /*
77  * C90 3.3.7, C99 6.5.7 and C11 6.5.7 all say the same: If E1 has a signed
78  * type and a negative value, the resulting value is implementation-defined.
79  *
80  * These standards don't guarantee anything about the lower bits of the
81  * resulting value, which are generally independent of whether the shift is
82  * performed in signed arithmetics or in unsigned arithmetics.  The C99
83  * rationale talks about signed shifts, but does not provide any guarantee
84  * either.  It merely suggests that platforms are free to use unsigned shifts
85  * even if the operand type is signed.
86  *
87  * K&R provides more guarantees by saying: Right shifting a signed quantity
88  * will fill with sign bits ("arithmetic shift") on some machines such as the
89  * PDP-11, and with 0-bits ("logical shift") on others.
90  *
91  * https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html says:
92  * Signed '>>' acts on negative numbers by sign extension.
93  *
94  * This means that at least in GCC mode, lint may decide to not warn about
95  * these cases.
96  */
97 void
shr_signed_ignoring_high_bits(int x)98 shr_signed_ignoring_high_bits(int x)
99 {
100 
101 	/*
102 	 * All sane platforms should define that 'x >> 0 == x', even if x is
103 	 * negative.
104 	 */
105 	/* expect+1: warning: bitwise '>>' on signed value possibly nonportable [117] */
106 	if (x >> 0 != 0)
107 		return;
108 
109 	/*
110 	 * If x is negative, x >> 1 is nonzero, no matter whether the shift
111 	 * is arithmetic or logical.
112 	 */
113 	/* expect+1: warning: bitwise '>>' on signed value possibly nonportable [117] */
114 	if (x >> 1 != 0)
115 		return;
116 
117 	/*
118 	 * The highest bit may be 0 or 1, the others should be well-defined
119 	 * on all sane platforms, making it irrelevant whether the actual
120 	 * shift operation is arithmetic or logical.
121 	 */
122 	/* expect+1: warning: bitwise '>>' on signed value possibly nonportable [117] */
123 	if (((x >> 1) & 1) != 0)
124 		return;
125 
126 	/*
127 	 * The result of this expression is the same with arithmetic and
128 	 * logical shifts since the filled bits are masked out.
129 	 */
130 	/* expect+1: warning: bitwise '>>' on signed value possibly nonportable [117] */
131 	if (((x >> 31) & 1) != 0)
132 		return;
133 
134 	/*
135 	 * In this case, arithmetic shift results in 2 while logical shift
136 	 * results in 0.  This difference is what this warning is about.
137 	 */
138 	/* expect+1: warning: bitwise '>>' on signed value possibly nonportable [117] */
139 	if (((x >> 31) & 2) != 0)
140 		return;
141 
142 	/*
143 	 * The result of '&' is guaranteed to be positive, so don't warn.
144 	 * Code like this typically occurs in hexdump functions.
145 	 */
146 	if ((x & 0xf0) >> 4 != 0)
147 		return;
148 }
149