r240146 - Introduce type nullability specifiers for C/C++.
Douglas Gregor
dgregor at apple.com
Mon Jun 22 10:18:46 PDT 2015
> On Jun 19, 2015, at 11:10 AM, Aaron Ballman <aaron at aaronballman.com> wrote:
>
> On Fri, Jun 19, 2015 at 1:51 PM, Douglas Gregor <dgregor at apple.com <mailto:dgregor at apple.com>> wrote:
>> Author: dgregor
>> Date: Fri Jun 19 12:51:05 2015
>> New Revision: 240146
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=240146&view=rev
>> Log:
>> Introduce type nullability specifiers for C/C++.
>>
>> Introduces the type specifiers __nonnull, __nullable, and
>> __null_unspecified that describe the nullability of the pointer type
>> to which the specifier appertains. Nullability type specifiers improve
>> on the existing nonnull attributes in a few ways:
>> - They apply to types, so one can represent a pointer to a non-null
>> pointer, use them in function pointer types, etc.
>> - As type specifiers, they are syntactically more lightweight than
>> __attribute__s or [[attribute]]s.
>> - They can express both the notion of 'should never be null' and
>> also 'it makes sense for this to be null', and therefore can more
>> easily catch errors of omission where one forgot to annotate the
>> nullability of a particular pointer (this will come in a subsequent
>> patch).
>>
>> Nullability type specifiers are maintained as type sugar, and
>> therefore have no effect on mangling, encoding, overloading,
>> etc. Nonetheless, they will be used for warnings about, e.g., passing
>> 'null' to a method that does not accept it.
>>
>> This is the C/C++ part of rdar://problem/18868820.
>
> This is great stuff! I have some trivial comments below.
>
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=240146&r1=240145&r2=240146&view=diff
>> ==============================================================================
>> --- cfe/trunk/include/clang/Basic/Attr.td (original)
>> +++ cfe/trunk/include/clang/Basic/Attr.td Fri Jun 19 12:51:05 2015
>> @@ -960,6 +960,22 @@ def ReturnsNonNull : InheritableAttr {
>> let Documentation = [Undocumented];
>> }
>>
>> +// Nullability type attributes.
>> +def TypeNonNull : TypeAttr {
>> + let Spellings = [Keyword<"__nonnull">];
>> + let Documentation = [Undocumented];
>> +}
>> +
>> +def TypeNullable : TypeAttr {
>> + let Spellings = [Keyword<"__nullable">];
>> + let Documentation = [Undocumented];
>> +}
>> +
>> +def TypeNullUnspecified : TypeAttr {
>> + let Spellings = [Keyword<"__null_unspecified">];
>> + let Documentation = [Undocumented];
>> +}
>
> Please add documentation for these type attributes (we frown on new
> attributes that are flagged as Undocumented).
Good call, r240296.
>> Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=240146&r1=240145&r2=240146&view=diff
>> ==============================================================================
>> --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
>> +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Fri Jun 19 12:51:05 2015
>> @@ -65,6 +65,10 @@ def ext_keyword_as_ident : ExtWarn<
>> "%select{here|for the remainder of the translation unit}1">,
>> InGroup<KeywordCompat>;
>>
>> +def ext_nullability : Extension<
>> + "type nullability specifier %0 is a Clang extension">,
>> + InGroup<DiagGroup<"nullability-extension">>;
>
> Please have %0 quoted in the diagnostic.
It’s not necessary; we pass in an IdentifierInfo* here.
>
>>
>> Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=240146&r1=240145&r2=240146&view=diff
>> ==============================================================================
>> --- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
>> +++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Jun 19 12:51:05 2015
>> @@ -687,6 +687,28 @@ void Parser::ParseOpenCLQualifiers(Parse
>> AttributeList::AS_Keyword);
>> }
>>
>> +void Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) {
>> + // Treat these like attributes, even though they're type specifiers.
>> + while (true) {
>> + switch (Tok.getKind()) {
>> + case tok::kw___nonnull:
>> + case tok::kw___nullable:
>> + case tok::kw___null_unspecified: {
>> + IdentifierInfo *AttrName = Tok.getIdentifierInfo();
>> + SourceLocation AttrNameLoc = ConsumeToken();
>> + if (!getLangOpts().ObjC1)
>> + Diag(AttrNameLoc, diag::ext_nullability)
>> + << AttrName;
>> + attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
>> + AttributeList::AS_Keyword);
>> + break;
>> + }
>> + default:
>> + return;
>
> Would it be more clear to move the default to be the first label in
> the switch, and have it break instead of return (in case we would like
> to do post-processing of these at some point)?
Personally, I find it clearer the way it is.
>>
>> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=240146&r1=240145&r2=240146&view=diff
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Jun 19 12:51:05 2015
>> @@ -2465,6 +2465,28 @@ static void mergeParamDeclAttributes(Par
>> if (!foundAny) newDecl->dropAttrs();
>> }
>>
>> +static void mergeParamDeclTypes(ParmVarDecl *NewParam,
>> + const ParmVarDecl *OldParam,
>> + Sema &S) {
>> + if (auto Oldnullability = OldParam->getType()->getNullability(S.Context)) {
>> + if (auto Newnullability = NewParam->getType()->getNullability(S.Context)) {
>
> Can we put the dereference into the assignment expression, since these
> are only ever used as dereferenced?
We cannot, because we’re getting an Optional<NullabilityKind> here, and we need to check whether we have a value.
>
>> + if (*Oldnullability != *Newnullability) {
>> + S.Diag(NewParam->getLocation(), diag::warn_mismatched_nullability_attr)
>> + << static_cast<unsigned>(*Newnullability)
>> + << static_cast<unsigned>(*Oldnullability);
>> + S.Diag(OldParam->getLocation(), diag::note_previous_declaration);
>> + }
>> + }
>> + else {
>
> Formatting.
Okay.
>> +/// Distribute a nullability type attribute that cannot be applied to
>> +/// the type specifier to a pointer, block pointer, or member pointer
>> +/// declarator, complaining if necessary.
>> +///
>> +/// \returns true if the nullability annotation was distributed, false
>> +/// otherwise.
>> +static bool distributeNullabilityTypeAttr(TypeProcessingState &state,
>> + QualType type,
>> + AttributeList &attr) {
>> + Declarator &declarator = state.getDeclarator();
>> +
>> + /// Attempt to move the attribute to the specified chunk.
>> + auto moveToChunk = [&](DeclaratorChunk &chunk, bool inFunction) -> bool {
>> + // If there is already a nullability attribute there, don't add
>> + // one.
>> + if (hasNullabilityAttr(chunk.getAttrListRef()))
>> + return false;
>> +
>> + // Complain about the nullability qualifier being in the wrong
>> + // place.
>> + unsigned pointerKind
>> + = chunk.Kind == DeclaratorChunk::Pointer ? (inFunction ? 3 : 0)
>> + : chunk.Kind == DeclaratorChunk::BlockPointer ? 1
>> + : inFunction? 4 : 2;
>
> Can we replace the magic numbers with something else?
Sure, we can give these meaningful names.
- Doug
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150622/035d1f9d/attachment.html>
More information about the cfe-commits
mailing list