Re: Why is this not an error in Visual C?



On 2009-05-04, Ben Bacarisse <ben.usenet@xxxxxxxxx> wrote:
Kaz Kylheku <kkylheku@xxxxxxxxx> writes:

On 2009-05-02, Han from China <autistic-pedantry@xxxxxxxxxxx> wrote:
Kaz Kylheku wrote:
Han from China wrote:
The constraint that is violated is 6.7{4}:

All declarations in the same scope that refer to the same object or
function shall specify compatible types.

To demonstrate a constraint violation, we must show that

extern int foo(int,int,int,int);

and

int foo(a,b,c,d,e)

int a,b,c,d,e;
{
...
}

involve declarations of incompatible types.

They are not declarations of incompatible types.

They are according to 6.7.5.3{15}:

__For two function types to be compatible__ ... If one type has a
parameter type list and the other type is specified by a function
definition that contains a (possibly empty) identifer list, both shall
agree in the number of parameters, and the type of each prototype
parameter shall be compatible with the type that results from the
application of the default argument promotions to the type of the
corresponding identifier.

So this actually does require implementations to pull out the full type
info from an old-style defintion. Not only number of parameters, but their
promoted types from the old-style declarations that precede the
body.

This is not a constraint so there is no requirement on an
implementation to spot the problem.

This is not a constraint, but it's a semantic rule. The rule essentially
says that when an old-style function definition is processed, then
the parameter declarations are incorporated into the type info for that
function. The function is declared to have a type which includes information
about the number of parameters which it has, and their types.

As far as I'm concerned, this full type info constitutes a prototype.
No reasonable, sane distinction can be drawn between the term ``prototype'' as
used in the context of the C language, and ``the state of knowing the number
and types of arguments of a function''.

The constraint that is violated is elsewhere, as Han From China pointed
out, namely in 6.7{4}:

All declarations in the same scope that refer to the same object or function
shall specify compatible types.

Good work, HFC.

Yet, we are to believe the old-style definition does not serve as a
prototype!

Well, yes, because it does not serve as one!

In any case, this this doesn't invalidate the applicability of constraint
6.7{4}, because that constraint is not predicated in any way on whether some
declaration serves or doesn't serve as a prototype! It's just about
type compatibility, with no exception for functions that are not
considered prototypes.

Given these declarations:

int foo(int);

int foo(x)
double x;
{
}

It's clear that they have incompatible types by 6.7.5.13{15} and that they are
two declarations for the same identifier, in the same scope, which consequently
violates 6.7{4}.

Now this second declaration is supposedly not a prototype. What this means is
that even though C implementations are required to record the full type
information for a function definition, even if it is old-style, they must not
use it when translating calls to the function. Doh?

In other words, the type information is all there, but using it is forbidden;
there must be a bit in the symbol table which tells the compiler ``all the type
info for this function is here, but do not make use of it when compiling a call
to that function; pretend that its argument list has not been declared.
Oh, but do use it when considering whether another declartion of this name is
compatible with this one.''

Sorry, that makes no sense. Sound engineering dictates that if you have the
type info, you simply use it whenever applicable.

I am sure you can see
the difference between the default argument promotions and the type
conversion and checking that a prototype provides.

If the compiler knows what the parameter types are, it should generate code
which converts the argument expressions to those types, and diagnose any
constraints if the expressions are not assignment-compatible compatible with
the parameter types.

For instance after the definition

int foo(a)
int a;
{
}

the call

foo(3.0);

should behave exactly as if we had:

extern int foo(int);
foo(3.0);

this is because foo was in fact declared to have type ``int (int)''.

This is like not fastening a seatbelt or putting on a life jacket, when these
safety devices are available.

State-of-the-art statically typed languages go out of the way to infer type
information in the absence of declarations, yet here it is being thrown away.
.



Relevant Pages

  • Re: Why is this not an error in Visual C?
    ... int foo ... What we're looking for to describe MSVC as broken is a constraint ... involve declarations of incompatible types. ... compatibility and of a composite type, ...
    (comp.lang.c)
  • Re: Why is this not an error in Visual C?
    ... says that when an old-style function definition is processed, ... That is, I think, `int fint x; ... Concerning the compatibility of function ... All declarations in the same scope that refer to the same object or function ...
    (comp.lang.c)
  • Re: Why is this not an error in Visual C?
    ... says that when an old-style function definition is processed, ... That is, I think, `int fint x; ... Concerning the compatibility of function ... All declarations in the same scope that refer to the same object or function ...
    (comp.lang.c)
  • Re: typedef Used to Cast Function Pointers
    ... >> the result shall compare equal to the original pointer. ... integer type, usually int. ... The more complicated cases are compatibility between or with ... Both prototyped and unprototyped declarations of a ...
    (comp.lang.c)
  • Re: Why is this not an error in Visual C?
    ... because that constraint is not predicated in any way on whether some ... declaration serves or doesn't serve as a prototype! ... Given these declarations: ...
    (comp.lang.c)