[[maybe_unused]] 在成员变量上,GCC 警告(错误地?)属性被忽略
[[maybe_unused]] on member variable, GCC warns (incorrectly?) that attribute is ignored
在下面example:
struct Foo {
[[maybe_unused]] int member = 1;
void bar() {
[[maybe_unused]] int local = 0;
}
};
int main(int argc, char* argv[]) {
Foo f{};
f.bar();
return 0;
}
GCC 会发出警告,而 Clang 和 MSVC 不会:
warning: 'maybe_unused' attribute ignored [-Wattributes]
[[maybe_unused]] int member = 1;
据我所知,这应该是合法的(并且不会被编译器忽略)。根据 standard:
10.6.7 Maybe unused attribute [dcl.attr.unused]
...
2. The attribute may be applied to the declaration of a class, a typedef-name, a variable, a non-static data member, a function, an enumeration, or an enumerator.
...
我讨厌挥动 "compiler bug" 锤子,但我不确定在这种情况下它还能是什么。
有没有人有任何见解?
任何属性都可以出于任何原因 "ignored by the compiler",除非标准另有规定(例如在明确禁止的位置使用属性)。
GCC 并不是说你不能把一个放在那里;它是说把一个放在那里不会做任何事情,因为他们可能不会警告可能未使用的成员变量。
GCC 不会首先就未使用的成员变量向您发出警告,因此该属性没有任何用途,这就是它警告您忽略它的原因。这只是一个警告,您的代码仍然合法。
既然我再次查看了这个,我无法让 Clang 警告未使用的成员,因此您可以删除该属性以满足所有编译器。
如果你想在 GCC 中完全禁用警告,你可以使用这个编译标志:
-Wno-attributes
下面是一个有选择地禁用警告的示例,但它并不漂亮:
struct Foo {
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wattributes"
#endif
[[maybe_unused]] int member = 1;
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
void bar() {
[[maybe_unused]] int local = 0;
}
};
int main(int argc, char* argv[]) {
Foo f{};
f.bar();
return 0;
}
#ifdef __GNUC__
是必需的,因为 MSVC 在看到 #pragma GCC
时会发出警告。
As far as I can tell, this should be legal (and not ignored by the compiler).
更正:
- 应该是合法的:是的,它可以应用于非静态数据成员的声明,
- 不应忽略:不,由实现决定是否以及如何使用此属性。
虽然 [dcl.attr.unused]/2 指定 maybe_unused
属性 可以 应用于非静态数据成员的声明 [emphasis 我的]:
The attribute may be applied to the declaration of a class, a typedef-name, a variable (including a structured binding declaration), a non-static data member, a function, an enumeration, or an enumerator.
对于如何应用此属性的实现没有严格的要求,只有建议 至于实现应该如何应用它,根据 [dcl.attr.unused]/4 [emphasis 我的]:
Recommended practice: For an entity marked maybe_unused, implementations should not emit a warning that the entity or its structured bindings (if any) are used or unused. For a structured binding declaration not marked maybe_unused
, implementations should not emit such a warning unless all of its structured bindings are unused.
这意味着只要实现 允许它 应用于非静态数据成员的声明,它们就符合标准,并且不是编译器错误该属性未使用 推荐的 实践实现,即使我们可以争辩说编译器应该能够诊断使用内部定义的 class 的未使用的非静态数据成员单个翻译单元内的链接。例如。在以下示例中:
// test.cpp
namespace {
struct Foo {
int member{1};
void bar() {
[[maybe_unused]] int local = 0;
}
};
void bar() {
Foo f{};
f.bar();
}
} // namespace
未使用Foo
的非静态数据成员member
;这是可诊断的,maybe_unused
属性可以用来抑制这种实现定义的未使用警告。但是,GCC 和 Clang 都没有针对上述情况发出警告,并且没有与本地 class 或 [=97= 的“未使用 public 字段相关的警告] 隐藏内部链接”既不是 GCC 也不是 Clang。
那么我们可能会问自己为什么 Clang 不会 发出一个实现定义的警告,即对于非静态数据成员,该属性将被忽略?原因是 Clang 确实为未使用的 private 静态数据成员发出 -Wunused-private-field
warning:
struct Foo {
void bar() {
int local = 0;
}
private:
int member{1};
// Clang: warning: private field 'member' is not used
};
而 GCC 没有,这也包括为什么 GCC(正确地)警告 maybe_unused
属性将被非静态数据成员(甚至是私有数据成员)忽略,因为它根本不会诊断未使用的私有数据成员(而 Clang 是)。这些行为都是正确的,因为它属于实现定义行为的领域。
我们可能会注意到 2016 年存在一份 GCC 错误报告,要求提供 Clang 实现的功能:
已经
... Confirming as an enhancement.
在重复标记的错误报告 Bug 87409 - Implement -Wunused-private-field 中,Jonathan Wakely 评论说 如果 此功能要在 GCC 中实现,他们还需要实现为(可能)未使用的属性抑制它:
Clang suppresses the warning if the member declaration has attribute unused, which we would need to do too.
处理实现定义行为中的实现差异
由于这里没有编译器错误需要解决,Foo
class(如果它有,比如说,(可能)未使用的私有数据成员),w.r.t。未使用的警告,例如是使用特定于实现的编译指示,如所示在 中,尝试调整所选编译器的实现定义行为。
另一种方法是考虑在全局范围内完全删除 Clang 的 -Wunused-private-field
警告 (-Wno-unused-private-field
),而将此类诊断留给静态分析工具。
请注意,以下内容即使表面上正确,实际上也行不通。只有更广泛的选项 -Wno-attributes
才能抑制此警告。
一种解决方法是为 gcc 使用标志 -Wno-ignored-attributes
-Wno-ignored-attributes
(C and C++ only)
This option controls warnings when an attribute is ignored. This is different from the -Wattributes
option in that it warns whenever the compiler decides to drop an attribute, not that the attribute is either unknown, used in a wrong place, etc. This warning is enabled by default.
如果您使用的是 CMake,这将如下所示:
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# using GCC
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-ignored-attributes")
endif ()
Detecting compiler in CMake
Adding compiler flags in CMake
在下面example:
struct Foo {
[[maybe_unused]] int member = 1;
void bar() {
[[maybe_unused]] int local = 0;
}
};
int main(int argc, char* argv[]) {
Foo f{};
f.bar();
return 0;
}
GCC 会发出警告,而 Clang 和 MSVC 不会:
warning: 'maybe_unused' attribute ignored [-Wattributes]
[[maybe_unused]] int member = 1;
据我所知,这应该是合法的(并且不会被编译器忽略)。根据 standard:
10.6.7 Maybe unused attribute [dcl.attr.unused]
...
2. The attribute may be applied to the declaration of a class, a typedef-name, a variable, a non-static data member, a function, an enumeration, or an enumerator.
...
我讨厌挥动 "compiler bug" 锤子,但我不确定在这种情况下它还能是什么。
有没有人有任何见解?
任何属性都可以出于任何原因 "ignored by the compiler",除非标准另有规定(例如在明确禁止的位置使用属性)。
GCC 并不是说你不能把一个放在那里;它是说把一个放在那里不会做任何事情,因为他们可能不会警告可能未使用的成员变量。
GCC 不会首先就未使用的成员变量向您发出警告,因此该属性没有任何用途,这就是它警告您忽略它的原因。这只是一个警告,您的代码仍然合法。
既然我再次查看了这个,我无法让 Clang 警告未使用的成员,因此您可以删除该属性以满足所有编译器。
如果你想在 GCC 中完全禁用警告,你可以使用这个编译标志:
-Wno-attributes
下面是一个有选择地禁用警告的示例,但它并不漂亮:
struct Foo {
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wattributes"
#endif
[[maybe_unused]] int member = 1;
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
void bar() {
[[maybe_unused]] int local = 0;
}
};
int main(int argc, char* argv[]) {
Foo f{};
f.bar();
return 0;
}
#ifdef __GNUC__
是必需的,因为 MSVC 在看到 #pragma GCC
时会发出警告。
As far as I can tell, this should be legal (and not ignored by the compiler).
更正:
- 应该是合法的:是的,它可以应用于非静态数据成员的声明,
- 不应忽略:不,由实现决定是否以及如何使用此属性。
虽然 [dcl.attr.unused]/2 指定 maybe_unused
属性 可以 应用于非静态数据成员的声明 [emphasis 我的]:
The attribute may be applied to the declaration of a class, a typedef-name, a variable (including a structured binding declaration), a non-static data member, a function, an enumeration, or an enumerator.
对于如何应用此属性的实现没有严格的要求,只有建议 至于实现应该如何应用它,根据 [dcl.attr.unused]/4 [emphasis 我的]:
Recommended practice: For an entity marked maybe_unused, implementations should not emit a warning that the entity or its structured bindings (if any) are used or unused. For a structured binding declaration not marked
maybe_unused
, implementations should not emit such a warning unless all of its structured bindings are unused.
这意味着只要实现 允许它 应用于非静态数据成员的声明,它们就符合标准,并且不是编译器错误该属性未使用 推荐的 实践实现,即使我们可以争辩说编译器应该能够诊断使用内部定义的 class 的未使用的非静态数据成员单个翻译单元内的链接。例如。在以下示例中:
// test.cpp
namespace {
struct Foo {
int member{1};
void bar() {
[[maybe_unused]] int local = 0;
}
};
void bar() {
Foo f{};
f.bar();
}
} // namespace
未使用Foo
的非静态数据成员member
;这是可诊断的,maybe_unused
属性可以用来抑制这种实现定义的未使用警告。但是,GCC 和 Clang 都没有针对上述情况发出警告,并且没有与本地 class 或 [=97= 的“未使用 public 字段相关的警告] 隐藏内部链接”既不是 GCC 也不是 Clang。
那么我们可能会问自己为什么 Clang 不会 发出一个实现定义的警告,即对于非静态数据成员,该属性将被忽略?原因是 Clang 确实为未使用的 private 静态数据成员发出 -Wunused-private-field
warning:
struct Foo {
void bar() {
int local = 0;
}
private:
int member{1};
// Clang: warning: private field 'member' is not used
};
而 GCC 没有,这也包括为什么 GCC(正确地)警告 maybe_unused
属性将被非静态数据成员(甚至是私有数据成员)忽略,因为它根本不会诊断未使用的私有数据成员(而 Clang 是)。这些行为都是正确的,因为它属于实现定义行为的领域。
我们可能会注意到 2016 年存在一份 GCC 错误报告,要求提供 Clang 实现的功能:
已经
... Confirming as an enhancement.
在重复标记的错误报告 Bug 87409 - Implement -Wunused-private-field 中,Jonathan Wakely 评论说 如果 此功能要在 GCC 中实现,他们还需要实现为(可能)未使用的属性抑制它:
Clang suppresses the warning if the member declaration has attribute unused, which we would need to do too.
处理实现定义行为中的实现差异
由于这里没有编译器错误需要解决,Foo
class(如果它有,比如说,(可能)未使用的私有数据成员),w.r.t。未使用的警告,例如是使用特定于实现的编译指示,如所示在
另一种方法是考虑在全局范围内完全删除 Clang 的 -Wunused-private-field
警告 (-Wno-unused-private-field
),而将此类诊断留给静态分析工具。
请注意,以下内容即使表面上正确,实际上也行不通。只有更广泛的选项 -Wno-attributes
才能抑制此警告。
一种解决方法是为 gcc 使用标志 -Wno-ignored-attributes
-Wno-ignored-attributes
(C and C++ only)This option controls warnings when an attribute is ignored. This is different from the
-Wattributes
option in that it warns whenever the compiler decides to drop an attribute, not that the attribute is either unknown, used in a wrong place, etc. This warning is enabled by default.
如果您使用的是 CMake,这将如下所示:
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# using GCC
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-ignored-attributes")
endif ()
Detecting compiler in CMake
Adding compiler flags in CMake