[[maybe_unused]] on member variable, GCC warns (incorrectly?) that attribute is ignored

落爺英雄遲暮 提交于 2021-01-26 22:51:20

问题


In the following 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 emits a warning where Clang and MSVC do not:

warning: 'maybe_unused' attribute ignored [-Wattributes]
     [[maybe_unused]] int member = 1;

As far as I can tell, this should be legal (and not ignored by the compiler). According to the 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.
...

I hate to swing around the "compiler bug" hammer, but I'm not sure what else it could be in this case.

Does anyone have any insight?


回答1:


Any attribute can be "ignored by the compiler" for any reason, except where the standard says otherwise (such as using an attribute in a location where it is expressly forbidden).

GCC isn't saying you can't put one there; it's saying that putting one there won't do anything, because they probably don't warn about maybe-unused member variables.




回答2:


GCC won't warn you for unused member variables in the first place so that attribute has no purpose, that's why it's warning you for ignoring it. It's only a warning, your code is still legal.




回答3:


As far as I can tell, this should be legal (and not ignored by the compiler).

Correction:

  • shall be legal: yes, it may be applied to a declaration of a non-static data member,
  • shall not be ignored: no, it's up to the implementation to decide whether or not and how to use this attribute.

Whilst [dcl.attr.unused]/2 specified that the maybe_unused attribute may be applied to a declaration of a non-static data member [emphasis mine]:

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.

there is no strict requirement on implementations on how to apply this attribute, only a recommendation as for how implementations should apply it, as per [dcl.attr.unused]/4 [emphasis mine]:

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.

This means as long as implementations allow it to be applied to a declaration of a non-static data member, they are standard compliant, and it is not a compiler bug that the attribute is non implemented using the recommended practice, even if we can argue that a compiler should be able to diagnose an unused non-static data member of a class defined with internal linkage within a single translation unit. E.g. in the following example:

// test.cpp
namespace {
struct Foo {
    int member{1};
    void bar() {
        [[maybe_unused]] int local = 0;
    }
};

void bar() {
    Foo f{};
    f.bar();
}
}  // namespace

The non-static data member member of Foo is not used; this is diagnosable and the maybe_unused attribute could arguably be used to suppress such an implementation-defined unused warning. However, neither GCC nor Clang warns for the case above, and afaict there are no warnings related to "unused public field of local class or class hidden with internal linkage" neither for GCC nor Clang.

Then we may as ourselves why Clang does not emit an implementation-defined warning that the attribute will be ignored for the case of non-static data members? The reason is that Clang does emit a -Wunused-private-field warning for non-used private static data members:

struct Foo {
    void bar() {
        int local = 0;
    }
private:
    int member{1};
    // Clang: warning: private field 'member' is not used 
};

Whereas GCC does not, which would also include why GCC (correctly) warns the maybe_unused attribute will be ignored by it for non-static data members (even private ones), as it will simply not diagnose non-used private data members (whereas Clang does). These behaviours are both correct, as it lies in the domain of implementation-defined behaviour.

We may note that there exists a GCC bug report from 2016 that asks for the feature which Clang implements:

  • Bug 72789 - add -Wunused-private-field

which has been

... Confirming as an enhancement.

In a duplicate-marked bug report, Bug 87409 - Implement -Wunused-private-field, Jonathan Wakely comments that if this feature were to be implemented in GCC, they would also need to implement the suppression of it for the (maybe) unused attribute:

Clang suppresses the warning if the member declaration has attribute unused, which we would need to do too.


Dealing with implementation variance in implementation-defined behaviour

As there are no compiler bugs to hammer down on here, a "portable" (for the specific compilers chosen) implementation of the Foo class (if it it were to have, say, (maybe) non-used private data members), w.r.t. unused warnings, would e.g. be to use implementation-specific pragmas, as shown e.g. in @0x5453: self-answer, to attempt to align the implementation-defined behaviours of the selected compilers.

An alternative approach would be to consider entirely removing Clang's -Wunused-private-field warning globally (-Wno-unused-private-field), leaving these kind of diagnostics to a static analysis tool instead.




回答4:


Now that I'm looking at this again I'm not able to get Clang to warn about the unused member, so you may be able to remove the attribute to satisfy all compilers.

If you want to disable the warning entirely in GCC, you can use this compile flag:

-Wno-attributes

And here's an example of selectively disabling the warning, but it's not pretty:

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;
}

The #ifdef __GNUC__s are required because MSVC emits warnings upon seeing #pragma GCC.




回答5:


Note, the following, even if apparently correct, doesn't actually work. Only the more extensive option -Wno-attributes menage to suppress this warning.


One workaround is to use for gcc the flag -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.


If you are using CMake, this will look like this:

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



来源:https://stackoverflow.com/questions/50646334/maybe-unused-on-member-variable-gcc-warns-incorrectly-that-attribute-is

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!