dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.26k stars 4.73k forks source link

debugreturn.h should not macroize C++ keywords #67470

Open GrabYourPitchforks opened 2 years ago

GrabYourPitchforks commented 2 years ago

The reserved keyword return is macroized in debugreturn.h:

https://github.com/dotnet/runtime/blob/3c3155d92a632c16197afc31e787ab2d9a2b5a4f/src/coreclr/inc/debugreturn.h#L25

https://github.com/dotnet/runtime/blob/3c3155d92a632c16197afc31e787ab2d9a2b5a4f/src/coreclr/inc/debugreturn.h#L93-L102

This is preventing import of some STL headers, causing build failures in PRs such as https://github.com/dotnet/runtime/pull/67464. Static analyzers like https://rules.sonarsource.com/cpp/RSPEC-5266 catch this as bad practice, and MSVC also flags this as an error.

Consider using a different name, such as CHECKED_RETURN, instead of piggybacking on the reserved keyword return.

jkotas commented 2 years ago

Note that we do this in non-shipping debug/checked builds only.

jkotas commented 2 years ago

Consider using a different name, such as CHECKED_RETURN, instead of piggybacking on the reserved keyword return.

The whole point of this hack is to catch bad accidental incorrect uses of the return statements. If we were to use different name, this hack would lose its point.

I guess the proper fix would require getting rid of the macros that prohibit use of the return statements.

GrabYourPitchforks commented 2 years ago

Thanks for the context. I was looking around at other patterns that might work, such as clever use of dtors, but couldn't find anything that worked as well as the #define trick we're using.

The page https://github.com/dotnet/runtime/blob/57bfe474518ab5b7cfe6bf7424a79ce3af9d6657/docs/coding-guidelines/clr-code-guide.md#214-dont-do-nonlocal-returns-from-within-gcprotect-blocks contains this text.

Why is GCPROTECT not implemented via a C++ smart pointer? The GCPROTECT macro originates in .NET Framework v1. All error handling was done explicitly at that time, without any use C++ exception handling or stack allocated holders.

Is there a technical reason forbidding reimplementing this functionality using C++ idioms like RAII for these scenarios, which would allow non-local returns? I can imagine that this would cause a decent amount of churn, assuming it's even pursuable.

Edit: I guess one can always do something silly with C++ lambdas if so inspired, which would cause the return to exit only the inner lambda, not the enclosing function. Changing the type away from "void" will cause return to generate a compiler error. Big downside is that F10 breaks in the debugger. :(

#define GCPROTECT_BEGIN() [&]() [[msvc::forceinline]] -> void {
#define GCPROTECT_END() }();
jkotas commented 2 years ago

The GCPROTECT macro was reimplemented using standard C++ idioms already. You can delete DEBUG_ASSURE_NO_RETURN_BEGIN use from it and also the quoted text from clr-code-guide.md.

However, we have number of other key macros that still use DEBUG_ASSURE_NO_RETURN_BEGIN (e.g. HELPER_METHOD_FRAME macros) that are hard to reimplement using C++ idioms.

C++ lambdas

FWIW, C++ lamdas come with significant code quality hit. We have tried to replace some macros in the GC with lamdas some time ago. We had to abandon the idea due to unacceptable performance impact.

AaronRobinsonMSFT commented 2 years ago

I guess the proper fix would require getting rid of the macros that prohibit use of the return statements.

@jkotas and @janvorli Thoughts on removing this compile time check? I agree it is unfortunate, but there is very little active development in this area anymore.

jkotas commented 2 years ago

there is very little active development in this area anymore.

I believe that some VM code that has to follow these no-return rules is being changed like every week.

Removing this compile time check will turn compile error into some sort of runtime crash. You can try to introduce a bad return inside HELPER_METHOD_FRAME and then try to debug the runtime crash to see what the experience looks like with this compile check deleted.

mangod9 commented 1 year ago

@AaronRobinsonMSFT probably something which can be moved out of 8?