forked from OSchip/llvm-project
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>. llvm-svn: 184250
This commit is contained in:
parent
5222608310
commit
5f508953bc
|
@ -2164,8 +2164,19 @@ void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
|
|||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
|
|
@ -2603,48 +2603,15 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
|
|||
|
||||
/// 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;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ id FUNC() {
|
|||
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;
|
||||
|
|
|
@ -78,3 +78,23 @@ void test2(Test2 *t) {
|
|||
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
|
||||
|
|
|
@ -38,14 +38,14 @@ int main() {
|
|||
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);
|
||||
|
|
|
@ -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> *) { }
|
|
@ -60,9 +60,8 @@ void test2(A** ap) {
|
|||
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 @@ float& cv2(const void*);
|
|||
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;
|
||||
|
|
Loading…
Reference in New Issue