cc65: Erroneous error for K & R function definitions with enum parameters

This gives an error with --standard c89, but should be OK:

enum E { I };
extern int f(enum E);
int f(e) 
  enum E e;
{
  return 1;
}
% cc65 --standard c89 /tmp/func3.c
/tmp/func3.c(5): Error: Conflicting function types for 'f'
/tmp/func3.c(7): Warning: Parameter 'e' is never used
1 errors and 1 warnings generated.

This works with gcc, and used to work with cc65. gcc godbolt old cc65 godbolt

I didn’t try to bisect, but maybe one of @acqn’s function handling changes broke this.

It would also be nice if the error message said what the compiler thought the conflicting types were.

The line numbers are also a bit strange, since lines 5 and 7 are the opening and closing curly braces, respectively.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 15 (15 by maintainers)

Commits related to this issue

Most upvoted comments

Wow that’s a lot to reply to. So I’ll break down into several posts.

The goal is to get to make clear what is the problem and how to resolve that, right? 😉

So let’s start with the “old K & R style” topic:

@mrdudz

mmmh, as far as i understand it, both cases are basically promoted to int, so they are “the same”. i am not sure how to interpret the standard here either 😃

No, I don’t think so. It reads to me that the prototype form doesn’t do that promotion for comparison, but only the “old K & R form” does.

@greg-king5

Also, I think that your cited part of https://port70.net/~nsz/c/c89/c89-draft.html#3.5.4.3 applies to only K & R function-definitions that have a parameter without a type declaration. It applies to

int f(e)
{
  return e;
}

I think that it doesn’t apply to

int f(e)
  enum E e;
{
  return e;
}

In other words,

1. the first definition has "an identifier list",

2. the second definition actually has "a parameter type list" -- the type merely is in a different place.

There are some statements with an example in the standard text (https://port70.net/~nsz/c/c89/c89-draft.html#3.7.1) that disagree, if I don’t misinterpret them:

quote begins

Semantics

The declarator in a function definition specifies the name of the function being defined and the identifiers of its parameters. If the declarator includes a parameter type list, the list also specifies the types of all the parameters; such a declarator also serves as a function prototype for later calls to the same function in the same translation unit. If the declarator includes an identifier list, the types of the parameters may be declared in a following declaration list. Any parameter that is not declared has type int .

Examples

         extern int max(int a, int b)
         {
                  return a > b ? a : b;
         }

Here extern is the storage-class specifier and int is the type specifier (each of which may be omitted as those are the defaults); max(int a, int b) is the function declarator; and

         { return a > b ? a : b; }

is the function body. The following similar definition uses the identifier-list form for the parameter declarations:

         extern int max(a, b)
         int a, b;
         {
                  return a > b ? a : b;
         }

Here int a, b; is the declaration list for the parameters, which may be omitted because those are the defaults. The difference between these two definitions is that the first form acts as a prototype declaration that forces conversion of the arguments of subsequent calls to the function, whereas the second form may not.

quote ends

That’s to say, the identifier-list form is not a parameter type list, even if the former had all types of the parameters specified.