编译 clang 的 <noreturn.h> 和 Windows headers 时出现 declspec 错误

declspec error when compiling clang's <noreturn.h> along with Windows headers

我正在尝试在 Windows 上建立一个我的项目,这对我来说是第一次。我是该平台的初学者。我正在使用 clang-cl 来支持 C11。源最初使用 <stdnoreturn.h> 中的 noreturn 来注释永远不会 return 的函数。我在编译时遇到了一大堆 declspec 错误,并尽可能将其缩小到一个微不足道的文件。

#include <stdnoreturn.h>
#include <stdlib.h>

要么靠自己打造,要么靠在一起 produce a laundry list of errors,所有类型完全相同:

__declspec attributes must be an identifier or string literal

所有人都对同一宏扩展的变化感到不满:

[build] C:\Program Files (x86)\Microsoft Visual Studio19\Community\VC\Tools\MSVC.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.0.1\include\stdnoreturn.h(27,18): note: expanded from macro 'noreturn'
[build] #define noreturn _Noreturn

我试过将 -fms-extensions 和 -fms-compatibility 传递给 clang-cl 但没有骰子。我最好的猜测是 clang 对 Windows 在 declspec 中放置关键字感到不安?我不太了解任何 MS 扩展。

使用普通的旧 _Noreturn 工作正常,所以我可以编译我的代码。但是有没有人更深入地了解这里发生的事情以及解决方法是什么?将 msvc 和 clang 组合在一起是天生的问题还是我做错了什么?

编辑:我是个白痴。

问题是宏扩展正在破坏 Windows SDK header 内部的 _declspec(noreturn)。解决方案很明显:

#include <stdlib.h>
#include <stdnoreturn.h>

构建得很好,因为宏是在使用 declspec(noreturn)

的 Windows SDK header 之后定义的

我在我的编辑中 post 编辑了答案,但为了结束这个问题,我将在此处 post 一个扩展版本。

问题来自于 C11 标准和 Windows-specific C/C++ 扩展之间的冲突。 Windows 使用早于 C11 的 declspec syntax 扩展了 storage-classes。它为 return 和 __declspec(noreturn) 没有的函数提供 storage-class。

不幸的是,这与 C11 中的关键字宏 noreturn 冲突。 Microsoft 可能不认为这是一个问题,因为他们没有声称对 C11 有任何支持。如果您尝试使用 Windows SDK headers 和宏定义,您的编译器将通过原始问题中列出的有点神秘的错误消息抱怨在 declspec 中使用关键字(noreturn扩展为 _Noreturn,C11 中添加的实际关键字)。

虽然答案很简单:只要您的代码不试图混合 __declspec(noreturn)noreturn,那将是多余的,只需包含 <stdnoreturn.h> header 在其他系统 header 之后。预处理器不会在 Windows SDK header 中扩展 noreturn,一切都会变得很糟糕。