Skip to content

Add possible workaround to compiler-error-c2603.md #44

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from

Conversation

KorkyPlunger
Copy link

Added information about a possible workaround for compiler error c2603. This workaround was tested in Visual Studio 2013.

Added information about a possible workaround for compiler error c2603. This workaround was tested in Visual Studio 2013.
@msftclas
Copy link

@KorkyPlunger,
Thanks for your contribution.
To ensure that the project team has proper rights to use your work, please complete the Contribution License Agreement at https://cla.microsoft.com.

It will cover your contributions to all Microsoft-managed open source projects.
Thanks,
Microsoft Pull Request Bot

@colin-home
Copy link
Contributor

The workaround does not appear to work, at least in the last couple of compiler versions.

C:\Users\corob\Documents\Projects\errors\C2603>type C2603b.cpp
// C2603b.cpp
struct C { C() {} };
extern inline void f1() {
   [&](){
      static C C1,C2,C3,C4,C5,C6,C7,C8,C9,C10,C11,C12,C14,C15,C16;
      static C C17,C18,C19,C20,C21,C22,C23,C24,C25,C26,C27,C28,C29,C30,C31,C32;
      static C C33;   // C2603 Comment this line out to avoid error
   }();
}

C:\Users\corob\Documents\Projects\errors\C2603>cl /c /W4 /Zc:threadSafeInit- /nologo C2603b.cpp
C2603b.cpp
C2603b.cpp(7): error C2603: 'f1::<lambda_86511597e343e85cae715b2bccf54cbd>::operator ()': Too 
many block scope static objects with constructor/destructors in function

The C2603 error does not occur in recent compilers where thread safe init is the default, hence the /Zc:threadSafeInit- switch to trigger it.

@KorkyPlunger
Copy link
Author

KorkyPlunger commented Jul 13, 2017

Interesting. We're using VS2013, and I tested this both in our production code and in a small test app. If you just create a basic Win32 console app using the project wizard in VS2013 and paste in the workaround code, that compiles cleanly for me (and fails with the error if you remove the lambda).

I tested this in VS2015 via http://webcompiler.cloudapp.net/ and you are correct: if I pass the /Zc:threadSafeInit- flag then it does not compile with the lambda. So it seems this workaround may be specific to VS 2013 (and possibly 2012?)

@KorkyPlunger
Copy link
Author

I've updated the PR to include information about version-specific differences.

@colin-home
Copy link
Contributor

I've run the lambda idea past the compiler team, and they do not like it for several reasons. One is that it probably works because in the 2013 compiler, this particular lambda breaks the inline/comdat request, so you are silently paying for a function call to f1 when you expect inline behavior. A code clarity issue arises because the statics in the lambda are only visible within the lambda, so you wind up with an oddly doubly-wrapped function body if you want to make use of them. And finally, this technique is not forward compatible with updated compilers that are better at inlining the lambda. When you update your toolset, this would once again expose the issue if you've turned on the backward compatibility flag. You'd wind up with a regression on an issue you thought you'd fixed.

If you're willing to pay the performance penalty of not having the function be comdat/inline, then you'd be better off making it explicit with a forwarding function, like so:

struct C { C() {} };
void f2() {
    static C C1,C2,C3,C4,C5,C6,C7,C8,C9,C10,C11,C12,C13,C14,C15,C16;
    static C C17,C18,C19,C20,C21,C22,C23,C24,C25,C26,C27,C28,C29,C30,C31,C32;
    static C C33;  // 33 variables are ok here because this function isn’t comdat.
}

extern inline void f1() {
     f2(); // delegate to f2 to do all the real work
}

One developer suggested that if the statics are all of the same type as in the example, as a work around, you could allocate an array as a single static entry, and use references to individual elements of the array. This has the dual advantage of both maintaining the inline/comdat performance, and of being something you wouldn't need to go back and fix up when you moved to a newer toolset.

Moving to a newer toolset that implements magic statics is really the best solution anyway; you can now define as many statics as you like without a krufty work around.

Mentions of the /Zc:threadSafeInit flag are a useful addition to this topic. I'll work on incorporating that information here.

@colin-home colin-home closed this Jul 13, 2017
@colin-home
Copy link
Contributor

Thanks to your input, I've poked some discussion of possible resolutions and a link to the /Zc:threadSafeInit topic into C2603. I appreciate your proposal and the time you took to work on it, even if it didn't go in exactly as you wrote it.

@KorkyPlunger
Copy link
Author

No problem, I was just hoping to save other developers time (and I hadn't checked the latest compilers before writing the proposal).

I agree that magic statics are the way to go. Glad we've got more information in the docs now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants