Awesome! This attribute has been incredibly awkward to use without this.
On Thu, Jan 16, 2014 at 10:24 PM, Ted Kremenek <[email protected]> wrote: > Author: kremenek > Date: Fri Jan 17 00:24:56 2014 > New Revision: 199467 > > URL: http://llvm.org/viewvc/llvm-project?rev=199467&view=rev > Log: > 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>. > > Modified: > cfe/trunk/include/clang/Basic/Attr.td > cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > cfe/trunk/lib/Sema/SemaChecking.cpp > cfe/trunk/lib/Sema/SemaDeclAttr.cpp > cfe/trunk/test/Sema/nonnull.c > cfe/trunk/test/SemaObjC/nonnull.m > > Modified: cfe/trunk/include/clang/Basic/Attr.td > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=199467&r1=199466&r2=199467&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Basic/Attr.td (original) > +++ cfe/trunk/include/clang/Basic/Attr.td Fri Jan 17 00:24:56 2014 > @@ -679,8 +679,9 @@ def NoMips16 : InheritableAttr, TargetSp > > def NonNull : InheritableAttr { > let Spellings = [GNU<"nonnull">, CXX11<"gnu", "nonnull">]; > - let Subjects = SubjectList<[ObjCMethod, FunctionLike, HasFunctionProto], > - WarnDiag, "ExpectedFunctionOrMethod">; > + let Subjects = SubjectList<[ObjCMethod, FunctionLike, HasFunctionProto, > + ParmVar], > + WarnDiag, > "ExpectedFunctionMethodOrParameter">; > let Args = [VariadicUnsignedArgument<"Args">]; > let AdditionalMembers = > [{bool isNonNull(unsigned idx) const { > > Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=199467&r1=199466&r2=199467&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jan 17 > 00:24:56 2014 > @@ -2351,6 +2351,9 @@ def err_attr_wrong_decl : Error< > def warn_attribute_nonnull_no_pointers : Warning< > "'nonnull' attribute applied to function with no pointer arguments">, > InGroup<IgnoredAttributes>; > +def warn_attribute_nonnull_parm_no_args : Warning< > + "'nonnull' attribute when used on parameters takes no arguments">, > + InGroup<IgnoredAttributes>; > def warn_attribute_malloc_pointer_only : Warning< > "'malloc' attribute only applies to functions returning a pointer > type">, > InGroup<IgnoredAttributes>; > > Modified: cfe/trunk/lib/Sema/SemaChecking.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=199467&r1=199466&r2=199467&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) > +++ cfe/trunk/lib/Sema/SemaChecking.cpp Fri Jan 17 00:24:56 2014 > @@ -736,6 +736,7 @@ static void CheckNonNullArguments(Sema & > const NamedDecl *FDecl, > const Expr * const *ExprArgs, > SourceLocation CallSiteLoc) { > + // Check the attributes attached to the method/function itself. > for (specific_attr_iterator<NonNullAttr> > I = FDecl->specific_attr_begin<NonNullAttr>(), > E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I) { > @@ -747,6 +748,21 @@ static void CheckNonNullArguments(Sema & > CheckNonNullArgument(S, ExprArgs[*i], CallSiteLoc); > } > } > + > + // Check the attributes on the parameters. > + ArrayRef<ParmVarDecl*> parms; > + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FDecl)) > + parms = FD->parameters(); > + else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(FDecl)) > + parms = MD->parameters(); > + > + unsigned argIndex = 0; > + for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = > parms.end(); > + I != E; ++I, ++argIndex) { > + const ParmVarDecl *PVD = *I; > + if (PVD->hasAttr<NonNullAttr>()) > + CheckNonNullArgument(S, ExprArgs[argIndex], CallSiteLoc); > + } > } > > /// Handles the checks for format strings, non-POD arguments to vararg > > Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=199467&r1=199466&r2=199467&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original) > +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Jan 17 00:24:56 2014 > @@ -1156,6 +1156,36 @@ static void possibleTransparentUnionPoin > } > } > > +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, D > 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 > 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; > > Modified: cfe/trunk/test/Sema/nonnull.c > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/nonnull.c?rev=199467&r1=199466&r2=199467&view=diff > > ============================================================================== > --- cfe/trunk/test/Sema/nonnull.c (original) > +++ cfe/trunk/test/Sema/nonnull.c Fri Jan 17 00:24:56 2014 > @@ -21,3 +21,14 @@ int main(void) { > > void foo(const char *str) __attribute__((nonnull("foo"))); // > expected-error{{'nonnull' attribute requires parameter 1 to be an integer > constant}} > void bar(int i) __attribute__((nonnull(1))); // expected-warning > {{'nonnull' attribute only applies to pointer arguments}} expected-warning > {{'nonnull' attribute applied to function with no pointer arguments}} > + > +void baz(__attribute__((nonnull)) const char *str); > +void baz2(__attribute__((nonnull(1))) const char *str); // > expected-warning {{'nonnull' attribute when used on parameters takes no > arguments}} > +void baz3(__attribute__((nonnull)) int x); // expected-warning > {{'nonnull' attribute only applies to pointer arguments}} > + > +void test_baz() { > + baz(0); // expected-warning {{null passed to a callee which requires a > non-null argument}} > + baz2(0); // no-warning > + baz3(0); // no-warning > +} > + > > Modified: cfe/trunk/test/SemaObjC/nonnull.m > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/nonnull.m?rev=199467&r1=199466&r2=199467&view=diff > > ============================================================================== > --- cfe/trunk/test/SemaObjC/nonnull.m (original) > +++ cfe/trunk/test/SemaObjC/nonnull.m Fri Jan 17 00:24:56 2014 > @@ -95,3 +95,17 @@ extern void DoSomethingNotNull(void *db) > } > @end > > +__attribute__((objc_root_class)) > + @interface TestNonNullParameters > +- (void) > doNotPassNullParameterNonPointerArg:(int)__attribute__((nonnull))x; // > expected-warning {{'nonnull' attribute only applies to pointer arguments}} > +- (void) doNotPassNullParameter:(id)__attribute__((nonnull))x; > +- (void) doNotPassNullParameterArgIndex:(id)__attribute__((nonnull(1)))x; > // expected-warning {{'nonnull' attribute when used on parameters takes no > arguments}} > +- (void) doNotPassNullOnMethod:(id)x __attribute__((nonnull(1))); > +@end > + > +void test(TestNonNullParameters *f) { > + [f doNotPassNullParameter:0]; // expected-warning {{null passed to a > callee which requires a non-null argument}} > + [f doNotPassNullParameterArgIndex:0]; // no-warning > + [f doNotPassNullOnMethod:0]; // expected-warning {{null passed to a > callee which requires a non-null argument}} > +} > + > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
