GCC 7,-Wimplicit-fallthrough 警告,以及清除它们的便携方式?
GCC 7, -Wimplicit-fallthrough warnings, and portable way to clear them?
我们正在捕获来自 GCC 7 的关于 switch 语句中隐式失败的警告。以前,我们在 Clang 下清除了它们(这就是下面看到的评论的原因):
g++ -DNDEBUG -g2 -O3 -std=c++17 -Wall -Wextra -fPIC -c authenc.cpp
asn.cpp: In member function ‘void EncodedObjectFilter::Put(const byte*, size_t)’:
asn.cpp:359:18: warning: this statement may fall through [-Wimplicit-fallthrough=]
m_state = BODY; // fall through
^
asn.cpp:361:3: note: here
case BODY:
^~~~
GCC manual 声明使用 __attribute__ ((fallthrough))
,但它不可移植。该手册还指出 "...也可以添加一个 fallthrough 注释来消除警告",但它只提供 FALLTHRU
(这真的是唯一的选择吗? ):
switch (cond)
{
case 1:
bar (0);
/* FALLTHRU */
default:
…
}
是否有一种可移植的方法来清除 Clang 和 GCC 的警告?如果有,那是什么?
GCC 期望标记注释在其自己的行中,如下所示:
m_state = BODY;
// fall through
case BODY:
标记也必须位于 case
标签之前;中间不能有右括号 }
.
fall through
是 GCC 认可的标记之一。不只是 FALLTHRU
。有关完整列表,请参阅 -Wimplicit-fallthrough
option. Also see this posting on the Red Hat Developer blog.
的文档
C++17 添加了一个 [[fallthrough]]
属性,可用于抑制此类警告。注意结尾的分号:
m_state = BODY;
[[fallthrough]];
case BODY:
Clang 支持 -Wimplicit-fallthrough
警告,但不会将它们作为 -Wall
或 -Wextra
的一部分启用。 Clang 不识别注释标记,因此必须对其使用基于属性的抑制(这目前意味着 C 前端的非标准 __attribute__((fallthrough))
构造)。
请注意,仅当编译器实际看到注释时,使用标记注释抑制警告才有效。如果预处理器单独运行,需要指示它保留注释,如-C
option of GCC. For example, to avoid spurious warnings with ccache,你需要在编译时指定-C
标志,或者,对于最近版本的ccache,使用keep_comments_cpp
选项。
C++17[[fallthrough]]
示例:
int main(int argc, char **argv) {
switch (argc) {
case 0:
argc = 1;
[[fallthrough]];
case 1:
argc = 2;
};
}
编译:
g++ -std=c++17 -Wimplicit-fallthrough main.cpp
如果删除 [[fallthrough]];
,GCC 警告:
main.cpp: In function ‘int main()’:
main.cpp:5:15: warning: this statement may fall through [-Wimplicit-fallthrough=]
argc = 1;
~~^~~
main.cpp:6:9: note: here
case 1:
^~~~
另请注意,该示例仅在遇到两种情况时才会出现警告:最后一个 case 语句(此处为 case 1
)即使没有 break
也不会生成警告。
以下构造也不会生成警告:
#include <cstdlib>
[[noreturn]] void my_noreturn_func() {
exit(1);
}
int main(int argc, char **argv) {
// Erm, an actual break
switch (argc) {
case 0:
argc = 1;
break;
case 1:
argc = 2;
}
// Return also works.
switch (argc) {
case 0:
argc = 1;
return 0;
case 1:
argc = 2;
}
// noreturn functions are also work.
//
switch (argc) {
case 0:
argc = 1;
my_noreturn_func();
case 1:
argc = 2;
}
// Empty case synonyms are fine.
switch (argc) {
case 0:
case 1:
argc = 2;
}
// Magic comment mentioned at:
//
switch (argc) {
case 0:
argc = 1;
// fall through
case 1:
argc = 2;
}
switch (argc) {
// GCC extension for pre C++17.
case 0:
argc = 1;
__attribute__ ((fallthrough));
case 1:
argc = 2;
}
switch (argc) {
// GCC examines all braches.
case 0:
if (argv[0][0] == 'm') {
[[fallthrough]];
} else {
return 0;
}
case 1:
argc = 2;
}
}
从最后一个可以看出,GCC检查了所有可能的分支,如果其中任何一个分支没有[[fallthrough]];
或break
或return
,就会发出警告。
您可能还想使用宏检查功能可用性,如 this GEM5 inspired snippet:
#if defined __has_cpp_attribute
#if __has_cpp_attribute(fallthrough)
#define MY_FALLTHROUGH [[fallthrough]]
#else
#define MY_FALLTHROUGH
#endif
#else
#define MY_FALLTHROUGH
#endif
另请参阅:https://en.cppreference.com/w/cpp/language/attributes/fallthrough
在 GCC 7.4.0、Ubuntu 18.04 上测试。
另见
C版本题:
清洁 C 解决方案:
int r(int a) {
switch(a) {
case 0:
a += 3;
case 1:
a += 2;
default:
a += a;
}
return a;
}
变成:
int h(int a) {
switch(a) {
case 0:
a += 3;
goto one;
case 1:
one:
a += 2;
goto others;
default:
others:
a += a;
}
return a;
}
编辑:按照 Stéphane Gourichon 在评论中的建议,将标签移到 case 语句之后,以便更容易地看到 fallthrough。
另一个例子:Linux内核提供了一个fallthrough
伪关键字宏。可用作:
switch (cond) {
case 1:
foo();
fallthrough;
case 2:
bar();
break;
default:
baz();
}
在内核中 v5.10 其实现方式如下:
#if __has_attribute(__fallthrough__)
# define fallthrough __attribute__((__fallthrough__))
#else
# define fallthrough do {} while (0) /* fallthrough */
#endif
没有人提到完全禁用警告,这可能不是 OP 正在寻找的答案,但我认为为了完整性应该包括它,因为它也适用于两个编译器:
-Wno-implicit-fallthrough
如果由于某种原因您无法更改源代码,这可以使编译输出保持干净,从而可以清楚地看到其他问题(但当然必须意识到自己丢失了什么)。
我们正在捕获来自 GCC 7 的关于 switch 语句中隐式失败的警告。以前,我们在 Clang 下清除了它们(这就是下面看到的评论的原因):
g++ -DNDEBUG -g2 -O3 -std=c++17 -Wall -Wextra -fPIC -c authenc.cpp
asn.cpp: In member function ‘void EncodedObjectFilter::Put(const byte*, size_t)’:
asn.cpp:359:18: warning: this statement may fall through [-Wimplicit-fallthrough=]
m_state = BODY; // fall through
^
asn.cpp:361:3: note: here
case BODY:
^~~~
GCC manual 声明使用 __attribute__ ((fallthrough))
,但它不可移植。该手册还指出 "...也可以添加一个 fallthrough 注释来消除警告",但它只提供 FALLTHRU
(这真的是唯一的选择吗? ):
switch (cond)
{
case 1:
bar (0);
/* FALLTHRU */
default:
…
}
是否有一种可移植的方法来清除 Clang 和 GCC 的警告?如果有,那是什么?
GCC 期望标记注释在其自己的行中,如下所示:
m_state = BODY;
// fall through
case BODY:
标记也必须位于 case
标签之前;中间不能有右括号 }
.
fall through
是 GCC 认可的标记之一。不只是 FALLTHRU
。有关完整列表,请参阅 -Wimplicit-fallthrough
option. Also see this posting on the Red Hat Developer blog.
C++17 添加了一个 [[fallthrough]]
属性,可用于抑制此类警告。注意结尾的分号:
m_state = BODY;
[[fallthrough]];
case BODY:
Clang 支持 -Wimplicit-fallthrough
警告,但不会将它们作为 -Wall
或 -Wextra
的一部分启用。 Clang 不识别注释标记,因此必须对其使用基于属性的抑制(这目前意味着 C 前端的非标准 __attribute__((fallthrough))
构造)。
请注意,仅当编译器实际看到注释时,使用标记注释抑制警告才有效。如果预处理器单独运行,需要指示它保留注释,如-C
option of GCC. For example, to avoid spurious warnings with ccache,你需要在编译时指定-C
标志,或者,对于最近版本的ccache,使用keep_comments_cpp
选项。
C++17[[fallthrough]]
示例:
int main(int argc, char **argv) {
switch (argc) {
case 0:
argc = 1;
[[fallthrough]];
case 1:
argc = 2;
};
}
编译:
g++ -std=c++17 -Wimplicit-fallthrough main.cpp
如果删除 [[fallthrough]];
,GCC 警告:
main.cpp: In function ‘int main()’:
main.cpp:5:15: warning: this statement may fall through [-Wimplicit-fallthrough=]
argc = 1;
~~^~~
main.cpp:6:9: note: here
case 1:
^~~~
另请注意,该示例仅在遇到两种情况时才会出现警告:最后一个 case 语句(此处为 case 1
)即使没有 break
也不会生成警告。
以下构造也不会生成警告:
#include <cstdlib>
[[noreturn]] void my_noreturn_func() {
exit(1);
}
int main(int argc, char **argv) {
// Erm, an actual break
switch (argc) {
case 0:
argc = 1;
break;
case 1:
argc = 2;
}
// Return also works.
switch (argc) {
case 0:
argc = 1;
return 0;
case 1:
argc = 2;
}
// noreturn functions are also work.
//
switch (argc) {
case 0:
argc = 1;
my_noreturn_func();
case 1:
argc = 2;
}
// Empty case synonyms are fine.
switch (argc) {
case 0:
case 1:
argc = 2;
}
// Magic comment mentioned at:
//
switch (argc) {
case 0:
argc = 1;
// fall through
case 1:
argc = 2;
}
switch (argc) {
// GCC extension for pre C++17.
case 0:
argc = 1;
__attribute__ ((fallthrough));
case 1:
argc = 2;
}
switch (argc) {
// GCC examines all braches.
case 0:
if (argv[0][0] == 'm') {
[[fallthrough]];
} else {
return 0;
}
case 1:
argc = 2;
}
}
从最后一个可以看出,GCC检查了所有可能的分支,如果其中任何一个分支没有[[fallthrough]];
或break
或return
,就会发出警告。
您可能还想使用宏检查功能可用性,如 this GEM5 inspired snippet:
#if defined __has_cpp_attribute
#if __has_cpp_attribute(fallthrough)
#define MY_FALLTHROUGH [[fallthrough]]
#else
#define MY_FALLTHROUGH
#endif
#else
#define MY_FALLTHROUGH
#endif
另请参阅:https://en.cppreference.com/w/cpp/language/attributes/fallthrough
在 GCC 7.4.0、Ubuntu 18.04 上测试。
另见
C版本题:
清洁 C 解决方案:
int r(int a) {
switch(a) {
case 0:
a += 3;
case 1:
a += 2;
default:
a += a;
}
return a;
}
变成:
int h(int a) {
switch(a) {
case 0:
a += 3;
goto one;
case 1:
one:
a += 2;
goto others;
default:
others:
a += a;
}
return a;
}
编辑:按照 Stéphane Gourichon 在评论中的建议,将标签移到 case 语句之后,以便更容易地看到 fallthrough。
另一个例子:Linux内核提供了一个fallthrough
伪关键字宏。可用作:
switch (cond) {
case 1:
foo();
fallthrough;
case 2:
bar();
break;
default:
baz();
}
在内核中 v5.10 其实现方式如下:
#if __has_attribute(__fallthrough__)
# define fallthrough __attribute__((__fallthrough__))
#else
# define fallthrough do {} while (0) /* fallthrough */
#endif
没有人提到完全禁用警告,这可能不是 OP 正在寻找的答案,但我认为为了完整性应该包括它,因为它也适用于两个编译器:
-Wno-implicit-fallthrough
如果由于某种原因您无法更改源代码,这可以使编译输出保持干净,从而可以清楚地看到其他问题(但当然必须意识到自己丢失了什么)。