3

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)

nickelpro
  • 2,537
  • 1
  • 19
  • 25
  • 4
    I'll blame Microsoft, now and forever :D – Antti Haapala -- Слава Україні Aug 04 '19 at 20:19
  • 1
    Do you specifically want to build with MSVC standard library? Using Clang with libstdc++ provided by MinGW is a good alternative. – HolyBlackCat Aug 04 '19 at 20:20
  • 1
    I guess this is a clang error, they never considered that the `noreturn` could be expanded to `_Noreturn` in `__declspec` – Antti Haapala -- Слава Україні Aug 04 '19 at 20:34
  • Can you please clarify if just the two includes in your first snippet cause the problem? The title says "along with Windows headers" but you did not show any includes of Windows headers. – M.M Aug 04 '19 at 22:53
  • Looks like the thing to do is file a bug report and don't use `stdnoreturn` unless you want to change compiler. FWIW msys2 clang and gcc both don't have the problem – M.M Aug 04 '19 at 23:00
  • Is your code including: `` or `` – user3629249 Aug 04 '19 at 23:03
  • @AnttiHaapala Is correct here, I would mark him correct if it was an answer. Likely clang's `` was never tested with the Windows SDK, just libc++ if at all. `__declspec` supports [a handful of modifiers](https://learn.microsoft.com/en-us/cpp/cpp/declspec?view=vs-2019). clang is upset because the preprocessor expands the `noreturn` into an invalid modifier. I don't know how anyone would even fix this, MS doesn't support C11 so it's valid for them to use `noreturn` as a keyword. clang would have to perform some magic to support this _specific_ macro. – nickelpro Aug 05 '19 at 22:23
  • Well I'm an idiot, writing that comment keyed me in to the solution – nickelpro Aug 05 '19 at 22:33

1 Answers1

2

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.

nickelpro
  • 2,537
  • 1
  • 19
  • 25
  • 2
    Alternatively, you can just skip [using `#include ` and just use `_Noreturn`](https://port70.net/~nsz/c/c11/n1570.html#7.23) for code that supports C11 features and also has to compile under MSVC. You'd probably need some `#ifdef`'s either way. – Andrew Henle Aug 07 '19 at 22:13