Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

Confusing error message when function pointer return type is not defined #39011

Open Quuxplusone opened 5 years ago

Quuxplusone commented 5 years ago
Bugzilla Link PR40039
Status NEW
Importance P enhancement
Reported by Yuxuan Shui (yshuiv7@gmail.com)
Reported on 2018-12-15 16:07:36 -0800
Last modified on 2018-12-19 09:47:01 -0800
Version trunk
Hardware PC Linux
CC dblaikie@gmail.com, llvm-bugs@lists.llvm.org, neeilans@live.com, richard-llvm@metafoo.co.uk
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also
Code:

    int (*func)(int *); // <- this is a normal function

    // this is a function that returns a function type,
    // which is totally fine
    int (*(*funcx)(int *))(int *);

    //typedef struct asd asdf; // <- code compiles with this line, as expected

    // what is clang complaining about?
    asdf (*func2)(int *);

For the last line, clang complains about:

    error: function cannot return function type 'int (int *)'

Which makes no sense to me.

Compiler explorer link: https://godbolt.org/z/dUf9t4
Quuxplusone commented 5 years ago
The two prior diagnostics describe what Clang is thinking:

<source>:8:8: warning: type specifier missing, defaults to 'int' [-Wimplicit-
int]
asdf (*func2)(int *);
       ^

<source>:8:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-
int]
asdf (*func2)(int *);
^

So Clang thinks the only way this could parse is if you forgot a type-specifier
in two places, and (following C tradition) assumes you missed an 'int'. So it's
imagining you wrote:

int asdf(int *func2)(int *);

... which declares asdf as a function taking an int* and returning a function
of type 'int (int *)'.

In this case it'd be better to diagnose that the type 'asdf' is unknown, which
is what Clang does in C++ mode, but we appear to intentionally(?) support
implicit int here as an extension, which makes it challenging to treat this as
anything other than the above (ill-formed but syntactically valid) function
declaration.

I'm leaving this open because I'd like for us to do better diagnosing this, but
realistically I think the only way that's going to happen is if we remove the
'implicit int' extension in the above case.
Quuxplusone commented 5 years ago
> we appear to intentionally(?) support implicit int here as an extension

For clarity: the "here" here is in a function parameter, in a context where no
specifier is present at all. It seems reasonable to support implicit int in a
function return type when no specifiers are present, because that's valid when
defining a function in at least some modes (GCC also permits such invalid
code). And in the case where another specifier is present, the declaration
would be valid in C89 (eg, "int f(register *param);" declares f as taking an
"int *"). But there is no language mode in which you can use "int f(*p);" to
declare a function taking an "int*".
Quuxplusone commented 5 years ago

I see. If we have to keep this error message, we can still add a note telling the user what might be wrong (I.e. they missed a type declaration)

Quuxplusone commented 5 years ago
BTW, GCC and clang have different opinions on how to parse this:

    asdf (*qwer);

GCC:

    <source>:1:7: error: expected declaration specifiers or '...' before '*' token
asdf (*qwer);
      ^

clang:

<source>:1:8: warning: type specifier missing, defaults to 'int' [-Wimplicit-
int]

asdf (*a);

       ^

<source>:1:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-
int]

asdf (*a);
^
Quuxplusone commented 5 years ago
It is actually a bit weirder:

    asdf (a);

Does not parse in clang, because:

<source>:3:5: error: a parameter list without types is only allowed in a
function definition

But clang happily accepts

    asdf (*a);
Quuxplusone commented 5 years ago

And asdf(a) parses in gcc as a functino declaration.