diff options
author | Ted Kremenek <kremenek@apple.com> | 2014-01-17 06:24:56 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2014-01-17 06:24:56 +0000 |
commit | 9aedc159ef4ccbacec1c77e0a425eb0f62bcf4f5 (patch) | |
tree | cc6d26c5454642c978f0f64bd5284fe049067b47 /clang/lib/Sema/SemaDeclAttr.cpp | |
parent | 07e4a66306af396f068cdae30c872037147a1824 (diff) | |
download | bcm5719-llvm-9aedc159ef4ccbacec1c77e0a425eb0f62bcf4f5.tar.gz bcm5719-llvm-9aedc159ef4ccbacec1c77e0a425eb0f62bcf4f5.zip |
Enhance attribute 'nonnull' to be applicable to parameters directly (infix).
This allows the following syntax:
void baz(__attribute__((nonnull)) const char *str);
instead of:
void baz(const char *str) __attribute__((nonnull(1)));
This also extends to Objective-C methods.
The checking logic in Sema is not as clean as I would like. Effectively
now we need to check both the FunctionDecl/ObjCMethodDecl and the parameters,
so the point of truth is spread in two places, but the logic isn't that
cumbersome.
Implements <rdar://problem/14691443>.
llvm-svn: 199467
Diffstat (limited to 'clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 48 |
1 files changed, 39 insertions, 9 deletions
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index b8116a7e8a6..06290672214 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1156,6 +1156,36 @@ static void possibleTransparentUnionPointerType(QualType &T) { } } +static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr, + SourceRange R) { + T = T.getNonReferenceType(); + possibleTransparentUnionPointerType(T); + + if (!T->isAnyPointerType() && !T->isBlockPointerType()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only) + << Attr.getName() << R; + return false; + } + return true; +} + +static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D, + const AttributeList &Attr) { + // Is the argument a pointer type? + if (!attrNonNullArgCheck(S, D->getType(), Attr, D->getSourceRange())) + return; + + if (Attr.getNumArgs() > 0) { + S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_parm_no_args) + << D->getSourceRange(); + return; + } + + D->addAttr(::new (S.Context) + NonNullAttr(Attr.getRange(), S.Context, 0, 0, + Attr.getAttributeSpellingListIndex())); +} + static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { SmallVector<unsigned, 8> NonNullArgs; for (unsigned i = 0; i < Attr.getNumArgs(); ++i) { @@ -1165,15 +1195,10 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; // Is the function argument a pointer type? - QualType T = getFunctionOrMethodArgType(D, Idx).getNonReferenceType(); - possibleTransparentUnionPointerType(T); - - if (!T->isAnyPointerType() && !T->isBlockPointerType()) { - // FIXME: Should also highlight argument in decl. - S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only) - << Attr.getName() << Ex->getSourceRange(); + // FIXME: Should also highlight argument in decl in the diagnostic. + if (!attrNonNullArgCheck(S, getFunctionOrMethodArgType(D, Idx), + Attr, Ex->getSourceRange())) continue; - } NonNullArgs.push_back(Idx); } @@ -3947,7 +3972,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_Mode: handleModeAttr (S, D, Attr); break; case AttributeList::AT_NoCommon: handleSimpleAttribute<NoCommonAttr>(S, D, Attr); break; - case AttributeList::AT_NonNull: handleNonNullAttr (S, D, Attr); break; + case AttributeList::AT_NonNull: + if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(D)) + handleNonNullAttrParameter(S, PVD, Attr); + else + handleNonNullAttr(S, D, Attr); + break; case AttributeList::AT_Overloadable: handleSimpleAttribute<OverloadableAttr>(S, D, Attr); break; case AttributeList::AT_Ownership: handleOwnershipAttr (S, D, Attr); break; |