From 0601700e8d8e8d0f42bea1c0137c04e8c8ae5ac3 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Tue, 18 Jun 2013 22:41:37 +0000 Subject: 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 . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184250 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ItaniumMangle.cpp | 15 ++++++++++++-- lib/Sema/SemaOverload.cpp | 39 +++---------------------------------- test/CodeGenObjCXX/catch-id-type.mm | 2 +- test/CodeGenObjCXX/mangle.mm | 20 +++++++++++++++++++ test/CodeGenObjCXX/rtti.mm | 8 ++++---- test/SemaObjCXX/overload-1.mm | 25 ------------------------ test/SemaObjCXX/overload.mm | 17 +++++++--------- 7 files changed, 48 insertions(+), 78 deletions(-) delete mode 100644 test/SemaObjCXX/overload-1.mm diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 20f699fafb..1d58e8df04 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -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()); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 5a40b1f8f2..b9daba95f6 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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()) { - if (const PointerType *PTFr = FromType->getAs()) - if ((PTTo->getPointeeType()->isObjCQualifiedIdType() && - PTFr->getPointeeType()->isObjCQualifiedIdType()) || - (PTTo->getPointeeType()->isObjCQualifiedClassType() && - PTFr->getPointeeType()->isObjCQualifiedClassType())) - continue; - } - else if (const ObjCObjectPointerType *PTTo = - ToType->getAs()) { - if (const ObjCObjectPointerType *PTFr = - FromType->getAs()) - 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 2d6cccc0f1..0a2b940ff1 100644 --- a/test/CodeGenObjCXX/catch-id-type.mm +++ b/test/CodeGenObjCXX/catch-id-type.mm @@ -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; diff --git a/test/CodeGenObjCXX/mangle.mm b/test/CodeGenObjCXX/mangle.mm index 45a93a196d..7b2ffe3802 100644 --- a/test/CodeGenObjCXX/mangle.mm +++ b/test/CodeGenObjCXX/mangle.mm @@ -78,3 +78,23 @@ void test2(Test2 *t) { Test2Template t1; Test2Templatealt_axis)> t2; } + +@protocol P; +void overload1(A

*) {} +// CHECK: define void @_Z9overload1PU11objcproto1P1A +void overload1(const A

*) {} +// CHECK: define void @_Z9overload1PKU11objcproto1P1A +void overload1(A

**) {} +// CHECK: define void @_Z9overload1PPU11objcproto1P1A +void overload1(A

*const*) {} +// CHECK: define void @_Z9overload1PKPU11objcproto1P1A +void overload1(A

***) {} +// CHECK: define void @_Z9overload1PPPU11objcproto1P1A +void overload1(void (f)(A

*)) {} +// CHECK: define void @_Z9overload1PFvPU11objcproto1P1AE + +template struct X { void f(); }; +template<> void X::f() {} +// CHECK: define void @_ZN1XIP1AE1fEv +template<> void X*>::f() {} +// CHECK: define void @_ZN1XIPU11objcproto1P1AE1fEv diff --git a/test/CodeGenObjCXX/rtti.mm b/test/CodeGenObjCXX/rtti.mm index 72de3ac980..e458f090a7 100644 --- a/test/CodeGenObjCXX/rtti.mm +++ b/test/CodeGenObjCXX/rtti.mm @@ -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

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

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 fc17ca2be9..0000000000 --- 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 *) { } // expected-note {{previous definition is here}} - -void f(id *) { } // expected-error {{conflicting types for 'f'}} - -void f(Class *) { } // expected-note {{previous definition is here}} - -void f(Class *) { } // expected-error {{conflicting types for 'f'}} - -@interface I @end - -void f(I *) { } // expected-note {{previous definition is here}} - -void f(I *) { } // expected-error {{conflicting types for 'f'}} - -@interface I1 @end - -void f1(I *) { } - -void f1(I1 *) { } diff --git a/test/SemaObjCXX/overload.mm b/test/SemaObjCXX/overload.mm index 6f24c59e3a..bb94d9ed92 100644 --- a/test/SemaObjCXX/overload.mm +++ b/test/SemaObjCXX/overload.mm @@ -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); // expected-note {{previous declaration}} expected-note {{not viable}} -float& qualid(id); // expected-error {{cannot be overloaded}} +int& qualid(id); +float& qualid(id); 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 p1 = 0; p1 = 0; -- cgit v1.2.1