I get the following error when creating a custom exception in a C++ module:
C:/Sync/Engine/Chorus/Base/win_9x.cpp:600:59: error: conflicting declaration of C function 'void __cxa_throw(void*, void*, void (__attribute__((thiscall)) *)(void*))'
600 | throw Crash(Win9xErrorCode::BAD_MAIN_CLASS);
| ^
In file included from C:/msys64/mingw32/include/c++/14.1.0/bits/version.h:49,
from C:/msys64/mingw32/include/c++/14.1.0/variant:36,
of module C:/msys64/mingw32/include/c++/14.1.0/variant, imported at C:/Sync/Engine/Chorus/Base/error.cppm:16,
of module Error, imported at C:/Sync/Engine/Chorus/Base/win_9x.cpp:217:
C:/msys64/mingw32/include/c++/14.1.0/variant:1349:5: note: previous declaration 'void __cxa_throw(void*, void*, void (*)(void*))'
1349 | { _GLIBCXX_THROW_OR_ABORT(bad_variant_access(__what)); }
| ^~~~~~~~~~~~~~~~~~~~~~~
I'm using the MSYS version of G++, version 14.1.0.
Is this a known (unimplemented) feature, or could it be something in my code?
Here's a simplified version of the declaration (...
is snipped code):
export module Error;
...
enum class ErrorType: uint8_t {
...
};
export enum class Win9xErrorCode: uint16_t {
...
};
export enum class WinXPErrorCode: uint16_t {
...
};
export class Crash: public std::exception {
public:
Crash(Win9xErrorCode crashCode) noexcept: code(crashCode), type(ErrorType::WIN9X) { }
Crash(WinXPErrorCode crashCode) noexcept: code(crashCode), type(ErrorType::WINXP) { }
private:
std::variant<Win9xErrorCode, WinXPErrorCode, Win7ErrorCode> code;
ErrorType type;
};
For reference, the code that trips is not in a module:
void setupMainWindow(...) {
WNDCLASSEX graphicsWindowClass = {
...
};
if(!RegisterClassEx(&graphicsWindowClass)) {
throw Crash(Win9xErrorCode::BAD_MAIN_CLASS);
}
}
This appears to be a bug in GCC, possibly related to (or caused by) Bug 114968 - [14/15 Regression] missing __thiscall
attribute on builtin declaration of __cxa_thread_atexit()
(which also affects __cxa_throw
). This bug specifically affects mingw for 32-bit Intel targets.
One declaration of __cxa_throw
is coming from a throw in <variant>
, and looks like void __cxa_throw(void*, void*, void (*)(void*))
. The other declaration of __cxa_throw
is coming from your module, and looks like void __cxa_throw(void*, void*, void (__attribute__((thiscall)) *)(void*))
. The only difference is that the destructor callback (third argument) is declared thiscall
in the module.
If you're using a version of GCC that predates the fix to that bug, I'd try upgrading. If you're using a version of GCC that already incorporates that fix, it's probable that the fix didn't solve the problem entirely, which would warrant a new bug report.