Switch the initialization of Objective-C message parameters (as occurs
during message sends) over to the new initialization code and away
from the C-only CheckSingleAssignmentConstraints. The enables the use
of C++ types in method parameters and message arguments, as well as
unifying more initialiation code overall.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102035 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 3af0cfc..e6884ba 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -13,6 +13,7 @@
 
 #include "Sema.h"
 #include "Lookup.h"
+#include "SemaInit.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprObjC.h"
@@ -204,30 +205,23 @@
   bool IsError = false;
   for (unsigned i = 0; i < NumNamedArgs; i++) {
     Expr *argExpr = Args[i];
+    ParmVarDecl *Param = Method->param_begin()[i];
     assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
 
-    QualType lhsType = Method->param_begin()[i]->getType();
-    QualType rhsType = argExpr->getType();
+    if (RequireCompleteType(argExpr->getSourceRange().getBegin(),
+                            Param->getType(),
+                            PDiag(diag::err_call_incomplete_argument)
+                              << argExpr->getSourceRange()))
+      return true;
 
-    // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8].
-    if (lhsType->isArrayType())
-      lhsType = Context.getArrayDecayedType(lhsType);
-    else if (lhsType->isFunctionType())
-      lhsType = Context.getPointerType(lhsType);
-
-    AssignConvertType Result =
-      CheckSingleAssignmentConstraints(lhsType, argExpr);
-    if (Result == Incompatible && !getLangOptions().CPlusPlus &&
-        CheckTransparentUnionArgumentConstraints(lhsType, argExpr)
-        == Sema::Compatible)
-      Result = Compatible;
-        
-    if (Args[i] != argExpr) // The expression was converted.
-      Args[i] = argExpr; // Make sure we store the converted expression.
-
-    IsError |=
-      DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType,
-                               argExpr, AA_Sending);
+    InitializedEntity Entity = InitializedEntity::InitializeParameter(Param);
+    OwningExprResult ArgE = PerformCopyInitialization(Entity,
+                                                      SourceLocation(),
+                                                      Owned(argExpr->Retain()));
+    if (ArgE.isInvalid())
+      IsError = true;
+    else
+      Args[i] = ArgE.takeAs<Expr>();
   }
 
   // Promote additional arguments to variadic methods.
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index a015dd7..6a9efbd 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -3088,7 +3088,10 @@
     return Sema::AA_Initializing;
 
   case InitializedEntity::EK_Parameter:
-    // FIXME: Can we tell when we're sending vs. passing?
+    if (Entity.getDecl() && 
+        isa<ObjCMethodDecl>(Entity.getDecl()->getDeclContext()))
+      return Sema::AA_Sending;
+
     return Sema::AA_Passing;
 
   case InitializedEntity::EK_Result:
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index bfbb0f4..ba11470 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -142,7 +142,12 @@
   /// \brief Create the initialization entity for a parameter that is
   /// only known by its type.
   static InitializedEntity InitializeParameter(QualType Type) {
-    return InitializedEntity(EK_Parameter, SourceLocation(), Type);
+    InitializedEntity Entity;
+    Entity.Kind = EK_Parameter;
+    Entity.Type = Type;
+    Entity.Parent = 0;
+    Entity.VariableOrMember = 0;
+    return Entity;
   }
 
   /// \brief Create the initialization entity for the result of a function.
diff --git a/test/SemaObjCXX/message.mm b/test/SemaObjCXX/message.mm
index 91b11f1..97ee499 100644
--- a/test/SemaObjCXX/message.mm
+++ b/test/SemaObjCXX/message.mm
@@ -75,3 +75,18 @@
   return [super method];
 }
 @end
+
+struct String {
+  String(const char *);
+};
+
+struct MutableString : public String { };
+
+// C++-specific parameter types
+@interface I5
+- method:(const String&)str1 other:(String&)str2;
+@end
+
+void test_I5(I5 *i5, String s) {
+  [i5 method:"hello" other:s];
+}
diff --git a/test/SemaObjCXX/objc-pointer-conv.mm b/test/SemaObjCXX/objc-pointer-conv.mm
index 02ed58b..2504dce 100644
--- a/test/SemaObjCXX/objc-pointer-conv.mm
+++ b/test/SemaObjCXX/objc-pointer-conv.mm
@@ -32,7 +32,7 @@
 void Func (I* arg);  // expected-note {{candidate function not viable: no known conversion from 'I const *' to 'I *' for 1st argument}}
 
 void foo(const I *p, I* sel) {
-  [sel Meth : p];	// expected-error {{sending 'I const *' to parameter of incompatible type 'I *'}}
+  [sel Meth : p];	// expected-error {{cannot initialize a parameter of type 'I *' with an lvalue of type 'I const *'}}
   Func(p);		// expected-error {{no matching function for call to 'Func'}}
 }