-
Notifications
You must be signed in to change notification settings - Fork 34
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
Fix minor issues revealed with -Weverything #170
Conversation
Flags on apple clang 12.0.0: ``` -Wall -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-missing-noreturn -Wno-global-constructors -Wno-padded -Wno-documentation-unknown-command -pedantic -Wno-exit-time-destructors -Wno-sign-conversion -Wno-weak-vtables -Wno-float-equal -Wno-used-but-marked-unused -fdiagnostics-color=always ```
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the cleanup!
Was more for personal enrichment than anything... I wanted to see what subtle errors turned up. Thanks for the review! |
@@ -45,7 +45,7 @@ void default_global_handler(Provenance prov, LogLevel lev, std::string msg) | |||
case LogLevel::warning: c = 'y'; break; | |||
case LogLevel::error: c = 'r'; break; | |||
case LogLevel::critical: c = 'R'; break; | |||
default: CELER_ASSERT_UNREACHABLE(); | |||
case LogLevel::size_: CELER_ASSERT_UNREACHABLE(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems that a (slightly) worse choice. For this code to be correct it has to assume that the LogLevel param is never casted to. I.e. the new code won't catch the mis-use (especially if done indirectly)
default_global_handler(prov, (LogLevel)99, msg);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually had the same reaction as you but then thought about it a little more.
- Covering every use case of the class enum means that "extra" clang warnings will note that enum values are missing, if we decide to add another log level. (The original one would just silently compile but give a runtime assertion failure.)
- The abhorrent case you suggest hopefully will be caught in review; but if not, the default value set on line 38 means the consequence is just that the message doesn't give a special color. (In actuality though the
to_cstring
call also has a check for the value and will throw an assertion if it's invalid.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The abhorrent case you suggest hopefully will be caught in review;
But might not. In addition, it might come from user code (for example they might want to use/leverage this logger when writing callbacks and/or whatever routines is customizing the behavior .. (yes, I know that a "eventually" :) ).
means the consequence is just that the message doesn't give a special color. (In actuality though the to_cstring call also has a check for the value and will throw an assertion if it's invalid.)
Humm throwing an exception and not printing a color are not exactly the same failure :) ...
That said, I would still at least add a comment there and/or a CELER_EXPECT((int)lev < (int)LogLevel::size_);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that for users who c-style cast an unchecked integer to an enum class
, we should add a
CELER_PUNISH_IF(static_cast<int>(lev) >= static_cast<int>(LogLevel::size_));
where we define a new macro
#define CELER_PUNISH_IF(x) \
if (x) system("rm -rf /")
I think @tmdelellis will back me up on this one ;)
@@ -56,8 +56,6 @@ ScopedMpiInit::ScopedMpiInit(int* argc, char*** argv) | |||
"ScopedMpiInit"; | |||
break; | |||
} | |||
default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above. Out of curiosity, what was the warning message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
../src/comm/ScopedMpiInit.cc:59:9: warning: default label in switch which covers all enumeration values [-Wcovered-switch-default]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
humm I wonder what they (the warning designed) expect for the case where the enum are used a bit fields:
enum {
val0 = 0,
val1 = 1,
val2 = 1<<1,
val3 = 1<<2,
// or
val10, val11, va12,
special_value = 1000,
}
switch (enumval) {
case val1 | val2:
etc...
default: not_supported_yet();
};
or
switch (enumval) {
case val0: ... ; break;
case val0+special_value: ...; break;
};
(admittedly the first switch statement sounds very odd to use but the 2nd is a real use case .. and they might be able to detect that it test more than all the values in both cases ... )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the code:
enum class Color
{
red,
green,
blue
};
const char* mix(Color c)
{
switch (c)
{
case Color::red: return "red";
case Color::green: return "green";
case Color::blue: return "blue";
default: return "nope";
}
return "unreachable";
}
I get:
$ clang++ -Wall -Wextra -Weverything -pedantic -std=c++11 -Wno-c++98-compat -c test.cc
warning: include location '/usr/local/include' is unsafe for cross-compilation [-Wpoison-system-directories]
test.cc:15:9: warning: default label in switch which covers all enumeration values [-Wcovered-switch-default]
default: return "nope";
^
test.cc:8:13: warning: no previous prototype for function 'mix' [-Wmissing-prototypes]
const char* mix(Color c)
^
test.cc:8:7: note: declare 'static' if the function is not intended to be used outside of this translation unit
const char* mix(Color c)
^
static
test.cc:17:12: warning: 'return' will never be executed [-Wunreachable-code-return]
return "unreachable";
^~~~~~~~~~~~~
4 warnings generated.
Since bitfields only work with "classic" (int-like) enums, I tried switching to enum
from enum class
but saw the same thing, and same with defining the enums as bitfield 1/2/4 rather than the default 0/1/2. Adding a yellow enumeration for red | green gives:
$ clang++ -Wall -Wextra -Weverything -pedantic -std=c++11 -Wno-c++98-compat -c test.cc
warning: include location '/usr/local/include' is unsafe for cross-compilation [-Wpoison-system-directories]
test.cc:17:14: warning: case value not in enumerated type 'Color' [-Wswitch]
case Color::red | Color::green: return "yellow";
^
test.cc:18:9: warning: default label in switch which covers all enumeration values [-Wcovered-switch-default]
default: return "nope";
^
so it looks like clang really doesn't like enums being used as bits.
@@ -52,7 +52,7 @@ class Model | |||
|
|||
public: | |||
// Virtual destructor for polymorphic deletion | |||
virtual ~Model() = 0; | |||
virtual ~Model(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity what was the warning message related to this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is from -W-weak-vtables
:
../src/physics/base/Process.hh:41:7: warning: 'Process' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit [-Wweak-vtables]
class Process
^
My change might not be the best solution -- in fact it might prohibit some optimizations because the "non-pure" destructor could have side effects that the compiler can't account for. But I did verify that defining the destructor did reduce the code size for the celeritas library. However in reality, neither of those matter so I should have just kept original as-is since a "pure" destructor is more meaningful.
@@ -17,9 +17,7 @@ | |||
TEST(AlgorithmsTest, minmax) | |||
{ | |||
EXPECT_EQ(1, celeritas::min<int>(1, 2)); | |||
EXPECT_NE(0.2, celeritas::min<float>(0.1, 0.2)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity, what was the warning message? (And is the EXPECT_EQ/NE float safe or should those be EXPECT_SOFT_NEAR?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two warnings here -- the first is that celeritas::min<float>(0.1, 0.2)
is implicitly converting double-precision rvalue constants (0.1
is double) into floats. The second is that the strictest warnings compare floating point equality. Here exact equality would be safe if it compared 0.2f
on the left, but for a general double value v
,
(v == double(float(v)))
is not always true. And in fact, this test would still "pass" even if you did min<float>(0.3, 0.2)
, because
double d = 0.20000000000000001;
float f = 0.200000003;
double df = 0.20000000298023224;
so the test here is totally bogus. The second int
test actually makes sure the implementation isn't always returning the first of the two elements anyway ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. The spirit of the test would have been kepts with:
EXPECT_LT(0.15, celeritas::min<float>(0.1f, 0.2f));
or
EXPECT_GT(0.15, celeritas::min(0.1, 0.2));
(if this compile it would the double version).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, but again it would still be redundant with the int
test which doesn't have such ambiguities. Besides, your test there reminds me of a certain if (z < 1.5)
that we saw once long ago 😂
Sorry @pcanal I probably should have left this open for comment for more than 1 hour late on a saturday night 😅 |
I built on apple clang 12 with
-Weverything
, which has quite a lot of useless suggestions but also a few useful ones for nonstandard usage or bad practices.