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/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 4d054fb..7606e84 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -725,8 +725,7 @@
       << 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 f1da408..a1c170c 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -95,6 +95,50 @@
 void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
                                  Expr **Args, unsigned NumArgs)
 {
+  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();
+  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 {