]> granicus.if.org Git - clang/commitdiff
Diagnose missing sentinel argument on a funciton call
authorFariborz Jahanian <fjahanian@apple.com>
Thu, 14 May 2009 18:00:00 +0000 (18:00 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Thu, 14 May 2009 18:00:00 +0000 (18:00 +0000)
with sentinel attribute.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71778 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaExpr.cpp
test/Sema/function-sentinel-attr.c [new file with mode: 0644]

index bd5818de6b8c143ae6e0dbbc9cd63437d99ef8db..c51ad3e1dfa42e57f023c6d971ef98d437991c28 100644 (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;
index a1c170cf2846c79f205dcea7451563d3455e383a..6a7bca0165a65c2d736b5ae74688bae1f6401b25 100644 (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;
+  }
+  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);
   }
-  if (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/test/Sema/function-sentinel-attr.c b/test/Sema/function-sentinel-attr.c
new file mode 100644 (file)
index 0000000..6630479
--- /dev/null
@@ -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}}
+}