From 4a528035fd7956515ac26149fe5d6ea41aed2fc0 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 14 May 2009 18:00:00 +0000 Subject: [PATCH] Diagnose missing sentinel argument on a funciton call with sentinel attribute. llvm-svn: 71778 --- .../clang/Basic/DiagnosticSemaKinds.td | 4 +- clang/lib/Sema/SemaExpr.cpp | 56 +++++++++++++------ clang/test/Sema/function-sentinel-attr.c | 30 ++++++++++ 3 files changed, 71 insertions(+), 19 deletions(-) create mode 100644 clang/test/Sema/function-sentinel-attr.c diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index bd5818de6b8c..c51ad3e1dfa4 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -780,9 +780,9 @@ def note_unavailable_here : Note< 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">; + "missing sentinel in %select{function|method}0 %select{call|dispatch}1">; def note_sentinel_here : Note< - "method has been explicitly marked sentinel here">; + "%select{function|method}0 has been explicitly marked sentinel here">; def warn_missing_prototype : Warning< "no previous prototype for function %0">, InGroup>, DefaultIgnore; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index a1c170cf2846..6a7bca0165a6 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -98,24 +98,44 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, 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(); + + // FIXME. ObjCMethodDecl and FunctionDecl need be derived from the + // same common base class. Then we won't be needing two versions of + // the same code. unsigned int i = 0; - for (P = MD->param_begin(); (P != E && i < NumArgs); ++P) { - if (nullPos) - --nullPos; - else - ++i; + bool warnNotEnoughArgs = false; + int isMethod = 0; + if (ObjCMethodDecl *MD = dyn_cast(D)) { + // skip over named parameters. + ObjCMethodDecl::param_iterator P, E = MD->param_end(); + for (P = MD->param_begin(); (P != E && i < NumArgs); ++P) { + if (nullPos) + --nullPos; + else + ++i; + } + warnNotEnoughArgs = (P != E || i >= NumArgs); + isMethod = 1; } - if (P != E || i >= NumArgs) { + else if (FunctionDecl *FD = dyn_cast(D)) { + // skip over named parameters. + ObjCMethodDecl::param_iterator P, E = FD->param_end(); + for (P = FD->param_begin(); (P != E && i < NumArgs); ++P) { + if (nullPos) + --nullPos; + else + ++i; + } + warnNotEnoughArgs = (P != E || i >= NumArgs); + } + else + return; + + if (warnNotEnoughArgs) { Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName(); - Diag(D->getLocation(), diag::note_sentinel_here); + Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; return; } int sentinel = i; @@ -125,7 +145,7 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, } if (sentinelPos > 0) { Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName(); - Diag(D->getLocation(), diag::note_sentinel_here); + Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; return; } while (i < NumArgs-1) { @@ -135,8 +155,8 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, 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); + Diag(Loc, diag::warn_missing_sentinel) << isMethod << isMethod; + Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; } return; } @@ -2619,8 +2639,10 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, << Fn->getSourceRange()); // Do special checking on direct calls to functions. - if (FDecl) + if (FDecl) { + DiagnoseSentinelCalls(FDecl, LParenLoc, Args, NumArgs); return CheckFunctionCall(FDecl, TheCall.take()); + } return Owned(TheCall.take()); } diff --git a/clang/test/Sema/function-sentinel-attr.c b/clang/test/Sema/function-sentinel-attr.c new file mode 100644 index 000000000000..66304796127f --- /dev/null +++ b/clang/test/Sema/function-sentinel-attr.c @@ -0,0 +1,30 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +#define NULL (void*)0 + +#define ATTR __attribute__ ((__sentinel__)) + +void foo1 (int x, ...) ATTR; // expected-note {{function has been explicitly marked sentinel here}} +void foo5 (int x, ...) __attribute__ ((__sentinel__(1))); // expected-note {{function has been explicitly marked sentinel here}} +void foo6 (int x, ...) __attribute__ ((__sentinel__(5))); // expected-note {{function has been explicitly marked sentinel here}} +void foo7 (int x, ...) __attribute__ ((__sentinel__(0))); // expected-note {{function has been explicitly marked sentinel here}} +void foo10 (int x, ...) __attribute__ ((__sentinel__(1,1))); +void foo12 (int x, ... ) ATTR; // expected-note {{function has been explicitly marked sentinel here}} + +int main () +{ + + foo1(1, NULL); // OK + foo1(1, 0) ; // expected-warning {{missing sentinel in function call}} + foo5(1, NULL, 2); // OK + foo5(1,2,NULL, 1); // OK + foo5(1, NULL, 2, 1); // expected-warning {{missing sentinel in function call}} + + foo6(1,2,3,4,5,6,7); // expected-warning {{missing sentinel in function call}} + foo6(1,NULL,3,4,5,6,7); // OK + foo7(1); // expected-warning {{not enough variable arguments in 'foo7' declaration to fit a sentinel}} + foo7(1, NULL); // OK + + foo12(1); // expected-warning {{not enough variable arguments in 'foo12' declaration to fit a sentinel}} +} +