This is a proposal to add a new Clang-specific attribute to ensure that field initializations are performed explicitly.
For example, if we have
struct B {
[[clang::explicit]] int f1;
};
then the warning would trigger if we do B b{};
, e.g.:
field 'f1' is left uninitialized, but was marked as requiring initialization
This prevents callers from accidentally forgetting to initialize fields, particularly when new fields are added to the type.
There is a prototyped implementation of this proposal in:
FAQ
Naming
The choice of explicit
was based on the fact that the word explicit
in the language has always meant āmust be spelled out in the source codeā, and the same meaning is used here ā it is difficult to imagine a different meaning for explicit
in such a context.
Nevertheless, explicit
is just a suggestion, and this proposal is open to other names. Iād suggest must_init
, requires_init
, as some alternatives to consider that also seem fairly self-explanatory.
Regardless of the name, we should avoid causing potential confusion for readers who are unfamiliar with the attribute. For example, required
may cause confusion with requires
, and must_specify
on a field may leave users wondering āwhere must I specify what?ā
Opt-Out Mechanism
The intention is that this is a warning, and thus disabling the warning at the usage site would be sufficient to opt-out of all initializations within the expression.
There is no intention of allowing opting out of initializing a single field in a class that has multiple fields requiring explicit initialization. The rationale is that valid usages of this are likely to be very rare, and it would also potentially greatly complicate the proposal.
What About Non-Aggregates?
I find this be a difficult question. Some plausible options include:
- Allowing this attribute inside all classes, or
- Only allowing this attribute inside classes that are aggregates, or
- Only allowing this attribute inside classes that would be aggregates in C++20 (to avoid inconsistent behavior in pre-C++20 mode)
For the sake of ease of implementation & understandability, I have implemented the first option so far.
I am not entirely sure as to what the correct behavior for non-aggregate classes would be, but I suspect this diagnostic should avoid triggering on member-initialization lists in constructors, because member-initialization lists are already coupled tightly to the rest of the class, and generally authored together. Forcing the classās own constructor to initialize its own field (especially in a manner where field-initializers are insufficient) is a much less common use case.
However, other designs are plausible, and to allow better more flexibility in the future evolution of the design, perhaps we should enforce that this attribute is only applied on aggregates.
Input on the best path forward here is welcome.
Variables That Arenāt Fields
This attribute is only meant for fields. I donāt expect it to be very useful for other kinds of variables, as āthis must be initializedā would be redundant for them ā simply initializing them would enforce the same.
Class-Level Attributes
It would make sense to allow this attribute on an entire class. However, my inclination is to defer the implementation of that extension rather than blocking this proposal on that extension, for a few reasons:
- A mild desire to see this used in practice prior to extending the design.
- Avoiding the natural subsequent desire to include an āopt-outā mechanism (e.g.,
[[clang::explicit(false)]]
), which would further complicate the proposal & implementation - Additional work on my part that Iād have to find bandwidth for
I donāt expect the current design of this proposal would conflict with such extensions in the future.
Opt-In vs. Opt-Out
One can imagine a compiler flag flipping the requirements, using an opt-out attribute instead of opt-in.
I expect such a feature would be very difficult for most users to utilize in practice, as uninitialized structs are very common, and it is quite intractable for users to modify third-party & system headers to annotate everything fully. Common code as simple as
struct stat s;
int result = stat("path", &s);
would now break due to the lack of field initializations.
However, if the need for this nevertheless arises, I believe it can be achieved coherently with the current design, in a similar manner as to opt-out attributes for a class-level attribute.
Clang consensus called in this message.