gcc >=10.1 和 clang 不检测未使用但设置 lambda

gcc >=10.1 and clang do not detect unused but set lambda

提问人:francesco 提问时间:5/8/2021 更新时间:5/8/2021 访问量:214

问:

请考虑以下程序:

template <unsigned int I>
int f(int x)
{
    auto task = [&]() { ++x; };
    if constexpr (I == 0) {
        task();
    }
    return x;
}

int main()
{
    f<1>(3);
}

在 gcc 9.3 上编译时,它会发出警告-std=c++17 -Wall -pedantic

warning: variable 'task' set but not used [-Wunused-but-set-variable]
    4 |     auto task = [&]() { ++x; };

但是对于较新的 gcc 版本,不会出现此类警告。请注意,根据手册,由 启用。-Wunused-but-set-variable-Wall

同样使用叮当声,不会出现这样的警告。

godbolt 上测试它。

这是编译器的缺点,还是这种行为(缺乏警告)是需要/预期的?

C++ GCC Clang 警告

评论

0赞 Davis Herring 5/8/2021
对于无法在 中声明的函数参数,警告是虚假的。对于局部变量,我想如果该变量仅在 constexpr 的一个臂中使用,我会想要它,如果?if
1赞 Ted Lyngmo 5/8/2021
我不会说缺点,但可以看作是一种回归。编译器没有义务“抓住”这一点——如果较新的语言发明迫使编译器开发人员抛弃某些情况,以免用不明智的警告淹没更新的、完全理智的情况,这可能是一个原因。纯属猜测。这也可能是个错误。
0赞 Marc Glisse 5/8/2021
我认为这是故意的。您没有打字名称或任何东西,它只是碰巧仅用于某些参数,而不用于其他参数。为什么要警告?
1赞 Sam Varshavchik 5/8/2021
恐怕这是“缺点”还是“想要/预期”,这是一个见仁见智的问题。无论哪种方式,都可以形成一个论点。我在这里没有看到事实可能的答案。
1赞 SergeyA 5/8/2021
@SamVarshavchik我很确定这不是一个缺点,我想,它被删除了作为修复程序。

答:

1赞 463035818_is_not_an_ai 5/8/2021 #1

请考虑以下略微修改的代码:

template <unsigned int I>
int f(int x)
{
    auto task = [&]() { ++x; };
    if constexpr (I == 0) {
        task();
    }
    return x;
}

int main()
{
    f<0>(3);
    f<1>(3);
}

使用 gcc 9.3 -std=c++2a -Wall -Werror,您会收到一个错误(警告被视为错误):

<source>: In instantiation of 'int f(int) [with unsigned int I = 1]':
<source>:14:11:   required from here
<source>:4:10: error: variable 'task' set but not used [-Werror=unused-but-set-variable]
    4 |     auto task = [&]() { ++x; };
      |          ^~~~
cc1plus: all warnings being treated as errors

这很糟糕,因为代码完全没问题,并且可以将其视为触发警告的错误。显然,这已在 gcc >= 10.1 中修复。

有人可能会争辩说,可以/应该将声明移动到分支中,但随后又认为这也使 gcc 发出警告:taskif constexpr

template <unsigned int I>
int f(int x)
{
    auto task = [&]() { ++x; };
    if constexpr (I == 0) {
        task();
    } else if constexpr (I == 1) {
        task();
    } 
    return x;
}

int main()
{
    f<0>(3);
    f<1>(3);
    f<2>(3);
}