Accept and pass arguments to __unknown_anytype in argument
positions of Objective-C methods.

It is possible to recover a lot of type information about
Objective-C methods from the reflective metadata for their
implementations.  This information is not rich when it
comes to struct types, however, and it is not possible to
produce a type in the debugger's round-tripped AST which
will really do anything useful during type-checking.
Therefore we allow __unknown_anytype in these positions,
which essentially disables type-checking for that argument.
We infer the parameter type to be the unqualified type of
the argument expression unless that expression is an
explicit cast, in which case it becomes the type-as-written
of that cast.

rdar://problem/12565338

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167896 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index bf4abfc..58c212b 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -11850,6 +11850,22 @@
   return RebuildUnknownAnyExpr(*this, ToType).Visit(E);
 }
 
+QualType Sema::checkUnknownAnyArg(Expr *&arg) {
+  // Filter out placeholders.
+  ExprResult argR = CheckPlaceholderExpr(arg);
+  if (argR.isInvalid()) return QualType();
+  arg = argR.take();
+
+  // If the argument is an explicit cast, use that exact type as the
+  // effective parameter type.
+  if (ExplicitCastExpr *castArg = dyn_cast<ExplicitCastExpr>(arg)) {
+    return castArg->getTypeAsWritten();
+  }
+
+  // Otherwise, try to pass by value.
+  return arg->getType().getUnqualifiedType();
+}
+
 static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) {
   Expr *orig = E;
   unsigned diagID = diag::err_uncasted_use_of_unknown_any;
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index e43b6bf..b0f9958 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -1196,6 +1196,19 @@
         !param->hasAttr<CFConsumedAttr>())
       argExpr = stripARCUnbridgedCast(argExpr);
 
+    // If the parameter is __unknown_anytype, infer its type
+    // from the argument.
+    if (param->getType() == Context.UnknownAnyTy) {
+      QualType paramType = checkUnknownAnyArg(argExpr);
+      if (paramType.isNull()) {
+        IsError = true;
+        continue;
+      }
+
+      // Update the parameter type in-place.
+      param->setType(paramType);
+    }
+
     if (RequireCompleteType(argExpr->getSourceRange().getBegin(),
                             param->getType(),
                             diag::err_call_incomplete_argument, argExpr))