[[maybe_unused]] 在成员变量上,GCC 警告(错误地?)该属性被忽略

0x5*_*453 12 c++ compiler-warnings compiler-bug c++17

在以下示例中

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;
}
Run Code Online (Sandbox Code Playgroud)

GCC 发出警告,其中 Clang 和 MSVC 没有:

warning: 'maybe_unused' attribute ignored [-Wattributes]
     [[maybe_unused]] int member = 1;
Run Code Online (Sandbox Code Playgroud)

据我所知,这应该是合法的(并且不会被编译器忽略)。根据标准

10.6.7 可能未使用的属性 [dcl.attr.unused]
...
2. 该属性可以应用于类的声明、typedef-name、变量、非静态数据成员、函数、枚举,或枚举器。
...

我讨厌在“编译器错误”锤子上摇摆不定,但我不确定在这种情况下还有什么可能。

有没有人有任何见解?

Nic*_*las 9

任何属性都可以出于任何原因“被编译器忽略”,除非标准另有说明(例如在明确禁止的位置使用属性)。

GCC 并不是说​​你不能在那里放一个;它说把一个放在那里不会做任何事情,因为他们可能不会警告可能未使用的成员变量。


dfr*_*fri 8

\n

据我所知,这应该是合法的(并且不会被编译器忽略)。

\n
\n

更正:

\n
    \n
  • 合法:是的,它可以应用于非静态数据成员的声明,
  • \n
  • 不应被忽略:不,由实现决定是否以及如何使用此属性。
  • \n
\n

虽然[dcl.attr.unused]/2指定该maybe_unused属性可以应用于非静态数据成员的声明 [强调我的]:

\n
\n

该属性可以应用于类、typedef-name、变量(包括结构化绑定声明)、非静态数据成员、函数、枚举或枚举器的声明。

\n
\n

对于如何应用此属性,实现没有严格要求,只有关于实现应如何应用它的建议,按照[dcl.attr.unused]/4 [重点是我的]:

\n
\n

推荐实践:对于标记为 Maybe_\xc2\xadunused 的实体,实现不应发出该实体或其结构化绑定(如果有)已使用或未使用的警告。对于未标记的结构化绑定声明maybe_\xc2\xadunused,除非其所有结构化绑定均未使用,否则实现不应发出此类警告。

\n
\n

这意味着只要实现允许将其应用于非静态数据成员的声明,它们就符合标准,并且即使我们可以争论,未使用推荐的做法实现该属性也不是编译器错误编译器应该能够诊断在单个翻译单元内使用内部链接定义的类的未使用的非静态数据成员。例如在下面的例子中:

\n
// test.cpp\nnamespace {\nstruct Foo {\n    int member{1};\n    void bar() {\n        [[maybe_unused]] int local = 0;\n    }\n};\n\nvoid bar() {\n    Foo f{};\n    f.bar();\n}\n}  // namespace\n
Run Code Online (Sandbox Code Playgroud)\n

不使用 的非静态数据成员memberFoo这是可以诊断的,并且该maybe_unused属性可以用来抑制此类实现定义的未使用警告。然而,GCC 和 Clang 都没有对上述情况发出警告,并且GCC 和 Clang 都没有与“本地类的未使用的公共字段或隐藏有内部链接的类”相关的警告。

\n

那么我们可能会想,为什么 Clang 不发出实现定义的警告,即对于非静态数据成员的情况,该属性将被忽略呢?原因是 Clang 确实对未使用的私有发出-Wunused-private-field警告静态数据成员

\n
struct Foo {\n    void bar() {\n        int local = 0;\n    }\nprivate:\n    int member{1};\n    // Clang: warning: private field \'member\' is not used \n};\n
Run Code Online (Sandbox Code Playgroud)\n

而 GCC 没有,这也包括为什么 GCC(正确地)警告maybe_unused非静态数据成员(甚至是私有数据成员)的属性将被忽略,因为它根本不会诊断未使用的私有数据成员(而 Clang 则这样做) )。这些行为都是正确的,因为它属于实现定义的行为领域。

\n

我们可能会注意到,2016 年有一个 GCC 错误报告,要求提供 Clang 实现的功能:

\n\n

这已经是

\n
\n

...确认为增强功能。

\n
\n

在重复标记的错误报告Bug 87409 - Implement -Wunused-private-field中,Jonathan Wakely 评论说,如果要在 GCC 中实现此功能,他们还需要对(可能)未使用的属性实现对其的抑制:

\n
\n

如果成员声明有未使用的属性,Clang 会抑制警告,我们也需要这样做。

\n
\n
\n

处理实现定义的行为中的实现差异

\n

由于这里没有编译器错误需要解决,所以类的“可移植”(对于所选的特定编译器)实现Foo(如果它有,比如说,(可能)未使用的私有数据成员),wrt 未使用警告,例如使用特定于实现的编译指示,如@0x5453: self-answer中所示,以尝试对齐所选编译器的实现定义的行为。

\n

另一种方法是考虑在全局范围内完全删除 Clang 的-Wunused-private-field警告 ( -Wno-unused-private-field),而将此类诊断留给静态分析工具。

\n