xref: /netbsd-src/tests/usr.bin/xlint/lint1/expr_cast.c (revision 360641f995d7499cd0671fd1b81a69e4a9f1f07a)
1*360641f9Srillig /*	$NetBSD: expr_cast.c,v 1.6 2024/06/08 13:50:47 rillig Exp $	*/
2e4a7be9bSrillig # 3 "expr_cast.c"
3e4a7be9bSrillig 
4e4a7be9bSrillig /*
5e4a7be9bSrillig  * Tests for value conversion using a cast-expression.
6e4a7be9bSrillig  *
7e4a7be9bSrillig  * K&R C does not mention any restrictions on the target type.
8e4a7be9bSrillig  * C90 requires both the source type and the target type to be scalar.
93c6cb8a2Srillig  *
103c6cb8a2Srillig  * GCC allows casting to a struct type but there is no documentation about
113c6cb8a2Srillig  * it at https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html.  See
123c6cb8a2Srillig  * c-typeck.c, function build_c_cast, RECORD_OR_UNION_TYPE_P.
13e4a7be9bSrillig  */
14e4a7be9bSrillig 
15e6298b92Srillig /* lint1-flags: -Sw -X 351 */
163c6cb8a2Srillig 
17e4a7be9bSrillig struct S {
18e4a7be9bSrillig 	int member;
19e4a7be9bSrillig };
20e4a7be9bSrillig 
21e4a7be9bSrillig struct S
cast(void)22e4a7be9bSrillig cast(void)
23e4a7be9bSrillig {
24e4a7be9bSrillig 	struct S {
25e4a7be9bSrillig 		double incompatible;
26e4a7be9bSrillig 	} local = {
27e4a7be9bSrillig 		0.0
28e4a7be9bSrillig 	};
29e4a7be9bSrillig 
303c6cb8a2Srillig 	/* expect+2: error: invalid cast from 'struct S' to 'struct S' [147] */
31fe7ce870Srillig 	/* expect+1: error: function 'cast' expects to return value [214] */
32e4a7be9bSrillig 	return (struct S)local;
33e4a7be9bSrillig }
34*360641f9Srillig 
35*360641f9Srillig /*
36*360641f9Srillig  * https://gnats.netbsd.org/22119
37*360641f9Srillig  *
38*360641f9Srillig  * Before 2021-02-28, lint crashed in cast() since the target type of the
39*360641f9Srillig  * cast is NULL.
40*360641f9Srillig */
41*360641f9Srillig void
cast_from_error(void)42*360641f9Srillig cast_from_error(void)
43*360641f9Srillig {
44*360641f9Srillig 	void (*f1)(void);
45*360641f9Srillig 
46*360641f9Srillig 	/* expect+1: error: 'p' undefined [99] */
47*360641f9Srillig 	f1 = (void (*)(void))p;
48*360641f9Srillig 	/* expect+2: error: function returns illegal type 'function(void) returning pointer to void' [15] */
49*360641f9Srillig 	/* expect+1: error: invalid cast from 'int' to 'function() returning pointer to function(void) returning pointer to void' [147] */
50*360641f9Srillig 	f1 = (void *()(void))p;		/* crash before 2021-02-28 */
51*360641f9Srillig }
52*360641f9Srillig 
53*360641f9Srillig /*
54*360641f9Srillig  * Pointer casts had been valid lvalues in GCC before 4.0.
55*360641f9Srillig  *
56*360641f9Srillig  * https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Lvalues.html#Lvalues
57*360641f9Srillig  *
58*360641f9Srillig  * C99 6.5.4 "Cast operators" footnote 85 says "A cast does not yield an
59*360641f9Srillig  * lvalue".
60*360641f9Srillig  */
61*360641f9Srillig 
62*360641f9Srillig void take_ptr(const void *);
63*360641f9Srillig 
64*360641f9Srillig void *
lvalue_cast(void * p)65*360641f9Srillig lvalue_cast(void *p)
66*360641f9Srillig {
67*360641f9Srillig 	struct str {
68*360641f9Srillig 		int member;
69*360641f9Srillig 	};
70*360641f9Srillig 
71*360641f9Srillig 	/* expect+2: error: a cast does not yield an lvalue [163] */
72*360641f9Srillig 	/* expect+1: error: left operand of '=' must be lvalue [114] */
73*360641f9Srillig 	((struct str *)p) = 0;
74*360641f9Srillig 
75*360641f9Srillig 	/* expect+2: error: a cast does not yield an lvalue [163] */
76*360641f9Srillig 	/* expect+1: error: operand of '&' must be lvalue [114] */
77*360641f9Srillig 	take_ptr(&(const void *)p);
78*360641f9Srillig 
79*360641f9Srillig 	return p;
80*360641f9Srillig }
81