From: Fariborz Jahanian Date: Wed, 13 May 2009 23:20:50 +0000 (+0000) Subject: Look for and diagnose missing sentinel argument on message X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=88f1ba0f0439e31ab57ffc088aa91137cadee585;p=clang Look for and diagnose missing sentinel argument on message dispatch arguments which have sentinel attribute. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71737 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 299299df2e..79299a4700 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -763,6 +763,12 @@ def warn_deprecated : Warning<"%0 is deprecated">, def warn_unavailable : Warning<"%0 is unavailable">; def note_unavailable_here : Note< "function has been explicitly marked %select{unavailable|deleted}0 here">; +def warn_not_enough_argument : Warning< + "not enough variable arguments in %0 declaration to fit a sentinel">; +def warn_missing_sentinel : Warning < + "missing sentinel in method dispatch">; +def note_sentinel_here : Note< + "method has been explicitly marked sentinel here">; def warn_missing_prototype : Warning< "no previous prototype for function %0">, InGroup>, DefaultIgnore; diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 4d054fb8e0..7606e84d52 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -725,8 +725,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { << Attr.getName() << 3 /*function or method*/; return; } - - // FIXME: Actually create the attribute. + d->addAttr(::new (S.Context) SentinelAttr(sentinel, nullPos)); } static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) { diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index f1da408669..a1c170cf28 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -95,6 +95,50 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, Expr **Args, unsigned NumArgs) { + const SentinelAttr *attr = D->getAttr(); + if (!attr) + return; + ObjCMethodDecl *MD = dyn_cast(D); + // FIXME: function calls for later. + if (!MD) + return; + int sentinelPos = attr->getSentinel(); + int nullPos = attr->getNullPos(); + // skip over named parameters. + ObjCMethodDecl::param_iterator P, E = MD->param_end(); + unsigned int i = 0; + for (P = MD->param_begin(); (P != E && i < NumArgs); ++P) { + if (nullPos) + --nullPos; + else + ++i; + } + if (P != E || i >= NumArgs) { + Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName(); + Diag(D->getLocation(), diag::note_sentinel_here); + return; + } + int sentinel = i; + while (sentinelPos > 0 && i < NumArgs-1) { + --sentinelPos; + ++i; + } + if (sentinelPos > 0) { + Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName(); + Diag(D->getLocation(), diag::note_sentinel_here); + return; + } + while (i < NumArgs-1) { + ++i; + ++sentinel; + } + Expr *sentinelExpr = Args[sentinel]; + if (sentinelExpr && (!sentinelExpr->getType()->isPointerType() || + !sentinelExpr->isNullPointerConstant(Context))) { + Diag(Loc, diag::warn_missing_sentinel); + Diag(D->getLocation(), diag::note_sentinel_here); + } + return; } SourceRange Sema::getExprRange(ExprTy *E) const { diff --git a/test/SemaObjC/method-sentinel-attr.m b/test/SemaObjC/method-sentinel-attr.m new file mode 100644 index 0000000000..8f31e9ab5e --- /dev/null +++ b/test/SemaObjC/method-sentinel-attr.m @@ -0,0 +1,37 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +#define NULL (void*)0 + +#define ATTR __attribute__ ((__sentinel__)) + +@interface INTF +- (void) foo1 : (int)x, ... ATTR; // expected-note {{method has been explicitly marked sentinel here}} +- (void) foo3 : (int)x __attribute__ ((__sentinel__)) ; // expected-warning {{'sentinel' attribute only supported for variadic functions}} +- (void) foo5 : (int)x, ... __attribute__ ((__sentinel__(1))); // expected-note {{method has been explicitly marked sentinel here}} +- (void) foo6 : (int)x, ... __attribute__ ((__sentinel__(5))); // expected-note {{method has been explicitly marked sentinel here}} +- (void) foo7 : (int)x, ... __attribute__ ((__sentinel__(0))); // expected-note {{method has been explicitly marked sentinel here}} +- (void) foo8 : (int)x, ... __attribute__ ((__sentinel__("a"))); // expected-error {{'sentinel' attribute requires parameter 1 to be an integer constant}} +- (void) foo9 : (int)x, ... __attribute__ ((__sentinel__(-1))); // expected-error {{'sentinel' parameter 1 less than zero}} +- (void) foo10 : (int)x, ... __attribute__ ((__sentinel__(1,1))); +- (void) foo11 : (int)x, ... __attribute__ ((__sentinel__(1,1,3))); // expected-error {{attribute requires 0, 1 or 2 argument(s)}} +- (void) foo12 : (int)x, ... ATTR; // expected-note {{method has been explicitly marked sentinel here}} +@end + +int main () +{ + INTF *p; + + [p foo1:1, NULL]; // OK + [p foo1:1, 0]; // expected-warning {{missing sentinel in method dispatch}} + [p foo5:1, NULL, 2]; // OK + [p foo5:1, 2, NULL, 1]; // OK + [p foo5:1, NULL, 2, 1]; // expected-warning {{missing sentinel in method dispatch}} + + [p foo6:1,2,3,4,5,6,7]; // expected-warning {{missing sentinel in method dispatch}} + [p foo6:1,NULL,3,4,5,6,7]; // OK + [p foo7:1]; // expected-warning {{not enough variable arguments in 'foo7:' declaration to fit a sentinel}} + [p foo7:1, NULL]; // ok + + [p foo12:1]; // expected-warning {{not enough variable arguments in 'foo12:' declaration to fit a sentinel}} +} +