How to make gcc warn about narrowing function parameters - c++

The program below involves a function parameter that is implicitly narrowed. Information is potentially lost.
void func(short) {}
int main()
{
int i = 0x7fffffff;
func(i);
}
If I compile this program (either as C or C++) with gcc using -Wall -Wextra I receive no warnings!
Surely, this behavior would often be considered undesirable.
Is there some gcc command-line parameter that would trigger a diagnostic message when these narrowing conversions occur?

Use -Wconversion for gcc/clang. /W4 can be used for VC++.
online compiler

Related

Is printing an enum without a cast okay in C++?

#include <stdio.h>
enum class TEST_ENUM{
VALUE =1,
};
int main( ){
// Gcc will warn.
printf("%u", TEST_ENUM::VALUE);
// Both clang and gcc are happy.
printf("%u", uint32_T(TEST_ENUM::VALUE));
}
Godbolt link
In the above example, gcc will emit the following diagnostic:
<source>:8:12: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'TEST_ENUM' [-Wformat=]
printf("%u", TEST_ENUM::VALUE);
Regardless of compiler version or warnings enabled, I cannot seem to get clang to emit that same diagnostic. Since this is a warnning and not an error, I assume both are standards compliant. Why does gcc complain when clang won't? Is gcc being overly cautious here, or is there actually something worth warning about?
From cppreference:
... - arguments specifying data to print. If any argument after default conversions is not the type expected by the corresponding conversion specifier, or if there are fewer arguments than required by format, the behavior is undefined. If there are more arguments than required by format, the extraneous arguments are evaluated and ignored
Is gcc being overly cautious here, or is there actually something worth warning about?
Not at all overly cautios. You are passing a parameter of wrong type!
Since this is a warnning and not an error, I assume both are standards compliant. Why does gcc complain when clang won't?
When your code has undefined behavior then compilers are not required to issue any diagnostics. GCC is just being nice to you here.
If you are forced to use a type-unsafe API you can always wrap it into something type-safe :
void Log(const TEST_ENUM& x) {
the_actual_logging_api( "%u", static_cast<std:underlying_type<TEST_ENUM>>(x));
}

Narrowing conversion from `int` (constant expression) to `unsigned int` - MSVC vs gcc vs clang

constexpr int i = 100;
struct F { F(unsigned int){} };
int main() { F{i}; }
The snippet above:
Compiles with no warnings on g++ 7 with -Wall -Wextra -Wpedantic.
Compiles with no warnings on clang++ 4 with -Wall -Wextra -Wpedantic.
Fails to compile on MSVC 2017:
conversion from 'const int' to 'unsigned int' requires a narrowing conversion
Q: is MSVC wrong here?
live example on godbolt.org
int i = 100;
struct F { F(unsigned int){} };
int main() { F{i}; }
Compiles with warnings on g++ 7 with -Wall -Wextra -Wpedantic:
narrowing conversion of 'i' from 'int' to 'unsigned int'
Fails to compile clang++ 4 with -Wall -Wextra -Wpedantic:
non-constant-expression cannot be narrowed from type 'int' to 'unsigned int' in initializer list
Fails to compile on MSVC 2017:
conversion from 'const int' to 'unsigned int' requires a narrowing conversion
Q: is g++ wrong here? (i.e. should it produce an hard error?)
live example on godbolt.org
There is never a requirement that any C++ program produce a hard error. There are requirements to print diagnostics. The form of the diagnostic is unspecified by the standard: an old joke is that printing out a single space satisifies the diagnostic requirements of the standard. That would be a quality of implementation issue.
There are ill-formed programs upon which the standard places no restrictions on their behavior, and sometimes a mandatory diagnostic.
There are cases where a program is ill-formed and a diagnostic is required. One way to handle that is to produce a message saying it is an error, then do not generate any binary to run. Another way is to produce a message saying it is a warning, then produce a binary that can be run.
So, g++ is not wrong under the standard for merely printing out a warning.
The resulting program is technically all undefined behavior; g++ could format your hard drive when it runs without violating the standard. That would be considered a quality of implementation issue.
Shafik's answer here covers the first question. i is constant expression and its value fits the target type; there should be no warning or error about the narrowing conversion.
The C++ standard does not defend you against hostile compilers.
Reportedly, -pedantic-errors can be passed to g++ to have it generate hard errors instead of warnings when the standard mandates the resulting program would be ill-formed.

Different compiler behavior for expression: auto p {make_pointer()};

Which is the correct behaviour for the following program?
// example.cpp
#include <iostream>
#include <memory>
struct Foo {
void Bar() const {
std::cout << "Foo::Bar()" << std::endl;
}
};
std::shared_ptr<Foo> MakeFoo() {
return std::make_shared<Foo>();
}
int main() {
auto p { MakeFoo() };
p->Bar();
}
When I compile it in my Linux RHEL 6.6 workstation, I obtain the following results:
$ g++ -v
gcc version 5.1.0 (GCC)
$ g++ example.cpp -std=c++14 -Wall -Wextra -pedantic
$ ./a.out
Foo::Bar()
but
$ clang++ -v
clang version 3.6.0 (trunk 217965)
$ clang++ example.cpp -std=c++14 -Wall -Wextra -pedantic
example.cpp:16:4: error: member reference type 'std::initializer_list<std::shared_ptr<Foo> >' is not a pointer; maybe you meant to use '.'?
p->Bar();
~^~
example.cpp:16:6: error: no member named 'Bar' in 'std::initializer_list<std::shared_ptr<Foo> >'
p->Bar();
~ ^
2 errors generated.
and
$ icpc -v
icpc version 15.0.3 (gcc version 5.1.0 compatibility)
$ icpc example.cpp -std=c++14 -Wall -Wextra -pedantic
example.cpp(16): error: expression must have pointer type
p->Bar();
^
compilation aborted for example.cpp (code 2)
Tl;DR
This behavior is subject to a proposal and an Evolution Working Group issue. There is some ambiguity as to whether this is considered a C++14 defect or a C++1z proposal. If it turns out to be a C++14 defect then gcc's behavior is correct for C++14. On the other hand if this is really a C++1z proposal then clang and icpc are exhibiting correct behavior.
Details
It looks like this case is covered by N3681 which says:
Auto and braced initializers cause a teachability problem; we want to
teach people to use uniform initialization, but we need to
specifically tell programmers to avoid braces with auto. In C++14, we
now have more cases where auto and braces are problematic; return type
deduction for functions partially avoids the problem, since returning
a braced-list won't work as it's not an expression. However, returning
an auto variable initialized from a braced initializer still returns
an initializer_list, inviting undefined behaviour. Lambda init
captures have the same problem. This paper proposes to change a
brace-initialized auto to not deduce to an initializer list, and to
ban brace-initialized auto for cases where the braced-initializer has
more than one element.
and provides the following examples:
auto x = foo(); // copy-initialization
auto x{foo}; // direct-initialization, initializes an initializer_list
int x = foo(); // copy-initialization
int x{foo}; // direct-initialization
So I think clang is currently correct, the latest version of clang provides this warning:
warning: direct list initialization of a variable with a deduced type
will change meaning in a future version of Clang; insert an '=' to
avoid a change in behavior [-Wfuture-compat]
From EWG issue 161 that N3922 was adopted for this.
As Praetorian notes the proposal recommends this is a C++14 defect:
Direction from EWG is that we consider this a defect in C++14.
but clang's C++1z implementation status notes this as a C++1z proposal which is not implemented.
So if this is a C++14 defect, that would make gcc correct but it is not clear to me if this is really a defect or a proposal.
T.C. points out in a comment here that it seems like the clang developers do intended to back-port this. It has not happened and it is not clear why.

C question: no warning?

main()
{
printf("Hello World.");
}
Why does no warning is produced in gcc compiler even though we declare main() with return type 'int'
Because you're not using the -Wall flag. When you do, you should get:
foo.c:1: warning: return type defaults to ‘int’
foo.c: In function ‘main’:
foo.c:1: warning: implicit declaration of function ‘printf’
foo.c:1: warning: incompatible implicit declaration of built-in function ‘printf’
foo.c:1: warning: control reaches end of non-void function
Did you forget to compile with warnings enabled:
gcc -Wall ...
Your main function return nothing. so modify in void main().
Usually is:
int main() { printf("Hello world"); return 0; }
No warning is produced because that's legal ANSI C89. Functions without a specified return type are implicitly assumed to return int.
If you want to compile as C89, but be warned about using implicit int, you should pass either -Wimplicit-int as a command line argument (or -Wall, which enables that warning, along with a number of others).
If you want to compile as C99, you should pass -std=c99 and -pedantic-errors, which will cause the compiler to issue an error if you use implicit int.

Why cast unused return values to void?

int fn();
void whatever()
{
(void) fn();
}
Is there any reason for casting an unused return value to void, or am I right in thinking it's a complete waste of time?
David's answer pretty much covers the motivation for this, to explicitly show other "developers" that you know this function returns but you're explicitly ignoring it.
This is a way to ensure that where necessary error codes are always handled.
I think for C++ this is probably the only place that I prefer to use C-style casts too, since using the full static cast notation just feels like overkill here. Finally, if you're reviewing a coding standard or writing one, then it's also a good idea to explicitly state that calls to overloaded operators (not using function call notation) should be exempt from this too:
class A {};
A operator+(A const &, A const &);
int main () {
A a;
a + a; // Not a problem
(void)operator+(a,a); // Using function call notation - so add the cast.
At work we use that to acknowledge that the function has a return value but the developer has asserted that it is safe to ignore it. Since you tagged the question as C++ you should be using static_cast:
static_cast<void>(fn());
As far as the compiler goes casting the return value to void has little meaning.
The true reason for doing this dates back to a tool used on C code, called lint.
It analyzes code looking for possible problems and issuing warnings and suggestions. If a function returned a value which was then not checked, lint would warn in case this was accidental. To silence lint on this warning, you cast the call to (void).
Casting to void is used to suppress compiler warnings for unused variables and unsaved return values or expressions.
The Standard(2003) says in §5.2.9/4 says,
Any expression can be explicitly converted to type “cv void.” The expression value is discarded.
So you can write :
//suppressing unused variable warnings
static_cast<void>(unusedVar);
static_cast<const void>(unusedVar);
static_cast<volatile void>(unusedVar);
//suppressing return value warnings
static_cast<void>(fn());
static_cast<const void>(fn());
static_cast<volatile void>(fn());
//suppressing unsaved expressions
static_cast<void>(a + b * 10);
static_cast<const void>( x &&y || z);
static_cast<volatile void>( m | n + fn());
All forms are valid. I usually make it shorter as:
//suppressing expressions
(void)(unusedVar);
(void)(fn());
(void)(x &&y || z);
Its also okay.
Since c++17 we have the [[maybe_unused]] attribute which can be used instead of the void cast.
Cast to void is costless. It is only information for compiler how to treat it.
For the functionality of you program casting to void is meaningless. I would also argue that you should not use it to signal something to the person that is reading the code, as suggested in the answer by David. If you want to communicate something about your intentions, it is better to use a comment. Adding a cast like this will only look strange and raise questions about the possible reason. Just my opinion...
As of C++11 you can also do:
std::ignore = fn();
This should achieve the same result on functions marked with [[nodiscard]]
C++17 [[nodiscard]]
C++17 standardized the "return value ignored business" with an attribute.
Therefore, I hope that compliant implementations will always warn only when nodiscard is given, and never warn otherwise.
Example:
main.cpp
[[nodiscard]] int f() {
return 1;
}
int main() {
f();
}
compile:
g++ -std=c++17 -ggdb3 -O0 -Wall -Wextra -pedantic -o main.out main.cpp
outcome:
main.cpp: In function ‘int main()’:
main.cpp:6:6: warning: ignoring return value of ‘int f()’, declared with attribute nodiscard [-Wunused-result]
6 | f();
| ~^~
main.cpp:1:19: note: declared here
1 | [[nodiscard]] int f() {
|
The following all avoid the warning:
(void)f();
[[maybe_unused]] int i = f();
I wasn't able to use maybe_unused directly on the f() call:
[[maybe_unused]] f();
gives:
main.cpp: In function ‘int main()’:
main.cpp:6:5: warning: attributes at the beginning of statement are ignored [-Wattributes]
6 | [[maybe_unused]] f();
| ^~~~~~~~~~~~~~~~
The (void) cast working does not appear to be mandatory but is "encouraged" in the standard: How can I intentionally discard a [[nodiscard]] return value?
Also as seen from the warning message, one "solution" to the warning is to add -Wno-unused-result:
g++ -std=c++17 -ggdb3 -O0 -Wall -Wextra -pedantic -Wno-unused-result -o main.out main.cpp
although I wouldn't of course recommend ignoring warnings globally like this.
C++20 also allows you to add a reason to the nodiscard as in [[nodiscard("reason")]] as mentioned at: https://en.cppreference.com/w/cpp/language/attributes/nodiscard
GCC warn_unused_result attribute
Before the standardization of [[nodiscard]], and for C before they finally decide to standardize attributes, GCC implemented the exact same functionality with the warn_unused_result:
int f() __attribute__ ((warn_unused_result));
int f() {
return 1;
}
int main() {
f();
}
which gives:
main.cpp: In function ‘int main()’:
main.cpp:8:6: warning: ignoring return value of ‘int f()’, declared with attribute warn_unused_result [-Wunused-result]
8 | f();
| ~^~
It should be noted then that since ANSI C does not have a standard for this, ANSI C does not specify which C standard library functions have the attribute or not and therefore implementations have made their own decisions on what should or not be marked with warn_unuesd_result, which is why in general you would have to use the (void) cast to ignore returns of any calls to standard library functions to fully avoid warnings in any implementation.
Tested in GCC 9.2.1, Ubuntu 19.10.
Also when verifying your code complies to MISRA (or other) standards, static-analysis tools such as LDRA will not allow you to call a function that has a return type without having it return a value unless you explicitly cast the returned value to (void)