0

code snippet:

#include <iostream>

int main()
{
    std::function<int(int)> func = [](int data)->int{
        std::cout << "this is " << data << "\n";
    };
    
    func(3);
}

output

this is 3

I expected the above not to compile at all, but to my supprise it did compile. the compiler only generated this warning:

main.cpp:7:5: warning: non-void lambda does not return a value [-Wreturn-type]
    };
    ^
1 warning generated.

My question is why wasnt a compile error generated?

African_king
  • 177
  • 1
  • 8
  • 2
    Because compiler has is not obligated to emit an error in this case. – Revolver_Ocelot Feb 26 '23 at 22:48
  • 3
    Why does any non-`void` function that doesn't return compile? – user4581301 Feb 26 '23 at 22:48
  • 1
    The standard doesn't require that, thus gcc does not by default check that. It can be enabled with -Wreturn-type or -Wall. Additional checks and errors can't be enabled, unless -Werror is used. – 273K Feb 26 '23 at 22:52
  • This is probably ub ? – Eriss69 Feb 26 '23 at 22:54
  • @273K why is that so....it lik epromising the compiler and failing to deliver on that promise. In this case you promised the compiler you would return and integer and you failed to do so....that seems like somthing the compiler shouldnt compromise on. – African_king Feb 26 '23 at 22:58
  • Because compilers are unable to check if all possible code flows return. `throw`, `abort`, `terminate` and many other functions do not return. – 273K Feb 26 '23 at 23:01
  • 1
    @African_king If it was required that every execution path in a function provably ends with a `return` statement, then it might become necessary to add `return` statements that you know may never be reached, e.g. because of preconditions on the function arguments. That would mean you need to add unnecessary dead code to your functions and possibly add branches that you know can't be taken. Adding such overhead is not in C++'s philosophy. – user17732522 Feb 26 '23 at 23:03
  • 2
    @user17732522 -- and if you did that, the compiler would complain about unreachable code. – Pete Becker Feb 26 '23 at 23:13
  • 1
    If you **enable** the warning (e.g., `-Wreturn-type`), then the compiler will generate a warning. If you enable **treat warnings as errors**, then a compiler error will be generated. My counter question is: why aren't you enabling warnings, and treating warnings as errors? – Eljay Feb 27 '23 at 13:38
  • @Eljay i thought this was serious enough that the compiler would generate an error..to your point I have now mae a vow to my sef to treat all warnings as errors.. due to this insight..as in something as serious as this. – African_king Feb 27 '23 at 17:06

1 Answers1

3

My question is why wasnt a compile error generated?

Reaching the closing } of any usual function that is declared to have a non-void return type causes undefined behavior. The compiler does not have to diagnose this at all and in fact cannot generally do that (since it is an undecidable problem). It can't make it an error instead of a warning in general either, because it would need to prove that the function is actually called with the problematic execution path. If the function is never called in such a way that it will reach the closing }, then the program still has well-defined behavior and is not ill-formed.

The body of a lambda is nothing but the body of the operator() member function of the closure type generated from the lambda and the same rules apply to it. The return type declared on the lambda expression is the return type declared on this operator() member function.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • why cant it do so......you told the compiler you would be returning a value, but failed to do so at the end of the function.I am trying to imagine a world where the compiler can't prove this is an error. From this answer I am guessing that the compiler would have generated an error if I had an addtional statement like "int x = func(3)". Much appreciated? – African_king Feb 26 '23 at 23:04
  • 1
    @African_king In your specific case the compiler may be able to see that the function always reaches `}` when called (setting aside possible exceptions thrown from `std::cout <<`), but even then it would need to do some deeper analysis through `std::function` to prove that you are also actually calling it, because as I wrote, as long as you never call your function, the program has well-defined behavior. – user17732522 Feb 26 '23 at 23:07
  • 1
    @African_king But in general it is impossible to verify whether a function will or will not reach `}`. It is an undecidable problem equivalent to the halting problem and that's not even taking into account that the function might only be called with certain arguments that will never take the problematic path. – user17732522 Feb 26 '23 at 23:07
  • I see thanks for the useful insight. I did not think of it this way. Thanks once again. – African_king Feb 26 '23 at 23:09