Does C++ enforce return statements? - c++

Okay, little oddity I discovered with my C++ compiler.
I had a not-overly complex bit of code to refactor, and I accidentally managed to leave in a path that didn't have a return statement. My bad. On the other hand, this compiled, and segfaulted when I ran it and that path was hit, obviously.
Here's my question: Is this a compiler bug, or is there no guarantee that a C++ compiler will enforce the need for a return statement in a non-void return function?
Oh, and to be clear, in this case it was an unecessary if statement without an accompanying else. No gotos, no exits, no aborts.

Personally I think this should be an error:
int f() {
}
int main() {
int n = f();
return 0;
}
but most compilers treat it as a warning, and you may even have to use compiler switches to get that warning. For example, on g++ you need -Wall to get:
[neilb#GONERIL NeilB]$ g++ -Wall nr.cpp
nr.cpp: In function 'int f()':
nr.cpp:2: warning: no return statement in function returning non-void
Of course, with g++ you should always compile with at least -Wall anyway.

There is no guarantee that a C++ compiler will enforce that. A C++ function could jump out of its control flow by mechanisms unknown to the compiler. Context switches when C++ is used to write an OS kernel is an example of that. An uncaught exception thrown by a called function (whose code isn't necessarily available to the caller) is another one.
Some other languages, like Java, explicitly enforce that with knowledge available at compile time, all paths return a value. In C++ this isn't true, as is with many other occasions in the language, like accessing an array out of its bounds isn't checked either.

The compiler doesn't enforce this because you have knowledge about what paths are practically possible that the compiler doesn't. The compiler typically only knows about that particular file, not others that may affect the flow inside any given function. So, it isn't an error.
In Visual Studio, though, it is a warning. And we should pay attention to all warnings.... right? :)
Edit:
There seems to be some discussion about when this could happen. Here's a modified but real example from my personal code library;
enum TriBool { Yes, No, Maybe };
TriBool GetResult(int input) {
if (TestOne(input)) {
return Yes;
} else if (TestTwo(input)) {
return No;
}
}
Bear with me because this is old code. Originally there was an "else return maybe" in there. :) If TestOne and TestTwo are in a different compilation unit then when the compiler hits this code, it can not tell if TestOne and TestTwo could both return false for a given input. You, as the programmer that wrote TestOne and TestTwo, know that if TestOne fails then TestTwo will succeed. Maybe there are side effects of those tests so they have to be done. Would it be better to write it without the "else if"? Maybe. Probably. But the point is that this is legal C++ and the compiler can't know if it is possible to exit without a return statement. It is, I agree, ugly and not good coding but it is legal and Visual Studio will give you a warning but it will compile.
Remember that C++ isn't about protecting you from yourself. It is about letting you do what your heart desires within the constraints of the language even if that includes shooting yourself in the foot.

Related

If forgetting to return in C++ is undefined behaviour, why compiler do not enforce it? [duplicate]

Unlike Java, in C/C++ the following is allowed:
int* foo ()
{
if(x)
return p;
// What if control reaches here?
}
This often causes crashes and it is hard to debug problems. Why doesn't the standard enforce to have a final return for non-void functions? (Compilers generate an error for a wrong return value.)
Is there a flag in GCC or MSVC to enforce this? (something like -Wunused-result)
It is not allowed (undefined behaviour). However, the standard does not require a diagnostic in this case.
The standard doesn't require the last statement to be return because of code like this:
while (true) {
if (condition) return 0;
}
This always returns 0, but a dumb compiler cannot see it. Note that the standard does not mandate smart compilers. A return statement after the while block would be a waste which a dumb compiler would not be able to optimise out. The standard does not want to require the programmer to write waste code just to satisfy a dumb compiler.
g++ -Wall is smart enough to emit a diagnostic on my machine.
Use the -Wall flag in GCC.
warning: control reaches end of non-void function
Or more specifically, -Wreturn-type.
My guess: Because sometimes the programmer knows better than the compiler. With this simple example, it's clear that someting is wrong, but consider a switch of many values, or many checks in general. You, as the coder, know that certain values just will not be passed in to the function, but the compiler doesn't and just hints you, that there might be something wrong.
#include <iostream>
int foo(){
if(false)
return 5;
}
int main(){
int i = foo();
std::cout << i;
}
Note that even warning level 1 on MSVC gives the following warning:
warning C4715: 'foo' : not all control paths return a value
You can convert the warning into an error by using the following compiler options
-Wreturn-type -Werror=return-type.
Check out This link
The obvious answer is: because it's not an error. It's only an error if
x is false and if the caller uses the return value, neither of which
can necessarily be determined by the compiler, at least in the general
case.
In this particular case (returning a pointer), it wouldn't be too
difficult to require a return for all paths; Java does this. In
general, however, it's not reasonable in C++ to require this, since in
C++, you can return user defined types for which it may be impossible to
construct a value (no default constructor, etc.) So we have the
situation where the programmer might not be able to provide a return
in a branch that he or she knows can't be taken, and the compiler can't
determine that the branch can't be taken.
Most compilers will warn in such cases, when it can determine the flow.
All of the ones I've seen also warn in some cases where it's clearly
impossible to fall off the end, however. (Both g++ and VC++ warn about:
int
bar( char ch )
{
switch ( ch & 0xC0 ) {
case 0x00:
case 0x40:
return 0;
case 0x80:
return -1;
case 0xC0:
return 1;
}
}
, at least with the usual options. Although it's quite clear that this
function never falls off the end.)
As far as I remember, Visual Studio 2008 warns you about a "execution path that does not have a return value". It is allowed in the meaning of that "C++ won't stop you from shooting you in the foot". So you are to think, not the compiler.
What the standard says about this kind of programming is that it produces undefined behavior.
Undefined behavior is the joy and pity of C/C++, but it is also a fundamental feature of the language design that allows for many of the low-level optimizations that make C a sort of "high level assembler" (it is not, actually, but just to give you an idea).
So, while redirecting to John's answer about the switch to use with GCC, to know "why" the standard does not prevent that, I would point to a very interesting analysis of undefined behavior and all of its misteries: What Every C Programmer Should Know About Undefined Behavior. It makes for a very instructive reading.

Why can I compile a code with 2 returns?

Since am comming from a java island, I wounder why the compiler doesnt warns about unreachable code in something like:
int main(int argc, char** argV)
{
std::list<int> lst = {1,2,3,4};
return 0;
std::cout << "Done!!!" << std::endl;
return 0;
}
my question:
Why can I compile a code with 2 returns?
my Compiler is gcc for c++11, on Windows, code block
I wounder why the compiler doesnt warns about unreachable code in something like
It is pretty well explained in gcc documentaion about warnings:
-Wunreachable-code
Warn if the compiler detects that code will never be executed. This option is intended to warn when the compiler detects
that at least a whole line of source code will never be executed,
because some condition is never satisfied or because it is after a
procedure that never returns.
It is possible for this option to produce a warning even though there
are circumstances under which part of the affected line can be
executed, so care should be taken when removing apparently-unreachable
code.
For instance, when a function is inlined, a warning may mean that the
line is unreachable in only one inlined copy of the function.
This option is not made part of -Wall because in a debugging version
of a program there is often substantial code which checks correct
functioning of the program and is, hopefully, unreachable because the
program does work. Another common use of unreachable code is to
provide behavior which is selectable at compile-time.
Though g++ 5.1.0 does not produce any warnings for this code even with this option enabled.
Why shouldn't you be able to compile code that has multiple returns?
Because the code is unreachable? Most compilers can issue a warning for that.
However, I often see code like:
if(a)
{
// Do stuff
}
else
{
// Do other stuff
if(b)
{
// Do more stuff
}
else
{
// Do other more stuff
}
}
That could be simplified as
if(a)
{
// Do stuff
return;
}
// Do other stuff
if(b)
{
// Do more stuff
return;
}
// Do other more stuff
About a decade ago, people frowned on having more than one return in a function of method, but there really is no reason to continue frowning on it with modern compilers.
Because this part
std::cout << "Done!!!" << std::endl;
return 0;
will never be called because of the first return statement, but it is not an error aborting the compilation, rather the compiler might drop a warning, depending on what compiler you are using (e.g. Microsofts VC++ compiler warns you about that).
Unreachable code is not a compile error in C++, but usually gives a warning, depending on your compiler and flags.
You can try to add -Wall option when you call your compiler. This will
active many useful warning.
Mainly because more often than not the compiler cannot know for sure. (There have been attempts to do this in Java but there the criteria for defining reachability have been decided upon.)
In this case, indeed, it is obvious.
Some compilers do issue reachability warnings but the C++ standard does not require this.
No answer on reachability is complete without referencing this: https://en.wikipedia.org/wiki/Halting_problem
As a final remark on Java, consider these two Java snippets:
if (true){
return;
}
; // this statement is defined to be reachable
and
while (true){
return;
}
; // this statement is defined to be unreachable
The worst of both worlds is attained, in my humble opinion.
There are two reasons for this:
C++ has many standards (c++11, c++14, c++17 etc. ) unlike java (java is very rigid in standard and only thing that matters really with java is the version you are using), so, some compilers might warn you about the unreachable code while others might not.
The statements after return 0, though are unreachable logically, do not cause any fatal error like ambiguity, syntax error, etc. and can be compiled easily (if the compiler wills to ;) ).

Why does this C++ snippet compile (non-void function does not return a value) [duplicate]

This question already has answers here:
Why does flowing off the end of a non-void function without returning a value not produce a compiler error?
(11 answers)
Closed 6 years ago.
I found this in one of my libraries this morning:
static tvec4 Min(const tvec4& a, const tvec4& b, tvec4& out)
{
tvec3::Min(a,b,out);
out.w = min(a.w,b.w);
}
I'd expect a compiler error because this method doesn't return anything, and the return type is not void.
The only two things that come to mind are
In the only place where this method is called, the return value isn't being used or stored. (This method was supposed to be void - the tvec4 return type is a copy-and-paste error)
a default constructed tvec4 is being created, which seems a bit unlike, oh, everything else in C++.
I haven't found the part of the C++ spec that addresses this. References (ha) are appreciated.
Update
In some circumstances, this generates an error in VS2012. I haven't narrowed down specifics, but it's interesting, nonetheless.
This is undefined behavior from the C++11 draft standard section 6.6.3 The return statement paragraph 2 which says:
[...] Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function. [...]
This means that the compiler is not obligated provide an error nor a warning usually because it can be difficult to diagnose in all cases. We can see this from the definition of undefined behavior in the draft standard in section 1.3.24 which says:
[...]Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).[...]
Although in this case we can get both gcc and clang to generate a wanring using the -Wall flag, which gives me a warning similar to this:
warning: control reaches end of non-void function [-Wreturn-type]
We can turn this particular warning into an error using the -Werror=return-type flag. I also like to use -Wextra -Wconversion -pedantic for my own personal projects.
As ComicSansMS mentions in Visual Studio this code would generate C4716 which is an error by default, the message I see is:
error C4716: 'Min' : must return a value
and in the case where not all code paths would return a value then it would generate C4715, which is a warning.
Maybe some elaboration on the why part of the question:
As it turns out, it is actually quite hard† for a C++ compiler to determine whether a function exits without a return value. In addition to the code paths that end in explicit return statements and the ones that fall off the end of the function, you also have to consider potential exception throws or longjmps in the function itself, as well as all of its callees.
While it is quite easy for a compiler to identify a function that looks like it might be missing a return, it is considerably harder to prove that it is missing a return. In order to lift compiler vendors of this burden, the standard does not require this to generate an error.
So compiler vendors are free to generate a warning if they are quite sure that a function is missing a return and the user is then free to ignore/mask that warning in those rare cases where the compiler was actually wrong.
†: In the general case, this is equivalent to the halting problem, so it is actually impossible for a machine to decide this reliably.
Compile your code with -Wreturn-type option:
$ g++ -Wreturn-type source.cpp
This will give you warning. You can turn the warning into error if you use -Werror too:
$ g++ -Wreturn-type -Werror source.cpp
Note that this will turn all warnings into errors. So if you want error for specific warning, say -Wreturn-type, just type return-type without -W part as:
$ g++ -Werror=return-type source.cpp
In general you should always use -Wall option which includes most common warnings — this includes missing return statement also. Along with -Wall, you can use -Wextra also, which includes other warnings not included by -Wall.
Maybe some additional elaboration on the why part of the question.
C++ was designed so that a very large body of pre-existing body of C code compiles with minimum amount of changes. Unfortunately, C itself was paying a similar duty to earliest pre-standard C which did not even have the void keyword and instead relied on a default return type of int. C functions usually did return values, and whenever code superficially similar to Algol/Pascal/Basic procedures was written without any return statements, the function was, under the hood, returning whichever garbage was left on the stack. Neither the caller nor the callee assigns the value of the garbage in a reliable way. If the garbage is then ignored by every caller, everything is fine and C++ inherits the moral obligation to compile such code.
(If the returned value is used by the caller, the code may behave non-deterministically, similar to processing of an uninitialized variable. Could the difference be reliably identified by a compiler, in a hypothetical successor language to C? This is hardly possible. The caller and the callee may be in different compilation units.)
The implicit int is just a part of the C legacy involved here. A "dispatcher" function might, depending on a parameter, return a variety of types from some code branches, and return no useful value from other code branches. Such a function would generally be declared to return a type long enough to hold any of the possible types and the caller might need to cast it or extract it from a union.
So the deepest cause is probably the C language creators' belief that procedures that do not return any value are just an unimportant special case of functions that do; this problem got aggravated by the lack of focus on type safety of function calls in the oldest C dialects.
While C++ did break compatibility with some of the worst aspects of C (example), the willingness to compile a return statement without a value (or the implicit value-less return at the end of a function) was not one of them.
As already mentioned, this is undefined behavior and will give you a compiler warning. Most places I've worked require you to turn on compiler settings to treat warnings as errors - which enforces that all your code must compile with 0 errors and 0 warnings. This is a good example of why that is a good idea.
This is more of the standard C++ rule/feature which tends to be flexible with things and which tends to be more close to C.
But when we talk of the compilers, GCC or VS, they are more for professional usage and for variety of development purposes and hence put more strict development rules as per your needs.
That makes sense also, my personal opinion, because the language is all about features and its usage whereas compiler defines the rules for optimal and best way of using it as per your needs.
As mentioned in above post, compiler sometimes gives the error, sometimes gives warning and also it has the option of skipping these warning etc, indicating the freedom to use the language and its features in a way that suits us best.
Along with this there are several other questions mentioning this behaviour of returning a result without having a return statement. One simple example would be:
int foo(int a, int b){ int c = a+b;}
int main(){
int c = 5;
int d = 5;
printf("f(%d,%d) is %d\n", c, d, foo(c,d));
return 0;
}
Could this anomaly be due stack properties and more specifically:
Zero-Address Machines
In zero-address machines, locations of both operands are assumed to be at a default location.
These machines use the stack as the source of the input operands and the result goes back into
the stack. Stack is a LIFO (last-in-first-out) data structure that all processors support, whether
or not they are zero-address machines. As the name implies, the last item placed on the stack
is the first item to be taken out of the stack. All operations on this type of machine assume that the required input operands are the top
two values on the stack. The result of the operation is placed on top of the stack.
In addition to that, for accessing memory to read and write data same registers are used as data source and destination(DS (data segment) register), that store first the variables needed for the calculation and then the returned result.
Note:
with this answer I would like to discuss one possible explanation of the strange behaviour at machine (instruction) level as it has already a context and its covered in adequately wide range.

C++11 Do all control paths still need to return a value?

This my seem like a ridiculous question but today I wrote a member function in C++ that is supposed to return and int but doesn't always. I even wrote a really simple function that doesn't return a value...
int derp()
{
if (11 == 22) return 0;
}
Is this a recent change? is my compiler broken? lol
EDIT: this does compile btw
In a non-void function all control paths must return. The key issue here is that the compiler is not required to diagnose it. Note that compile and is correct are not necessarily the same. All correct code compiles, but not all code that compiles is correct.
No, C++ never required all control paths to return a value. It's valid in C++11 and C++03 as well (syntactically).
Some compilers can detect most situations where you're missing a return, but a diagnostics is not required. Most will not issue a diagnostic if there's at least a control path that returns.
Regardless, it's UB.

Why isn't there any compiler error when a return statement is not present?

Unlike Java, in C/C++ the following is allowed:
int* foo ()
{
if(x)
return p;
// What if control reaches here?
}
This often causes crashes and it is hard to debug problems. Why doesn't the standard enforce to have a final return for non-void functions? (Compilers generate an error for a wrong return value.)
Is there a flag in GCC or MSVC to enforce this? (something like -Wunused-result)
It is not allowed (undefined behaviour). However, the standard does not require a diagnostic in this case.
The standard doesn't require the last statement to be return because of code like this:
while (true) {
if (condition) return 0;
}
This always returns 0, but a dumb compiler cannot see it. Note that the standard does not mandate smart compilers. A return statement after the while block would be a waste which a dumb compiler would not be able to optimise out. The standard does not want to require the programmer to write waste code just to satisfy a dumb compiler.
g++ -Wall is smart enough to emit a diagnostic on my machine.
Use the -Wall flag in GCC.
warning: control reaches end of non-void function
Or more specifically, -Wreturn-type.
My guess: Because sometimes the programmer knows better than the compiler. With this simple example, it's clear that someting is wrong, but consider a switch of many values, or many checks in general. You, as the coder, know that certain values just will not be passed in to the function, but the compiler doesn't and just hints you, that there might be something wrong.
#include <iostream>
int foo(){
if(false)
return 5;
}
int main(){
int i = foo();
std::cout << i;
}
Note that even warning level 1 on MSVC gives the following warning:
warning C4715: 'foo' : not all control paths return a value
You can convert the warning into an error by using the following compiler options
-Wreturn-type -Werror=return-type.
Check out This link
The obvious answer is: because it's not an error. It's only an error if
x is false and if the caller uses the return value, neither of which
can necessarily be determined by the compiler, at least in the general
case.
In this particular case (returning a pointer), it wouldn't be too
difficult to require a return for all paths; Java does this. In
general, however, it's not reasonable in C++ to require this, since in
C++, you can return user defined types for which it may be impossible to
construct a value (no default constructor, etc.) So we have the
situation where the programmer might not be able to provide a return
in a branch that he or she knows can't be taken, and the compiler can't
determine that the branch can't be taken.
Most compilers will warn in such cases, when it can determine the flow.
All of the ones I've seen also warn in some cases where it's clearly
impossible to fall off the end, however. (Both g++ and VC++ warn about:
int
bar( char ch )
{
switch ( ch & 0xC0 ) {
case 0x00:
case 0x40:
return 0;
case 0x80:
return -1;
case 0xC0:
return 1;
}
}
, at least with the usual options. Although it's quite clear that this
function never falls off the end.)
As far as I remember, Visual Studio 2008 warns you about a "execution path that does not have a return value". It is allowed in the meaning of that "C++ won't stop you from shooting you in the foot". So you are to think, not the compiler.
What the standard says about this kind of programming is that it produces undefined behavior.
Undefined behavior is the joy and pity of C/C++, but it is also a fundamental feature of the language design that allows for many of the low-level optimizations that make C a sort of "high level assembler" (it is not, actually, but just to give you an idea).
So, while redirecting to John's answer about the switch to use with GCC, to know "why" the standard does not prevent that, I would point to a very interesting analysis of undefined behavior and all of its misteries: What Every C Programmer Should Know About Undefined Behavior. It makes for a very instructive reading.