[[nodiscard]] attribute different compilation result for GCC and Clang

1.7k views Asked by At
#include <iostream>
#include <memory>

class A
{
public:
    static [[nodiscard]] std::unique_ptr<A> create();
    virtual int get_version() = 0;
    virtual ~A() = default;
};

class B : public A
{
public:
    [[nodiscard]] int get_version() override
    {
        return 20;
    }
};

std::unique_ptr<A>
A::create()
{
    return std::make_unique<B>();
}

int main()
{
    auto a = A::create();
    [[maybe_unused]] int v  = a->get_version();
}

I tried to use [[nodiscard]] to not allow ignoring the return value of A::create(). But, I get different compilation output in GCC and Clang.

Tried with

GCC:

<source>:7:12: warning: attribute ignored [-Wattributes]
     static [[nodiscard]] std::unique_ptr<A> create();
            ^
<source>:7:12: note: an attribute that appertains to a type-specifier is ignored
ASM generation compiler returned: 0
<source>:7:12: warning: attribute ignored [-Wattributes]
     static [[nodiscard]] std::unique_ptr<A> create();
            ^
<source>:7:12: note: an attribute that appertains to a type-specifier is ignored
Execution build compiler returned: 0
Program returned: 0

Clang:

<source>:7:14: error: 'nodiscard' attribute cannot be applied to types
    static [[nodiscard]] std::unique_ptr<A> create();
             ^
1 error generated.
ASM generation compiler returned: 1
<source>:7:14: error: 'nodiscard' attribute cannot be applied to types
    static [[nodiscard]] std::unique_ptr<A> create();
             ^
1 error generated.
Execution build compiler returned: 1

Am I doing something wrong? And why does these compilers have different behavior?

This code works with MSVC v19.33 properly without any errors or warnings: https://godbolt.org/z/dWsv4jTo5

1

There are 1 answers

7
463035818_is_not_an_ai On BEST ANSWER

You can see here https://eel.is/c++draft/class.mem#general that the attribute can only appear first in a member declaration. Hence this

static [[nodiscard]] std::unique_ptr<A> create();

is wrong. And should be

[[nodiscard]] static std::unique_ptr<A> create();

Your code has a typo.

Newever versions of gcc report a more clear error:

source>:7:12: error: standard attributes in middle of decl-specifiers
    7 |     static [[nodiscard]] std::unique_ptr<A> create();
      |            ^
<source>:7:12: note: standard attributes must precede the decl-specifiers to apply to the declaration, or follow them to apply to the type
<source>:7:12: warning: attribute ignored [-Wattributes]
<source>:7:12: note: an attribute that appertains to a type-specifier is ignored

Actually I do not know if it has to be reported as error or if a warning is ok too. I don't think it relly matters, because you need to fix it anyhow, and unless you ignore warnings you cannot miss it. MSCV not diagnosing the issue is not nice. However, you should also keep in mind that [[nodiscard]] like similar attributes merely encourage the compiler to issue a warning. There is no gurantee to get a warning when it is discarded.