paul@UUNET.UU.NET (Paul Hudson) (03/22/89)
I've restored the infamous "possible loss of precision" lint warning. (But improved). On assigment, return etc it warns when the "signedness" of a variable is implicitly changed when a "longer" variable is assigned to a "shorter". Longer and shorter are interpreted in the wide sense that char is shorter than short is shorter than int is shorter than long (and commented out) is shorter than long long. when an enumeration variable is assigned to an enumertion variable of a different type. These are sufficiently picky that many people won't want them on. They ought to be given different -W options, but as supplied here they're on by default (not recommended). Given the following C: main() { char c; short s; int i; long l; float f; double d; struct st { int i:9; } st; c = s; s = i; i = l; f = d; c = (char)s; s = (short)i; i = (int)l; f = (float)d; d = i; i = d; c = c; s = c; i = s; l = i; l = l; st.i = i; c = st.i; s = st.i; i = st.i; } It produces the following warnings .... t.c: In function main: t.c:14: warning: possible loss of precision on assignment t.c:15: warning: possible loss of precision on assignment t.c:16: warning: possible loss of precision on assignment t.c:17: warning: double shortened to float on assignment t.c:24: warning: implicit conversion of integer to real on assignment t.c:25: warning: implicit conversion of real to integer on assignment t.c:34: warning: possible loss of precision on assignment t.c:35: warning: possible loss of precision on assignment Note that casting prevents the warning! Note that assigment to a short or char from a bit field produces a warning. I don't like this. Perhaps some more knowledgable person could point out how I tell the type's really a bit field. It's difficult to warn about bitfields because casts can't be used to remove the warning. What's needed is an extension to casts to allow "(int :4)i" constructs. The code at the end of this message is intended to be added to convert_for_assignment like this (patch not used because I've made other changes) /* Arithmetic types all interconvert, and enum is treated like int. */ if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == ENUMERAL_TYPE) && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE)) { + warn_on_assignment(TYPE_MAIN_VARIANT(type), TYPE_MAIN_VARIANT(rhstype), errtype); return convert (type, rhs); } Paul Hudson Snail mail: Monotype ADG Email: ...!ukc!acorn!moncam!paul Science Park, paul@moncam.co.uk Milton Road, "Sun Microsysytems: Cambridge, The Company is Arrogant (TM)" CB4 4FQ /* * Make lots of picky warnings about assigments */ warn_on_assignment(lhs, rhs, errstr) tree lhs, rhs; char *errstr; { if (TREE_CODE(lhs) == REAL_TYPE) { if (TREE_CODE(rhs) == INTEGER_TYPE) warning ("implicit conversion of integer to real on %s", errstr); else if (TREE_CODE(rhs) == ENUMERAL_TYPE) warning ("implicit conversion of enumeral to real on %s", errstr); else if (lhs == float_type_node && rhs == double_type_node) warning ("%s implicitly converts double to float on %s", errstr); } else if (TREE_CODE(lhs) == INTEGER_TYPE) { if (TREE_CODE(rhs) == INTEGER_TYPE) { if (TREE_UNSIGNED(lhs) && !TREE_UNSIGNED(rhs)) { warning("%s of unsigned from signed", errstr); } else if (!TREE_UNSIGNED(lhs) && TREE_UNSIGNED(rhs)) { warning("%s of signed from unsigned", errstr); } /* here we want to warn about assigments of longs to ints, even though usually they have the same number of bits */ if (size_order(lhs) < size_order(rhs)) warning("possible loss of precision on %s", errstr); } else if (TREE_CODE(rhs) == ENUMERAL_TYPE) { if (TYPE_PRECISION(rhs) > TYPE_PRECISION(lhs)) warning ("some values of enumeration may be lost on %s", errstr); } else { warning ("implicit conversion of real to integer on %s", errstr); } } else { /* enumeration */ /* This doesn't work very well because enumeration constants seem to be ints if (TREE_CODE(rhs) != ENUMERAL_TYPE) warning ("implicit conversion of non-enumeral to enumeral on %s", errstr); */ else if (lhs != rhs) { warning ("%s of enumeral type from different enumeral type", errstr); } } } /* * Return a number in the same order as the ordering of the sizes of the types, * ie char < short < int < long < long long. This is used instead of TYPE_PRECISION * because for example we'd like to warn about assigments of ints from longs, but on many * machines they are both 32 bits. */ int size_order(type) tree type; { if (type == unsigned_char_type_node || type == signed_char_type_node || type == char_type_node) return 1; else if (type == short_integer_type_node || type == short_unsigned_type_node) return 2; else if (type == integer_type_node || type == unsigned_type_node) return 3; else if (type == long_integer_type_node || type == long_unsigned_type_node) return 4; return 0; /* For some reason these aren't in c-tree.h (but are in c-decl.c) else if (type == long_long_integer_type_node || type == long_long_unsigned_type_node) return 5; */ }