I'm trying to get a project of mine building on Windows, which is a first for me. I'm a beginner to the platform. I'm using clang-cl to support C11. The source originally used noreturn
from <stdnoreturn.h>
to annotate function that will never return. I ended up with a whole bunch of declspec errors when compiling, and narrowed it down to as trivial a file as I could.
#include <stdnoreturn.h>
#include <stdlib.h>
Either on their own build fine, but together they produce a laundry list of errors, all of the exact same type:
__declspec attributes must be an identifier or string literal
all of which are unhappy about variations on the same macro expansion:
[build] C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.22.27905\include\vcruntime.h(326,20): error: __declspec attributes must be an identifier or string literal
[build] __declspec(noreturn) void __cdecl __report_gsfailure(_In_ uintptr_t _StackCookie);
[build] ^
[build] C:\PROGRA~1\LLVM\lib\clang\8.0.1\include\stdnoreturn.h(27,18): note: expanded from macro 'noreturn'
[build] #define noreturn _Noreturn
I've tried passing -fms-extensions and -fms-compatibility to clang-cl and got no dice. My best guess is clang is upset that Windows is putting a keyword in that declspec? I don't know much about any MS extensions.
Using plain old _Noreturn
works fine, so I can get my code to compile. But does anyone have more insight into what's going on here and what the fix is? Is combining msvc and clang just inherently janky or am I doing something wrong?
EDIT: I'm an idiot.
The problem is that the macro expansion is breaking _declspec(noreturn)
inside of Windows SDK headers. The solution is obvious:
#include <stdlib.h>
#include <stdnoreturn.h>
Which builds just fine, because the macro is defined after the Windows SDK header that uses declspec(noreturn)
I've posted the answer in my edit, but in order to close the question I'll post an extended version here.
The problem comes from a conflict between the C11 standard and Windows-specific extensions to C/C++. Windows extends storage-classes using the declspec syntax, which predates C11. It provides a storage-class for functions which don't return with __declspec(noreturn)
.
Unfortunately this conflicts with the keyword macro noreturn
from C11. Microsoft likely doesn't see this as a problem, since they don't claim any support for C11. If you try to use Windows SDK headers with the macro defined, your compiler will complain about using a keyword in the declspec through the somewhat cryptic error message listed in the original question (noreturn
expands into _Noreturn
, the actual keyword added in C11).
The answer is pretty simple though: as long as your code isn't trying to mix __declspec(noreturn)
and noreturn
, which would be redundant, just include the <stdnoreturn.h>
header after the other system headers. The preprocessor won't expand noreturn
inside the Windows SDK headers, and everything will be copacetic.