[cfe-dev] ISO C3X proposal: nonnull qualifier

Alejandro Colomar (man-pages) via cfe-dev cfe-dev at lists.llvm.org
Wed Dec 1 14:24:33 PST 2021


Hi Dmitry,

On 11/23/21 13:45, Dmitri Gribenko wrote:
>>
>> Let's imagine a scenario where C3X specifies that non-qualified pointers
>> are nonnull.  And there's only a qualifier, _Nullable, to allow NULL.
>> Asigning _Nullable to nonnull would issue a diagnostic.
> 
> I think C3X specifying that non-qualified pointers are nonnnull would
> be a showstopper, I don't think it is likely to happen given how the
> users and the committee value backward compatibility that C has
> offered throughout the decades.

Agreed.  I even found some cases where it would cause previously-correct
code to misbehave, so changing normal pointers to mean nonnull pointers
is not possible at this point.  Compilers may allow that with pragmas
anyway.

> 
> If I were to speculate what would happen if C3X did flip the default,
> I think it would be treated by the community as a language fork.

Yes

> Pre-C3X headers won't work correctly when included in C3X programs,
> making incremental adoption of C3X syntax, as it was intended to be
> used, impossible. Projects would likely invent a NULLABLE macro, which
> would expand to _Nullable in C3X and nothing in earlier versions, to
> enable an incremental transition.
> 
> That's why Clang introduced the pragma, enabling new rules to be
> adopted incrementally.

Let's avoid forking C :)

> 
>> Also, do you have any experience in avoiding to diagnose a _Nullable to
>> nonnull assignment _after_ explicitly comparing to NULL?  I.e., allow
>> the following:
>>
>> int *_Nullable p;
>> int *q;
>>
>> if (!p)
>>         q = p;
> 
> Internally at Google we have a checker based on the dataflow analysis
> framework (https://lists.llvm.org/pipermail/cfe-dev/2021-October/069098.html)
> that diagnoses usages of std::optional<T>::value() not guarded by
> has_value(). We are planning to upstream it after we finish
> upstreaming the dataflow framework itself. Ensuring guarded usage of
> std::optional<T>::value() is very similar to diagnosing dereferences
> of nullable pointers. I think a lot of the experience is transferable.
> However, we haven't attempted to implement a pointer nullability check
> yet, so I don't yet understand all corner cases that arise in real
> world software.
> 
> However, fundamentally, there are a few questions that you need to answer:
> 
> - does _Nullable create a distinct type or not? It is extremely
> important when you consider C++.

Let's talk about _Nonnull, which is more likely to be added.

I would say no.  Neither const or restrict create a new type, but a
qualified version of a type.  _Nonnull has a behavior somewhat in
between restrict and const.

> 
> - do you want nullability-related diagnostics to be mandatory, or
> optional? For example, a compiler is not required to issue a
> diagnostic about a program that violates the constraints of
> `restrict`.

I think this should be similar to const, so a mandatory warning would be
better.  But still I have doubts, because this is much more complex to
diagnose than const violations (there should be no diagnostic after an
explicit NULL check).

> 
> If _Nullable does not create a distinct type, and `T*` is the same
> type as `T* _Nullable`, then we can't rely on the regular type system
> mechanisms to issue diagnostics.
> 
> If _Nullable creates a distinct type, then according to regular C type
> checking rules, you would get a warning on the `q = p` assignment
> regardless of the `if (!p)` check. That's how the C type system works,
> it is not flow-sensitive.
> 
> If we want the diagnostics to be fllow-sensitive like in your example
> (I think it would be the best choice), then we need to add a new
> flow-sensitive component to the C type system. I don't think there is
> a precedent for this in C right now. I'm not sure how the committee or
> implementors would react to such a proposal.

Yes, it's complex.  It should be flow-sensitive.  Right now there's a
precedent, I think: 'restrict'.  But there are no mandatory warnings
AFAIK.  This would go one step further, and would probably be the most
complex addition to the language ever.  A minimal complying compiler
would need to be much more complex than ever, which is a bad thing.

Right now I have two voices in my head saying opposite things:  on one
hand this would add a lot of complexity to the C language, and I don't
like that;  on the other hand, this would make standard C much more safe
than it is regarding pointers, and for the plain user, it would reduce
the cognitive complexity of making sure null pointers are not passed
where they shouldn't.

GCC adding _Nonnull before the standard would be a good first step.


Cheers,
Alex


More information about the cfe-dev mailing list