r199467 - Enhance attribute 'nonnull' to be applicable to parameters directly (infix).
Ted Kremenek
kremenek at apple.com
Thu Jan 16 22:24:56 PST 2014
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)));
+ at 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}}
+}
+
More information about the cfe-commits
mailing list