Search code examples
c++cvisual-studiocompiler-warnings

What is the Visual Studio warning equivalent of GCC's -Wreturn-type?


Does Visual Studio have a warning (or warnings) that is the equivalent of GCC's -Wreturn-type?

More specifically, I am looking for a Visual Studio warning (or warnings) that will warn for instances in functions whose return types are not void where

  1. There is a return statement with no return value; or
  2. It is possible function execution could "fall off" the end of the function body without returning a value

I am not concerned with the other part of -Wreturn-type that warns whenever a function is defined with a return type that defaults to int.

For reference, the GCC warning options can be found here.


Solution

  • As pointed out in the comments, this can be done with C4033, C4716, C4715.

    User n. 1.8e9-where's-my-share m. also makes a very good point about how to find MSVC warnings in general:

    If you want to find out whether a warning that you want exists, just enable all [using /Wall] and test against a small piece of code. If there is a warning, congrats, you found it. If not, tough luck, there isn't any.

    I tested both with .c and .cpp file extensions, just in case the compiler behaved differently based on the language it is compiling (and sure enough, the behaviour was different for test 2).

    None of my tests ever complain about main(), because main() is special, as it is the only function in C and C++ that defaults to returning 0 if no explicit return is provided.

    All of the tests below were done using Visual Studio 2015's compiler (i.e., C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\cl.exe), and the commands were issued from the VS2015 x86 Native Tools Command Prompt.

    If I am missing any test cases, please leave a comment to let me know.

    Tests

    C tests

    Test 1 - Empty function with int return type

    test_warnings.c:

    int main() {}
    
    int foo() {}
    

    Compile results:

    >cl /nologo /W0 /we4033 /we4716 /we4715 C:\Users\Administrator\src\test-code\test_warnings.c
    test_warnings.c
    c:\users\administrator\src\test-code\test_warnings.c(3) : error C4716: 'foo': must return a value
    

    Test 2 - Function with int return type with a return without a value

    test_warnings.c:

    int main() {}
    
    int foo() {
        return;
    }
    

    Compile results:

    >cl /nologo /W0 /we4033 /we4716 /we4715 C:\Users\Administrator\src\test-code\test_warnings.c
    test_warnings.c
    C:\Users\Administrator\src\test-code\test_warnings.c(4): error C4033: 'foo' must return a value
    

    Test 3 - Function with int return type where execution could "fall off" the end of the function

    This test demonstrates that these warnings are not enough, as there is no warning or error emitted for this code.

    test_warnings.c:

    #include <stdlib.h>
    #include <time.h>
    
    int main() {}
    
    int foo() {
        int rand_num;
        srand(time(0));
        rand_num = rand();
    
        if (rand_num > 1) {
            return 0;
        }
    }
    

    Compile results:

    >cl /nologo /W0 /we4033 /we4716 /we4715 C:\Users\Administrator\src\test-code\test_warnings.c
    test_warnings.c
    c:\users\administrator\src\test-code\test_warnings.c(14) : error C4715: 'foo': not all control paths return a value
    

    C++ tests

    Test 1 - Empty function with int return type

    test_warnings.cpp:

    int main() {}
    
    int foo() {}
    

    Compile results:

    >cl /nologo /W0 /we4033 /we4716 /we4715 C:\Users\Administrator\src\test-code\test_warnings.cpp
    test_warnings.cpp
    c:\users\administrator\src\test-code\test_warnings.cpp(3) : error C4716: 'foo': must return a value
    

    Test 2 - Function with int return type with a return without a value

    test_warnings.cpp:

    int main() {}
    
    int foo() {
        return;
    }
    

    Compile results:

    >cl /nologo /W0 /we4033 /we4716 /we4715 C:\Users\Administrator\src\test-code\test_warnings.cpp
    test_warnings.cpp
    C:\Users\Administrator\src\test-code\test_warnings.cpp(4): error C2561: 'foo': function must return a value
    C:\Users\Administrator\src\test-code\test_warnings.cpp(3): note: see declaration of 'foo'
    

    Test 3 - Function with int return type where execution could "fall off" the end of the function

    test_warnings.cpp:

    #include <stdlib.h>
    #include <time.h>
    
    int main() {}
    
    int foo() {
        int rand_num;
        srand(time(0));
        rand_num = rand();
    
        if (rand_num > 1) {
            return 0;
        }
    }
    

    Compile results:

    >cl /nologo /W0 /we4033 /we4716 /we4715 C:\Users\Administrator\src\test-code\test_warnings.cpp
    test_warnings.cpp
    c:\users\administrator\src\test-code\test_warnings.cpp(14) : error C4715: 'foo': not all control paths return a value
    

    Can you get this with just C4715?

    I reran my tests above to see if you can get the same behaviour with just C4715, and here are my results. The command I used for testing this was

    cl /nologo /W0 /we4715 <path to file>
    
    Test C C++
    Test 1 No warning or error Triggers C4716 as an error, even though this is not turned on (which makes sense, as the docs for this warning say it is automatically promoted to error unless #pragma warning is used to prevent this)
    Test 2 No warning or error Triggers C2561 (a compiler error)
    Test 3 Triggers C4715 Triggers C4715

    This means C4715 is sufficient for C++, but not sufficient for C.

    Notes

    C4715 may warn if you call a function that never returns. For example, if you call a function that ends with while (true) {} or throw "error message";. To avoid this, declare the function that never returns with __declspec(noreturn), or if you are using C++11 or newer, you can use the more portable [[noreturn]] in the function declaration. (If you are calling a standard library function like exit(), the compiler will not issue a warning because it will know that function never returns.)

    For some interesting related discussion, see Why does flowing off the end of a non-void function without returning a value not produce a compiler error?.