Subject: Re: ansi.h merger
To: None <eeh@netbsd.org, tv@wasabisystems.com>
From: None <eeh@netbsd.org>
List: tech-toolchain
Date: 07/28/2001 19:17:41
| On 28 Jul 2001 eeh@netbsd.org wrote:
|
| : | If the struct member really is "int", you have to cast it anyway -- you lose
| : | signedness if you try to autoconvert it to size_t (which is unsigned).  This
| : | is required.
| : |
| : | If the struct member is "unsigned [int]", you shouldn't have to cast it, as
| : | the autoconversion rules in C99 will let this be promoted to "unsigned long"
| : | (where that is the type of size_t) without a warning.
| :
| : OTOH, if you assign a size_t to that member, on some platforms you need
| : to cast it since size_t is unsigned long and you lose precision, and on
| : others (most) you don't.
|
| If the member is "int", you still have to cast it, because a conversion from
| unsigned to signed is not implicitly compatible.  This should be warned by
| both lint and gcc.
|
| If the member is "unsigned [int]", you might miss the warning on some
| platforms, depending on how size_t is typedef'd.  However, provided size_t
| is typedefed as "unsigned long", there are -W options to gcc that should
| warn about this particular case on all platforms.

Todd:  This is what propted this move in the first place.  size_t is *NOT*
unsigned long on any 32-bit platform except sparc and vax.  (And arm32 ELF
now Matt Thomas made that change, but that was later.)  This means no
warning what so ever on m68k, mips, sh3, and x86.


|
| ===
|
| : The problem is that most people are running machines in the latter
| : category and do not get warnings when they fail to add the correct casts
| : that are required on 64-bit platforms.
|
| There are ways to make gcc warn about this, actually.  For the size_t case,
| if typedefed as "unsigned long", any conversion to "int" or "unsigned [int]"
| can be flagged at compile time as an unportable implicit conversion.

This already happens.  The problem is with platforms where size_t is
"unsigned int".

| In fact, you can add some gcc extensions (that might be enabled by a
| compile-time "-D"efine) that will make all nonprimitive integer typedefs
| incompatible for implicit conversion with primitive types, if you wish.
| This would probably provide the type of auditing necessary to flag problems
| on all platforms that you want, *without* going to the length of allowing
| people to write sloppy code by flattening types arbitrarily.

So you want to hack gcc so all conversions to/from size_t always require
explicit casts even if they are to another priimitive or typedef of
the same type?  

| ===
|
| : | : | :     strncpy(foo, bar, 13);
| : | : | :
| : | : | : Well, is that 13U or 13UL? Or should I need to cast it to (size_t)13?
| : | : |
| : | : | C99 type conversion rules allow this case to be promoted without a warning,
| : | : | because the default case of nonnegative "int" constant can be promoted to
| : | : | "unsigned int" and then "unsigned long" automatically.
|
| : | Then we should fix lint.  It shouldn't bitch on this case, because "13" is a
| : | nonnegative constant.
| :
| : Or it should always bitch on all platforms whenever you do any implicit
| : conversions since they could possibly be wrong on other platforms.
|
| No, I was specifically pointing out that lint should not bitch when a
| nonnegative integer *constant* that would otherwise be of type "int" or
| "unsigned [int]" was implicitly converted to "unsigned long [int]".
|
| Lint should bitch on all implicit conversions that involve downsizing of a
| type or changing signedness, because those do break.  In most cases, if we
| plan such an ansi.h merger carefully (and I'm not saying it cannot be done
| at least partially), we can set up the typedefs to flag this in as many
| cases as possible.

Those downsizing conversions are platform dependent.  That's why all
platforms should be using `long' and `unsigned long' for ptrdiff_t
and size_t.

|
| The problem goes both ways:
|
| * If you define all 32-bit types as "[unsigned] int", you get warnings if
|   trying to convert implicitly a "[unsigned] long" into the nonprimitive
|   type.
|
| * On the other hand, if you define 32-bit types on ILP32 as "[unsigned]
|   long", you get warnings if trying to convert implicitly to an "[unsigned]
|   int" primitive, such as in the struct assignment example above.
|
| Neither situation necessarily alleviates the issues of badly written code,
| or some platforms having to clean up after others.

Then you should always issue warnings.

Eduardo