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));