Why Does Flowing Off the End of a Non-Void Function Without Returning a Value Not Produce a Compiler Error

Why does flowing off the end of a non-void function without returning a value not produce a compiler error?

C99 and C++ standards require non-void functions to return a value, except main. The missing return statement in main will be defined (to return 0). In C++ it's undefined behaviour if execution actually reaches the end of a non-void function other than main, while in C it's only UB if the caller uses the return value.

This means functions can look like they might reach the end without returning a value, but actually can't reach the closing }. John Kugelman's answer shows some examples, like a noreturn function called from one side of an if. It's only undefined behaviour if execution actually does get to the end without reaching a return earlier. The rationale includes that checking if every real code path returns a value is quite difficult (without knowing which functions never return), so it's not illegal to compile a function like your example, only to actually call it like your main does.

As an extension, at least one compiler (MSVC) allows a return value to be set with inline assembly, but most others still require a return statement in functions that use inline asm.

From C++11 draft:

§ 6.6.3/2

Flowing off the end of a function [...] results in undefined behavior in a value-returning function.

§ 3.6.1/5

If control reaches the end of main without encountering a return statement, the effect is that of executing

return 0;

Note that the behaviour described in C++ 6.6.3/2 is not the same in C.


gcc will give you a warning if you call it with -Wreturn-type option.

-Wreturn-type Warn whenever a function is defined with a return-type that
defaults to int. Also warn about any
return statement with no return-value
in a function whose return-type is not
void (falling off the end of the
function body is considered returning
without a value), and about a return
statement with an expression in a
function whose return-type is void.

This warning is enabled by -Wall.


Just as a curiosity, look what this code does:

#include <iostream>

int foo() {
int a = 5;
int b = a + 1;
}

int main() { std::cout << foo() << std::endl; } // may print 6

This code has formally undefined behaviour, and in practice it's calling convention and architecture dependent. On one particular system, with one particular compiler, the return value is the result of last expression evaluation, stored in the eax register of that system's processor, if you disable optimization.

This seems to be a consequence of GCC internals with optimization disabled, because in that case it picks the return-value register if it needs any to implement a statement. With optimization enabled in C++ mode, GCC and clang assume this path of execution is unreachable because it contains undefined behaviour. They don't even emit a ret instruction, so execution falls into the next function in the .text section. Of course undefined behaviour means that anything could happen.

Is it Undefined behavior to not having a return statement for a non-void function in which control can never off over the end?

The two statements are in no way contradictory.

The first statement is about what happens when control flow exits a non-void function without executing a return statement. The second statement is about what happens when control flow does not exit the function at all. Calls to functions like exit or std::terminate do not ever have control flow proceed past the point when those functions are called.

But that has nothing to do with the nature of the return value.

The behavior of the program when a non-void function runs out of stuff to do without an explicit return statement (or throw. Or co_return these days) is governed by [stmt.return]/2:

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.

What does a non void C function without return statement actually return? [duplicate]

  1. what does a non void function without any return statement actually return ? Could it be the last allocated variable on the stack ?

The C standard does not define the behavior if a function does not execute return with a value and the return value of the function is used.

(There is some evidence that, in some situations, GCC deliberately returns the value of the last full expression evaluated in the function, but that was discussed in comments some time ago, and I do not have a reference.)

GCC raises a warning for that , but not an error. Wouldn't a compiler error be actually more pertinent for such a case instead of a compiler warning ?

The C standard does not prohibit a function with a non-void return type from returning without returning a value (by allowing program control to flow to the terminating } of the function definition). So a conforming compiler should allow this in the function definition, meaning it can warn but should not produce an error. It is allowed to call such a function and not use its return value; that has behavior defined by the C standard.

If the compiler can see that a function call uses the return value of a function that does not return a value, the compiler could produce an error for that.

It is occasionally useful for a function with a non-void return type to return a value in some situations and not in others, such as a function that accepts a command to perform and returns a value when a “Get value of setting” command is performed and does not return a value when a “Set value of setting” command is performed.

Why do I get the warning 'control reaches end of non-void function' even when the return is guaranteed

The compiler correctly assumes that r is a variable value, it does not process it as a constant, that being the case it cannot be sure what the value is going to be and therefore if the body of the cycle will or will not be executed.

If you use a constant the warning goes away because the compiler will assemble the code using a constant value.

You can check this behavior here.

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

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.

control reaches end of non-void function produces error instead of warning

I'm wondering if there's a workaround to convert this error to a warning using compiler flags?

I would expect the -Wno-error option to have that effect. It should also be possible to narrow the scope of that to the specific diagnostic you report, but beware: there is no way with command-line options alone to narrow the effect to this particular instance of the issue.

Addendum

The question having been edited to show that the diagnostic category is return-type, I can say that one would use -Wno-error=return-type to make all diagnostics of this type warnings instead of errors.



Related Topics



Leave a reply



Submit