[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