Fix warnings reported by MSVC (-W2) and clang-cl (-W4)#13243
Fix warnings reported by MSVC (-W2) and clang-cl (-W4)#13243shindere merged 18 commits intoocaml:trunkfrom
-W2) and clang-cl (-W4)#13243Conversation
nojb
left a comment
There was a problem hiding this comment.
Thanks! A chunk of the diff is dead code removal and clearly correct. Some of the other changes involve introducing explicit type casts; it would be good to have a second opinion because this can sometimes be tricky. Otherwise, I am happy to approve this PR.
@dustanddreams maybe you can take a look? Thanks!
| #define Enter_gc_preserve_vals(dom_st, wosize) do { \ | ||
| CAMLparam0(); \ | ||
| CAMLlocalN(vals_copy, (wosize)); \ | ||
| for (mlsize_t j = 0; j < (wosize); j++) vals_copy[j] = vals[j]; \ |
There was a problem hiding this comment.
Why did you had to introduce a new local for the loop counter? Enter_gc_preserve_vals is only used from the Do_alloc_small macro next to it, which declares mlsize_t i.
Is there a warning about the use of i which is neither local to nor an argument of the macro? If so, such a too-pendantic warning ought to be disabled.
There was a problem hiding this comment.
caml_alloc_9 defines parameters from a to i:
CAMLexport value caml_alloc_9 (tag_t tag, value a, value b, value c, value d,
value e, value f, value g, value h, value i)
{
Do_alloc_small(9, tag, a, b, c, d, e, f, g, h, i);
}then Do_alloc_small expands to
#define Do_alloc_small(wosize, tag, ...) \
{ \
Caml_check_caml_state(); \
value v; \
value vals[wosize] = {__VA_ARGS__}; \
mlsize_t i; \
CAMLassert ((tag) < 256); \
// ...the local i shadows the i parameter, thus the warning. Also, the Enter_gc_preserve_vals relies on the outer block declaring i, which I don't find particularly nice.
My intent was to kill two birds with one stone: first remove the shadowing warning by renaming the local i to j, then reduce the scope of the for loop iterators.
This was an incursion into MSVC level 4 warnings, so I'll just withdraw this commit.
| Alloc_small(v, wosize, tag, Enter_gc_preserve_vals); \ | ||
| for (i = 0; i < (wosize); i++) { \ | ||
| Field(v, i) = vals[i]; \ | ||
| for (mlsize_t j = 0; j < (wosize); j++) { \ |
There was a problem hiding this comment.
Almost the same question here. Why did you have to rename the variable and reduce its scope? Did you get a shadowing warning? If so, wouldn't simply rename from i to something else in both macros would be good enough?
There was a problem hiding this comment.
See the answer above. I'll withdraw the commit.
runtime/ints.c
Outdated
| } | ||
| } | ||
| if (sign < 0) res = - res; | ||
| if (sign < 0) res = ~res + 1; |
There was a problem hiding this comment.
Not really fond of this. Wouldn't res = (uint64_t)-res be good enough to silence those warnings?
There was a problem hiding this comment.
I agree with @dustanddreams 's comment. Writing ~x + 1 instead of -x is correct but really hard to read.
There was a problem hiding this comment.
res is already uint64_t. Not sure how (uint64_t)-(int64_t)res really behaves.
res = UINT64_MAX - res + 1 isn't an improvement.
What if we went with a comment? res = ~res + 1 /* res = -res */
There was a problem hiding this comment.
If res is already int64_t, then (uint64_t)-res will work nicely, since its value has already been bounds checked above so we know 0 <= res <= INT64_MAX.
There was a problem hiding this comment.
I think you've misread, res is unsigned (uint64_t). The compiler warning is probably overzealous, but the compiler doesn't like when an unary minus is applied to an unsigned integer.
There was a problem hiding this comment.
Ah, so two casts. Ugly but still more human-friendly than bitmasking.
There was a problem hiding this comment.
Turns out a single cast is sufficient.
xavierleroy
left a comment
There was a problem hiding this comment.
I reviewed this PR a while ago but apparently forgot to submit the review. I'm globally in favor of this PR, but there are a few places where I think a better fix is warranted, see below.
runtime/major_gc.c
Outdated
| heap_sweep_words = (uintnat)heap_words; | ||
|
|
||
| total_cycle_work = | ||
| heap_sweep_words + (heap_words * 100 / (100 + caml_percent_free)); | ||
| heap_sweep_words + (uintnat)(heap_words * 100 / (100 + caml_percent_free)); |
There was a problem hiding this comment.
The original code is strange: why is heap_words a double-precision FP number when it obviously always holds integer values? I'd rather declare heap_words as uintnat and fix the only place where it needs to be converted to FP:
total_cycle_work =
heap_sweep_words + (uintnat) ((double) heap_words * 100.0 / (100.0 + caml_percent_free));
runtime/ints.c
Outdated
| } | ||
| } | ||
| if (sign < 0) res = - res; | ||
| if (sign < 0) res = ~res + 1; |
There was a problem hiding this comment.
I agree with @dustanddreams 's comment. Writing ~x + 1 instead of -x is correct but really hard to read.
runtime/caml/platform.h
Outdated
| Caml_inline uintnat atomic_fetch_sub_verify_ge0(atomic_uintnat* p, uintnat v) { | ||
| uintnat result = atomic_fetch_sub(p,v); |
There was a problem hiding this comment.
I'm used to "fetch and add", so "fetch and sub" feels a bit strange. Why not declare the second parameter as intnat v and keep using "fetch and add -1" ? This way the rest of the code doesn't need to be changed.
There was a problem hiding this comment.
It wouldn't work for direct calls to atomic_fetch_sub. There's just one of them, I'll keep it. Your idea works for the rest, thanks.
| { | ||
| int i; | ||
| for (i = 0; i < sizeof(posix_signals) / sizeof(int); i++) | ||
| for (int i = 0; i < (int)(sizeof(posix_signals) / sizeof(int)); i++) |
There was a problem hiding this comment.
Is the (int) cast necessary? Why change the original code?
There was a problem hiding this comment.
I wanted to avoid a clang-cl warning, but I ended up disabling this warning (too much to "fix"). I also thought this change had a nice symmetry with the one above.
runtime/signals.c(516,21): error: comparison of integers of different signs: 'int' and 'unsigned long long' [-Werror,-Wsign-compare]
516 | for (int i = 0; i < sizeof(posix_signals) / sizeof(int); i++)
| ~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6e6a091 to
e48bc05
Compare
|
I think I've addressed all the comments, many thanks for the reviews. |
5b011b0 to
c2f6f38
Compare
|
@dustanddreams are you happy with the PR in its current state?
If so, I'm happy to approve on your behalf.
|
|
It's conflicting with trunk now, I need to rebase. |
|
Antonin Décimo (2024/07/18 08:26 -0700):
It's conflicting with trunk now, I need to rebase.
Oops, sorry, too quick.
|
|
Rebased! |
|
Thanks. Happy to approve on somebody's behalf if necessary.
|
This makes CAMLunused macros work with clang-cl, which doesn't define __GNUC__ and doesn't support this MSVC compiler pragma.
Avoids an unused variable warning for the perm value on Windows in:
int perm = Int_val(vperm);
ret = mkdir_os(path, perm);
> runtime/major_gc.c: warning C4244: '=': conversion from 'double' to 'uintnat', possible loss of data > runtime/major_gc.c: warning C4244: '=': conversion from 'double' to 'uintnat', possible loss of data Co-authored-by: Xavier Leroy <xavier.leroy@college-de-france.fr>
> runtime/gc_ctrl.c: warning C4244: 'initializing': conversion from 'uintnat' to 'double', possible loss of data > runtime/major_gc.c: warning C4244: 'initializing': conversion from 'uintnat' to 'double', possible loss of data > runtime/major_gc.c: warning C4244: 'initializing': conversion from 'intnat' to 'double', possible loss of data > runtime/major_gc.c: warning C4244: 'initializing': conversion from 'intnat' to 'double', possible loss of data
> runtime/major_gc.c(1353): warning C4244: 'initializing': conversion from 'intnat' to 'double', possible loss of data
> runtime/memprof.c: warning C4244: 'initializing': conversion from 'int32_t' to 'float', possible loss of data
gettimeofday_win32.c: warning C4244: =: conversion from ULONGLONG to double, possible loss of data
> sleep_win32.c: warning C4244: function: conversion from double to DWORD, possible loss of data > select_win32.c: warning C4244: =: conversion from double to DWORD, possible loss of data
> runtime/ints.c: warning C4146: unary minus operator applied to unsigned type, result still unsigned > runtime/backtrace_nat.c: warning C4146: unary minus operator applied to unsigned type, result still unsigned > runtime/backtrace_nat.c: warning C4146: unary minus operator applied to unsigned type, result still unsigned
> unixsupport_win32.c: warning C4146: unary minus operator applied to unsigned type, result still unsigned > runtime/signals.c: warning C4146: unary minus operator applied to unsigned type, result still unsigned
Static values are zero-initialized by default. clang-cl would warn that the remaining fields are missing initializers.
This prevents warnings when -1 is converted to an unsigned type.
No need to test for versions of MSVC before 1939, they don't support C11 atomics. MSVC now supports the inline C keyword. No need for __assume(0) to mark unreachable code paths as ExitProcess is already __declspec(noreturn).
|
Rebased to fix conflicts. |
|
Thanks. Approving this on behalf of @dustanddreams.
|
This PR fixes warnings raised by MSVC at level 2, and clang-cl at level 4 (minus unused parameters and sign-compare). It should be rather uneventful. I think it's sane to enable some warnings rather than none at all (the current), but C compilers (and sometimes programmers too) have a tendency of being overzealous when they report issues.
MSVC really likes to warn when an assignment of two different ranges, like float to int, is made without an explicit cast. If the warnings C4244 and C4146 are too annoying, they could also be disabled.
Clang-cl
-Wallis equivalent to clang-Weverything, which is really too noisy, and enables some C++ warnings. Levels above 2 for MSVC are also noisy, and some warnings are even checking for C++ things in C. Someone with spare time might revisit this later…