Module Name:    src
Committed By:   rillig
Date:           Fri Jul  8 20:27:36 UTC 2022

Modified Files:
        src/tests/usr.bin/xlint/lint1: queries.c
        src/usr.bin/xlint/lint1: README.md tree.c

Log Message:
lint: fix query for redundant cast before assignment

Previously, 'i = (int)dbl' was marked as redundant, even though it
performs a value conversion.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/tests/usr.bin/xlint/lint1/queries.c
cvs rdiff -u -r1.8 -r1.9 src/usr.bin/xlint/lint1/README.md
cvs rdiff -u -r1.472 -r1.473 src/usr.bin/xlint/lint1/tree.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/tests/usr.bin/xlint/lint1/queries.c
diff -u src/tests/usr.bin/xlint/lint1/queries.c:1.1 src/tests/usr.bin/xlint/lint1/queries.c:1.2
--- src/tests/usr.bin/xlint/lint1/queries.c:1.1	Tue Jul  5 22:50:41 2022
+++ src/tests/usr.bin/xlint/lint1/queries.c	Fri Jul  8 20:27:36 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: queries.c,v 1.1 2022/07/05 22:50:41 rillig Exp $	*/
+/*	$NetBSD: queries.c,v 1.2 2022/07/08 20:27:36 rillig Exp $	*/
 # 3 "queries.c"
 
 /*
@@ -17,6 +17,50 @@
 
 /* lint1-extra-flags: -q 1,2,3,4,5,6,7 */
 
+typedef unsigned char u8_t;
+typedef unsigned short u16_t;
+typedef unsigned int u32_t;
+typedef unsigned long long u64_t;
+typedef signed char s8_t;
+typedef signed short s16_t;
+typedef signed int s32_t;
+typedef signed long long s64_t;
+
+typedef float f32_t;
+typedef double f64_t;
+typedef float _Complex c32_t;
+typedef double _Complex c64_t;
+
+u8_t u8;
+u16_t u16;
+u32_t u32;
+u64_t u64;
+
+s8_t s8;
+s16_t s16;
+s32_t s32;
+s64_t s64;
+
+struct {
+	unsigned u8:8;
+	unsigned u9:9;
+	unsigned u10:10;
+	unsigned u32:32;
+	int s8:8;
+	int s9:9;
+	int s10:10;
+	int s32:32;
+} bits;
+
+f32_t f32;
+f64_t f64;
+
+c32_t c32;
+c64_t c64;
+
+char *str;
+const char *cstr;
+
 int
 Q1(double dbl)
 {
@@ -27,8 +71,7 @@ Q1(double dbl)
 int
 Q2(double dbl)
 {
-	/* expect+2: cast from floating point 'double' to integer 'int' [Q2] */
-	/* expect+1: redundant cast from 'double' to 'int' before assignment [Q7] */
+	/* expect+1: cast from floating point 'double' to integer 'int' [Q2] */
 	return (int)dbl;
 }
 
@@ -83,19 +126,85 @@ Q6(int i)
 	i = (int)i + 1;
 }
 
-extern void *allocate(unsigned long);
+extern void *allocate(void);
 
-char *
+void
 Q7(void)
 {
-	/* expect+1: redundant cast from 'pointer to void' to 'pointer to char' before assignment [Q7] */
-	char *str = (char *)allocate(64);
 
-	if (str == (void *)0)
-		/* expect+1: redundant cast from 'pointer to void' to 'pointer to char' before assignment [Q7] */
-		str = (char *)allocate(64);
+	/* expect+2: no-op cast from 'unsigned char' to 'unsigned char' [Q6] */
+	/* expect+1: redundant cast from 'unsigned char' to 'unsigned char' before assignment [Q7] */
+	u8 = (u8_t)u8;
+	u8 = (u8_t)u16;
+	u8 = (u16_t)u8;
+	/* expect+1: no-op cast from 'unsigned short' to 'unsigned short' [Q6] */
+	u8 = (u16_t)u16;
+	/* expect+1: no-op cast from 'unsigned char' to 'unsigned char' [Q6] */
+	u16 = (u8_t)u8;
+	u16 = (u8_t)u16;
+	/* expect+1: redundant cast from 'unsigned char' to 'unsigned short' before assignment [Q7] */
+	u16 = (u16_t)u8;
+	/* expect+2: no-op cast from 'unsigned short' to 'unsigned short' [Q6] */
+	/* expect+1: redundant cast from 'unsigned short' to 'unsigned short' before assignment [Q7] */
+	u16 = (u16_t)u16;
+
+	/* Mixing signed and unsigned types. */
+	u8 = (u8_t)s8;
+	s8 = (s8_t)u8;
+	/* expect+1: redundant cast from 'unsigned char' to 'short' before assignment [Q7] */
+	s16 = (s16_t)u8;
+	/* expect+1: redundant cast from 'signed char' to 'short' before assignment [Q7] */
+	s16 = (s16_t)s8;
+
 
-	return str;
+	/*
+	 * Neither GCC nor Clang accept typeof(bit-field), as that would add
+	 * unnecessary complexity.  Lint accepts it but silently discards the
+	 * bit-field portion from the type; see add_type.
+	 */
+	/* expect+1: redundant cast from 'unsigned char' to 'unsigned int' before assignment [Q7] */
+	bits.u9 = (typeof(bits.u9))u8;
+
+
+	/* expect+2: no-op cast from 'float' to 'float' [Q6] */
+	/* expect+1: redundant cast from 'float' to 'float' before assignment [Q7] */
+	f32 = (f32_t)f32;
+	f32 = (f32_t)f64;
+	f32 = (f64_t)f32;
+	/* expect+1: no-op cast from 'double' to 'double' [Q6] */
+	f32 = (f64_t)f64;
+	/* expect+1: no-op cast from 'float' to 'float' [Q6] */
+	f64 = (f32_t)f32;
+	f64 = (f32_t)f64;
+	/* expect+1: redundant cast from 'float' to 'double' before assignment [Q7] */
+	f64 = (f64_t)f32;
+	/* expect+2: no-op cast from 'double' to 'double' [Q6] */
+	/* expect+1: redundant cast from 'double' to 'double' before assignment [Q7] */
+	f64 = (f64_t)f64;
+
+
+	/* expect+2: no-op cast from 'float _Complex' to 'float _Complex' [Q6] */
+	/* expect+1: redundant cast from 'float _Complex' to 'float _Complex' before assignment [Q7] */
+	c32 = (c32_t)c32;
+	c32 = (c32_t)c64;
+	c32 = (c64_t)c32;
+	/* expect+1: no-op cast from 'double _Complex' to 'double _Complex' [Q6] */
+	c32 = (c64_t)c64;
+	/* expect+1: no-op cast from 'float _Complex' to 'float _Complex' [Q6] */
+	c64 = (c32_t)c32;
+	c64 = (c32_t)c64;
+	/* expect+1: redundant cast from 'float _Complex' to 'double _Complex' before assignment [Q7] */
+	c64 = (c64_t)c32;
+	/* expect+2: no-op cast from 'double _Complex' to 'double _Complex' [Q6] */
+	/* expect+1: redundant cast from 'double _Complex' to 'double _Complex' before assignment [Q7] */
+	c64 = (c64_t)c64;
+
+
+	/* expect+1: redundant cast from 'pointer to void' to 'pointer to char' before assignment [Q7] */
+	str = (char *)allocate();
+	/* expect+1: redundant cast from 'pointer to void' to 'pointer to const char' before assignment [Q7] */
+	cstr = (const char *)allocate();
+	cstr = (char *)allocate();
 }
 
 

Index: src/usr.bin/xlint/lint1/README.md
diff -u src/usr.bin/xlint/lint1/README.md:1.8 src/usr.bin/xlint/lint1/README.md:1.9
--- src/usr.bin/xlint/lint1/README.md:1.8	Tue Jul  5 22:50:41 2022
+++ src/usr.bin/xlint/lint1/README.md	Fri Jul  8 20:27:36 2022
@@ -1,4 +1,4 @@
-[//]: # ($NetBSD: README.md,v 1.8 2022/07/05 22:50:41 rillig Exp $)
+[//]: # ($NetBSD: README.md,v 1.9 2022/07/08 20:27:36 rillig Exp $)
 
 # Introduction
 
@@ -161,15 +161,16 @@ See `expr_free_all`.
 
 Useful breakpoints are:
 
-| Function            | File   | Remarks                                              |
-|---------------------|--------|------------------------------------------------------|
-| build_binary        | tree.c | Creates an expression for a unary or binary operator |
-| initialization_expr | init.c | Checks a single initializer                          |
-| expr                | tree.c | Checks a full expression                             |
-| typeok              | tree.c | Checks two types for compatibility                   |
-| vwarning_at         | err.c  | Prints a warning                                     |
-| verror_at           | err.c  | Prints an error                                      |
-| assert_failed       | err.c  | Prints the location of a failed assertion            |
+| Function/Code       | File    | Remarks                                              |
+|---------------------|---------|------------------------------------------------------|
+| build_binary        | tree.c  | Creates an expression for a unary or binary operator |
+| initialization_expr | init.c  | Checks a single initializer                          |
+| expr                | tree.c  | Checks a full expression                             |
+| typeok              | tree.c  | Checks two types for compatibility                   |
+| vwarning_at         | err.c   | Prints a warning                                     |
+| verror_at           | err.c   | Prints an error                                      |
+| assert_failed       | err.c   | Prints the location of a failed assertion            |
+| `switch (yyn)`      | cgram.c | Reduction of a grammar rule                          |
 
 # Tests
 

Index: src/usr.bin/xlint/lint1/tree.c
diff -u src/usr.bin/xlint/lint1/tree.c:1.472 src/usr.bin/xlint/lint1/tree.c:1.473
--- src/usr.bin/xlint/lint1/tree.c:1.472	Wed Jul  6 22:26:30 2022
+++ src/usr.bin/xlint/lint1/tree.c	Fri Jul  8 20:27:36 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: tree.c,v 1.472 2022/07/06 22:26:30 rillig Exp $	*/
+/*	$NetBSD: tree.c,v 1.473 2022/07/08 20:27:36 rillig Exp $	*/
 
 /*
  * Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID)
-__RCSID("$NetBSD: tree.c,v 1.472 2022/07/06 22:26:30 rillig Exp $");
+__RCSID("$NetBSD: tree.c,v 1.473 2022/07/08 20:27:36 rillig Exp $");
 #endif
 
 #include <float.h>
@@ -116,20 +116,20 @@ u64_fill_right(uint64_t x)
 	return x;
 }
 
-static bool
-ic_maybe_signed(const type_t *tp, const integer_constraints *ic)
+static unsigned
+width_in_bits(const type_t *tp)
 {
 
-	return !is_uinteger(tp->t_tspec) &&
-	    (ic->bclr & ((uint64_t)1 << 63)) == 0;
+	lint_assert(is_integer(tp->t_tspec));
+	return tp->t_bitfield ? tp->t_flen : size_in_bits(tp->t_tspec);
 }
 
-static unsigned
-ic_length_in_bits(const type_t *tp)
+static bool
+ic_maybe_signed(const type_t *tp, const integer_constraints *ic)
 {
 
-	lint_assert(is_integer(tp->t_tspec));
-	return tp->t_bitfield ? tp->t_flen : size_in_bits(tp->t_tspec);
+	return !is_uinteger(tp->t_tspec) &&
+	    (ic->bclr & ((uint64_t)1 << 63)) == 0;
 }
 
 static integer_constraints
@@ -137,7 +137,7 @@ ic_any(const type_t *tp)
 {
 	integer_constraints c;
 
-	uint64_t vbits = value_bits(ic_length_in_bits(tp));
+	uint64_t vbits = value_bits(width_in_bits(tp));
 	if (is_uinteger(tp->t_tspec)) {
 		c.smin = INT64_MIN;
 		c.smax = INT64_MAX;
@@ -177,7 +177,7 @@ static integer_constraints
 ic_cvt(const type_t *ntp, const type_t *otp, integer_constraints a)
 {
 
-	if (ic_length_in_bits(ntp) > ic_length_in_bits(otp) &&
+	if (width_in_bits(ntp) > width_in_bits(otp) &&
 	    is_uinteger(otp->t_tspec))
 		return a;
 	return ic_any(ntp);
@@ -2476,7 +2476,7 @@ can_represent(const type_t *tp, const tn
 	debug_step("%s: type '%s'", __func__, type_name(tp));
 	debug_node(tn);
 
-	uint64_t nmask = value_bits(ic_length_in_bits(tp));
+	uint64_t nmask = value_bits(width_in_bits(tp));
 	if (!is_uinteger(tp->t_tspec))
 		nmask >>= 1;
 
@@ -3351,6 +3351,42 @@ build_colon(bool sys, tnode_t *ln, tnode
 	return ntn;
 }
 
+static bool
+is_cast_redundant(const tnode_t *tn)
+{
+	const type_t *ntp = tn->tn_type, *otp = tn->tn_left->tn_type;
+	tspec_t nt = ntp->t_tspec, ot = otp->t_tspec;
+
+	if (nt == BOOL && ot == BOOL)
+		return true;
+
+	if (is_integer(nt) && is_integer(ot)) {
+		unsigned int nw = width_in_bits(ntp), ow = width_in_bits(otp);
+		if (is_uinteger(nt) == is_uinteger(ot))
+		       return nw >= ow;
+		return is_uinteger(ot) && nw > ow;
+	}
+
+	if (is_floating(nt) && is_floating(ot))
+		return size_in_bits(nt) >= size_in_bits(ot);
+
+	if (is_complex(nt) && is_complex(ot))
+		return size_in_bits(nt) >= size_in_bits(ot);
+
+	if (nt == PTR && ot == PTR) {
+		if (!ntp->t_subt->t_const && otp->t_subt->t_const)
+			return false;
+		if (!ntp->t_subt->t_volatile && otp->t_subt->t_volatile)
+			return false;
+
+		if (ntp->t_subt->t_tspec == VOID ||
+		    otp->t_subt->t_tspec == VOID)
+			return true;
+	}
+
+	return false;
+}
+
 /*
  * Create a node for an assignment operator (both = and op= ).
  */
@@ -3409,7 +3445,8 @@ build_assignment(op_t op, bool sys, tnod
 	}
 
 	if (any_query_enabled && rn->tn_op == CVT && rn->tn_cast &&
-	    eqtype(ln->tn_type, rn->tn_type, false, false, NULL)) {
+	    eqtype(ln->tn_type, rn->tn_type, false, false, NULL) &&
+	    is_cast_redundant(rn)) {
 		/* redundant cast from '%s' to '%s' before assignment */
 		query_message(7,
 		    type_name(rn->tn_left->tn_type), type_name(rn->tn_type));

Reply via email to