Diagnose missing sentinel argument on a funciton call

with sentinel attribute.

llvm-svn: 71778
This commit is contained in:
Fariborz Jahanian 2009-05-14 18:00:00 +00:00
parent 2daacd1f08
commit 4a528035fd
3 changed files with 71 additions and 19 deletions

View File

@ -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<DiagGroup<"missing-prototypes">>, DefaultIgnore;

View File

@ -98,24 +98,44 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
const SentinelAttr *attr = D->getAttr<SentinelAttr>();
if (!attr)
return;
ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(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<ObjCMethodDecl>(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<FunctionDecl>(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());
}

View File

@ -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}}
}