llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.24k stars 12.07k forks source link

clangd -Wunneeded-internal-declaration false positive diagnostic, doesn't show in clang++ #117000

Open syyyr opened 2 days ago

syyyr commented 2 days ago

Hi, I have this code (sorry it has Qt, I'm not able to reproduce it without it):

#include <QObject>
#include <iostream>

namespace {
void bar()
{
    std::cerr << "Hello from bar\n";
}
}

void foo()
{
    auto x = new QObject;
    QObject::connect(x, &QObject::destroyed, x, [] (const auto& ptr) {
        bar();
    });
    delete x;
}

int main()
{
    foo();
}

This code results in bar() being called and "Hello from bar" being printed. However, when I open this file in my editor, where I use clangd, I get a warning that says:

clang: Function 'bar' is not needed and will not be emitted (-Wunneeded-internal-declaration)

This is wrong, it is needed, because it is called.

The command I use to compile this program is:

clang++ -Wunneeded-internal-declaration -std=c++20 main.cpp $(pkg-config  --cflags --libs Qt6Core)

My clang version:

$ clang++ --version
clang version 18.1.8
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

$ clangd --version
clangd version 18.1.8
Features: linux
Platform: x86_64-pc-linux-gnu
llvmbot commented 2 days ago

@llvm/issue-subscribers-clangd

Author: Václav Kubernát (syyyr)

Hi, I have this code (sorry it has Qt, I'm not able to reproduce it without it): ```cpp #include <QObject> #include <iostream> namespace { void bar() { std::cerr << "Hello from bar\n"; } } void foo() { auto x = new QObject; QObject::connect(x, &QObject::destroyed, x, [] (const auto& ptr) { bar(); }); delete x; } int main() { foo(); } ``` This code results in `bar()` being called and "Hello from bar" being printed. However, when I open this file in my editor, where I use clangd, I get a warning that says: ``` clang: Function 'bar' is not needed and will not be emitted (-Wunneeded-internal-declaration) ``` This is wrong, because it is needed, because it is called. - I do not get this warning, when I run the compilation manually (via clang++). - The clangd warning disappears if I remove the unused lambda argument (clang++ does warn about it). The command I use to compile this program is: ``` clang++ -Wunneeded-internal-declaration -std=c++20 main.cpp $(pkg-config --cflags --libs Qt6Core) ``` My clang version: ``` $ clang++ --version clang version 18.1.8 Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin $ clangd --version clangd version 18.1.8 Features: linux Platform: x86_64-pc-linux-gnu ```
HighCommander4 commented 2 days ago

Reduced testcase:

test.hpp:

template <typename F>
void call(F f) { f(0); }

test.cpp:

#include "test.hpp"

namespace {
  void bar() {}
}

void foo() {
  call([](auto) { bar(); });
}

int main() {
  foo();  
}
HighCommander4 commented 2 days ago

The issue is that clangd skips parsing the bodies of function templates in included headers for performance reasons, so it doesn't see the call to bar() that's inside the instantiation of call().

I think this performance optimization means clangd is unable to reliably issue -Wunneeded-internal-declaration. Maybe clangd should just disable this warning even if it's present in the compile flags?

A workaround for now is to disable the warning for clangd by adding the following to a .clangd config file:

CompileFlags:
  Add: [-Wno-unneeded-internal-declaration]