forked from OSchip/llvm-project
Diagnose missing sentinel argument on a funciton call
with sentinel attribute. llvm-svn: 71778
This commit is contained in:
parent
2daacd1f08
commit
4a528035fd
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
Loading…
Reference in New Issue