mirror of
https://github.com/intel/llvm.git
synced 2026-01-27 06:06:34 +08:00
Patch to implemented objective-c's dynamic object pointer qualified with
the protocol list (id<P,...> types). llvm-svn: 45121
This commit is contained in:
@@ -49,6 +49,7 @@ void ASTContext::PrintStats() const {
|
||||
|
||||
unsigned NumTagStruct = 0, NumTagUnion = 0, NumTagEnum = 0, NumTagClass = 0;
|
||||
unsigned NumObjcInterfaces = 0, NumObjcQualifiedInterfaces = 0;
|
||||
unsigned NumObjcQualifiedIds = 0;
|
||||
|
||||
for (unsigned i = 0, e = Types.size(); i != e; ++i) {
|
||||
Type *T = Types[i];
|
||||
@@ -83,6 +84,8 @@ void ASTContext::PrintStats() const {
|
||||
++NumObjcInterfaces;
|
||||
else if (isa<ObjcQualifiedInterfaceType>(T))
|
||||
++NumObjcQualifiedInterfaces;
|
||||
else if (isa<ObjcQualifiedIdType>(T))
|
||||
++NumObjcQualifiedIds;
|
||||
else {
|
||||
QualType(T, 0).dump();
|
||||
assert(0 && "Unknown type!");
|
||||
@@ -106,6 +109,8 @@ void ASTContext::PrintStats() const {
|
||||
fprintf(stderr, " %d interface types\n", NumObjcInterfaces);
|
||||
fprintf(stderr, " %d protocol qualified interface types\n",
|
||||
NumObjcQualifiedInterfaces);
|
||||
fprintf(stderr, " %d protocol qualified id types\n",
|
||||
NumObjcQualifiedIds);
|
||||
fprintf(stderr, "Total bytes = %d\n", int(NumBuiltin*sizeof(BuiltinType)+
|
||||
NumPointer*sizeof(PointerType)+NumArray*sizeof(ArrayType)+
|
||||
NumComplex*sizeof(ComplexType)+NumVector*sizeof(VectorType)+
|
||||
@@ -677,7 +682,7 @@ QualType ASTContext::getTypedefType(TypedefDecl *Decl) {
|
||||
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
|
||||
|
||||
QualType Canonical = Decl->getUnderlyingType().getCanonicalType();
|
||||
Decl->TypeForDecl = new TypedefType(Decl, Canonical);
|
||||
Decl->TypeForDecl = new TypedefType(Type::TypeName, Decl, Canonical);
|
||||
Types.push_back(Decl->TypeForDecl);
|
||||
return QualType(Decl->TypeForDecl, 0);
|
||||
}
|
||||
@@ -713,6 +718,29 @@ QualType ASTContext::getObjcQualifiedInterfaceType(ObjcInterfaceDecl *Decl,
|
||||
return QualType(QType, 0);
|
||||
}
|
||||
|
||||
/// getObjcQualifiedIdType - Return a
|
||||
/// getObjcQualifiedIdType type for the given interface decl and
|
||||
/// the conforming protocol list.
|
||||
QualType ASTContext::getObjcQualifiedIdType(TypedefDecl *Decl,
|
||||
ObjcProtocolDecl **Protocols,
|
||||
unsigned NumProtocols) {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
ObjcQualifiedIdType::Profile(ID, Protocols, NumProtocols);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (ObjcQualifiedIdType *QT =
|
||||
ObjcQualifiedIdTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(QT, 0);
|
||||
|
||||
// No Match;
|
||||
QualType Canonical = Decl->getUnderlyingType().getCanonicalType();
|
||||
ObjcQualifiedIdType *QType =
|
||||
new ObjcQualifiedIdType(Decl, Canonical, Protocols, NumProtocols);
|
||||
Types.push_back(QType);
|
||||
ObjcQualifiedIdTypes.InsertNode(QType, InsertPos);
|
||||
return QualType(QType, 0);
|
||||
}
|
||||
|
||||
/// getTypeOfExpr - Unlike many "get<Type>" functions, we can't unique
|
||||
/// TypeOfExpr AST's (since expression's are never shared). For example,
|
||||
/// multiple declarations that refer to "typeof(x)" all contain different
|
||||
@@ -1043,7 +1071,13 @@ void ASTContext::getObjcEncodingForType(QualType T, std::string& S) const
|
||||
}
|
||||
|
||||
S += encoding;
|
||||
} else if (const PointerType *PT = T->getAsPointerType()) {
|
||||
}
|
||||
else if (const ObjcQualifiedIdType *QIT = dyn_cast<ObjcQualifiedIdType>(T)) {
|
||||
// Treat id<P...> same as 'id' for encoding purposes.
|
||||
return getObjcEncodingForType(QIT->getDecl()->getUnderlyingType(), S);
|
||||
|
||||
}
|
||||
else if (const PointerType *PT = T->getAsPointerType()) {
|
||||
QualType PointeeTy = PT->getPointeeType();
|
||||
if (isObjcIdType(PointeeTy) || PointeeTy->isObjcInterfaceType()) {
|
||||
S += '@';
|
||||
@@ -1221,6 +1255,13 @@ bool ASTContext::QualifiedInterfaceTypesAreCompatible(QualType lhs,
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: id<P1,...> vs. id<P,...>
|
||||
#if 0
|
||||
bool ASTContext::QualifiedIdTypesAreCompatible(QualType lhs,
|
||||
QualType rhs) {
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ASTContext::vectorTypesAreCompatible(QualType lhs, QualType rhs) {
|
||||
const VectorType *lVector = lhs->getAsVectorType();
|
||||
const VectorType *rVector = rhs->getAsVectorType();
|
||||
|
||||
@@ -539,6 +539,17 @@ void ObjcQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, &Protocols[0], getNumProtocols());
|
||||
}
|
||||
|
||||
void ObjcQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
ObjcProtocolDecl **protocols,
|
||||
unsigned NumProtocols) {
|
||||
for (unsigned i = 0; i != NumProtocols; i++)
|
||||
ID.AddPointer(protocols[i]);
|
||||
}
|
||||
|
||||
void ObjcQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, &Protocols[0], getNumProtocols());
|
||||
}
|
||||
|
||||
/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
|
||||
/// potentially looking through *all* consequtive typedefs. This returns the
|
||||
/// sum of the type qualifiers, so if you have:
|
||||
@@ -780,6 +791,22 @@ void ObjcQualifiedInterfaceType::getAsStringInternal(
|
||||
InnerString = ObjcQIString + InnerString;
|
||||
}
|
||||
|
||||
void ObjcQualifiedIdType::getAsStringInternal(
|
||||
std::string &InnerString) const {
|
||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
||||
InnerString = ' ' + InnerString;
|
||||
std::string ObjcQIString = "id";
|
||||
ObjcQIString += '<';
|
||||
int num = getNumProtocols();
|
||||
for (int i = 0; i < num; i++) {
|
||||
ObjcQIString += getProtocols(i)->getName();
|
||||
if (i < num-1)
|
||||
ObjcQIString += ',';
|
||||
}
|
||||
ObjcQIString += '>';
|
||||
InnerString = ObjcQIString + InnerString;
|
||||
}
|
||||
|
||||
void TagType::getAsStringInternal(std::string &InnerString) const {
|
||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
||||
InnerString = ' ' + InnerString;
|
||||
|
||||
@@ -224,7 +224,7 @@ Type* TypedefType::CreateImpl(ASTContext& Context, Deserializer& D) {
|
||||
std::vector<Type*>& Types =
|
||||
const_cast<std::vector<Type*>&>(Context.getTypes());
|
||||
|
||||
TypedefType* T = new TypedefType(NULL,QualType::ReadVal(D));
|
||||
TypedefType* T = new TypedefType(Type::TypeName, NULL,QualType::ReadVal(D));
|
||||
Types.push_back(T);
|
||||
|
||||
D.ReadPtr(T->Decl); // May be backpatched.
|
||||
|
||||
@@ -251,6 +251,10 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
|
||||
assert(0 && "FIXME: add missing functionality here");
|
||||
break;
|
||||
|
||||
case Type::ObjcQualifiedId:
|
||||
assert(0 && "FIXME: add missing functionality here");
|
||||
break;
|
||||
|
||||
case Type::Tagged:
|
||||
const TagType &TT = cast<TagType>(Ty);
|
||||
const TagDecl *TD = TT.getDecl();
|
||||
|
||||
@@ -490,7 +490,10 @@ void RewriteTest::RewriteForwardProtocolDecl(ObjcForwardProtocolDecl *PDecl) {
|
||||
void RewriteTest::RewriteObjcMethodDecl(ObjcMethodDecl *OMD,
|
||||
std::string &ResultStr) {
|
||||
ResultStr += "\nstatic ";
|
||||
ResultStr += OMD->getResultType().getAsString();
|
||||
if (isa<ObjcQualifiedIdType>(OMD->getResultType()))
|
||||
ResultStr += "id";
|
||||
else
|
||||
ResultStr += OMD->getResultType().getAsString();
|
||||
ResultStr += "\n";
|
||||
|
||||
// Unique method name
|
||||
@@ -548,7 +551,10 @@ void RewriteTest::RewriteObjcMethodDecl(ObjcMethodDecl *OMD,
|
||||
for (int i = 0; i < OMD->getNumParams(); i++) {
|
||||
ParmVarDecl *PDecl = OMD->getParamDecl(i);
|
||||
ResultStr += ", ";
|
||||
ResultStr += PDecl->getType().getAsString();
|
||||
if (isa<ObjcQualifiedIdType>(PDecl->getType()))
|
||||
ResultStr += "id";
|
||||
else
|
||||
ResultStr += PDecl->getType().getAsString();
|
||||
ResultStr += " ";
|
||||
ResultStr += PDecl->getName();
|
||||
}
|
||||
@@ -989,10 +995,13 @@ static void scanToNextArgument(const char *&argRef) {
|
||||
}
|
||||
|
||||
bool RewriteTest::needToScanForQualifiers(QualType T) {
|
||||
// FIXME: we don't currently represent "id <Protocol>" in the type system.
|
||||
|
||||
if (T == Context->getObjcIdType())
|
||||
return true;
|
||||
|
||||
if (isa<ObjcQualifiedIdType>(T))
|
||||
return true;
|
||||
|
||||
if (const PointerType *pType = T->getAsPointerType()) {
|
||||
Type *pointeeType = pType->getPointeeType().getTypePtr();
|
||||
if (isa<ObjcQualifiedInterfaceType>(pointeeType))
|
||||
@@ -1311,6 +1320,9 @@ ObjcInterfaceDecl *RewriteTest::isSuperReceiver(Expr *recExpr) {
|
||||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
|
||||
if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
|
||||
if (!strcmp(PVD->getName(), "self")) {
|
||||
// is this id<P1..> type?
|
||||
if (isa<ObjcQualifiedIdType>(CE->getType()))
|
||||
return 0;
|
||||
if (const PointerType *PT = CE->getType()->getAsPointerType()) {
|
||||
if (ObjcInterfaceType *IT =
|
||||
dyn_cast<ObjcInterfaceType>(PT->getPointeeType())) {
|
||||
@@ -1504,7 +1516,9 @@ Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
|
||||
// Make all implicit casts explicit...ICE comes in handy:-)
|
||||
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) {
|
||||
// Reuse the ICE type, it is exactly what the doctor ordered.
|
||||
userExpr = new CastExpr(ICE->getType(), userExpr, SourceLocation());
|
||||
userExpr = new CastExpr(isa<ObjcQualifiedIdType>(ICE->getType())
|
||||
? Context->getObjcIdType()
|
||||
: ICE->getType(), userExpr, SourceLocation());
|
||||
}
|
||||
MsgExprs.push_back(userExpr);
|
||||
// We've transferred the ownership to MsgExprs. Null out the argument in
|
||||
@@ -1525,10 +1539,13 @@ Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) {
|
||||
if (ObjcMethodDecl *mDecl = Exp->getMethodDecl()) {
|
||||
// Push any user argument types.
|
||||
for (int i = 0; i < mDecl->getNumParams(); i++) {
|
||||
QualType t = mDecl->getParamDecl(i)->getType();
|
||||
QualType t = isa<ObjcQualifiedIdType>(mDecl->getParamDecl(i)->getType())
|
||||
? Context->getObjcIdType()
|
||||
: mDecl->getParamDecl(i)->getType();
|
||||
ArgTypes.push_back(t);
|
||||
}
|
||||
returnType = mDecl->getResultType();
|
||||
returnType = isa<ObjcQualifiedIdType>(mDecl->getResultType())
|
||||
? Context->getObjcIdType() : mDecl->getResultType();
|
||||
} else {
|
||||
returnType = Context->getObjcIdType();
|
||||
}
|
||||
|
||||
@@ -2292,13 +2292,16 @@ Sema::ExprResult Sema::ActOnInstanceMessage(
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
bool receiverIsQualId =
|
||||
dyn_cast<ObjcQualifiedIdType>(RExpr->getType()) != 0;
|
||||
// FIXME (snaroff): checking in this code from Patrick. Needs to be
|
||||
// revisited. how do we get the ClassDecl from the receiver expression?
|
||||
while (receiverType->isPointerType()) {
|
||||
PointerType *pointerType =
|
||||
static_cast<PointerType*>(receiverType.getTypePtr());
|
||||
receiverType = pointerType->getPointeeType();
|
||||
}
|
||||
if (!receiverIsQualId)
|
||||
while (receiverType->isPointerType()) {
|
||||
PointerType *pointerType =
|
||||
static_cast<PointerType*>(receiverType.getTypePtr());
|
||||
receiverType = pointerType->getPointeeType();
|
||||
}
|
||||
ObjcInterfaceDecl* ClassDecl;
|
||||
if (ObjcQualifiedInterfaceType *QIT =
|
||||
dyn_cast<ObjcQualifiedInterfaceType>(receiverType)) {
|
||||
@@ -2312,6 +2315,23 @@ Sema::ExprResult Sema::ActOnInstanceMessage(
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!Method)
|
||||
Diag(lbrac, diag::warn_method_not_found_in_protocol,
|
||||
std::string("-"), Sel.getName(),
|
||||
SourceRange(lbrac, rbrac));
|
||||
}
|
||||
else if (ObjcQualifiedIdType *QIT =
|
||||
dyn_cast<ObjcQualifiedIdType>(receiverType)) {
|
||||
// search protocols
|
||||
for (unsigned i = 0; i < QIT->getNumProtocols(); i++) {
|
||||
ObjcProtocolDecl *PDecl = QIT->getProtocols(i);
|
||||
if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel)))
|
||||
break;
|
||||
}
|
||||
if (!Method)
|
||||
Diag(lbrac, diag::warn_method_not_found_in_protocol,
|
||||
std::string("-"), Sel.getName(),
|
||||
SourceRange(lbrac, rbrac));
|
||||
}
|
||||
else {
|
||||
assert(ObjcInterfaceType::classof(receiverType.getTypePtr()) &&
|
||||
|
||||
@@ -113,6 +113,16 @@ static QualType ConvertDeclSpecToType(const DeclSpec &DS, ASTContext &Ctx) {
|
||||
reinterpret_cast<ObjcProtocolDecl**>(PPDecl),
|
||||
DS.NumProtocolQualifiers());
|
||||
}
|
||||
else if (TypedefDecl *typeDecl = dyn_cast<TypedefDecl>(D)) {
|
||||
if (Ctx.getObjcIdType() == Ctx.getTypedefType(typeDecl)
|
||||
&& DS.getProtocolQualifiers()) {
|
||||
// id<protocol-list>
|
||||
Action::DeclTy **PPDecl = &(*DS.getProtocolQualifiers())[0];
|
||||
return Ctx.getObjcQualifiedIdType(typeDecl,
|
||||
reinterpret_cast<ObjcProtocolDecl**>(PPDecl),
|
||||
DS.NumProtocolQualifiers());
|
||||
}
|
||||
}
|
||||
// TypeQuals handled by caller.
|
||||
return Ctx.getTypedefType(cast<TypedefDecl>(D));
|
||||
}
|
||||
|
||||
@@ -777,6 +777,7 @@
|
||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
|
||||
compatibilityVersion = "Xcode 2.4";
|
||||
hasScannedForEncodings = 1;
|
||||
mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
|
||||
projectDirPath = "";
|
||||
|
||||
@@ -42,6 +42,7 @@ class ASTContext {
|
||||
llvm::FoldingSet<FunctionTypeNoProto> FunctionTypeNoProtos;
|
||||
llvm::FoldingSet<FunctionTypeProto> FunctionTypeProtos;
|
||||
llvm::FoldingSet<ObjcQualifiedInterfaceType> ObjcQualifiedInterfaceTypes;
|
||||
llvm::FoldingSet<ObjcQualifiedIdType> ObjcQualifiedIdTypes;
|
||||
/// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts.
|
||||
/// This is lazily created. This is intentionally not serialized.
|
||||
llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> ASTRecordLayouts;
|
||||
@@ -168,6 +169,13 @@ public:
|
||||
/// the conforming protocol list.
|
||||
QualType getObjcQualifiedInterfaceType(ObjcInterfaceDecl *Decl,
|
||||
ObjcProtocolDecl **ProtocolList, unsigned NumProtocols);
|
||||
|
||||
/// getObjcQualifiedIdType - Return an ObjcQualifiedIdType for a
|
||||
/// given 'id' and conforming protocol list.
|
||||
QualType getObjcQualifiedIdType(TypedefDecl *Decl,
|
||||
ObjcProtocolDecl **ProtocolList,
|
||||
unsigned NumProtocols);
|
||||
|
||||
|
||||
/// getTypeOfType - GCC extension.
|
||||
QualType getTypeOfExpr(Expr *e);
|
||||
|
||||
@@ -220,6 +220,7 @@ public:
|
||||
FunctionNoProto, FunctionProto,
|
||||
TypeName, Tagged,
|
||||
ObjcInterface, ObjcQualifiedInterface,
|
||||
ObjcQualifiedId,
|
||||
TypeOfExp, TypeOfTyp // GNU typeof extension.
|
||||
};
|
||||
private:
|
||||
@@ -819,7 +820,9 @@ protected:
|
||||
|
||||
class TypedefType : public Type {
|
||||
TypedefDecl *Decl;
|
||||
TypedefType(TypedefDecl *D, QualType can) : Type(TypeName, can), Decl(D) {
|
||||
protected:
|
||||
TypedefType(TypeClass tc, TypedefDecl *D, QualType can)
|
||||
: Type(tc, can), Decl(D) {
|
||||
assert(!isa<TypedefType>(can) && "Invalid canonical type");
|
||||
}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
@@ -951,6 +954,40 @@ public:
|
||||
}
|
||||
static bool classof(const ObjcQualifiedInterfaceType *) { return true; }
|
||||
};
|
||||
|
||||
/// ObjcQualifiedIdType - to represent id<protocol-list>
|
||||
class ObjcQualifiedIdType : public TypedefType,
|
||||
public llvm::FoldingSetNode {
|
||||
// List of protocols for this protocol conforming 'id' type
|
||||
// List is sorted on protocol name. No protocol is enterred more than once.
|
||||
llvm::SmallVector<ObjcProtocolDecl*, 8> Protocols;
|
||||
|
||||
ObjcQualifiedIdType(TypedefDecl *TD, QualType can,
|
||||
ObjcProtocolDecl **Protos, unsigned NumP) :
|
||||
TypedefType(ObjcQualifiedId, TD, can),
|
||||
Protocols(Protos, Protos+NumP) { }
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
public:
|
||||
|
||||
ObjcProtocolDecl *getProtocols(unsigned i) const {
|
||||
return Protocols[i];
|
||||
}
|
||||
unsigned getNumProtocols() const {
|
||||
return Protocols.size();
|
||||
}
|
||||
|
||||
virtual void getAsStringInternal(std::string &InnerString) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
ObjcProtocolDecl **protocols, unsigned NumProtocols);
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == ObjcQualifiedId;
|
||||
}
|
||||
static bool classof(const ObjcQualifiedIdType *) { return true; }
|
||||
|
||||
};
|
||||
|
||||
/// RecordType - This is a helper class that allows the use of isa/cast/dyncast
|
||||
/// to detect TagType objects of structs/unions/classes.
|
||||
|
||||
@@ -470,6 +470,8 @@ DIAG(err_statically_allocated_object, ERROR,
|
||||
"statically allocated Objective-C object '%0'")
|
||||
DIAG(warn_method_not_found, WARNING,
|
||||
"method '%0%1' not found (return type defaults to 'id')")
|
||||
DIAG(warn_method_not_found_in_protocol, WARNING,
|
||||
"method '%0%1' not found in protocol (return type defaults to 'id')")
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Semantic Analysis
|
||||
|
||||
14
clang/test/Sema/id-test-3.m
Normal file
14
clang/test/Sema/id-test-3.m
Normal file
@@ -0,0 +1,14 @@
|
||||
// RUN: clang -rewrite-test %s
|
||||
|
||||
@protocol P
|
||||
- (id<P>) Meth: (id<P>) Arg;
|
||||
@end
|
||||
|
||||
@interface INTF<P>
|
||||
- (id<P>)IMeth;
|
||||
@end
|
||||
|
||||
@implementation INTF
|
||||
- (id<P>)IMeth { return [(id<P>)self Meth: 0]; }
|
||||
- (id<P>) Meth : (id<P>) Arg {}
|
||||
@end
|
||||
16
clang/test/Sema/protocol-id-test-1.m
Normal file
16
clang/test/Sema/protocol-id-test-1.m
Normal file
@@ -0,0 +1,16 @@
|
||||
// RUN: clang -verify %s
|
||||
|
||||
@interface FF
|
||||
- (void) Meth;
|
||||
@end
|
||||
|
||||
@protocol P
|
||||
@end
|
||||
|
||||
@interface INTF<P>
|
||||
- (void)IMeth;
|
||||
@end
|
||||
|
||||
@implementation INTF
|
||||
- (void)IMeth {INTF<P> *pi; [pi Meth]; } // expected-warning {{method '-Meth' not found in protocol (return type defaults to 'id')}}
|
||||
@end
|
||||
14
clang/test/Sema/protocol-id-test-2.m
Normal file
14
clang/test/Sema/protocol-id-test-2.m
Normal file
@@ -0,0 +1,14 @@
|
||||
// RUN: clang -verify %s
|
||||
|
||||
@protocol P
|
||||
@end
|
||||
|
||||
@interface INTF<P>
|
||||
- (void)IMeth;
|
||||
- (void) Meth;
|
||||
@end
|
||||
|
||||
@implementation INTF
|
||||
- (void)IMeth { [(id<P>)self Meth]; } // expected-warning {{method '-Meth' not found in protocol (return type defaults to 'id')}}
|
||||
- (void) Meth {}
|
||||
@end
|
||||
Reference in New Issue
Block a user