Search code examples
c++visual-c++constructorvisual-c++-2008unreachable-code

Unreachable code at constructor's closing brace


I'm working on an application built with VC9 and I've hit upon a warning I don't fully understand: why is there an "unreachable code" warning on the closing brace of the constructor?

The minimal testcase to reproduce the issue is:

__declspec(noreturn) void foo() {
  // Do something, then terminate the program
}
struct A {
  A() {
    foo();
  } // d:\foo.cpp(7) : warning C4702: unreachable code
};
int main() {
  A a;
}

This must be compiled with /W4 to trigger the warning. Alternatively, you can compile with /we4702 to force an error on the detection of this warning.

d:\>cl /c /W4 foo.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 15.00.21022.08 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

foo.cpp
d:\foo.cpp(7) : warning C4702: unreachable code

Can someone explain what, precisely, is unreachable here? My best theory is that it's the destructor, but I'd like a definitive answer.

If I want to make this code warning-clean, how can I achieve that? The best I can come up with is convert this to a compile-time error.

struct A {
private:
  A(); // No, you can't construct this!
};
int main() {
  A a;
}

Edit: for clarification, terminating the program with a noreturn function doesn't normally cause an unreachable code warning on the closing brace enclosing that function call.

__declspec(noreturn) void foo() {
  // Do something, then terminate the program
}
struct A {
  A() {
  }
  ~A() {
    foo();
  }
};
int main() {
  A a;
}

Results in:

d:\>cl /c /W4 foo3.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 15.00.21022.08 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

foo3.cpp

Solution

  • Gorpik is on the right track. I've created two similar test cases, compiled them, and disassembled them and I think I've come to understand the underlying reason: the constructor always generates a return statement implicitly and this return statement is unreachable due to the noreturn function.

    noreturn_constructor.cpp

    __declspec(noreturn) void foo() {
      // Do something, then terminate the program
    }
    struct A {
      A() {
        foo();
      }
      ~A() {
      }
    };
    int main() {
      A a;
    }
    

    noreturn_destructor.cpp

    __declspec(noreturn) void foo() {
      // Do something, then terminate the program
    }
    struct A {
      A() {
      }
      ~A() {
        foo();
      }
    };
    int main() {
      A a;
    }
    

    diff -u *.disasm

    --- noreturn_constructor.disasm 2012-05-30 11:15:02.000000000 -0400
    +++ noreturn_destructor.disasm  2012-05-30 11:15:08.000000000 -0400
    @@ -2,7 +2,7 @@
     Copyright (C) Microsoft Corporation.  All rights reserved.
    
    
    -Dump of file noreturn_constructor.obj
    +Dump of file noreturn_destructor.obj
    
     File Type: COFF OBJECT
    
    @@ -35,15 +35,15 @@
    
     ??0A@@QEAA@XZ (public: __cdecl A::A(void)):
       0000000000000000: 48 89 4C 24 08     mov         qword ptr [rsp+8],rcx
    -  0000000000000005: 48 83 EC 28        sub         rsp,28h
    -  0000000000000009: E8 00 00 00 00     call        ?foo@@YAXXZ
    -  000000000000000E: 48 8B 44 24 30     mov         rax,qword ptr [rsp+30h]
    -  0000000000000013: 48 83 C4 28        add         rsp,28h
    -  0000000000000017: C3                 ret
    +  0000000000000005: 48 8B 44 24 08     mov         rax,qword ptr [rsp+8]
    +  000000000000000A: C3                 ret
    
     ??1A@@QEAA@XZ (public: __cdecl A::~A(void)):
       0000000000000000: 48 89 4C 24 08     mov         qword ptr [rsp+8],rcx
    -  0000000000000005: C3                 ret
    +  0000000000000005: 48 83 EC 28        sub         rsp,28h
    +  0000000000000009: E8 00 00 00 00     call        ?foo@@YAXXZ
    +  000000000000000E: 48 83 C4 28        add         rsp,28h
    +  0000000000000012: C3                 ret
    
       Summary
    

    The unreachable code is this implicit return statement, which is generated in the constructor but not the destructor:

    -  000000000000000E: 48 8B 44 24 30     mov         rax,qword ptr [rsp+30h]
    +  0000000000000005: 48 8B 44 24 08     mov         rax,qword ptr [rsp+8]