-
-
Notifications
You must be signed in to change notification settings - Fork 22.8k
Add STATIC_ASSERT_INCOMPLETE_TYPE
to enforce include minimality.
#107587
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
base: master
Are you sure you want to change the base?
Conversation
bef82a3
to
e5bf679
Compare
Is a good idea as it really needs discussion of its own. It looks fine to me (barring the question about the define above). |
We could expand this assert to headers by making the template reusable. The easiest way would probably be |
I'm not sure I understand, could you expand on the idea? Edit: Ohh, I think I get it. You mean probably something like this, right? (pseudocode) // <my_header.h>
bool was_already_incomplete = is_incomplete_type_v<Type>();
#include "abc.h"
#include "def.h"
#include "gi.h"
if (!was_already_incomplete && is_incomplete_type_v<Type>()) {
#error "Class was incomplete etc."
} |
Does that actually achieve anything that can't be done by putting this in the cpp? Apart from making the builds more likely to fail due to change in inclusion order? |
I don't think so. But it's clever! 😄 |
bfce35b
to
9bb4311
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fine to me, but this will need a check by @akien-mga .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When suggesting __COUNTER__
for assertion reuse, this is what I was referring to:
// typedefs.h
template <typename T, int Counter, typename = void>
struct is_fully_defined : std::false_type {};
template <typename T, int Counter>
struct is_fully_defined<T, Counter, std::void_t<decltype(sizeof(T))>> : std::true_type {};
template <typename T, int Counter>
constexpr bool is_fully_defined_v = is_fully_defined<T, Counter>::value;
#if !defined(SCU_BUILD_ENABLED) && !defined(DEV_ENABLED) && !defined(DEBUG_ENABLED)
/// Enforces the requirement that a class is not fully defined.
/// This can be used to reduce include coupling and keep compile times low.
/// The check must be made at the top of the corresponding .cpp file of a header.
#define STATIC_ASSERT_INCOMPLETE_CLASS(m_type) \
class m_type; \
static_assert(!is_fully_defined_v<m_type, __COUNTER__>, #m_type " was unexpectedly fully defined. Please check the include hierarchy of '" __FILE__ "' and remove includes that resolve the class.");
#else
#define STATIC_ASSERT_INCOMPLETE_CLASS(m_type)
#endif
...
// ustring.cpp
#include "ustring.h"
STATIC_ASSERT_INCOMPLETE_CLASS(Dictionary); // Expectation: pass.
// Old: !is_fully_defined_v<Dictionary>. Passes.
// New: !is_fully_defined_v<Dictionary, 0>. Passes.
#include "core/variant/dictionary.h"
STATIC_ASSERT_INCOMPLETE_CLASS(Dictionary); // Expectation: fail.
// Old: !is_fully_defined_v<Dictionary>. Reuses previous template. Passes.
// New: !is_fully_defined_v<Dictionary, 1>. Distinct template. Fails.
Oh, that makes a lot more sense than what I thought you meant. |
Add enforcements against `Dictionary` for `ustring.h` and two for `Dictionary` and `String` from `array.h`.
9bb4311
to
12b7635
Compare
STATIC_ASSERT_INCOMPLETE_CLASS
to enforce include minimality.STATIC_ASSERT_INCOMPLETE_TYPE
to enforce include minimality.
Cross-includes are our main compile time problem right now. Not only does parsing take long, also every small change to a header file leads to hundreds of recompilations of compile units. It's time to do something.
STATIC_ASSERT_INCOMPLETE_TYPE
is designed to protect ourselves against unnecessary includes. It lets us enforce certain couplings are not made, such as an include todictionary.h
fromustring.h
. The assertion is made only for release build, to avoid interfering with the development cycle.(This check was originally made for #107492, but I split it off to make it easier to discuss it separately).
I enforce 3 assumptions in this PR that already hold (no
Dictionary
include fromString
, andDictionary
andString
fromArray
). There are many others we should be making. This is left to do as follow-up PRs (e.g. #106434).