[PATCH] Add mangling for protocol-qualified ObjC types

Eli Friedman eli.friedman at gmail.com
Fri Jun 14 17:00:29 PDT 2013


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.

-Eli
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130614/bbb37a7a/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,37 @@
 
   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.
+      QualType chkTy = ArgT;
+      Qualifiers ptrQuals;
+      bool hadPtr = false;
+      if (const PointerType *PT = chkTy->getAs<PointerType>()) {
+        SplitQualType splitPointee = PT->getPointeeType().split();
+        ptrQuals = splitPointee.Quals;
+        chkTy = QualType(splitPointee.Ty, 0);
+        hadPtr = true;
+      }
+      if (const ObjCObjectPointerType *Ptr =
+              chkTy->getAs<ObjCObjectPointerType>()) {
+        ArgT = Ptr->getPointeeType();
+        SplitQualType split = ArgT.split();
+        Qualifiers quals = split.Quals;
+        const ObjCObjectType *ty = split.Ty->castAs<ObjCObjectType>();
+        ArgT = ty->getBaseType();
+        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 +2197,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)) {
+      bool FoundDifferentQuals = false;
       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;
+        if (const PointerType *PTFr = FromType->getAs<PointerType>()) {
+          SplitQualType ToSplit = PTTo->getPointeeType().split();
+          SplitQualType FromSplit = PTFr->getPointeeType().split();
+          ToType = QualType(ToSplit.Ty, 0);
+          FromType = QualType(FromSplit.Ty, 0);
+          if (ToSplit.Quals != FromSplit.Quals)
+            FoundDifferentQuals = true;
+        }
       }
-      else if (const ObjCObjectPointerType *PTTo =
+      if (const ObjCObjectPointerType *PTTo =
                  ToType->getAs<ObjCObjectPointerType>()) {
         if (const ObjCObjectPointerType *PTFr =
-              FromType->getAs<ObjCObjectPointerType>())
-          if (Context.hasSameUnqualifiedType(
-                PTTo->getObjectType()->getBaseType(),
-                PTFr->getObjectType()->getBaseType()))
-            continue;
+              FromType->getAs<ObjCObjectPointerType>()) {
+          SplitQualType ToSplit = PTTo->getPointeeType().split();
+          SplitQualType FromSplit = PTFr->getPointeeType().split();
+          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);


More information about the cfe-commits mailing list