Skip to content

unnecessary <stdlib.h> suggested for QList #1655

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
firewave opened this issue Nov 22, 2024 · 10 comments
Open

unnecessary <stdlib.h> suggested for QList #1655

firewave opened this issue Nov 22, 2024 · 10 comments

Comments

@firewave
Copy link
Contributor

#include <QList>

void f()
{
    QList<int> l;
}
$ include-what-you-use $(pkg-config --cflags-only-I Qt6Core) input.cpp

input.cpp should add these lines:
#include <stdlib.h>  // for free

input.cpp should remove these lines:

The full include-list for input.cpp:
#include <stdlib.h>  // for free
#include <QList>     // for QList
---

This started with 0.23.

@firewave firewave changed the title unnecessary <stdint.h> suggested for QList unnecessary <stdlib.h> suggested for QList Nov 22, 2024
@firewave
Copy link
Contributor Author

I assume this might apply to other Qt containers.

@bolshakov-a
Copy link
Contributor

I cannot reproduce it with Qt 6.4.2. I get:

input.cpp should add these lines:
#include "qlist.h"  // for QList

input.cpp should remove these lines:
- #include <QList>  // lines 1-1

The full include-list for input.cpp:
#include "qlist.h"  // for QList

with your command line options and "has correct #includes/fwd-decls" when using qt5-11.imp mapping file. Which exact Qt version do you use?

An IWYU log might probably be helpful as well.

@firewave
Copy link
Contributor Author

with your command line options and "has correct #includes/fwd-decls" when using qt5-11.imp mapping file. Which exact Qt version do you use?

I forgot to mention that. Will make sure my reports reflect that.

This is with Qt 6.7+ without using the mapping files as the official includes now carry IWYU annotations.

@bolshakov-a
Copy link
Contributor

I still have correct #includes/fwd-decls with Qt 6.8.1.

@firewave
Copy link
Contributor Author

firewave commented Feb 1, 2025

I can reproduce it on Kali Linux using include-what-you-use 0.23-1+b1, gcc 14.2.0-12, clang 19.1.6-1+b1 and Qt 6.7.2.

Here's the -Xiwyu --verbose=8 output:
verbose.log

On my other distros I unfortunately have no up-to-date IWYU or Qt.

@bolshakov-a
Copy link
Contributor

Surprisingly, the difference was because I used the 12th version of libstdc++ and not the 14th. (A change in Qt introducing the call to free took place as well, though, since 6.4.2).

IWYU has an heuristic to block reports of an internal stuff referenced inside templates from external libraries and resolved at instantiation time:

// If we see the instantiated template using a type or decl (such as

If some header in the template instantiation chain "provides" a declaration, then the declaration is not reported. "Provides" means "has anywhere in its #include tree" for "public" headers and "includes directly" for other headers:
// Everyone gets to provide from their direct includes. Public

The problem is that IWYU pragmas don't mark any header as public. Public headers are meant to exist in external libraries, for which there are mapping files. Therefore, as long as you don't use any Qt mapping file, the Qt headers are handled as if they are under your control. Hence, despite <QList> actually has #include <stdlib.h> buried inside its #include tree, IWYU doesn't "sees" it and decides that you are responsible for including it at the template instantiation place. Such a mapping file fixes the problem:

[
  { "include": ["\"qlist.h\"", "public", "<QList>", "public"] }
]

Note that "qlist.h" should be marked as public, not private. <QList> doesn't appear in the instantiating template chain (it is essentially empty file) and is not considered by IWYU. Maybe, the logic can be tweaked, e.g. not only public but also private headers should be considered as providing all their #include tree for template internals (after all, private headers should not be included bypassing public ones).

In comparison with IWYU 0.22, 0.23 indeed has a change leading to this report. I think it was mine (#1528). free is handled earlier as should-be-present at template definition site, because all of its overloads are in a single file. But as I argued in #1525 and in that comment, it can't be known for sure, so it is better to require the #include at the instantiation (user) side. A code not declaring a function referenced with unqualified call inside an uninstantiated template is absolutely valid. It may be a customization point, after all (Sutter, Alexandrescu, "C++ Coding Standards", rule No. 65).

But why the problem didn't appear to me? qlist.h includes directly several standard headers, which IWYU considers as public, of course. In particular, it is <functional>. In libstdc++-12, it included <bits/stl_algo.h> and then stopped doing so here. In turn, <bits/stl_algo.h> includes <cstdlib>, which is why qlist.h "provided" it on my system.

I think the best way of fixing this would be to make a PR in Qt adding #include <cstdlib> into qarraydatapointer.h. I think if a library is claimed to be IWYU-friendly, it should follow the IWYU principle by itself. However, the change in Qt has already been reverted recently.

@bolshakov-a
Copy link
Contributor

Maybe, the logic can be tweaked, e.g. not only public but also private headers should be considered as providing all their #include tree for template internals

It turns out that such logic is already present in IWYU (see private_headers_behind-related stuff in IwyuPreprocessorInfo::PopulateIntendsToProvideMap()), but it doesn't always work properly due to the angle-quote confusion. ConvertToQuotedInclude function adds the angle brackets only to system headers:

return AddQuotes(path, entry.path_type == HeaderSearchPath::kSystemPath);

which doesn't seem to be correct but might be a trade-off, I'm not sure.

Therefore, if you use -isystem flag for Qt paths instead of -I, you should be able to use a mapping file which marks qlist.h as private, e.g. any Qt mapping file distributed with IWYU.

@firewave
Copy link
Contributor Author

Therefore, if you use -isystem flag for Qt paths instead of -I, you should be able to use a mapping file which marks qlist.h as private, e.g. any Qt mapping file distributed with IWYU.

That is an annoyance of pkg-config. It only returns -I paths so you need to convert these to -isystem. This should wreck havoc in various cases but it appears I am the only person which is irked by this.

This and the angle-quote confusion is something I also ran into with Cppcheck but I didn't have the time to look into this yet.

But the original issue was encountered with a compilation database generated by CMake and the Qt includes are system ones in that case.

@bolshakov-a
Copy link
Contributor

That is an annoyance of pkg-config. It only returns -I paths so you need to convert these to -isystem. This should wreck havoc in various cases but it appears I am the only person which is irked by this.

I think that not so many people still use IWYU and even less open issues. Probably, someone will fix it on the IWYU side some day...

But the original issue was encountered with a compilation database generated by CMake and the Qt includes are system ones in that case.

But you were not using a mapping file as you've said.

@firewave
Copy link
Contributor Author

I think that not so many people still use IWYU and even less open issues. Probably, someone will fix it on the IWYU side some day...

I was not speaking about IWYU but about everything out there. If it is not a system header you should e.g. get flooded with compiler warnings you cannot fix.

But you were not using a mapping file as you've said.

Yes, because I want to move the annotations ahead so you do not need any at all. It is unfeasible to generate mappings for a library above a certain threshold. Unfortunately I am not even remotely focused on that right now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants