Introduce a new mangling for protocol-qualified ObjC types in C++.  This allows
to provide proper overloading, and also prevents mangling conflicts with
template arguments of protocol-qualified type.

This is a non-backward-compatible mangling change, but per discussion with
John, the benefits outweigh this cost.

Fixes <rdar://problem/14074822>.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184250 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 20f699f..1d58e8d 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -2164,8 +2164,19 @@
 }
 
 void CXXNameMangler::mangleType(const ObjCObjectType *T) {
-  // We don't allow overloading by different protocol qualification,
-  // so mangling them isn't necessary.
+  if (!T->qual_empty()) {
+    // Mangle protocol qualifiers.
+    SmallString<64> QualStr;
+    llvm::raw_svector_ostream QualOS(QualStr);
+    QualOS << "objcproto";
+    ObjCObjectType::qual_iterator i = T->qual_begin(), e = T->qual_end();
+    for ( ; i != e; ++i) {
+      StringRef name = (*i)->getName();
+      QualOS << name.size() << name;
+    }
+    QualOS.flush();
+    Out << 'U' << QualStr.size() << QualStr;
+  }
   mangleType(T->getBaseType());
 }
 
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 5a40b1f..b9daba9 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -2603,48 +2603,15 @@
 
 /// FunctionArgTypesAreEqual - This routine checks two function proto types
 /// for equality of their argument types. Caller has already checked that
-/// they have same number of arguments. This routine assumes that Objective-C
-/// pointer types which only differ in their protocol qualifiers are equal.
-/// If the parameters are different, ArgPos will have the parameter index
-/// of the first different parameter.
+/// they have same number of arguments.  If the parameters are different,
+/// ArgPos will have the parameter index of the first different parameter.
 bool Sema::FunctionArgTypesAreEqual(const FunctionProtoType *OldType,
                                     const FunctionProtoType *NewType,
                                     unsigned *ArgPos) {
-  if (!getLangOpts().ObjC1) {
-    for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(),
-         N = NewType->arg_type_begin(),
-         E = OldType->arg_type_end(); O && (O != E); ++O, ++N) {
-      if (!Context.hasSameType(*O, *N)) {
-        if (ArgPos) *ArgPos = O - OldType->arg_type_begin();
-        return false;
-      }
-    }
-    return true;
-  }
-
   for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(),
        N = NewType->arg_type_begin(),
        E = OldType->arg_type_end(); O && (O != E); ++O, ++N) {
-    QualType ToType = (*O);
-    QualType FromType = (*N);
-    if (!Context.hasSameType(ToType, FromType)) {
-      if (const PointerType *PTTo = ToType->getAs<PointerType>()) {
-        if (const PointerType *PTFr = FromType->getAs<PointerType>())
-          if ((PTTo->getPointeeType()->isObjCQualifiedIdType() &&
-               PTFr->getPointeeType()->isObjCQualifiedIdType()) ||
-              (PTTo->getPointeeType()->isObjCQualifiedClassType() &&
-               PTFr->getPointeeType()->isObjCQualifiedClassType()))
-            continue;
-      }
-      else if (const ObjCObjectPointerType *PTTo =
-                 ToType->getAs<ObjCObjectPointerType>()) {
-        if (const ObjCObjectPointerType *PTFr =
-              FromType->getAs<ObjCObjectPointerType>())
-          if (Context.hasSameUnqualifiedType(
-                PTTo->getObjectType()->getBaseType(),
-                PTFr->getObjectType()->getBaseType()))
-            continue;
-      }
+    if (!Context.hasSameType(*O, *N)) {
       if (ArgPos) *ArgPos = O - OldType->arg_type_begin();
       return false;
     }
diff --git a/test/CodeGenObjCXX/catch-id-type.mm b/test/CodeGenObjCXX/catch-id-type.mm
index 2d6cccc..0a2b940 100644
--- a/test/CodeGenObjCXX/catch-id-type.mm
+++ b/test/CodeGenObjCXX/catch-id-type.mm
@@ -31,7 +31,7 @@
     catch( id error )
     { 
       // CHECK:      landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
-      // CHECK-NEXT:   catch i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIP4INTF to i8*)
+      // CHECK-NEXT:   catch i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIPU11objcproto1P4INTF to i8*)
       // CHECK-NEXT:   catch i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIP11objc_object to i8*)
       // CHECK-NEXT:   catch i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIP10objc_class to i8*)
       error = error; 
diff --git a/test/CodeGenObjCXX/mangle.mm b/test/CodeGenObjCXX/mangle.mm
index 45a93a1..7b2ffe3 100644
--- a/test/CodeGenObjCXX/mangle.mm
+++ b/test/CodeGenObjCXX/mangle.mm
@@ -78,3 +78,23 @@
   Test2Template<decltype(t.dimension)> t1;
   Test2Template<decltype(t->alt_axis)> t2;
 }
+
+@protocol P;
+void overload1(A<P>*) {}
+// CHECK: define void @_Z9overload1PU11objcproto1P1A
+void overload1(const A<P>*) {}
+// CHECK: define void @_Z9overload1PKU11objcproto1P1A
+void overload1(A<P>**) {}
+// CHECK: define void @_Z9overload1PPU11objcproto1P1A
+void overload1(A<P>*const*) {}
+// CHECK: define void @_Z9overload1PKPU11objcproto1P1A
+void overload1(A<P>***) {}
+// CHECK: define void @_Z9overload1PPPU11objcproto1P1A
+void overload1(void (f)(A<P>*)) {}
+// CHECK: define void @_Z9overload1PFvPU11objcproto1P1AE
+
+template<typename T> struct X { void f(); };
+template<> void X<A*>::f() {}
+// CHECK: define void @_ZN1XIP1AE1fEv
+template<> void X<A<P>*>::f() {}
+// CHECK: define void @_ZN1XIPU11objcproto1P1AE1fEv
diff --git a/test/CodeGenObjCXX/rtti.mm b/test/CodeGenObjCXX/rtti.mm
index 72de3ac..e458f09 100644
--- a/test/CodeGenObjCXX/rtti.mm
+++ b/test/CodeGenObjCXX/rtti.mm
@@ -38,14 +38,14 @@
   const std::type_info &t5 = typeid(c);
   const std::type_info &t6 = typeid(*c);
 
-  // CHECK: store {{.*}} @_ZTIP11objc_object
-  // CHECK: store {{.*}} @_ZTI11objc_object
+  // CHECK: store {{.*}} @_ZTIPU11objcproto1P11objc_object
+  // CHECK: store {{.*}} @_ZTIU11objcproto1P11objc_object
   id<P> i2 = 0;
   const std::type_info &t7 = typeid(i2);
   const std::type_info &t8 = typeid(*i2);
 
-  // CHECK: store {{.*}} @_ZTIP10objc_class
-  // CHECK: store {{.*}} @_ZTI10objc_class
+  // CHECK: store {{.*}} @_ZTIPU11objcproto1P10objc_class
+  // CHECK: store {{.*}} @_ZTIU11objcproto1P10objc_class
   Class<P> c2 = 0;
   const std::type_info &t9 = typeid(c2);
   const std::type_info &t10 = typeid(*c2);
diff --git a/test/SemaObjCXX/overload-1.mm b/test/SemaObjCXX/overload-1.mm
deleted file mode 100644
index fc17ca2..0000000
--- a/test/SemaObjCXX/overload-1.mm
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-@protocol Proto1 @end
-
-@protocol Proto2 @end
-
-void f(id<Proto1> *) { }		// expected-note {{previous definition is here}}
-
-void f(id<Proto1, Proto2> *) { }	// expected-error {{conflicting types for 'f'}}
-
-void f(Class<Proto1> *) { }		// expected-note {{previous definition is here}}
-
-void f(Class<Proto1, Proto2> *) { }	// expected-error {{conflicting types for 'f'}}
-
-@interface I @end
-
-void f(I<Proto1> *) { }		// expected-note {{previous definition is here}}
-
-void f(I<Proto1, Proto2> *) { }		// expected-error {{conflicting types for 'f'}}
-
-@interface I1 @end
-
-void f1(I<Proto1> *) { }
-
-void f1(I1<Proto1, Proto2> *) { }
diff --git a/test/SemaObjCXX/overload.mm b/test/SemaObjCXX/overload.mm
index 6f24c59..bb94d9e 100644
--- a/test/SemaObjCXX/overload.mm
+++ b/test/SemaObjCXX/overload.mm
@@ -60,9 +60,8 @@
   bp = ap; // expected-warning{{incompatible pointer types assigning to 'B **' from 'A **'}}
 }
 
-// FIXME: we should either allow overloading here or give a better diagnostic
-int& cv(A*); // expected-note {{previous declaration}} expected-note 2 {{not viable}}
-float& cv(const A*); // expected-error {{cannot be overloaded}}
+int& cv(A*);
+float& cv(const A*);
 
 int& cv2(void*);
 float& cv2(const void*);
@@ -70,22 +69,20 @@
 void cv_test(A* a, B* b, const A* ac, const B* bc) {
   int &i1 = cv(a);
   int &i2 = cv(b);
-  float &f1 = cv(ac); // expected-error {{no matching function}}
-  float &f2 = cv(bc); // expected-error {{no matching function}}
+  float &f1 = cv(ac);
+  float &f2 = cv(bc);
   int& i3 = cv2(a);
   float& f3 = cv2(ac);
 }
 
-// We agree with GCC that these can't be overloaded.
-int& qualid(id<P0>); // expected-note {{previous declaration}} expected-note {{not viable}}
-float& qualid(id<P1>); // expected-error {{cannot be overloaded}}
+int& qualid(id<P0>);
+float& qualid(id<P1>);
 
 void qualid_test(A *a, B *b, C *c) {
   int& i1 = qualid(a);
   int& i2 = qualid(b);
 
-  // This doesn't work only because the overload was rejected above.
-  float& f1 = qualid(c); // expected-error {{no matching function}}
+  float& f1 = qualid(c);
 
   id<P0> p1 = 0;
   p1 = 0;