Search code examples
windowsc++1764-bit32-bitcl.exe

Different errors between cl.exe 64-bit and 32-bit


I have the following source code:

#include <functional>
#include <minwindef.h>
#include <winerror.h>
#include <libloaderapi.h>
#include <winreg.h>

namespace ffmock
{

/**
 * @brief Primary template
 */
template<typename T>
struct function_traits;

/**
 * @brief Template specialization for APIs
 */
template<typename RetType_t, typename... Args_t>
struct function_traits<RetType_t(Args_t...)>
{
    using Ret_t = RetType_t;
    using Sig_t = Ret_t(Args_t...);
    using Ptr_t = Ret_t(*)(Args_t...);
    using Api_t = std::function<Sig_t>;
};

template<typename RetType_t, typename API_t, RetType_t RetValue, DWORD Error2Set = NO_ERROR>
class
Mock
{
protected:

    using Traits_t = function_traits<API_t>;
    using Ret_t = typename Traits_t::Ret_t;
    using Ptr_t = typename Traits_t::Ptr_t;
    using Api_t = typename Traits_t::Api_t;
    using Mock_t = Mock;

    Mock(HMODULE Module, const char* ApiName);
 
    template<typename... Args_t>
    Ret_t operator()(Args_t&... Args);
};

} // namespace ffmock

#pragma warning(disable:4273) // inconsistent dll linkage

namespace Mocks
{

class FFRegCloseKey
    : public ::ffmock::Mock<LSTATUS, decltype(::RegCloseKey), ERROR_INVALID_HANDLE>
{
    friend
    FFMOCK_IMPORT
    LSTATUS
    APIENTRY
    ::RegCloseKey(
        _In_ HKEY Key
        );

    FFRegCloseKey(HMODULE Module) : Mock_t(Module, "RegCloseKey")
    {
    }
};

} // namespace Mocks

extern "C"    
FFMOCK_IMPORT
LSTATUS
APIENTRY
RegCloseKey(HKEY Key)
{
    static Mocks::FFRegCloseKey mock(LoadLibraryW(L"advapi32.dll"));
    return mock(Key);
}

The program compiles cleanly with the 64-bit version of the Microsoft compiler. However, using the 32-bit version of the same compiler results in numerous errors. Here's the 64-bit compiler's output:

  • Executing task: C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC/14.38.33130/bin/Hostx64/x64/cl.exe /nologo /Fodemo/bin/x64/ /std:c++17 /EHsc /D_DEBUG /D_AMD64_ /DWIN64 /D_UNICODE /DUNICODE /D_CONSOLE /DFFMOCK_IMPORT=__declspec(dllexport) /c C:\Play\ffmock\demo\tst\Test.cpp

Test.cpp * Press any key to close the terminal.

The 32-bit compiler's output:

  • Executing task: C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC/14.38.33130/bin/Hostx86/x86/cl.exe /nologo /Fodemo/bin/x64/ /std:c++17 /EHsc /D_DEBUG /D_X86_ /DWIN32 /D_UNICODE /DUNICODE /D_CONSOLE /DFFMOCK_IMPORT=__declspec(dllexport) /c C:\Play\ffmock\demo\tst\Test.cpp

Test.cpp C:\Play\ffmock\demo\tst\Test.cpp(42): error C2027: use of undefined type 'ffmock::function_traits<API_t>' with [ API_t=LSTATUS (HKEY) ] C:\Play\ffmock\demo\tst\Test.cpp(41): note: see declaration of 'ffmock::function_traits<API_t>'
with [ API_t=LSTATUS (HKEY) ] C:\Play\ffmock\demo\tst\Test.cpp(42): note: the template instantiation context (the oldest one first) is C:\Play\ffmock\demo\tst\Test.cpp(64): note: see reference to class template instantiation 'ffmock::Mock<LSTATUS,LSTATUS (HKEY),6,0>' being compiled C:\Play\ffmock\demo\tst\Test.cpp(42): error C2061: syntax error: identifier 'Ret_t' C:\Play\ffmock\demo\tst\Test.cpp(43): error C2027: use of undefined type 'ffmock::function_traits<API_t>' with [ API_t=LSTATUS (HKEY) ] C:\Play\ffmock\demo\tst\Test.cpp(41): note: see declaration of 'ffmock::function_traits<API_t>'
with [ API_t=LSTATUS (HKEY) ] C:\Play\ffmock\demo\tst\Test.cpp(43): error C2061: syntax error: identifier 'Ptr_t' C:\Play\ffmock\demo\tst\Test.cpp(44): error C2027: use of undefined type 'ffmock::function_traits<API_t>' with [ API_t=LSTATUS (HKEY) ] C:\Play\ffmock\demo\tst\Test.cpp(41): note: see declaration of 'ffmock::function_traits<API_t>'
with [ API_t=LSTATUS (HKEY) ] C:\Play\ffmock\demo\tst\Test.cpp(44): error C2061: syntax error: identifier 'Api_t' C:\Play\ffmock\demo\tst\Test.cpp(50): error C2143: syntax error: missing ';' before '(' C:\Play\ffmock\demo\tst\Test.cpp(50): error C2238: unexpected token(s) preceding ';' C:\Play\ffmock\demo\tst\Test.cpp(50): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int C:\Play\ffmock\demo\tst\Test.cpp(50): error C2988: unrecognizable template declaration/definition C:\Play\ffmock\demo\tst\Test.cpp(50): error C2059: syntax error: '' C:\Play\ffmock\demo\tst\Test.cpp(92): error C3889: call to object of class type 'Mocks::FFRegCloseKey': no matching call operator found C:\Play\ffmock\demo\tst\Test.cpp(50): note: could be 'int ffmock::Mock<LSTATUS,LSTATUS (HKEY),6,0>::operator ()(Args_t &...)'

  • The terminal process "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\bin\Hostx86\x86\cl.exe '/nologo', '/Fodemo/bin/x64/', '/std:c++17', '/EHsc', '/D_DEBUG', '/D_X86_', '/DWIN32', '/D_UNICODE', '/DUNICODE', '/D_CONSOLE', '/DFFMOCK_IMPORT=__declspec(dllexport)', '/c', 'C:\Play\ffmock\demo\tst\Test.cpp'" terminated with exit code: 2. * Press any key to close the terminal.

Can anyone suggest how to fix these errors?


Solution

  • Thank @igor-tandetnik for helping solve this issue.

    There are two ways to solve this issue:

    1. Once I added /Gz (__stdcall) to the command line, the code compiles.

    2. Specialize the secondary template

      template<typename RetType_t, typename... Args_t>

      struct function_traits<RetType_t __stdcall(Args_t...)>

      {

      using Ret_t = RetType_t;
      
      using Sig_t = Ret_t __stdcall(Args_t...);
      
      using Ptr_t = Ret_t(__stdcall*)(Args_t...);
      
      using Api_t = std::function<Sig_t>;
      

      };