Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
like image 592
mrkj Avatar asked May 30 '12 14:05

mrkj


3 Answers

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]
like image 172
mrkj Avatar answered Sep 27 '22 23:09

mrkj


There are no destructors to be called at the end of A::A(), so that's not the problem. What cannot be reached is the actual construction of the object, which happens after the constructor has finished its execution. Since it can never finish, that compiler-generated code is unreachable.

like image 42
Gorpik Avatar answered Sep 27 '22 22:09

Gorpik


The declspec(noreturn) on foo is producing this warning. You're telling the compiler that this function does not return. So the compiler is emitting a warning that your constructor will never complete.

like image 45
Anon Mail Avatar answered Sep 27 '22 23:09

Anon Mail