[PATCH] Add mangling for protocol-qualified ObjC types

Eli Friedman eli.friedman at gmail.com
Fri Jun 14 17:54:58 PDT 2013


On Fri, Jun 14, 2013 at 5:00 PM, Eli Friedman <eli.friedman at gmail.com>wrote:

> Attached is a patch to add a mangling for protocol-qualified ObjC types
> (like id<MyProtocol>).  The mangling is pretty straightforward:
>
> <protocol-qualfied-type> ::= U10__protqual <protocol name>+ E <base-type>
>
> This is necessary so we can mangle things like protocol qualified types in
> template parameters without causing a conflict with unqualified types (see,
> e.g. <rdar://problem/14074822>).
>
> The obvious issue here is that this isn't ABI-compatible with previous
> clang versions.  However, the question of ABI-compatibility doesn't
> actually come up in common cases.  clang currently has code in Sema which
> prevents overloading a function based on an argument where the only
> difference is protocol qualification.  Taking advantage of this, this patch
> avoids changing the mangling for any function where protocol qualifications
> only show up in arguments of type ObjC interface pointer and arguments of
> type pointer-to-ObjC interface pointer.  Doug and I think that this is
> enough to avoid the worst of the ABI breakage.
>
> (This patch also changes the relevant overloading code in Sema to be a bit
> more consistent with what it considers an overload, to make IRGen easier to
> implement.)
>
> John, I would appreciate any comments you have.
>

Attaching updated version which fixes a couple bugs.

-Eli
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130614/c2206019/attachment.html>
-------------- next part --------------
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp	(revision 184016)
+++ lib/AST/ItaniumMangle.cpp	(working copy)
@@ -332,7 +332,8 @@
   void mangleType(const TagType*);
   void mangleType(TemplateName);
   void mangleBareFunctionType(const FunctionType *T,
-                              bool MangleReturnType);
+                              bool MangleReturnType,
+                              bool QualProtocolHack);
   void mangleNeonVectorType(const VectorType *T);
 
   void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value);
@@ -480,7 +481,7 @@
   }
 
   mangleBareFunctionType(FD->getType()->getAs<FunctionType>(), 
-                         MangleReturnType);
+                         MangleReturnType, /*QualProtocolHack*/true);
 }
 
 static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
@@ -1352,7 +1353,8 @@
   Out << "Ul";
   const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
                                    getAs<FunctionProtoType>();
-  mangleBareFunctionType(Proto, /*MangleReturnType=*/false);        
+  mangleBareFunctionType(Proto, /*MangleReturnType=*/false,
+                         /*QualProtocolHack*/false);        
   Out << "E";
   
   // The number is omitted for the first closure type with a given 
@@ -1919,7 +1921,8 @@
 
   // FIXME: We don't have enough information in the AST to produce the 'Y'
   // encoding for extern "C" function types.
-  mangleBareFunctionType(T, /*MangleReturnType=*/true);
+  mangleBareFunctionType(T, /*MangleReturnType=*/true,
+                         /*QualProtocolHack*/false);
 
   // Mangle the ref-qualifier, if present.
   mangleRefQualifier(T->getRefQualifier());
@@ -1930,7 +1933,8 @@
   llvm_unreachable("Can't mangle K&R function prototypes");
 }
 void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
-                                            bool MangleReturnType) {
+                                            bool MangleReturnType,
+                                            bool QualProtocolHack) {
   // We should never be mangling something without a prototype.
   const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
 
@@ -1955,8 +1959,39 @@
 
   for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
                                          ArgEnd = Proto->arg_type_end();
-       Arg != ArgEnd; ++Arg)
-    mangleType(Context.getASTContext().getSignatureParameterType(*Arg));
+       Arg != ArgEnd; ++Arg) {
+    QualType argT = Context.getASTContext().getSignatureParameterType(*Arg);
+    if (QualProtocolHack) {
+      // Change the mangling of protocol-qualified id to match the Sema hack
+      // in Sema::FunctionArgTypesAreEqual.
+      const Type *chkTy = argT.getTypePtr();
+      Qualifiers ptrQuals;
+      bool hadPtr = false;
+      if (const PointerType *PT = chkTy->getAs<PointerType>()) {
+        SplitQualType splitPointee =
+            PT->getPointeeType().getSplitDesugaredType();
+        ptrQuals = splitPointee.Quals;
+        chkTy = splitPointee.Ty;
+        hadPtr = true;
+      }
+      if (const ObjCObjectPointerType *Ptr =
+              chkTy->getAs<ObjCObjectPointerType>()) {
+        argT = Ptr->getPointeeType();
+        SplitQualType split = argT.getSplitDesugaredType();
+        Qualifiers quals = split.Quals;
+        const ObjCObjectType *ty = split.Ty->castAs<ObjCObjectType>();
+        argT = ty->getBaseType();
+        argT = Context.getASTContext().getObjCObjectType(argT, 0, 0);
+        argT = Context.getASTContext().getQualifiedType(argT, quals);
+        argT = Context.getASTContext().getObjCObjectPointerType(argT);
+        if (hadPtr) {
+          argT = Context.getASTContext().getQualifiedType(argT, ptrQuals);
+          argT = Context.getASTContext().getPointerType(argT);
+        }
+      }
+    }
+    mangleType(argT);
+  }
 
   FunctionTypeDepth.pop(saved);
 
@@ -2164,8 +2199,16 @@
 }
 
 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.
+    Out << "U10__protqual";
+    ObjCObjectType::qual_iterator i = T->qual_begin(), e = T->qual_end();
+    for ( ; i != e; ++i) {
+      StringRef name = (*i)->getName();
+      Out << name.size() << name;
+    }
+    Out << "E";
+  }
   mangleType(T->getBaseType());
 }
 
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp	(revision 184016)
+++ lib/Sema/SemaOverload.cpp	(working copy)
@@ -2621,23 +2621,32 @@
     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;
+      bool FoundDifferentQuals = false;
+      SplitQualType ToSplit = ToType.getSplitDesugaredType();
+      SplitQualType FromSplit = FromType.getSplitDesugaredType();
+      if (const PointerType *PTTo = ToSplit.Ty->getAs<PointerType>()) {
+        if (const PointerType *PTFr = FromSplit.Ty->getAs<PointerType>()) {
+          ToSplit = PTTo->getPointeeType().getSplitDesugaredType();
+          FromSplit = PTFr->getPointeeType().getSplitDesugaredType();
+          if (ToSplit.Quals != FromSplit.Quals)
+            FoundDifferentQuals = true;
+        }
       }
-      else if (const ObjCObjectPointerType *PTTo =
-                 ToType->getAs<ObjCObjectPointerType>()) {
+      if (const ObjCObjectPointerType *PTTo =
+                 ToSplit.Ty->getAs<ObjCObjectPointerType>()) {
         if (const ObjCObjectPointerType *PTFr =
-              FromType->getAs<ObjCObjectPointerType>())
-          if (Context.hasSameUnqualifiedType(
-                PTTo->getObjectType()->getBaseType(),
-                PTFr->getObjectType()->getBaseType()))
-            continue;
+                   FromSplit.Ty->getAs<ObjCObjectPointerType>()) {
+          ToSplit = PTTo->getPointeeType().getSplitDesugaredType();
+          FromSplit = PTFr->getPointeeType().getSplitDesugaredType();
+          ToType = ToSplit.Ty->castAs<ObjCObjectType>()->getBaseType();
+          FromType = FromSplit.Ty->castAs<ObjCObjectType>()->getBaseType();
+          if (ToSplit.Quals != FromSplit.Quals)
+            FoundDifferentQuals = true;
+        }
       }
+      if (!FoundDifferentQuals && Context.hasSameType(ToType, FromType))
+        continue;
+
       if (ArgPos) *ArgPos = O - OldType->arg_type_begin();
       return false;
     }
Index: test/CodeGenObjCXX/catch-id-type.mm
===================================================================
--- test/CodeGenObjCXX/catch-id-type.mm	(revision 184016)
+++ test/CodeGenObjCXX/catch-id-type.mm	(working copy)
@@ -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* }* @_ZTIPU10__protqual1PE4INTF 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; 
Index: test/CodeGenObjCXX/mangle.mm
===================================================================
--- test/CodeGenObjCXX/mangle.mm	(revision 184016)
+++ test/CodeGenObjCXX/mangle.mm	(working copy)
@@ -78,3 +78,25 @@
   Test2Template<decltype(t.dimension)> t1;
   Test2Template<decltype(t->alt_axis)> t2;
 }
+
+ at protocol P;
+void overload1(A<P>*) {}
+// CHECK: define void @_Z9overload1P1A
+void overload2(A*) {}
+// CHECK: define void @_Z9overload2P1A
+void overload1(const A<P>*) {}
+// CHECK: define void @_Z9overload1PK1A
+void overload1(A<P>**) {}
+// CHECK: define void @_Z9overload1PP1A
+void overload1(A<P>*const*) {}
+// CHECK: define void @_Z9overload1PKP1A
+void overload1(A<P>***) {}
+// CHECK: define void @_Z9overload1PPPU10__protqual1PE1A
+void overload1(void (f)(A<P>*)) {}
+// CHECK: define void @_Z9overload1PFvPU10__protqual1PE1AE
+
+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 @_ZN1XIPU10__protqual1PE1AE1fEv
Index: test/CodeGenObjCXX/rtti.mm
===================================================================
--- test/CodeGenObjCXX/rtti.mm	(revision 184016)
+++ test/CodeGenObjCXX/rtti.mm	(working copy)
@@ -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 {{.*}} @_ZTIPU10__protqual1PE11objc_object
+  // CHECK: store {{.*}} @_ZTIU10__protqual1PE11objc_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 {{.*}} @_ZTIPU10__protqual1PE10objc_class
+  // CHECK: store {{.*}} @_ZTIU10__protqual1PE10objc_class
   Class<P> c2 = 0;
   const std::type_info &t9 = typeid(c2);
   const std::type_info &t10 = typeid(*c2);
Index: test/SemaObjCXX/overload.mm
===================================================================
--- test/SemaObjCXX/overload.mm	(revision 184016)
+++ test/SemaObjCXX/overload.mm	(working copy)
@@ -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,8 +69,8 @@
 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);
 }


More information about the cfe-commits mailing list