Skip to content

[4.14] C17 fixes (strict prototypes and others) #12577

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 19, 2023

Conversation

MisterDA
Copy link
Contributor

Changes backported from trunk to fix strict prototypes, old style definition, unused variables warnings. The warnings are raised by clang (by default in GNU C17 mode), failing the build of the compiler (with the warnings-as-error -Werror flag), and headers with non-strict prototypes leak into user code, adding warnings when compiling C stubs or when using the bytecode compiler.
I've regrouped the commits by topic, since the issues took multiple PRs to get fixed in trunk, and that code can be slightly different between 4.14 and 5.x ;)

It is always possible to cast a function pointer to another function
pointer type, and cast again to the original type before calling the
pointed function. I pick the base

    typedef value (*c_primitive)(void);

to store the functions in the array, and cast them back in the
interpreter according to the arity described by the opcode.

Some references:
- [Function pointers in C][1]
- [Function pointer casts][2]

[1]: https://frama-c.com/2013/08/24/Function-pointers-in-C.html
[2]: https://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

The primitives function pointers can be stored as simple void
pointers:

(Comment by Xavier Leroy: ocaml#11763 (comment))

> Note that ISO C forbids casting a function pointer to type void *,
> but we've been doing this for a very long time, and all C compilers
> that I know of are happy with this.

This is documented by C11 Standard J.5.7, Function pointer casts.

The prototypes in `prims.c` and the headers differ, but:

(Comment by Xavier Leroy: ocaml#11763 (comment))

> On the one hand, it's not legal C11 to declare value f(void) a
> function f that is defined in another compilation unit as value
> f(value), say; while I think it is correct to declare it value f(),
> like we currently do. On the other hand, this is no worse than the
> many other "not legal C11" things we already do.

(cherry picked from commit 8db1817)

Use strict prototypes on primitives in bytecomp

The bytecode compiler also extracts the list of primitives to a C
file, similarly as the Makefile. The Makefile was fixed in
8db1817 to account for stricter C
function prototypes, but the bytecomp problems were not discovered
back then.

As the startup code includes `caml/mlvalues.h`, two primitives are
declared twice with conflicting types. We prevent this with
preprocessor tricks before including the header.

The generated C code now also uses the same names as in the Makefile.

(cherry picked from commit e650dd9)
As a reminder, `f()` declares `f` as an old-style function that can be
applied to any number of arguments.

(cherry picked from commit 87f12bb)
(cherry picked from commit 28c4300)
Copy link
Contributor

@NickBarnes NickBarnes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Very glad to see the end of K&R.

for i = 0 to Array.length prim - 1 do
fprintf outchan " %s,\n" prim.(i)
done;
fprintf outchan " (primitive) 0 };\n";
fprintf outchan " 0 };\n";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why lose this cast? Also, is there a reason we don't say "NULL"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are backports, the goal is to align on the current trunk code.
To the best of my knowledge, the cast is unnecessary here. IIRC (strict) C only requires casting NULL to the correct pointer type as an argument to a variadic function. The code has always been this way, the version in this file was using casts, but the version in the makefiles wasn't. I chose to remove unnecessary information.
As for using 0 or NULL, they're also equivalent in this context. No strong opinion here.

fprintf outchan "const char * caml_names_of_builtin_cprim[] = {\n";
for i = 0 to Array.length prim - 1 do
fprintf outchan " \"%s\",\n" prim.(i)
done;
fprintf outchan " (char *) 0 };\n"
fprintf outchan " 0 };\n"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why lose this cast? And why not "NULL"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same arguments as above.

@@ -1049,12 +1049,10 @@ void read_declarations(void)
void output_token_type(void)
{
bucket * bp;
int n;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these changes to suppress an unused variable warning?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's activated by default in clang, and fails the build. This code has been rewritten at some point in trunk, so the problem had evaporated on its own.

@MisterDA
Copy link
Contributor Author

The fun thing is that the transition from fn() to fn(void) is required in C11/C17 but not in C23, as they now have the same semantics, akin to C++.

Copy link
Contributor

@xavierleroy xavierleroy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice backporting work, and very useful too. Thanks!

@xavierleroy
Copy link
Contributor

I'm running a round of "CI precheck" with this PR, just to make sure. Will merge after this.

@xavierleroy xavierleroy merged commit 06c65f9 into ocaml:4.14 Sep 19, 2023
@MisterDA MisterDA deleted the 4.14-c17 branch September 19, 2023 08:21
dra27 pushed a commit to dra27/ocaml that referenced this pull request Jul 29, 2024
On 4.14 branch: C17 fixes (strict prototypes and others)
dra27 pushed a commit to dra27/ocaml that referenced this pull request Jul 29, 2024
On 4.14 branch: C17 fixes (strict prototypes and others)
dra27 pushed a commit to dra27/ocaml that referenced this pull request Jul 29, 2024
On 4.14 branch: C17 fixes (strict prototypes and others)
dra27 pushed a commit to dra27/ocaml that referenced this pull request Jul 29, 2024
On 4.14 branch: C17 fixes (strict prototypes and others)
dra27 pushed a commit to dra27/ocaml that referenced this pull request Jul 29, 2024
On 4.14 branch: C17 fixes (strict prototypes and others)
dra27 pushed a commit to dra27/ocaml that referenced this pull request Jul 29, 2024
On 4.14 branch: C17 fixes (strict prototypes and others)
dra27 pushed a commit to dra27/ocaml that referenced this pull request Jul 29, 2024
On 4.14 branch: C17 fixes (strict prototypes and others)
dra27 pushed a commit to dra27/ocaml that referenced this pull request Jul 29, 2024
On 4.14 branch: C17 fixes (strict prototypes and others)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants