When compiling the code below with cl /c /clr /W4 the compiler says
warning C4793: 'Interface::'vcall'{0}'' : function compiled as native
So the pragma does not seem to have any effect.. Is there a way to fix this? Or is this a bug (the pragma does work with a non-template class)? Can this warning safely be disabled?
#pragma unmanaged
struct Interface
{
virtual void Foo() = 0;
};
template< class T >
struct UsesFunPtr
{
UsesFunPtr()
{
&T::Foo;
}
};
void DoIt()
{
UsesFunPtr< Interface > a;
}
#pragma managed
Update: if I remove the last line the warning goes away – so following ComicSansMs’ answer: when exactly is at the time of definition for the template? Can anyone explain why the last line, after which no code follows, still affects the code before it?
Big revision, since (in the comments) the poster explains why &T:Foo; was not an issue.
The origins of this warning are somewhat stupidly complex.
After investigation we find the following from Microsoft, which ComicSansMS also posted:
This is for a function template, not for a class template as you are using.
In fact, this function template instantion is relevant in a circumspect way. But the peculiar way this warning behaves has to do with the compilation process.
The compiler is actually generating managed code for calling and using the UsesFunPtr ctor when you end the file it with #pragma managed. It gives a warning that there’s some unmanaged code in it. Here’s an in-depth analysis of why.
Thunks are basically wrapper functions around certain vtable calls; Wikipedia has a decent article on the subject. The reason you are generating a thunk is because you are taking the address of a function (&T::Foo).
If the last line of your file is this:
it will stop complaining, even if you have mixed managed and unmanaged code in that object. It is because of a disconnect between the front-end and back-end that “confuses” things: it will compile that code I spoke of above with the last #pragma command.
If you’ll notice, this warning is not a compile-time warning. It comes after the compile, when it says “Generating code…” If you revise your DoIt() function like so:
You will get a warning about truncation during “Compiling x.cpp”, then it will move to the code generation phase (Generating code…), where it will give the warning this question is about.
The compiler is the front-end which parses, etc. and creates a sort-of intermediate binary format, kind of like Java bytecode. The code generator is the back-end which creates the actual output on the target platform from this bytecode (Windows x86 in this case).
Optimizations aren’t made until the back-end gets hold of the code. A thunk is a form of optimization, thus, it is the code generator (that takes semi-compiled IL code) that makes the warning, and not the compiler. It is not an optimization that can be turned off in any way I know of, because it is sort of a standard practice.
It is the compiler, however, that instantiates that template; the back-end just sees a complete class and is told to make sense of it.
There is a difference when compiling managed C++/CLI. Sometimes the compiler is able to use what’s known as link-time code generation. When this happens, the linker is the one to call the back-end; when it isn’t possible (for various reasons), it goes through the generic process of compiling (front end->back end->linker).
A #pragma is passed into the IL in the order it is received. This seems to indicate that the function support code for UsesFunPtr is actually “appended to the end,” after the #pragma managed has happened. So even though your code is in an unmanaged space, the code generator sees:
The generator has no way to differentiate if you meant that UsesFunPtr ctor, or even class, to be completely managed or unmanaged code, because the IL it gets doesn’t really connect the two. It sees a function that creates it that is unmanaged (by pragma), and support functions that work on it and produce thunks in managed space (by pragma). It can’t tell the connection. Since you put that #pragma there, it is just continuing with the last #pragma it saw. The generated support code is managed.
You’ll notice that if you put #pragma unmanaged at the very end, even if there’s managed code that mixes the templates, you won’t get that warning. This is because it is compiling that code as unmanaged and thus thunks aren’t an issue.
How to sum this all up? #pragma managed at the end causes a miscommunication (or would it be a wrong assumption?) between the front end and the back end, and the back end complains about it.
Wee, that was a fun one!