зеркало из https://github.com/microsoft/clang-1.git
This patch includes a conceptually simple, but very intrusive/pervasive change.
The idea is to segregate Objective-C "object" pointers from general C pointers (utilizing the recently added ObjCObjectPointerType). The fun starts in Sema::GetTypeForDeclarator(), where "SomeInterface *" is now represented by a single AST node (rather than a PointerType whose Pointee is an ObjCInterfaceType). Since a significant amount of code assumed ObjC object pointers where based on C pointers/structs, this patch is very tedious. It should also explain why it is hard to accomplish this in smaller, self-contained patches. This patch does most of the "heavy lifting" related to moving from PointerType->ObjCObjectPointerType. It doesn't include all potential "cleanups". The good news is additional cleanups can be done later (some are noted in the code). This patch is so large that I didn't want to include any changes that are purely aesthetic. By making the ObjC types truly built-in, they are much easier to work with (and require fewer "hacks"). For example, there is no need for ASTContext::isObjCIdStructType() or ASTContext::isObjCClassStructType()! We believe this change (and the follow-up cleanups) will pay dividends over time. Given the amount of code change, I do expect some fallout from this change (though it does pass all of the clang tests). If you notice any problems, please let us know asap! Thanks. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@75314 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
7ecbfbcddd
Коммит
14108da7f7
|
@ -107,7 +107,6 @@ class ASTContext {
|
||||||
|
|
||||||
/// ObjCIdType - a pseudo built-in typedef type (set by Sema).
|
/// ObjCIdType - a pseudo built-in typedef type (set by Sema).
|
||||||
QualType ObjCIdType;
|
QualType ObjCIdType;
|
||||||
const RecordType *IdStructType;
|
|
||||||
|
|
||||||
/// ObjCSelType - another pseudo built-in typedef type (set by Sema).
|
/// ObjCSelType - another pseudo built-in typedef type (set by Sema).
|
||||||
QualType ObjCSelType;
|
QualType ObjCSelType;
|
||||||
|
@ -119,7 +118,6 @@ class ASTContext {
|
||||||
|
|
||||||
/// ObjCClassType - another pseudo built-in typedef type (set by Sema).
|
/// ObjCClassType - another pseudo built-in typedef type (set by Sema).
|
||||||
QualType ObjCClassType;
|
QualType ObjCClassType;
|
||||||
const RecordType *ClassStructType;
|
|
||||||
|
|
||||||
QualType ObjCConstantStringType;
|
QualType ObjCConstantStringType;
|
||||||
RecordDecl *CFConstantStringTypeDecl;
|
RecordDecl *CFConstantStringTypeDecl;
|
||||||
|
@ -375,7 +373,7 @@ public:
|
||||||
|
|
||||||
/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for the
|
/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for the
|
||||||
/// given interface decl and the conforming protocol list.
|
/// given interface decl and the conforming protocol list.
|
||||||
QualType getObjCObjectPointerType(ObjCInterfaceDecl *Decl,
|
QualType getObjCObjectPointerType(QualType OIT = QualType(),
|
||||||
ObjCProtocolDecl **ProtocolList = 0,
|
ObjCProtocolDecl **ProtocolList = 0,
|
||||||
unsigned NumProtocols = 0);
|
unsigned NumProtocols = 0);
|
||||||
|
|
||||||
|
@ -770,26 +768,18 @@ public:
|
||||||
bool isObjCIdType(QualType T) const {
|
bool isObjCIdType(QualType T) const {
|
||||||
return T == ObjCIdType;
|
return T == ObjCIdType;
|
||||||
}
|
}
|
||||||
bool isObjCIdStructType(QualType T) const {
|
|
||||||
if (!IdStructType) // ObjC isn't enabled
|
|
||||||
return false;
|
|
||||||
return T->getAsStructureType() == IdStructType;
|
|
||||||
}
|
|
||||||
bool isObjCClassType(QualType T) const {
|
bool isObjCClassType(QualType T) const {
|
||||||
return T == ObjCClassType;
|
return T == ObjCClassType;
|
||||||
}
|
}
|
||||||
bool isObjCClassStructType(QualType T) const {
|
|
||||||
if (!ClassStructType) // ObjC isn't enabled
|
|
||||||
return false;
|
|
||||||
return T->getAsStructureType() == ClassStructType;
|
|
||||||
}
|
|
||||||
bool isObjCSelType(QualType T) const {
|
bool isObjCSelType(QualType T) const {
|
||||||
assert(SelStructType && "isObjCSelType used before 'SEL' type is built");
|
assert(SelStructType && "isObjCSelType used before 'SEL' type is built");
|
||||||
return T->getAsStructureType() == SelStructType;
|
return T->getAsStructureType() == SelStructType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the safety of assignment from LHS to RHS
|
// Check the safety of assignment from LHS to RHS
|
||||||
bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
|
bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
|
||||||
|
const ObjCObjectPointerType *RHSOPT);
|
||||||
|
bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
|
||||||
const ObjCInterfaceType *RHS);
|
const ObjCInterfaceType *RHS);
|
||||||
bool areComparableObjCPointerTypes(QualType LHS, QualType RHS);
|
bool areComparableObjCPointerTypes(QualType LHS, QualType RHS);
|
||||||
|
|
||||||
|
|
|
@ -396,9 +396,13 @@ public:
|
||||||
bool isVectorType() const; // GCC vector type.
|
bool isVectorType() const; // GCC vector type.
|
||||||
bool isExtVectorType() const; // Extended vector type.
|
bool isExtVectorType() const; // Extended vector type.
|
||||||
bool isObjCObjectPointerType() const; // Pointer to *any* ObjC object.
|
bool isObjCObjectPointerType() const; // Pointer to *any* ObjC object.
|
||||||
|
// FIXME: change this to 'raw' interface type, so we can used 'interface' type
|
||||||
|
// for the common case.
|
||||||
bool isObjCInterfaceType() const; // NSString or NSString<foo>
|
bool isObjCInterfaceType() const; // NSString or NSString<foo>
|
||||||
bool isObjCQualifiedInterfaceType() const; // NSString<foo>
|
bool isObjCQualifiedInterfaceType() const; // NSString<foo>
|
||||||
bool isObjCQualifiedIdType() const; // id<foo>
|
bool isObjCQualifiedIdType() const; // id<foo>
|
||||||
|
bool isObjCIdType() const; // id
|
||||||
|
bool isObjCClassType() const; // Class
|
||||||
bool isTemplateTypeParmType() const; // C++ template type parameter
|
bool isTemplateTypeParmType() const; // C++ template type parameter
|
||||||
bool isNullPtrType() const; // C++0x nullptr_t
|
bool isNullPtrType() const; // C++0x nullptr_t
|
||||||
|
|
||||||
|
@ -443,9 +447,12 @@ public:
|
||||||
const ComplexType *getAsComplexIntegerType() const; // GCC complex int type.
|
const ComplexType *getAsComplexIntegerType() const; // GCC complex int type.
|
||||||
const ExtVectorType *getAsExtVectorType() const; // Extended vector type.
|
const ExtVectorType *getAsExtVectorType() const; // Extended vector type.
|
||||||
const ObjCObjectPointerType *getAsObjCObjectPointerType() const;
|
const ObjCObjectPointerType *getAsObjCObjectPointerType() const;
|
||||||
|
// The following is a convenience method that returns an ObjCObjectPointerType
|
||||||
|
// for object declared using an interface.
|
||||||
|
const ObjCObjectPointerType *getAsObjCInterfacePointerType() const;
|
||||||
|
const ObjCObjectPointerType *getAsObjCQualifiedIdType() const;
|
||||||
const ObjCInterfaceType *getAsObjCInterfaceType() const;
|
const ObjCInterfaceType *getAsObjCInterfaceType() const;
|
||||||
const ObjCQualifiedInterfaceType *getAsObjCQualifiedInterfaceType() const;
|
const ObjCQualifiedInterfaceType *getAsObjCQualifiedInterfaceType() const;
|
||||||
const ObjCObjectPointerType *getAsObjCQualifiedIdType() const;
|
|
||||||
const TemplateTypeParmType *getAsTemplateTypeParmType() const;
|
const TemplateTypeParmType *getAsTemplateTypeParmType() const;
|
||||||
|
|
||||||
const TemplateSpecializationType *
|
const TemplateSpecializationType *
|
||||||
|
@ -460,6 +467,10 @@ public:
|
||||||
/// This method should never be used when type qualifiers are meaningful.
|
/// This method should never be used when type qualifiers are meaningful.
|
||||||
const Type *getArrayElementTypeNoTypeQual() const;
|
const Type *getArrayElementTypeNoTypeQual() const;
|
||||||
|
|
||||||
|
/// getPointeeType - If this is a pointer or ObjC object pointer, this
|
||||||
|
/// returns the respective pointee.
|
||||||
|
QualType getPointeeType() const;
|
||||||
|
|
||||||
/// getDesugaredType - Return the specified type with any "sugar" removed from
|
/// getDesugaredType - Return the specified type with any "sugar" removed from
|
||||||
/// the type. This takes off typedefs, typeof's etc. If the outer level of
|
/// the type. This takes off typedefs, typeof's etc. If the outer level of
|
||||||
/// the type is already concrete, it returns it unmodified. This is similar
|
/// the type is already concrete, it returns it unmodified. This is similar
|
||||||
|
@ -1809,53 +1820,6 @@ public:
|
||||||
static bool classof(const TypenameType *T) { return true; }
|
static bool classof(const TypenameType *T) { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// ObjCObjectPointerType - Used to represent 'id', 'Interface *', 'id <p>',
|
|
||||||
/// and 'Interface <p> *'.
|
|
||||||
///
|
|
||||||
/// Duplicate protocols are removed and protocol list is canonicalized to be in
|
|
||||||
/// alphabetical order.
|
|
||||||
class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
|
|
||||||
ObjCInterfaceDecl *Decl;
|
|
||||||
// List of protocols for this protocol conforming object type
|
|
||||||
// List is sorted on protocol name. No protocol is entered more than once.
|
|
||||||
llvm::SmallVector<ObjCProtocolDecl*, 8> Protocols;
|
|
||||||
|
|
||||||
ObjCObjectPointerType(ObjCInterfaceDecl *D,
|
|
||||||
ObjCProtocolDecl **Protos, unsigned NumP) :
|
|
||||||
Type(ObjCObjectPointer, QualType(), /*Dependent=*/false),
|
|
||||||
Decl(D), Protocols(Protos, Protos+NumP) { }
|
|
||||||
friend class ASTContext; // ASTContext creates these.
|
|
||||||
|
|
||||||
public:
|
|
||||||
ObjCInterfaceDecl *getDecl() const { return Decl; }
|
|
||||||
|
|
||||||
/// isObjCQualifiedIdType - true for "id <p>".
|
|
||||||
bool isObjCQualifiedIdType() const { return Decl == 0 && Protocols.size(); }
|
|
||||||
|
|
||||||
/// qual_iterator and friends: this provides access to the (potentially empty)
|
|
||||||
/// list of protocols qualifying this interface.
|
|
||||||
typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator;
|
|
||||||
|
|
||||||
qual_iterator qual_begin() const { return Protocols.begin(); }
|
|
||||||
qual_iterator qual_end() const { return Protocols.end(); }
|
|
||||||
bool qual_empty() const { return Protocols.size() == 0; }
|
|
||||||
|
|
||||||
/// getNumProtocols - Return the number of qualifying protocols in this
|
|
||||||
/// interface type, or 0 if there are none.
|
|
||||||
unsigned getNumProtocols() const { return Protocols.size(); }
|
|
||||||
|
|
||||||
void Profile(llvm::FoldingSetNodeID &ID);
|
|
||||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
|
||||||
const ObjCInterfaceDecl *Decl,
|
|
||||||
ObjCProtocolDecl **protocols, unsigned NumProtocols);
|
|
||||||
virtual void getAsStringInternal(std::string &InnerString,
|
|
||||||
const PrintingPolicy &Policy) const;
|
|
||||||
static bool classof(const Type *T) {
|
|
||||||
return T->getTypeClass() == ObjCObjectPointer;
|
|
||||||
}
|
|
||||||
static bool classof(const ObjCObjectPointerType *) { return true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for
|
/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for
|
||||||
/// object oriented design. They basically correspond to C++ classes. There
|
/// object oriented design. They basically correspond to C++ classes. There
|
||||||
/// are two kinds of interface types, normal interfaces like "NSString" and
|
/// are two kinds of interface types, normal interfaces like "NSString" and
|
||||||
|
@ -1868,10 +1832,15 @@ protected:
|
||||||
ObjCInterfaceType(TypeClass tc, ObjCInterfaceDecl *D) :
|
ObjCInterfaceType(TypeClass tc, ObjCInterfaceDecl *D) :
|
||||||
Type(tc, QualType(), /*Dependent=*/false), Decl(D) { }
|
Type(tc, QualType(), /*Dependent=*/false), Decl(D) { }
|
||||||
friend class ASTContext; // ASTContext creates these.
|
friend class ASTContext; // ASTContext creates these.
|
||||||
|
|
||||||
|
// FIXME: These can go away when we move ASTContext::canAssignObjCInterfaces
|
||||||
|
// to this class (as a static helper).
|
||||||
|
bool isObjCIdInterface() const;
|
||||||
|
bool isObjCClassInterface() const;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ObjCInterfaceDecl *getDecl() const { return Decl; }
|
ObjCInterfaceDecl *getDecl() const { return Decl; }
|
||||||
|
|
||||||
/// qual_iterator and friends: this provides access to the (potentially empty)
|
/// qual_iterator and friends: this provides access to the (potentially empty)
|
||||||
/// list of protocols qualifying this interface. If this is an instance of
|
/// list of protocols qualifying this interface. If this is an instance of
|
||||||
/// ObjCQualifiedInterfaceType it returns the list, otherwise it returns an
|
/// ObjCQualifiedInterfaceType it returns the list, otherwise it returns an
|
||||||
|
@ -1893,11 +1862,85 @@ public:
|
||||||
static bool classof(const ObjCInterfaceType *) { return true; }
|
static bool classof(const ObjCInterfaceType *) { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// ObjCObjectPointerType - Used to represent 'id', 'Interface *', 'id <p>',
|
||||||
|
/// and 'Interface <p> *'.
|
||||||
|
///
|
||||||
|
/// Duplicate protocols are removed and protocol list is canonicalized to be in
|
||||||
|
/// alphabetical order.
|
||||||
|
class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
|
||||||
|
QualType PointeeType; // will always point to an interface type.
|
||||||
|
|
||||||
|
// List of protocols for this protocol conforming object type
|
||||||
|
// List is sorted on protocol name. No protocol is entered more than once.
|
||||||
|
llvm::SmallVector<ObjCProtocolDecl*, 8> Protocols;
|
||||||
|
|
||||||
|
ObjCObjectPointerType(QualType T, ObjCProtocolDecl **Protos, unsigned NumP) :
|
||||||
|
Type(ObjCObjectPointer, QualType(), /*Dependent=*/false),
|
||||||
|
PointeeType(T), Protocols(Protos, Protos+NumP) { }
|
||||||
|
friend class ASTContext; // ASTContext creates these.
|
||||||
|
friend class ObjCInterfaceType; // To enable 'id' and 'Class' predicates.
|
||||||
|
|
||||||
|
static ObjCInterfaceType *IdInterfaceT;
|
||||||
|
static ObjCInterfaceType *ClassInterfaceT;
|
||||||
|
static void setIdInterface(QualType T) {
|
||||||
|
IdInterfaceT = dyn_cast<ObjCInterfaceType>(T.getTypePtr());
|
||||||
|
}
|
||||||
|
static void setClassInterface(QualType T) {
|
||||||
|
ClassInterfaceT = dyn_cast<ObjCInterfaceType>(T.getTypePtr());
|
||||||
|
}
|
||||||
|
static ObjCInterfaceType *getIdInterface() { return IdInterfaceT; }
|
||||||
|
static ObjCInterfaceType *getClassInterface() { return ClassInterfaceT; }
|
||||||
|
public:
|
||||||
|
// Get the pointee type. Pointee is required to always be an interface type.
|
||||||
|
// Note: Pointee can be a TypedefType whose canonical type is an interface.
|
||||||
|
// Example: typedef NSObject T; T *var;
|
||||||
|
QualType getPointeeType() const { return PointeeType; }
|
||||||
|
|
||||||
|
const ObjCInterfaceType *getInterfaceType() const {
|
||||||
|
return PointeeType->getAsObjCInterfaceType();
|
||||||
|
}
|
||||||
|
ObjCInterfaceDecl *getInterfaceDecl() const {
|
||||||
|
return getInterfaceType()->getDecl();
|
||||||
|
}
|
||||||
|
/// isObjCQualifiedIdType - true for "id <p>".
|
||||||
|
bool isObjCQualifiedIdType() const {
|
||||||
|
return getInterfaceType() == IdInterfaceT && Protocols.size();
|
||||||
|
}
|
||||||
|
bool isObjCIdType() const {
|
||||||
|
return getInterfaceType() == IdInterfaceT && !Protocols.size();
|
||||||
|
}
|
||||||
|
bool isObjCClassType() const {
|
||||||
|
return getInterfaceType() == ClassInterfaceT && !Protocols.size();
|
||||||
|
}
|
||||||
|
/// qual_iterator and friends: this provides access to the (potentially empty)
|
||||||
|
/// list of protocols qualifying this interface.
|
||||||
|
typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator;
|
||||||
|
|
||||||
|
qual_iterator qual_begin() const { return Protocols.begin(); }
|
||||||
|
qual_iterator qual_end() const { return Protocols.end(); }
|
||||||
|
bool qual_empty() const { return Protocols.size() == 0; }
|
||||||
|
|
||||||
|
/// getNumProtocols - Return the number of qualifying protocols in this
|
||||||
|
/// interface type, or 0 if there are none.
|
||||||
|
unsigned getNumProtocols() const { return Protocols.size(); }
|
||||||
|
|
||||||
|
void Profile(llvm::FoldingSetNodeID &ID);
|
||||||
|
static void Profile(llvm::FoldingSetNodeID &ID, QualType T,
|
||||||
|
ObjCProtocolDecl **protocols, unsigned NumProtocols);
|
||||||
|
virtual void getAsStringInternal(std::string &InnerString,
|
||||||
|
const PrintingPolicy &Policy) const;
|
||||||
|
static bool classof(const Type *T) {
|
||||||
|
return T->getTypeClass() == ObjCObjectPointer;
|
||||||
|
}
|
||||||
|
static bool classof(const ObjCObjectPointerType *) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
/// ObjCQualifiedInterfaceType - This class represents interface types
|
/// ObjCQualifiedInterfaceType - This class represents interface types
|
||||||
/// conforming to a list of protocols, such as INTF<Proto1, Proto2, Proto1>.
|
/// conforming to a list of protocols, such as INTF<Proto1, Proto2, Proto1>.
|
||||||
///
|
///
|
||||||
/// Duplicate protocols are removed and protocol list is canonicalized to be in
|
/// Duplicate protocols are removed and protocol list is canonicalized to be in
|
||||||
/// alphabetical order.
|
/// alphabetical order.
|
||||||
|
/// FIXME: Remove this class (converting uses to ObjCObjectPointerType).
|
||||||
class ObjCQualifiedInterfaceType : public ObjCInterfaceType,
|
class ObjCQualifiedInterfaceType : public ObjCInterfaceType,
|
||||||
public llvm::FoldingSetNode {
|
public llvm::FoldingSetNode {
|
||||||
|
|
||||||
|
@ -1983,7 +2026,7 @@ inline QualType::GCAttrTypes QualType::getObjCGCAttr() const {
|
||||||
return AT->getElementType().getObjCGCAttr();
|
return AT->getElementType().getObjCGCAttr();
|
||||||
if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CT))
|
if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CT))
|
||||||
return EXTQT->getObjCGCAttr();
|
return EXTQT->getObjCGCAttr();
|
||||||
if (const PointerType *PT = CT->getAsPointerType())
|
if (const ObjCObjectPointerType *PT = CT->getAsObjCObjectPointerType())
|
||||||
return PT->getPointeeType().getObjCGCAttr();
|
return PT->getPointeeType().getObjCGCAttr();
|
||||||
return GCNone;
|
return GCNone;
|
||||||
}
|
}
|
||||||
|
@ -2115,6 +2158,18 @@ inline bool Type::isObjCQualifiedIdType() const {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
inline bool Type::isObjCIdType() const {
|
||||||
|
if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType()) {
|
||||||
|
return OPT->isObjCIdType();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
inline bool Type::isObjCClassType() const {
|
||||||
|
if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType()) {
|
||||||
|
return OPT->isObjCClassType();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
inline bool Type::isTemplateTypeParmType() const {
|
inline bool Type::isTemplateTypeParmType() const {
|
||||||
return isa<TemplateTypeParmType>(CanonicalType.getUnqualifiedType());
|
return isa<TemplateTypeParmType>(CanonicalType.getUnqualifiedType());
|
||||||
}
|
}
|
||||||
|
@ -2134,12 +2189,12 @@ inline bool Type::isOverloadableType() const {
|
||||||
|
|
||||||
inline bool Type::hasPointerRepresentation() const {
|
inline bool Type::hasPointerRepresentation() const {
|
||||||
return (isPointerType() || isReferenceType() || isBlockPointerType() ||
|
return (isPointerType() || isReferenceType() || isBlockPointerType() ||
|
||||||
isObjCInterfaceType() || isObjCQualifiedIdType() ||
|
isObjCInterfaceType() || isObjCObjectPointerType() ||
|
||||||
isObjCQualifiedInterfaceType() || isNullPtrType());
|
isObjCQualifiedInterfaceType() || isNullPtrType());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Type::hasObjCPointerRepresentation() const {
|
inline bool Type::hasObjCPointerRepresentation() const {
|
||||||
return (isObjCInterfaceType() || isObjCQualifiedIdType() ||
|
return (isObjCInterfaceType() || isObjCObjectPointerType() ||
|
||||||
isObjCQualifiedInterfaceType());
|
isObjCQualifiedInterfaceType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool IsLocType(QualType T) {
|
static inline bool IsLocType(QualType T) {
|
||||||
return T->isPointerType() || T->isObjCQualifiedIdType()
|
return T->isPointerType() || T->isObjCObjectPointerType()
|
||||||
|| T->isBlockPointerType();
|
|| T->isBlockPointerType();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,8 +42,8 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
|
||||||
Idents(idents), Selectors(sels),
|
Idents(idents), Selectors(sels),
|
||||||
BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {
|
BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {
|
||||||
if (size_reserve > 0) Types.reserve(size_reserve);
|
if (size_reserve > 0) Types.reserve(size_reserve);
|
||||||
InitBuiltinTypes();
|
|
||||||
TUDecl = TranslationUnitDecl::Create(*this);
|
TUDecl = TranslationUnitDecl::Create(*this);
|
||||||
|
InitBuiltinTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTContext::~ASTContext() {
|
ASTContext::~ASTContext() {
|
||||||
|
@ -190,11 +190,10 @@ void ASTContext::InitBuiltinTypes() {
|
||||||
LongDoubleComplexTy = getComplexType(LongDoubleTy);
|
LongDoubleComplexTy = getComplexType(LongDoubleTy);
|
||||||
|
|
||||||
BuiltinVaListType = QualType();
|
BuiltinVaListType = QualType();
|
||||||
ObjCIdType = QualType();
|
|
||||||
IdStructType = 0;
|
|
||||||
ObjCClassType = QualType();
|
|
||||||
ClassStructType = 0;
|
|
||||||
|
|
||||||
|
ObjCIdType = QualType();
|
||||||
|
ObjCClassType = QualType();
|
||||||
|
|
||||||
ObjCConstantStringType = QualType();
|
ObjCConstantStringType = QualType();
|
||||||
|
|
||||||
// void * type
|
// void * type
|
||||||
|
@ -1071,7 +1070,7 @@ QualType ASTContext::getObjCGCQualType(QualType T,
|
||||||
|
|
||||||
if (T->isPointerType()) {
|
if (T->isPointerType()) {
|
||||||
QualType Pointee = T->getAsPointerType()->getPointeeType();
|
QualType Pointee = T->getAsPointerType()->getPointeeType();
|
||||||
if (Pointee->isPointerType()) {
|
if (Pointee->isPointerType() || Pointee->isObjCObjectPointerType()) {
|
||||||
QualType ResultType = getObjCGCQualType(Pointee, GCAttr);
|
QualType ResultType = getObjCGCQualType(Pointee, GCAttr);
|
||||||
return getPointerType(ResultType);
|
return getPointerType(ResultType);
|
||||||
}
|
}
|
||||||
|
@ -1847,15 +1846,18 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols,
|
||||||
|
|
||||||
/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for
|
/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for
|
||||||
/// the given interface decl and the conforming protocol list.
|
/// the given interface decl and the conforming protocol list.
|
||||||
QualType ASTContext::getObjCObjectPointerType(ObjCInterfaceDecl *Decl,
|
QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT,
|
||||||
ObjCProtocolDecl **Protocols,
|
ObjCProtocolDecl **Protocols,
|
||||||
unsigned NumProtocols) {
|
unsigned NumProtocols) {
|
||||||
|
if (InterfaceT.isNull())
|
||||||
|
InterfaceT = QualType(ObjCObjectPointerType::getIdInterface(), 0);
|
||||||
|
|
||||||
// Sort the protocol list alphabetically to canonicalize it.
|
// Sort the protocol list alphabetically to canonicalize it.
|
||||||
if (NumProtocols)
|
if (NumProtocols)
|
||||||
SortAndUniqueProtocols(Protocols, NumProtocols);
|
SortAndUniqueProtocols(Protocols, NumProtocols);
|
||||||
|
|
||||||
llvm::FoldingSetNodeID ID;
|
llvm::FoldingSetNodeID ID;
|
||||||
ObjCObjectPointerType::Profile(ID, Decl, Protocols, NumProtocols);
|
ObjCObjectPointerType::Profile(ID, InterfaceT, Protocols, NumProtocols);
|
||||||
|
|
||||||
void *InsertPos = 0;
|
void *InsertPos = 0;
|
||||||
if (ObjCObjectPointerType *QT =
|
if (ObjCObjectPointerType *QT =
|
||||||
|
@ -1864,7 +1866,7 @@ QualType ASTContext::getObjCObjectPointerType(ObjCInterfaceDecl *Decl,
|
||||||
|
|
||||||
// No Match;
|
// No Match;
|
||||||
ObjCObjectPointerType *QType =
|
ObjCObjectPointerType *QType =
|
||||||
new (*this,8) ObjCObjectPointerType(Decl, Protocols, NumProtocols);
|
new (*this,8) ObjCObjectPointerType(InterfaceT, Protocols, NumProtocols);
|
||||||
|
|
||||||
Types.push_back(QType);
|
Types.push_back(QType);
|
||||||
ObjCObjectPointerTypes.InsertNode(QType, InsertPos);
|
ObjCObjectPointerTypes.InsertNode(QType, InsertPos);
|
||||||
|
@ -2745,25 +2747,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
|
||||||
S += 'j';
|
S += 'j';
|
||||||
getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false,
|
getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false,
|
||||||
false);
|
false);
|
||||||
} else if (T->isObjCQualifiedIdType()) {
|
}
|
||||||
getObjCEncodingForTypeImpl(getObjCIdType(), S,
|
|
||||||
ExpandPointedToStructures,
|
|
||||||
ExpandStructures, FD);
|
|
||||||
if (FD || EncodingProperty) {
|
|
||||||
// Note that we do extended encoding of protocol qualifer list
|
|
||||||
// Only when doing ivar or property encoding.
|
|
||||||
const ObjCObjectPointerType *QIDT = T->getAsObjCQualifiedIdType();
|
|
||||||
S += '"';
|
|
||||||
for (ObjCObjectPointerType::qual_iterator I = QIDT->qual_begin(),
|
|
||||||
E = QIDT->qual_end(); I != E; ++I) {
|
|
||||||
S += '<';
|
|
||||||
S += (*I)->getNameAsString();
|
|
||||||
S += '>';
|
|
||||||
}
|
|
||||||
S += '"';
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (const PointerType *PT = T->getAsPointerType()) {
|
else if (const PointerType *PT = T->getAsPointerType()) {
|
||||||
QualType PointeeTy = PT->getPointeeType();
|
QualType PointeeTy = PT->getPointeeType();
|
||||||
bool isReadOnly = false;
|
bool isReadOnly = false;
|
||||||
|
@ -2797,42 +2781,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
|
||||||
S.replace(S.end()-2, S.end(), replace);
|
S.replace(S.end()-2, S.end(), replace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isObjCIdStructType(PointeeTy)) {
|
if (isObjCSelType(PointeeTy)) {
|
||||||
S += '@';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (PointeeTy->isObjCInterfaceType()) {
|
|
||||||
if (!EncodingProperty &&
|
|
||||||
isa<TypedefType>(PointeeTy.getTypePtr())) {
|
|
||||||
// Another historical/compatibility reason.
|
|
||||||
// We encode the underlying type which comes out as
|
|
||||||
// {...};
|
|
||||||
S += '^';
|
|
||||||
getObjCEncodingForTypeImpl(PointeeTy, S,
|
|
||||||
false, ExpandPointedToStructures,
|
|
||||||
NULL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
S += '@';
|
|
||||||
if (FD || EncodingProperty) {
|
|
||||||
const ObjCInterfaceType *OIT =
|
|
||||||
PointeeTy.getUnqualifiedType()->getAsObjCInterfaceType();
|
|
||||||
ObjCInterfaceDecl *OI = OIT->getDecl();
|
|
||||||
S += '"';
|
|
||||||
S += OI->getNameAsCString();
|
|
||||||
for (ObjCInterfaceType::qual_iterator I = OIT->qual_begin(),
|
|
||||||
E = OIT->qual_end(); I != E; ++I) {
|
|
||||||
S += '<';
|
|
||||||
S += (*I)->getNameAsString();
|
|
||||||
S += '>';
|
|
||||||
}
|
|
||||||
S += '"';
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else if (isObjCClassStructType(PointeeTy)) {
|
|
||||||
S += '#';
|
|
||||||
return;
|
|
||||||
} else if (isObjCSelType(PointeeTy)) {
|
|
||||||
S += ':';
|
S += ':';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2937,7 +2886,61 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
|
||||||
}
|
}
|
||||||
S += '}';
|
S += '}';
|
||||||
}
|
}
|
||||||
else
|
else if (const ObjCObjectPointerType *OPT = T->getAsObjCObjectPointerType()) {
|
||||||
|
if (OPT->isObjCIdType()) {
|
||||||
|
S += '@';
|
||||||
|
return;
|
||||||
|
} else if (OPT->isObjCClassType()) {
|
||||||
|
S += '#';
|
||||||
|
return;
|
||||||
|
} else if (OPT->isObjCQualifiedIdType()) {
|
||||||
|
getObjCEncodingForTypeImpl(getObjCIdType(), S,
|
||||||
|
ExpandPointedToStructures,
|
||||||
|
ExpandStructures, FD);
|
||||||
|
if (FD || EncodingProperty) {
|
||||||
|
// Note that we do extended encoding of protocol qualifer list
|
||||||
|
// Only when doing ivar or property encoding.
|
||||||
|
const ObjCObjectPointerType *QIDT = T->getAsObjCQualifiedIdType();
|
||||||
|
S += '"';
|
||||||
|
for (ObjCObjectPointerType::qual_iterator I = QIDT->qual_begin(),
|
||||||
|
E = QIDT->qual_end(); I != E; ++I) {
|
||||||
|
S += '<';
|
||||||
|
S += (*I)->getNameAsString();
|
||||||
|
S += '>';
|
||||||
|
}
|
||||||
|
S += '"';
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
QualType PointeeTy = OPT->getPointeeType();
|
||||||
|
if (!EncodingProperty &&
|
||||||
|
isa<TypedefType>(PointeeTy.getTypePtr())) {
|
||||||
|
// Another historical/compatibility reason.
|
||||||
|
// We encode the underlying type which comes out as
|
||||||
|
// {...};
|
||||||
|
S += '^';
|
||||||
|
getObjCEncodingForTypeImpl(PointeeTy, S,
|
||||||
|
false, ExpandPointedToStructures,
|
||||||
|
NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
S += '@';
|
||||||
|
if (FD || EncodingProperty) {
|
||||||
|
const ObjCInterfaceType *OIT = OPT->getInterfaceType();
|
||||||
|
ObjCInterfaceDecl *OI = OIT->getDecl();
|
||||||
|
S += '"';
|
||||||
|
S += OI->getNameAsCString();
|
||||||
|
for (ObjCInterfaceType::qual_iterator I = OIT->qual_begin(),
|
||||||
|
E = OIT->qual_end(); I != E; ++I) {
|
||||||
|
S += '<';
|
||||||
|
S += (*I)->getNameAsString();
|
||||||
|
S += '>';
|
||||||
|
}
|
||||||
|
S += '"';
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else
|
||||||
assert(0 && "@encode for type not implemented!");
|
assert(0 && "@encode for type not implemented!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2967,23 +2970,12 @@ void ASTContext::setBuiltinVaListType(QualType T)
|
||||||
void ASTContext::setObjCIdType(QualType T)
|
void ASTContext::setObjCIdType(QualType T)
|
||||||
{
|
{
|
||||||
ObjCIdType = T;
|
ObjCIdType = T;
|
||||||
|
|
||||||
const TypedefType *TT = T->getAsTypedefType();
|
const TypedefType *TT = T->getAsTypedefType();
|
||||||
if (!TT)
|
assert(TT && "missing 'id' typedef");
|
||||||
return;
|
const ObjCObjectPointerType *OPT =
|
||||||
|
TT->getDecl()->getUnderlyingType()->getAsObjCObjectPointerType();
|
||||||
TypedefDecl *TD = TT->getDecl();
|
assert(OPT && "missing 'id' type");
|
||||||
|
ObjCObjectPointerType::setIdInterface(OPT->getPointeeType());
|
||||||
// typedef struct objc_object *id;
|
|
||||||
const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType();
|
|
||||||
// User error - caller will issue diagnostics.
|
|
||||||
if (!ptr)
|
|
||||||
return;
|
|
||||||
const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
|
|
||||||
// User error - caller will issue diagnostics.
|
|
||||||
if (!rec)
|
|
||||||
return;
|
|
||||||
IdStructType = rec;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTContext::setObjCSelType(QualType T)
|
void ASTContext::setObjCSelType(QualType T)
|
||||||
|
@ -3013,18 +3005,12 @@ void ASTContext::setObjCProtoType(QualType QT)
|
||||||
void ASTContext::setObjCClassType(QualType T)
|
void ASTContext::setObjCClassType(QualType T)
|
||||||
{
|
{
|
||||||
ObjCClassType = T;
|
ObjCClassType = T;
|
||||||
|
|
||||||
const TypedefType *TT = T->getAsTypedefType();
|
const TypedefType *TT = T->getAsTypedefType();
|
||||||
if (!TT)
|
assert(TT && "missing 'Class' typedef");
|
||||||
return;
|
const ObjCObjectPointerType *OPT =
|
||||||
TypedefDecl *TD = TT->getDecl();
|
TT->getDecl()->getUnderlyingType()->getAsObjCObjectPointerType();
|
||||||
|
assert(OPT && "missing 'Class' type");
|
||||||
// typedef struct objc_class *Class;
|
ObjCObjectPointerType::setClassInterface(OPT->getPointeeType());
|
||||||
const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType();
|
|
||||||
assert(ptr && "'Class' incorrectly typed");
|
|
||||||
const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
|
|
||||||
assert(rec && "'Class' incorrectly typed");
|
|
||||||
ClassStructType = rec;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
|
void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
|
||||||
|
@ -3123,6 +3109,8 @@ bool ASTContext::isObjCNSObjectType(QualType Ty) const {
|
||||||
/// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified
|
/// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified
|
||||||
/// ID type).
|
/// ID type).
|
||||||
bool ASTContext::isObjCObjectPointerType(QualType Ty) const {
|
bool ASTContext::isObjCObjectPointerType(QualType Ty) const {
|
||||||
|
if (Ty->isObjCObjectPointerType())
|
||||||
|
return true;
|
||||||
if (Ty->isObjCQualifiedIdType())
|
if (Ty->isObjCQualifiedIdType())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -3198,8 +3186,30 @@ static bool areCompatVectorTypes(const VectorType *LHS,
|
||||||
/// compatible for assignment from RHS to LHS. This handles validation of any
|
/// compatible for assignment from RHS to LHS. This handles validation of any
|
||||||
/// protocol qualifiers on the LHS or RHS.
|
/// protocol qualifiers on the LHS or RHS.
|
||||||
///
|
///
|
||||||
|
/// FIXME: Move the following to ObjCObjectPointerType/ObjCInterfaceType.
|
||||||
|
bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
|
||||||
|
const ObjCObjectPointerType *RHSOPT) {
|
||||||
|
// If either interface represents the built-in 'id' or 'Class' types,
|
||||||
|
// then return true (no need to call canAssignObjCInterfaces()).
|
||||||
|
if (LHSOPT->isObjCIdType() || RHSOPT->isObjCIdType() ||
|
||||||
|
LHSOPT->isObjCClassType() || RHSOPT->isObjCClassType())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
|
||||||
|
const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
|
||||||
|
if (!LHS || !RHS)
|
||||||
|
return false;
|
||||||
|
return canAssignObjCInterfaces(LHS, RHS);
|
||||||
|
}
|
||||||
|
|
||||||
bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
|
bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
|
||||||
const ObjCInterfaceType *RHS) {
|
const ObjCInterfaceType *RHS) {
|
||||||
|
// If either interface represents the built-in 'id' or 'Class' types,
|
||||||
|
// then return true.
|
||||||
|
if (LHS->isObjCIdInterface() || RHS->isObjCIdInterface() ||
|
||||||
|
LHS->isObjCClassInterface() || RHS->isObjCClassInterface())
|
||||||
|
return true;
|
||||||
|
|
||||||
// Verify that the base decls are compatible: the RHS must be a subclass of
|
// Verify that the base decls are compatible: the RHS must be a subclass of
|
||||||
// the LHS.
|
// the LHS.
|
||||||
if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
|
if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
|
||||||
|
@ -3245,25 +3255,14 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
|
||||||
|
|
||||||
bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {
|
bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {
|
||||||
// get the "pointed to" types
|
// get the "pointed to" types
|
||||||
const PointerType *LHSPT = LHS->getAsPointerType();
|
const ObjCObjectPointerType *LHSOPT = LHS->getAsObjCObjectPointerType();
|
||||||
const PointerType *RHSPT = RHS->getAsPointerType();
|
const ObjCObjectPointerType *RHSOPT = RHS->getAsObjCObjectPointerType();
|
||||||
|
|
||||||
if (!LHSPT || !RHSPT)
|
if (!LHSOPT || !RHSOPT)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QualType lhptee = LHSPT->getPointeeType();
|
return canAssignObjCInterfaces(LHSOPT, RHSOPT) ||
|
||||||
QualType rhptee = RHSPT->getPointeeType();
|
canAssignObjCInterfaces(RHSOPT, LHSOPT);
|
||||||
const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType();
|
|
||||||
const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType();
|
|
||||||
// ID acts sort of like void* for ObjC interfaces
|
|
||||||
if (LHSIface && isObjCIdStructType(rhptee))
|
|
||||||
return true;
|
|
||||||
if (RHSIface && isObjCIdStructType(lhptee))
|
|
||||||
return true;
|
|
||||||
if (!LHSIface || !RHSIface)
|
|
||||||
return false;
|
|
||||||
return canAssignObjCInterfaces(LHSIface, RHSIface) ||
|
|
||||||
canAssignObjCInterfaces(RHSIface, LHSIface);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible,
|
/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible,
|
||||||
|
@ -3406,8 +3405,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
|
||||||
// issue error.
|
// issue error.
|
||||||
if ((GCAttr == QualType::Weak && GCLHSAttr != GCAttr) ||
|
if ((GCAttr == QualType::Weak && GCLHSAttr != GCAttr) ||
|
||||||
(GCAttr == QualType::Strong && GCLHSAttr != GCAttr &&
|
(GCAttr == QualType::Strong && GCLHSAttr != GCAttr &&
|
||||||
LHSCan->isPointerType() && !isObjCObjectPointerType(LHSCan) &&
|
!LHSCan->isObjCObjectPointerType()))
|
||||||
!isObjCIdStructType(LHSCan->getAsPointerType()->getPointeeType())))
|
|
||||||
return QualType();
|
return QualType();
|
||||||
|
|
||||||
RHS = QualType(cast<ExtQualType>(RHS.getDesugaredType())->getBaseType(),
|
RHS = QualType(cast<ExtQualType>(RHS.getDesugaredType())->getBaseType(),
|
||||||
|
@ -3432,8 +3430,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
|
||||||
// issue error.
|
// issue error.
|
||||||
if ((GCAttr == QualType::Weak && GCRHSAttr != GCAttr) ||
|
if ((GCAttr == QualType::Weak && GCRHSAttr != GCAttr) ||
|
||||||
(GCAttr == QualType::Strong && GCRHSAttr != GCAttr &&
|
(GCAttr == QualType::Strong && GCRHSAttr != GCAttr &&
|
||||||
RHSCan->isPointerType() && !isObjCObjectPointerType(RHSCan) &&
|
!RHSCan->isObjCObjectPointerType()))
|
||||||
!isObjCIdStructType(RHSCan->getAsPointerType()->getPointeeType())))
|
|
||||||
return QualType();
|
return QualType();
|
||||||
|
|
||||||
LHS = QualType(cast<ExtQualType>(LHS.getDesugaredType())->getBaseType(),
|
LHS = QualType(cast<ExtQualType>(LHS.getDesugaredType())->getBaseType(),
|
||||||
|
@ -3460,47 +3457,12 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
|
||||||
if (RHSClass == Type::ExtVector) RHSClass = Type::Vector;
|
if (RHSClass == Type::ExtVector) RHSClass = Type::Vector;
|
||||||
|
|
||||||
// Consider qualified interfaces and interfaces the same.
|
// Consider qualified interfaces and interfaces the same.
|
||||||
|
// FIXME: Remove (ObjCObjectPointerType should obsolete this funny business).
|
||||||
if (LHSClass == Type::ObjCQualifiedInterface) LHSClass = Type::ObjCInterface;
|
if (LHSClass == Type::ObjCQualifiedInterface) LHSClass = Type::ObjCInterface;
|
||||||
if (RHSClass == Type::ObjCQualifiedInterface) RHSClass = Type::ObjCInterface;
|
if (RHSClass == Type::ObjCQualifiedInterface) RHSClass = Type::ObjCInterface;
|
||||||
|
|
||||||
// If the canonical type classes don't match.
|
// If the canonical type classes don't match.
|
||||||
if (LHSClass != RHSClass) {
|
if (LHSClass != RHSClass) {
|
||||||
const ObjCInterfaceType* LHSIface = LHS->getAsObjCInterfaceType();
|
|
||||||
const ObjCInterfaceType* RHSIface = RHS->getAsObjCInterfaceType();
|
|
||||||
|
|
||||||
// 'id' and 'Class' act sort of like void* for ObjC interfaces
|
|
||||||
if (LHSIface && (isObjCIdStructType(RHS) || isObjCClassStructType(RHS)))
|
|
||||||
return LHS;
|
|
||||||
if (RHSIface && (isObjCIdStructType(LHS) || isObjCClassStructType(LHS)))
|
|
||||||
return RHS;
|
|
||||||
|
|
||||||
// ID is compatible with all qualified id types.
|
|
||||||
if (LHS->isObjCQualifiedIdType()) {
|
|
||||||
if (const PointerType *PT = RHS->getAsPointerType()) {
|
|
||||||
QualType pType = PT->getPointeeType();
|
|
||||||
if (isObjCIdStructType(pType) || isObjCClassStructType(pType))
|
|
||||||
return LHS;
|
|
||||||
// FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true).
|
|
||||||
// Unfortunately, this API is part of Sema (which we don't have access
|
|
||||||
// to. Need to refactor. The following check is insufficient, since we
|
|
||||||
// need to make sure the class implements the protocol.
|
|
||||||
if (pType->isObjCInterfaceType())
|
|
||||||
return LHS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (RHS->isObjCQualifiedIdType()) {
|
|
||||||
if (const PointerType *PT = LHS->getAsPointerType()) {
|
|
||||||
QualType pType = PT->getPointeeType();
|
|
||||||
if (isObjCIdStructType(pType) || isObjCClassStructType(pType))
|
|
||||||
return RHS;
|
|
||||||
// FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true).
|
|
||||||
// Unfortunately, this API is part of Sema (which we don't have access
|
|
||||||
// to. Need to refactor. The following check is insufficient, since we
|
|
||||||
// need to make sure the class implements the protocol.
|
|
||||||
if (pType->isObjCInterfaceType())
|
|
||||||
return RHS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
|
// C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
|
||||||
// a signed integer type, or an unsigned integer type.
|
// a signed integer type, or an unsigned integer type.
|
||||||
if (const EnumType* ETy = LHS->getAsEnumType()) {
|
if (const EnumType* ETy = LHS->getAsEnumType()) {
|
||||||
|
@ -3611,9 +3573,6 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
|
||||||
return mergeFunctionTypes(LHS, RHS);
|
return mergeFunctionTypes(LHS, RHS);
|
||||||
case Type::Record:
|
case Type::Record:
|
||||||
case Type::Enum:
|
case Type::Enum:
|
||||||
// FIXME: Why are these compatible?
|
|
||||||
if (isObjCIdStructType(LHS) && isObjCClassStructType(RHS)) return LHS;
|
|
||||||
if (isObjCClassStructType(LHS) && isObjCIdStructType(RHS)) return LHS;
|
|
||||||
return QualType();
|
return QualType();
|
||||||
case Type::Builtin:
|
case Type::Builtin:
|
||||||
// Only exactly equal builtin types are compatible, which is tested above.
|
// Only exactly equal builtin types are compatible, which is tested above.
|
||||||
|
@ -3638,10 +3597,17 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
|
||||||
|
|
||||||
return QualType();
|
return QualType();
|
||||||
}
|
}
|
||||||
case Type::ObjCObjectPointer:
|
case Type::ObjCObjectPointer: {
|
||||||
// FIXME: finish
|
// FIXME: Incorporate tests from Sema::ObjCQualifiedIdTypesAreCompatible().
|
||||||
// Distinct qualified id's are not compatible.
|
if (LHS->isObjCQualifiedIdType() && RHS->isObjCQualifiedIdType())
|
||||||
|
return QualType();
|
||||||
|
|
||||||
|
if (canAssignObjCInterfaces(LHS->getAsObjCObjectPointerType(),
|
||||||
|
RHS->getAsObjCObjectPointerType()))
|
||||||
|
return LHS;
|
||||||
|
|
||||||
return QualType();
|
return QualType();
|
||||||
|
}
|
||||||
case Type::FixedWidthInt:
|
case Type::FixedWidthInt:
|
||||||
// Distinct fixed-width integers are not compatible.
|
// Distinct fixed-width integers are not compatible.
|
||||||
return QualType();
|
return QualType();
|
||||||
|
|
|
@ -280,7 +280,7 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
|
||||||
// of the interface (which has been reported). Recover gracefully.
|
// of the interface (which has been reported). Recover gracefully.
|
||||||
if (OID) {
|
if (OID) {
|
||||||
selfTy = Context.getObjCInterfaceType(OID);
|
selfTy = Context.getObjCInterfaceType(OID);
|
||||||
selfTy = Context.getPointerType(selfTy);
|
selfTy = Context.getObjCObjectPointerType(selfTy);
|
||||||
} else {
|
} else {
|
||||||
selfTy = Context.getObjCIdType();
|
selfTy = Context.getObjCIdType();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1095,6 +1095,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const {
|
||||||
switch (getStmtClass()) {
|
switch (getStmtClass()) {
|
||||||
default: break;
|
default: break;
|
||||||
case StringLiteralClass:
|
case StringLiteralClass:
|
||||||
|
case ObjCStringLiteralClass:
|
||||||
case ObjCEncodeExprClass:
|
case ObjCEncodeExprClass:
|
||||||
return true;
|
return true;
|
||||||
case CompoundLiteralExprClass: {
|
case CompoundLiteralExprClass: {
|
||||||
|
@ -1136,7 +1137,6 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const {
|
||||||
return cast<CastExpr>(this)->getSubExpr()->isConstantInitializer(Ctx);
|
return cast<CastExpr>(this)->getSubExpr()->isConstantInitializer(Ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isEvaluatable(Ctx);
|
return isEvaluatable(Ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -382,7 +382,8 @@ APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
|
||||||
const Expr* SubExpr = E->getSubExpr();
|
const Expr* SubExpr = E->getSubExpr();
|
||||||
|
|
||||||
// Check for pointer->pointer cast
|
// Check for pointer->pointer cast
|
||||||
if (SubExpr->getType()->isPointerType()) {
|
if (SubExpr->getType()->isPointerType() ||
|
||||||
|
SubExpr->getType()->isObjCObjectPointerType()) {
|
||||||
APValue Result;
|
APValue Result;
|
||||||
if (EvaluatePointer(SubExpr, Result, Info))
|
if (EvaluatePointer(SubExpr, Result, Info))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|
||||||
|
ObjCInterfaceType *ObjCObjectPointerType::IdInterfaceT;
|
||||||
|
ObjCInterfaceType *ObjCObjectPointerType::ClassInterfaceT;
|
||||||
|
|
||||||
bool QualType::isConstant(ASTContext &Ctx) const {
|
bool QualType::isConstant(ASTContext &Ctx) const {
|
||||||
if (isConstQualified())
|
if (isConstQualified())
|
||||||
return true;
|
return true;
|
||||||
|
@ -295,6 +298,15 @@ const FunctionProtoType *Type::getAsFunctionProtoType() const {
|
||||||
return dyn_cast_or_null<FunctionProtoType>(getAsFunctionType());
|
return dyn_cast_or_null<FunctionProtoType>(getAsFunctionType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QualType Type::getPointeeType() const {
|
||||||
|
if (const PointerType *PT = getAsPointerType())
|
||||||
|
return PT->getPointeeType();
|
||||||
|
if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType())
|
||||||
|
return OPT->getPointeeType();
|
||||||
|
if (const BlockPointerType *BPT = getAsBlockPointerType())
|
||||||
|
return BPT->getPointeeType();
|
||||||
|
return QualType();
|
||||||
|
}
|
||||||
|
|
||||||
const PointerType *Type::getAsPointerType() const {
|
const PointerType *Type::getAsPointerType() const {
|
||||||
// If this is directly a pointer type, return it.
|
// If this is directly a pointer type, return it.
|
||||||
|
@ -609,6 +621,14 @@ const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
|
||||||
|
if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType()) {
|
||||||
|
if (OPT->getInterfaceType())
|
||||||
|
return OPT;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const TemplateTypeParmType *Type::getAsTemplateTypeParmType() const {
|
const TemplateTypeParmType *Type::getAsTemplateTypeParmType() const {
|
||||||
// There is no sugar for template type parameters, so just return
|
// There is no sugar for template type parameters, so just return
|
||||||
// the canonical type pointer if it is the right class.
|
// the canonical type pointer if it is the right class.
|
||||||
|
@ -1016,16 +1036,18 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
|
void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
|
||||||
const ObjCInterfaceDecl *Decl,
|
QualType OIT, ObjCProtocolDecl **protocols,
|
||||||
ObjCProtocolDecl **protocols,
|
|
||||||
unsigned NumProtocols) {
|
unsigned NumProtocols) {
|
||||||
ID.AddPointer(Decl);
|
ID.AddPointer(OIT.getAsOpaquePtr());
|
||||||
for (unsigned i = 0; i != NumProtocols; i++)
|
for (unsigned i = 0; i != NumProtocols; i++)
|
||||||
ID.AddPointer(protocols[i]);
|
ID.AddPointer(protocols[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) {
|
void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) {
|
||||||
Profile(ID, getDecl(), &Protocols[0], getNumProtocols());
|
if (getNumProtocols())
|
||||||
|
Profile(ID, getPointeeType(), &Protocols[0], getNumProtocols());
|
||||||
|
else
|
||||||
|
Profile(ID, getPointeeType(), 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
|
void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
|
||||||
|
@ -1663,6 +1685,14 @@ void TypenameType::getAsStringInternal(std::string &InnerString, const PrintingP
|
||||||
InnerString = MyString + ' ' + InnerString;
|
InnerString = MyString + ' ' + InnerString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ObjCInterfaceType::isObjCIdInterface() const {
|
||||||
|
return this == ObjCObjectPointerType::getIdInterface();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ObjCInterfaceType::isObjCClassInterface() const {
|
||||||
|
return this == ObjCObjectPointerType::getClassInterface();
|
||||||
|
}
|
||||||
|
|
||||||
void ObjCInterfaceType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
|
void ObjCInterfaceType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
|
||||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
||||||
InnerString = ' ' + InnerString;
|
InnerString = ' ' + InnerString;
|
||||||
|
@ -1671,15 +1701,7 @@ void ObjCInterfaceType::getAsStringInternal(std::string &InnerString, const Prin
|
||||||
|
|
||||||
void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString,
|
void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString,
|
||||||
const PrintingPolicy &Policy) const {
|
const PrintingPolicy &Policy) const {
|
||||||
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
std::string ObjCQIString = getInterfaceType()->getDecl()->getNameAsString();
|
||||||
InnerString = ' ' + InnerString;
|
|
||||||
|
|
||||||
std::string ObjCQIString;
|
|
||||||
|
|
||||||
if (getDecl())
|
|
||||||
ObjCQIString = getDecl()->getNameAsString();
|
|
||||||
else
|
|
||||||
ObjCQIString = "id";
|
|
||||||
|
|
||||||
if (!qual_empty()) {
|
if (!qual_empty()) {
|
||||||
ObjCQIString += '<';
|
ObjCQIString += '<';
|
||||||
|
@ -1690,6 +1712,11 @@ void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString,
|
||||||
}
|
}
|
||||||
ObjCQIString += '>';
|
ObjCQIString += '>';
|
||||||
}
|
}
|
||||||
|
if (!isObjCIdType() && !isObjCQualifiedIdType())
|
||||||
|
ObjCQIString += " *"; // Don't forget the implicit pointer.
|
||||||
|
else if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
|
||||||
|
InnerString = ' ' + InnerString;
|
||||||
|
|
||||||
InnerString = ObjCQIString + InnerString;
|
InnerString = ObjCQIString + InnerString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,26 +31,21 @@
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|
||||||
static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
|
static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
|
||||||
Expr* Receiver = ME->getReceiver();
|
const Expr* Receiver = ME->getReceiver();
|
||||||
|
|
||||||
if (!Receiver)
|
if (!Receiver)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
QualType X = Receiver->getType();
|
if (const ObjCObjectPointerType *PT =
|
||||||
|
Receiver->getType()->getAsObjCObjectPointerType())
|
||||||
if (X->isPointerType()) {
|
return PT->getInterfaceType();
|
||||||
Type* TP = X.getTypePtr();
|
|
||||||
const PointerType* T = TP->getAsPointerType();
|
|
||||||
return dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Support ObjCQualifiedIdType?
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
|
static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
|
||||||
ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
|
const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
|
||||||
return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
|
return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
|
||||||
: NULL;
|
: NULL;
|
||||||
}
|
}
|
||||||
|
@ -67,7 +62,7 @@ class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
|
||||||
BugReporter& BR;
|
BugReporter& BR;
|
||||||
ASTContext &Ctx;
|
ASTContext &Ctx;
|
||||||
|
|
||||||
bool isNSString(ObjCInterfaceType* T, const char* suffix);
|
bool isNSString(const ObjCInterfaceType *T, const char* suffix);
|
||||||
bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
|
bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
|
||||||
|
|
||||||
void Warn(NodeTy* N, Expr* E, const std::string& s);
|
void Warn(NodeTy* N, Expr* E, const std::string& s);
|
||||||
|
@ -114,7 +109,7 @@ bool BasicObjCFoundationChecks::Audit(ExplodedNode<GRState>* N,
|
||||||
ObjCMessageExpr* ME =
|
ObjCMessageExpr* ME =
|
||||||
cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
|
cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
|
||||||
|
|
||||||
ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
|
const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
|
||||||
|
|
||||||
if (!ReceiverType)
|
if (!ReceiverType)
|
||||||
return false;
|
return false;
|
||||||
|
@ -129,8 +124,7 @@ bool BasicObjCFoundationChecks::Audit(ExplodedNode<GRState>* N,
|
||||||
|
|
||||||
name += 2;
|
name += 2;
|
||||||
|
|
||||||
// FIXME: Make all of this faster.
|
// FIXME: Make all of this faster.
|
||||||
|
|
||||||
if (isNSString(ReceiverType, name))
|
if (isNSString(ReceiverType, name))
|
||||||
return AuditNSString(N, ME);
|
return AuditNSString(N, ME);
|
||||||
|
|
||||||
|
@ -163,9 +157,8 @@ bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
|
||||||
// NSString checking.
|
// NSString checking.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
|
bool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T,
|
||||||
const char* suffix) {
|
const char* suffix) {
|
||||||
|
|
||||||
return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
|
return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -547,14 +547,12 @@ public:
|
||||||
return I == M.end() ? M.find(ObjCSummaryKey(S)) : I;
|
return I == M.end() ? M.find(ObjCSummaryKey(S)) : I;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjCInterfaceDecl* getReceiverDecl(Expr* E) {
|
const ObjCInterfaceDecl* getReceiverDecl(Expr* E) {
|
||||||
|
if (const ObjCObjectPointerType* PT =
|
||||||
const PointerType* PT = E->getType()->getAsPointerType();
|
E->getType()->getAsObjCObjectPointerType())
|
||||||
if (!PT) return 0;
|
return PT->getInterfaceDecl();
|
||||||
|
|
||||||
ObjCInterfaceType* OI = dyn_cast<ObjCInterfaceType>(PT->getPointeeType());
|
return NULL;
|
||||||
|
|
||||||
return OI ? OI->getDecl() : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator end() { return M.end(); }
|
iterator end() { return M.end(); }
|
||||||
|
@ -564,7 +562,7 @@ public:
|
||||||
Selector S = ME->getSelector();
|
Selector S = ME->getSelector();
|
||||||
|
|
||||||
if (Expr* Receiver = ME->getReceiver()) {
|
if (Expr* Receiver = ME->getReceiver()) {
|
||||||
ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
|
const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
|
||||||
return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
|
return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -886,20 +884,20 @@ bool RetainSummaryManager::isTrackedObjCObjectType(QualType Ty) {
|
||||||
if (!Ctx.isObjCObjectPointerType(Ty))
|
if (!Ctx.isObjCObjectPointerType(Ty))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// We assume that id<..>, id, and "Class" all represent tracked objects.
|
const ObjCObjectPointerType *PT = Ty->getAsObjCObjectPointerType();
|
||||||
const PointerType *PT = Ty->getAsPointerType();
|
|
||||||
if (PT == 0)
|
// Can be true for objects with the 'NSObject' attribute.
|
||||||
|
if (!PT)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// We assume that id<..>, id, and "Class" all represent tracked objects.
|
||||||
|
if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
|
||||||
|
PT->isObjCClassType())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const ObjCInterfaceType *OT = PT->getPointeeType()->getAsObjCInterfaceType();
|
|
||||||
|
|
||||||
// We assume that id<..>, id, and "Class" all represent tracked objects.
|
|
||||||
if (!OT)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Does the interface subclass NSObject?
|
// Does the interface subclass NSObject?
|
||||||
// FIXME: We can memoize here if this gets too expensive.
|
// FIXME: We can memoize here if this gets too expensive.
|
||||||
ObjCInterfaceDecl* ID = OT->getDecl();
|
const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
|
||||||
|
|
||||||
// Assume that anything declared with a forward declaration and no
|
// Assume that anything declared with a forward declaration and no
|
||||||
// @interface subclasses NSObject.
|
// @interface subclasses NSObject.
|
||||||
|
@ -908,7 +906,6 @@ bool RetainSummaryManager::isTrackedObjCObjectType(QualType Ty) {
|
||||||
|
|
||||||
IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
|
IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
|
||||||
|
|
||||||
|
|
||||||
for ( ; ID ; ID = ID->getSuperClass())
|
for ( ; ID ; ID = ID->getSuperClass())
|
||||||
if (ID->getIdentifier() == NSObjectII)
|
if (ID->getIdentifier() == NSObjectII)
|
||||||
return true;
|
return true;
|
||||||
|
@ -977,7 +974,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
|
||||||
case 17:
|
case 17:
|
||||||
// Handle: id NSMakeCollectable(CFTypeRef)
|
// Handle: id NSMakeCollectable(CFTypeRef)
|
||||||
if (!memcmp(FName, "NSMakeCollectable", 17)) {
|
if (!memcmp(FName, "NSMakeCollectable", 17)) {
|
||||||
S = (RetTy == Ctx.getObjCIdType())
|
S = (RetTy->isObjCIdType())
|
||||||
? getUnarySummary(FT, cfmakecollectable)
|
? getUnarySummary(FT, cfmakecollectable)
|
||||||
: getPersistentStopSummary();
|
: getPersistentStopSummary();
|
||||||
}
|
}
|
||||||
|
@ -2726,34 +2723,26 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
|
||||||
/// While the the return type can be queried directly from RetEx, when
|
/// While the the return type can be queried directly from RetEx, when
|
||||||
/// invoking class methods we augment to the return type to be that of
|
/// invoking class methods we augment to the return type to be that of
|
||||||
/// a pointer to the class (as opposed it just being id).
|
/// a pointer to the class (as opposed it just being id).
|
||||||
static QualType GetReturnType(Expr* RetE, ASTContext& Ctx) {
|
static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
|
||||||
|
|
||||||
QualType RetTy = RetE->getType();
|
QualType RetTy = RetE->getType();
|
||||||
|
// If RetE is not a message expression just return its type.
|
||||||
// FIXME: We aren't handling id<...>.
|
// If RetE is a message expression, return its types if it is something
|
||||||
const PointerType* PT = RetTy->getAsPointerType();
|
|
||||||
if (!PT)
|
|
||||||
return RetTy;
|
|
||||||
|
|
||||||
// If RetEx is not a message expression just return its type.
|
|
||||||
// If RetEx is a message expression, return its types if it is something
|
|
||||||
/// more specific than id.
|
/// more specific than id.
|
||||||
|
if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE))
|
||||||
|
if (const ObjCObjectPointerType *PT = RetTy->getAsObjCObjectPointerType())
|
||||||
|
if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() ||
|
||||||
|
PT->isObjCClassType()) {
|
||||||
|
// At this point we know the return type of the message expression is
|
||||||
|
// id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
|
||||||
|
// is a call to a class method whose type we can resolve. In such
|
||||||
|
// cases, promote the return type to XXX* (where XXX is the class).
|
||||||
|
const ObjCInterfaceDecl *D = ME->getClassInfo().first;
|
||||||
|
return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
|
||||||
|
}
|
||||||
|
|
||||||
ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(RetE);
|
return RetTy;
|
||||||
|
|
||||||
if (!ME || !Ctx.isObjCIdStructType(PT->getPointeeType()))
|
|
||||||
return RetTy;
|
|
||||||
|
|
||||||
ObjCInterfaceDecl* D = ME->getClassInfo().first;
|
|
||||||
|
|
||||||
// At this point we know the return type of the message expression is id.
|
|
||||||
// If we have an ObjCInterceDecl, we know this is a call to a class method
|
|
||||||
// whose type we can resolve. In such cases, promote the return type to
|
|
||||||
// Class*.
|
|
||||||
return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
|
void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
|
||||||
GRExprEngine& Eng,
|
GRExprEngine& Eng,
|
||||||
GRStmtNodeBuilder<GRState>& Builder,
|
GRStmtNodeBuilder<GRState>& Builder,
|
||||||
|
@ -3009,26 +2998,21 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
|
||||||
SVal V = St->getSValAsScalarOrLoc(Receiver);
|
SVal V = St->getSValAsScalarOrLoc(Receiver);
|
||||||
|
|
||||||
SymbolRef Sym = V.getAsLocSymbol();
|
SymbolRef Sym = V.getAsLocSymbol();
|
||||||
|
|
||||||
if (Sym) {
|
if (Sym) {
|
||||||
if (const RefVal* T = St->get<RefBindings>(Sym)) {
|
if (const RefVal* T = St->get<RefBindings>(Sym)) {
|
||||||
QualType Ty = T->getType();
|
if (const ObjCObjectPointerType* PT =
|
||||||
|
T->getType()->getAsObjCObjectPointerType())
|
||||||
if (const PointerType* PT = Ty->getAsPointerType()) {
|
ID = PT->getInterfaceDecl();
|
||||||
QualType PointeeTy = PT->getPointeeType();
|
|
||||||
|
|
||||||
if (ObjCInterfaceType* IT = dyn_cast<ObjCInterfaceType>(PointeeTy))
|
|
||||||
ID = IT->getDecl();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: this is a hack. This may or may not be the actual method
|
// FIXME: this is a hack. This may or may not be the actual method
|
||||||
// that is called.
|
// that is called.
|
||||||
if (!ID) {
|
if (!ID) {
|
||||||
if (const PointerType *PT = Receiver->getType()->getAsPointerType())
|
if (const ObjCObjectPointerType *PT =
|
||||||
if (const ObjCInterfaceType *p =
|
Receiver->getType()->getAsObjCObjectPointerType())
|
||||||
PT->getPointeeType()->getAsObjCInterfaceType())
|
ID = PT->getInterfaceDecl();
|
||||||
ID = p->getDecl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: The receiver could be a reference to a class, meaning that
|
// FIXME: The receiver could be a reference to a class, meaning that
|
||||||
|
|
|
@ -162,16 +162,22 @@ NSErrorCheck::CheckSignature(FunctionDecl& F, QualType& ResultTy,
|
||||||
bool NSErrorCheck::CheckNSErrorArgument(QualType ArgTy) {
|
bool NSErrorCheck::CheckNSErrorArgument(QualType ArgTy) {
|
||||||
|
|
||||||
const PointerType* PPT = ArgTy->getAsPointerType();
|
const PointerType* PPT = ArgTy->getAsPointerType();
|
||||||
if (!PPT) return false;
|
if (!PPT)
|
||||||
|
return false;
|
||||||
|
|
||||||
const PointerType* PT = PPT->getPointeeType()->getAsPointerType();
|
const ObjCObjectPointerType* PT =
|
||||||
if (!PT) return false;
|
PPT->getPointeeType()->getAsObjCObjectPointerType();
|
||||||
|
|
||||||
|
if (!PT)
|
||||||
|
return false;
|
||||||
|
|
||||||
const ObjCInterfaceType *IT =
|
const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
|
||||||
PT->getPointeeType()->getAsObjCInterfaceType();
|
|
||||||
|
|
||||||
if (!IT) return false;
|
// FIXME: Can ID ever be NULL?
|
||||||
return IT->getDecl()->getIdentifier() == II;
|
if (ID)
|
||||||
|
return II == ID->getIdentifier();
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) {
|
bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) {
|
||||||
|
|
|
@ -30,8 +30,8 @@ static bool AreTypesCompatible(QualType Derived, QualType Ancestor,
|
||||||
|
|
||||||
// Right now don't compare the compatibility of pointers. That involves
|
// Right now don't compare the compatibility of pointers. That involves
|
||||||
// looking at subtyping relationships. FIXME: Future patch.
|
// looking at subtyping relationships. FIXME: Future patch.
|
||||||
if ((Derived->isPointerType() || Derived->isObjCQualifiedIdType()) &&
|
if ((Derived->isPointerType() || Derived->isObjCObjectPointerType()) &&
|
||||||
(Ancestor->isPointerType() || Ancestor->isObjCQualifiedIdType()))
|
(Ancestor->isPointerType() || Ancestor->isObjCObjectPointerType()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return C.typesAreCompatible(Derived, Ancestor);
|
return C.typesAreCompatible(Derived, Ancestor);
|
||||||
|
|
|
@ -761,8 +761,10 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
|
||||||
// Unsupported types
|
// Unsupported types
|
||||||
return llvm::DIType();
|
return llvm::DIType();
|
||||||
case Type::ObjCObjectPointer: // Encode id<p> in debug info just like id.
|
case Type::ObjCObjectPointer: // Encode id<p> in debug info just like id.
|
||||||
return Slot = getOrCreateType(M->getContext().getObjCIdType(), Unit);
|
{
|
||||||
|
ObjCObjectPointerType *OPT = cast<ObjCObjectPointerType>(Ty);
|
||||||
|
return Slot = CreateType(OPT->getInterfaceType(), Unit);
|
||||||
|
}
|
||||||
case Type::ObjCQualifiedInterface: // Drop protocols from interface.
|
case Type::ObjCQualifiedInterface: // Drop protocols from interface.
|
||||||
case Type::ObjCInterface:
|
case Type::ObjCInterface:
|
||||||
return Slot = CreateType(cast<ObjCInterfaceType>(Ty), Unit);
|
return Slot = CreateType(cast<ObjCInterfaceType>(Ty), Unit);
|
||||||
|
|
|
@ -257,7 +257,6 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
|
||||||
Addr = Builder.CreateBitCast(Addr, MemTy, "storetmp");
|
Addr = Builder.CreateBitCast(Addr, MemTy, "storetmp");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder.CreateStore(Value, Addr, Volatile);
|
Builder.CreateStore(Value, Addr, Volatile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,11 +757,11 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
|
||||||
default: assert(0 && "Unknown unary operator lvalue!");
|
default: assert(0 && "Unknown unary operator lvalue!");
|
||||||
case UnaryOperator::Deref:
|
case UnaryOperator::Deref:
|
||||||
{
|
{
|
||||||
QualType T =
|
QualType T = E->getSubExpr()->getType()->getPointeeType();
|
||||||
E->getSubExpr()->getType()->getAsPointerType()->getPointeeType();
|
assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type");
|
||||||
|
|
||||||
LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()),
|
LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()),
|
||||||
ExprTy->getAsPointerType()->getPointeeType()
|
T.getCVRQualifiers(),
|
||||||
.getCVRQualifiers(),
|
|
||||||
getContext().getObjCGCAttrKind(T));
|
getContext().getObjCGCAttrKind(T));
|
||||||
// We should not generate __weak write barrier on indirect reference
|
// We should not generate __weak write barrier on indirect reference
|
||||||
// of a pointer to object; as in void foo (__weak id *param); *param = 0;
|
// of a pointer to object; as in void foo (__weak id *param); *param = 0;
|
||||||
|
@ -900,7 +899,10 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
|
||||||
Address = Builder.CreateGEP(Base, Idx, "arrayidx");
|
Address = Builder.CreateGEP(Base, Idx, "arrayidx");
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType T = E->getBase()->getType()->getAsPointerType()->getPointeeType();
|
QualType T = E->getBase()->getType()->getPointeeType();
|
||||||
|
assert(!T.isNull() &&
|
||||||
|
"CodeGenFunction::EmitArraySubscriptExpr(): Illegal base type");
|
||||||
|
|
||||||
LValue LV = LValue::MakeAddr(Address,
|
LValue LV = LValue::MakeAddr(Address,
|
||||||
T.getCVRQualifiers(),
|
T.getCVRQualifiers(),
|
||||||
getContext().getObjCGCAttrKind(T));
|
getContext().getObjCGCAttrKind(T));
|
||||||
|
@ -1261,8 +1263,7 @@ LValue CodeGenFunction::EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E) {
|
||||||
QualType ObjectTy;
|
QualType ObjectTy;
|
||||||
if (E->isArrow()) {
|
if (E->isArrow()) {
|
||||||
BaseValue = EmitScalarExpr(BaseExpr);
|
BaseValue = EmitScalarExpr(BaseExpr);
|
||||||
const PointerType *PTy = BaseExpr->getType()->getAsPointerType();
|
ObjectTy = BaseExpr->getType()->getPointeeType();
|
||||||
ObjectTy = PTy->getPointeeType();
|
|
||||||
CVRQualifiers = ObjectTy.getCVRQualifiers();
|
CVRQualifiers = ObjectTy.getCVRQualifiers();
|
||||||
} else {
|
} else {
|
||||||
LValue BaseLV = EmitLValue(BaseExpr);
|
LValue BaseLV = EmitLValue(BaseExpr);
|
||||||
|
|
|
@ -987,7 +987,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
|
Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
|
||||||
if (!Ops.Ty->isPointerType()) {
|
if (!Ops.Ty->isPointerType() && !Ops.Ty->isObjCObjectPointerType()) {
|
||||||
if (CGF.getContext().getLangOptions().OverflowChecking &&
|
if (CGF.getContext().getLangOptions().OverflowChecking &&
|
||||||
Ops.Ty->isSignedIntegerType())
|
Ops.Ty->isSignedIntegerType())
|
||||||
return EmitOverflowCheckedBinOp(Ops);
|
return EmitOverflowCheckedBinOp(Ops);
|
||||||
|
@ -998,20 +998,24 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
|
||||||
return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add");
|
return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Ops.Ty->getAsPointerType()->isVariableArrayType()) {
|
if (Ops.Ty->isPointerType() &&
|
||||||
|
Ops.Ty->getAsPointerType()->isVariableArrayType()) {
|
||||||
// The amount of the addition needs to account for the VLA size
|
// The amount of the addition needs to account for the VLA size
|
||||||
CGF.ErrorUnsupported(Ops.E, "VLA pointer addition");
|
CGF.ErrorUnsupported(Ops.E, "VLA pointer addition");
|
||||||
}
|
}
|
||||||
Value *Ptr, *Idx;
|
Value *Ptr, *Idx;
|
||||||
Expr *IdxExp;
|
Expr *IdxExp;
|
||||||
const PointerType *PT;
|
const PointerType *PT = Ops.E->getLHS()->getType()->getAsPointerType();
|
||||||
if ((PT = Ops.E->getLHS()->getType()->getAsPointerType())) {
|
const ObjCObjectPointerType *OPT =
|
||||||
|
Ops.E->getLHS()->getType()->getAsObjCObjectPointerType();
|
||||||
|
if (PT || OPT) {
|
||||||
Ptr = Ops.LHS;
|
Ptr = Ops.LHS;
|
||||||
Idx = Ops.RHS;
|
Idx = Ops.RHS;
|
||||||
IdxExp = Ops.E->getRHS();
|
IdxExp = Ops.E->getRHS();
|
||||||
} else { // int + pointer
|
} else { // int + pointer
|
||||||
PT = Ops.E->getRHS()->getType()->getAsPointerType();
|
PT = Ops.E->getRHS()->getType()->getAsPointerType();
|
||||||
assert(PT && "Invalid add expr");
|
OPT = Ops.E->getRHS()->getType()->getAsObjCObjectPointerType();
|
||||||
|
assert((PT || OPT) && "Invalid add expr");
|
||||||
Ptr = Ops.RHS;
|
Ptr = Ops.RHS;
|
||||||
Idx = Ops.LHS;
|
Idx = Ops.LHS;
|
||||||
IdxExp = Ops.E->getLHS();
|
IdxExp = Ops.E->getLHS();
|
||||||
|
@ -1027,8 +1031,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
|
||||||
else
|
else
|
||||||
Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
|
Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
|
||||||
}
|
}
|
||||||
|
const QualType ElementType = PT ? PT->getPointeeType() : OPT->getPointeeType();
|
||||||
const QualType ElementType = PT->getPointeeType();
|
|
||||||
// Handle interface types, which are not represented with a concrete
|
// Handle interface types, which are not represented with a concrete
|
||||||
// type.
|
// type.
|
||||||
if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(ElementType)) {
|
if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(ElementType)) {
|
||||||
|
@ -1066,7 +1069,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
|
||||||
return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
|
return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Ops.E->getLHS()->getType()->getAsPointerType()->isVariableArrayType()) {
|
if (Ops.E->getLHS()->getType()->isPointerType() &&
|
||||||
|
Ops.E->getLHS()->getType()->getAsPointerType()->isVariableArrayType()) {
|
||||||
// The amount of the addition needs to account for the VLA size for
|
// The amount of the addition needs to account for the VLA size for
|
||||||
// ptr-int
|
// ptr-int
|
||||||
// The amount of the division needs to account for the VLA size for
|
// The amount of the division needs to account for the VLA size for
|
||||||
|
@ -1075,7 +1079,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const QualType LHSType = Ops.E->getLHS()->getType();
|
const QualType LHSType = Ops.E->getLHS()->getType();
|
||||||
const QualType LHSElementType = LHSType->getAsPointerType()->getPointeeType();
|
const QualType LHSElementType = LHSType->getPointeeType();
|
||||||
if (!isa<llvm::PointerType>(Ops.RHS->getType())) {
|
if (!isa<llvm::PointerType>(Ops.RHS->getType())) {
|
||||||
// pointer - int
|
// pointer - int
|
||||||
Value *Idx = Ops.RHS;
|
Value *Idx = Ops.RHS;
|
||||||
|
|
|
@ -305,8 +305,8 @@ llvm::Value *CodeGenFunction::LoadObjCSelf() {
|
||||||
QualType CodeGenFunction::TypeOfSelfObject() {
|
QualType CodeGenFunction::TypeOfSelfObject() {
|
||||||
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
|
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
|
||||||
ImplicitParamDecl *selfDecl = OMD->getSelfDecl();
|
ImplicitParamDecl *selfDecl = OMD->getSelfDecl();
|
||||||
const PointerType *PTy =
|
const ObjCObjectPointerType *PTy = cast<ObjCObjectPointerType>(
|
||||||
cast<PointerType>(getContext().getCanonicalType(selfDecl->getType()));
|
getContext().getCanonicalType(selfDecl->getType()));
|
||||||
return PTy->getPointeeType();
|
return PTy->getPointeeType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1338,7 +1338,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
|
||||||
Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody()));
|
Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody()));
|
||||||
|
|
||||||
// @catch() and @catch(id) both catch any ObjC exception
|
// @catch() and @catch(id) both catch any ObjC exception
|
||||||
if (!CatchDecl || CGF.getContext().isObjCIdType(CatchDecl->getType())
|
if (!CatchDecl || CatchDecl->getType()->isObjCIdType()
|
||||||
|| CatchDecl->getType()->isObjCQualifiedIdType()) {
|
|| CatchDecl->getType()->isObjCQualifiedIdType()) {
|
||||||
// Use i8* null here to signal this is a catch all, not a cleanup.
|
// Use i8* null here to signal this is a catch all, not a cleanup.
|
||||||
ESelArgs.push_back(NULLPtr);
|
ESelArgs.push_back(NULLPtr);
|
||||||
|
@ -1348,10 +1348,11 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
|
||||||
}
|
}
|
||||||
|
|
||||||
// All other types should be Objective-C interface pointer types.
|
// All other types should be Objective-C interface pointer types.
|
||||||
const PointerType *PT = CatchDecl->getType()->getAsPointerType();
|
const ObjCObjectPointerType *OPT =
|
||||||
assert(PT && "Invalid @catch type.");
|
CatchDecl->getType()->getAsObjCObjectPointerType();
|
||||||
|
assert(OPT && "Invalid @catch type.");
|
||||||
const ObjCInterfaceType *IT =
|
const ObjCInterfaceType *IT =
|
||||||
PT->getPointeeType()->getAsObjCInterfaceType();
|
OPT->getPointeeType()->getAsObjCInterfaceType();
|
||||||
assert(IT && "Invalid @catch type.");
|
assert(IT && "Invalid @catch type.");
|
||||||
llvm::Value *EHType =
|
llvm::Value *EHType =
|
||||||
MakeConstantString(IT->getDecl()->getNameAsString());
|
MakeConstantString(IT->getDecl()->getNameAsString());
|
||||||
|
|
|
@ -2523,19 +2523,18 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
|
||||||
llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch");
|
llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch");
|
||||||
|
|
||||||
const ParmVarDecl *CatchParam = CatchStmt->getCatchParamDecl();
|
const ParmVarDecl *CatchParam = CatchStmt->getCatchParamDecl();
|
||||||
const PointerType *PT = 0;
|
const ObjCObjectPointerType *OPT = 0;
|
||||||
|
|
||||||
// catch(...) always matches.
|
// catch(...) always matches.
|
||||||
if (!CatchParam) {
|
if (!CatchParam) {
|
||||||
AllMatched = true;
|
AllMatched = true;
|
||||||
} else {
|
} else {
|
||||||
PT = CatchParam->getType()->getAsPointerType();
|
OPT = CatchParam->getType()->getAsObjCObjectPointerType();
|
||||||
|
|
||||||
// catch(id e) always matches.
|
// catch(id e) always matches.
|
||||||
// FIXME: For the time being we also match id<X>; this should
|
// FIXME: For the time being we also match id<X>; this should
|
||||||
// be rejected by Sema instead.
|
// be rejected by Sema instead.
|
||||||
if ((PT && CGF.getContext().isObjCIdStructType(PT->getPointeeType())) ||
|
if (OPT && (OPT->isObjCIdType()) || OPT->isObjCQualifiedIdType())
|
||||||
CatchParam->getType()->isObjCQualifiedIdType())
|
|
||||||
AllMatched = true;
|
AllMatched = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2551,8 +2550,8 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(PT && "Unexpected non-pointer type in @catch");
|
assert(OPT && "Unexpected non-object pointer type in @catch");
|
||||||
QualType T = PT->getPointeeType();
|
QualType T = OPT->getPointeeType();
|
||||||
const ObjCInterfaceType *ObjCType = T->getAsObjCInterfaceType();
|
const ObjCInterfaceType *ObjCType = T->getAsObjCInterfaceType();
|
||||||
assert(ObjCType && "Catch parameter must have Objective-C type!");
|
assert(ObjCType && "Catch parameter must have Objective-C type!");
|
||||||
|
|
||||||
|
@ -5443,7 +5442,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CGF.getContext().isObjCIdType(CatchDecl->getType()) ||
|
if (CatchDecl->getType()->isObjCIdType() ||
|
||||||
CatchDecl->getType()->isObjCQualifiedIdType()) {
|
CatchDecl->getType()->isObjCQualifiedIdType()) {
|
||||||
llvm::Value *IDEHType =
|
llvm::Value *IDEHType =
|
||||||
CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
|
CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
|
||||||
|
@ -5459,10 +5458,10 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
|
||||||
}
|
}
|
||||||
|
|
||||||
// All other types should be Objective-C interface pointer types.
|
// All other types should be Objective-C interface pointer types.
|
||||||
const PointerType *PT = CatchDecl->getType()->getAsPointerType();
|
const ObjCObjectPointerType *PT =
|
||||||
|
CatchDecl->getType()->getAsObjCObjectPointerType();
|
||||||
assert(PT && "Invalid @catch type.");
|
assert(PT && "Invalid @catch type.");
|
||||||
const ObjCInterfaceType *IT =
|
const ObjCInterfaceType *IT = PT->getInterfaceType();
|
||||||
PT->getPointeeType()->getAsObjCInterfaceType();
|
|
||||||
assert(IT && "Invalid @catch type.");
|
assert(IT && "Invalid @catch type.");
|
||||||
llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false);
|
llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false);
|
||||||
SelectorArgs.push_back(EHType);
|
SelectorArgs.push_back(EHType);
|
||||||
|
|
|
@ -215,6 +215,7 @@ static const llvm::Type* getTypeForFormat(const llvm::fltSemantics &format) {
|
||||||
const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
|
const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
|
||||||
const clang::Type &Ty = *Context.getCanonicalType(T);
|
const clang::Type &Ty = *Context.getCanonicalType(T);
|
||||||
|
|
||||||
|
//T->dump();
|
||||||
switch (Ty.getTypeClass()) {
|
switch (Ty.getTypeClass()) {
|
||||||
#define TYPE(Class, Base)
|
#define TYPE(Class, Base)
|
||||||
#define ABSTRACT_TYPE(Class, Base)
|
#define ABSTRACT_TYPE(Class, Base)
|
||||||
|
@ -353,10 +354,14 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
|
||||||
return T;
|
return T;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Type::ObjCObjectPointer:
|
case Type::ObjCObjectPointer: {
|
||||||
// Protocols don't influence the LLVM type.
|
// Qualified id types don't influence the LLVM type, here we always return
|
||||||
return ConvertTypeRecursive(Context.getObjCIdType());
|
// an opaque type for 'id'.
|
||||||
|
const llvm::Type *&T = InterfaceTypes[0];
|
||||||
|
if (!T)
|
||||||
|
T = llvm::OpaqueType::get();
|
||||||
|
return llvm::PointerType::getUnqual(T);
|
||||||
|
}
|
||||||
case Type::Record:
|
case Type::Record:
|
||||||
case Type::Enum: {
|
case Type::Enum: {
|
||||||
const TagDecl *TD = cast<TagType>(Ty).getDecl();
|
const TagDecl *TD = cast<TagType>(Ty).getDecl();
|
||||||
|
|
|
@ -480,6 +480,11 @@ void CXXNameMangler::mangleType(QualType T) {
|
||||||
Out << 'P';
|
Out << 'P';
|
||||||
mangleType(PT->getPointeeType());
|
mangleType(PT->getPointeeType());
|
||||||
}
|
}
|
||||||
|
else if (const ObjCObjectPointerType *PT =
|
||||||
|
dyn_cast<ObjCObjectPointerType>(T.getTypePtr())) {
|
||||||
|
Out << 'P';
|
||||||
|
mangleType(PT->getPointeeType());
|
||||||
|
}
|
||||||
// ::= R <type> # reference-to
|
// ::= R <type> # reference-to
|
||||||
else if (const LValueReferenceType *RT =
|
else if (const LValueReferenceType *RT =
|
||||||
dyn_cast<LValueReferenceType>(T.getTypePtr())) {
|
dyn_cast<LValueReferenceType>(T.getTypePtr())) {
|
||||||
|
|
|
@ -1531,6 +1531,7 @@ void PCHReader::InitializeContext(ASTContext &Ctx) {
|
||||||
Context->setObjCProtoType(GetType(Proto));
|
Context->setObjCProtoType(GetType(Proto));
|
||||||
if (unsigned Class = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS])
|
if (unsigned Class = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS])
|
||||||
Context->setObjCClassType(GetType(Class));
|
Context->setObjCClassType(GetType(Class));
|
||||||
|
|
||||||
if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_CF_CONSTANT_STRING])
|
if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_CF_CONSTANT_STRING])
|
||||||
Context->setCFConstantStringType(GetType(String));
|
Context->setCFConstantStringType(GetType(String));
|
||||||
if (unsigned FastEnum
|
if (unsigned FastEnum
|
||||||
|
@ -1934,13 +1935,12 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
|
||||||
|
|
||||||
case pch::TYPE_OBJC_OBJECT_POINTER: {
|
case pch::TYPE_OBJC_OBJECT_POINTER: {
|
||||||
unsigned Idx = 0;
|
unsigned Idx = 0;
|
||||||
ObjCInterfaceDecl *ItfD =
|
QualType OIT = GetType(Record[Idx++]);
|
||||||
cast_or_null<ObjCInterfaceDecl>(GetDecl(Record[Idx++]));
|
|
||||||
unsigned NumProtos = Record[Idx++];
|
unsigned NumProtos = Record[Idx++];
|
||||||
llvm::SmallVector<ObjCProtocolDecl*, 4> Protos;
|
llvm::SmallVector<ObjCProtocolDecl*, 4> Protos;
|
||||||
for (unsigned I = 0; I != NumProtos; ++I)
|
for (unsigned I = 0; I != NumProtos; ++I)
|
||||||
Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++])));
|
Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++])));
|
||||||
return Context->getObjCObjectPointerType(ItfD, Protos.data(), NumProtos);
|
return Context->getObjCObjectPointerType(OIT, Protos.data(), NumProtos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Suppress a GCC warning
|
// Suppress a GCC warning
|
||||||
|
|
|
@ -255,7 +255,7 @@ PCHTypeWriter::VisitObjCQualifiedInterfaceType(
|
||||||
|
|
||||||
void
|
void
|
||||||
PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
|
PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
|
||||||
Writer.AddDeclRef(T->getDecl(), Record);
|
Writer.AddTypeRef(T->getPointeeType(), Record);
|
||||||
Record.push_back(T->getNumProtocols());
|
Record.push_back(T->getNumProtocols());
|
||||||
for (ObjCInterfaceType::qual_iterator I = T->qual_begin(),
|
for (ObjCInterfaceType::qual_iterator I = T->qual_begin(),
|
||||||
E = T->qual_end(); I != E; ++I)
|
E = T->qual_end(); I != E; ++I)
|
||||||
|
|
|
@ -2163,9 +2163,10 @@ ObjCInterfaceDecl *RewriteObjC::isSuperReceiver(Expr *recExpr) {
|
||||||
if (!CurMethodDef || !CurMethodDef->isInstanceMethod()) return 0;
|
if (!CurMethodDef || !CurMethodDef->isInstanceMethod()) return 0;
|
||||||
|
|
||||||
if (ObjCSuperExpr *Super = dyn_cast<ObjCSuperExpr>(recExpr)) {
|
if (ObjCSuperExpr *Super = dyn_cast<ObjCSuperExpr>(recExpr)) {
|
||||||
const PointerType *PT = Super->getType()->getAsPointerType();
|
const ObjCObjectPointerType *OPT =
|
||||||
assert(PT);
|
Super->getType()->getAsObjCObjectPointerType();
|
||||||
ObjCInterfaceType *IT = cast<ObjCInterfaceType>(PT->getPointeeType());
|
assert(OPT);
|
||||||
|
const ObjCInterfaceType *IT = OPT->getInterfaceType();
|
||||||
return IT->getDecl();
|
return IT->getDecl();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -53,9 +53,9 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
|
||||||
|
|
||||||
// Don't desugar magic Objective-C types.
|
// Don't desugar magic Objective-C types.
|
||||||
Ty.getUnqualifiedType() != Context.getObjCIdType() &&
|
Ty.getUnqualifiedType() != Context.getObjCIdType() &&
|
||||||
|
Ty.getUnqualifiedType() != Context.getObjCClassType() &&
|
||||||
Ty.getUnqualifiedType() != Context.getObjCSelType() &&
|
Ty.getUnqualifiedType() != Context.getObjCSelType() &&
|
||||||
Ty.getUnqualifiedType() != Context.getObjCProtoType() &&
|
Ty.getUnqualifiedType() != Context.getObjCProtoType() &&
|
||||||
Ty.getUnqualifiedType() != Context.getObjCClassType() &&
|
|
||||||
|
|
||||||
// Not va_list.
|
// Not va_list.
|
||||||
Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) {
|
Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) {
|
||||||
|
@ -140,17 +140,6 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
|
||||||
Context.setObjCSelType(Context.getTypeDeclType(SelTypedef));
|
Context.setObjCSelType(Context.getTypeDeclType(SelTypedef));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Context.getObjCClassType().isNull()) {
|
|
||||||
RecordDecl *ClassTag = CreateStructDecl(Context, "objc_class");
|
|
||||||
QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag));
|
|
||||||
TypedefDecl *ClassTypedef =
|
|
||||||
TypedefDecl::Create(Context, CurContext, SourceLocation(),
|
|
||||||
&Context.Idents.get("Class"), ClassT);
|
|
||||||
PushOnScopeChains(ClassTag, TUScope);
|
|
||||||
PushOnScopeChains(ClassTypedef, TUScope);
|
|
||||||
Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Synthesize "@class Protocol;
|
// Synthesize "@class Protocol;
|
||||||
if (Context.getObjCProtoType().isNull()) {
|
if (Context.getObjCProtoType().isNull()) {
|
||||||
ObjCInterfaceDecl *ProtocolDecl =
|
ObjCInterfaceDecl *ProtocolDecl =
|
||||||
|
@ -160,20 +149,38 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
|
||||||
Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));
|
Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));
|
||||||
PushOnScopeChains(ProtocolDecl, TUScope);
|
PushOnScopeChains(ProtocolDecl, TUScope);
|
||||||
}
|
}
|
||||||
|
// Create the built-in decls/typedefs for 'id' and 'Class'.
|
||||||
// Synthesize "typedef struct objc_object { Class isa; } *id;"
|
|
||||||
if (Context.getObjCIdType().isNull()) {
|
if (Context.getObjCIdType().isNull()) {
|
||||||
RecordDecl *ObjectTag = CreateStructDecl(Context, "objc_object");
|
ObjCInterfaceDecl *IdIDecl =
|
||||||
|
ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(),
|
||||||
|
&Context.Idents.get("id"),
|
||||||
|
SourceLocation(), true);
|
||||||
|
QualType IdIType = Context.getObjCInterfaceType(IdIDecl);
|
||||||
|
QualType ObjCIdType = Context.getObjCObjectPointerType(IdIType);
|
||||||
|
|
||||||
QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag));
|
|
||||||
PushOnScopeChains(ObjectTag, TUScope);
|
|
||||||
TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext,
|
TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext,
|
||||||
SourceLocation(),
|
SourceLocation(),
|
||||||
&Context.Idents.get("id"),
|
&Context.Idents.get("id"),
|
||||||
ObjT);
|
ObjCIdType);
|
||||||
PushOnScopeChains(IdTypedef, TUScope);
|
PushOnScopeChains(IdTypedef, TUScope);
|
||||||
Context.setObjCIdType(Context.getTypeDeclType(IdTypedef));
|
Context.setObjCIdType(Context.getTypeDeclType(IdTypedef));
|
||||||
}
|
}
|
||||||
|
// Create the built-in decls/typedefs and type for "Class".
|
||||||
|
if (Context.getObjCClassType().isNull()) {
|
||||||
|
ObjCInterfaceDecl *ClassIDecl =
|
||||||
|
ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(),
|
||||||
|
&Context.Idents.get("Class"),
|
||||||
|
SourceLocation(), true);
|
||||||
|
QualType ClassIType = Context.getObjCInterfaceType(ClassIDecl);
|
||||||
|
QualType ObjCClassType = Context.getObjCObjectPointerType(ClassIType);
|
||||||
|
|
||||||
|
TypedefDecl *ClassTypedef = TypedefDecl::Create(Context, CurContext,
|
||||||
|
SourceLocation(),
|
||||||
|
&Context.Idents.get("Class"),
|
||||||
|
ObjCClassType);
|
||||||
|
PushOnScopeChains(ClassTypedef, TUScope);
|
||||||
|
Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
|
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
|
||||||
|
|
|
@ -3037,6 +3037,8 @@ public:
|
||||||
// Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1)
|
// Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1)
|
||||||
AssignConvertType CheckPointerTypesForAssignment(QualType lhsType,
|
AssignConvertType CheckPointerTypesForAssignment(QualType lhsType,
|
||||||
QualType rhsType);
|
QualType rhsType);
|
||||||
|
AssignConvertType CheckPointeeTypesForAssignment(QualType lhsType,
|
||||||
|
QualType rhsType);
|
||||||
|
|
||||||
// Helper function for CheckAssignmentConstraints involving two
|
// Helper function for CheckAssignmentConstraints involving two
|
||||||
// block pointer types.
|
// block pointer types.
|
||||||
|
|
|
@ -516,8 +516,6 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
|
||||||
if (New->isInvalidDecl() || OldD->isInvalidDecl())
|
if (New->isInvalidDecl() || OldD->isInvalidDecl())
|
||||||
return New->setInvalidDecl();
|
return New->setInvalidDecl();
|
||||||
|
|
||||||
bool objc_types = false;
|
|
||||||
|
|
||||||
// Allow multiple definitions for ObjC built-in typedefs.
|
// Allow multiple definitions for ObjC built-in typedefs.
|
||||||
// FIXME: Verify the underlying types are equivalent!
|
// FIXME: Verify the underlying types are equivalent!
|
||||||
if (getLangOptions().ObjC1) {
|
if (getLangOptions().ObjC1) {
|
||||||
|
@ -527,13 +525,15 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
|
||||||
case 2:
|
case 2:
|
||||||
if (!TypeID->isStr("id"))
|
if (!TypeID->isStr("id"))
|
||||||
break;
|
break;
|
||||||
Context.setObjCIdType(Context.getTypeDeclType(New));
|
// Install the built-in type for 'id', ignoring the current definition.
|
||||||
objc_types = true;
|
New->setTypeForDecl(Context.getObjCIdType().getTypePtr());
|
||||||
|
return;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
if (!TypeID->isStr("Class"))
|
if (!TypeID->isStr("Class"))
|
||||||
break;
|
break;
|
||||||
Context.setObjCClassType(Context.getTypeDeclType(New));
|
// Install the built-in type for 'Class', ignoring the current definition.
|
||||||
|
New->setTypeForDecl(Context.getObjCClassType().getTypePtr());
|
||||||
return;
|
return;
|
||||||
case 3:
|
case 3:
|
||||||
if (!TypeID->isStr("SEL"))
|
if (!TypeID->isStr("SEL"))
|
||||||
|
@ -578,7 +578,7 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
|
||||||
return New->setInvalidDecl();
|
return New->setInvalidDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objc_types || getLangOptions().Microsoft)
|
if (getLangOptions().Microsoft)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// C++ [dcl.typedef]p2:
|
// C++ [dcl.typedef]p2:
|
||||||
|
|
|
@ -117,7 +117,7 @@ static bool isFunctionOrMethodVariadic(Decl *d) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
|
static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
|
||||||
const PointerType *PT = T->getAsPointerType();
|
const ObjCObjectPointerType *PT = T->getAsObjCObjectPointerType();
|
||||||
if (!PT)
|
if (!PT)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1690,7 +1690,8 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAsPointerType())) {
|
if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAsPointerType()
|
||||||
|
|| RetTy->getAsObjCObjectPointerType())) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type)
|
S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type)
|
||||||
<< Attr.getName();
|
<< Attr.getName();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -2048,7 +2048,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
|
||||||
<< property->getDeclName() << Ivar->getDeclName();
|
<< property->getDeclName() << Ivar->getDeclName();
|
||||||
// Fall thru - see previous comment
|
// Fall thru - see previous comment
|
||||||
}
|
}
|
||||||
if ((Context.isObjCObjectPointerType(property->getType()) ||
|
if ((property->getType()->isObjCObjectPointerType() ||
|
||||||
PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
|
PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
|
||||||
getLangOptions().getGCMode() != LangOptions::NonGC) {
|
getLangOptions().getGCMode() != LangOptions::NonGC) {
|
||||||
Diag(PropertyLoc, diag::error_strong_property)
|
Diag(PropertyLoc, diag::error_strong_property)
|
||||||
|
|
|
@ -925,8 +925,8 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
||||||
QualType T;
|
QualType T;
|
||||||
|
|
||||||
if (getCurMethodDecl()->isInstanceMethod())
|
if (getCurMethodDecl()->isInstanceMethod())
|
||||||
T = Context.getPointerType(Context.getObjCInterfaceType(
|
T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType(
|
||||||
getCurMethodDecl()->getClassInterface()));
|
getCurMethodDecl()->getClassInterface()));
|
||||||
else
|
else
|
||||||
T = Context.getObjCClassType();
|
T = Context.getObjCClassType();
|
||||||
return Owned(new (Context) ObjCSuperExpr(Loc, T));
|
return Owned(new (Context) ObjCSuperExpr(Loc, T));
|
||||||
|
@ -1844,6 +1844,17 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
|
||||||
BaseExpr = RHSExp;
|
BaseExpr = RHSExp;
|
||||||
IndexExpr = LHSExp;
|
IndexExpr = LHSExp;
|
||||||
ResultType = PTy->getPointeeType();
|
ResultType = PTy->getPointeeType();
|
||||||
|
} else if (const ObjCObjectPointerType *PTy =
|
||||||
|
LHSTy->getAsObjCObjectPointerType()) {
|
||||||
|
BaseExpr = LHSExp;
|
||||||
|
IndexExpr = RHSExp;
|
||||||
|
ResultType = PTy->getPointeeType();
|
||||||
|
} else if (const ObjCObjectPointerType *PTy =
|
||||||
|
RHSTy->getAsObjCObjectPointerType()) {
|
||||||
|
// Handle the uncommon case of "123[Ptr]".
|
||||||
|
BaseExpr = RHSExp;
|
||||||
|
IndexExpr = LHSExp;
|
||||||
|
ResultType = PTy->getPointeeType();
|
||||||
} else if (const VectorType *VTy = LHSTy->getAsVectorType()) {
|
} else if (const VectorType *VTy = LHSTy->getAsVectorType()) {
|
||||||
BaseExpr = LHSExp; // vectors: V[123]
|
BaseExpr = LHSExp; // vectors: V[123]
|
||||||
IndexExpr = RHSExp;
|
IndexExpr = RHSExp;
|
||||||
|
@ -2089,6 +2100,8 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||||
MemberLoc));
|
MemberLoc));
|
||||||
else if (const PointerType *PT = BaseType->getAsPointerType())
|
else if (const PointerType *PT = BaseType->getAsPointerType())
|
||||||
BaseType = PT->getPointeeType();
|
BaseType = PT->getPointeeType();
|
||||||
|
else if (BaseType->isObjCObjectPointerType())
|
||||||
|
;
|
||||||
else if (getLangOptions().CPlusPlus && BaseType->isRecordType())
|
else if (getLangOptions().CPlusPlus && BaseType->isRecordType())
|
||||||
return Owned(BuildOverloadedArrowExpr(S, BaseExpr, OpLoc,
|
return Owned(BuildOverloadedArrowExpr(S, BaseExpr, OpLoc,
|
||||||
MemberLoc, Member));
|
MemberLoc, Member));
|
||||||
|
@ -2212,12 +2225,71 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||||
<< DeclarationName(&Member) << int(OpKind == tok::arrow));
|
<< DeclarationName(&Member) << int(OpKind == tok::arrow));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle properties on ObjC 'Class' types.
|
||||||
|
if (OpKind == tok::period && (BaseType->isObjCClassType())) {
|
||||||
|
// Also must look for a getter name which uses property syntax.
|
||||||
|
Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
|
||||||
|
if (ObjCMethodDecl *MD = getCurMethodDecl()) {
|
||||||
|
ObjCInterfaceDecl *IFace = MD->getClassInterface();
|
||||||
|
ObjCMethodDecl *Getter;
|
||||||
|
// FIXME: need to also look locally in the implementation.
|
||||||
|
if ((Getter = IFace->lookupClassMethod(Sel))) {
|
||||||
|
// Check the use of this method.
|
||||||
|
if (DiagnoseUseOfDecl(Getter, MemberLoc))
|
||||||
|
return ExprError();
|
||||||
|
}
|
||||||
|
// If we found a getter then this may be a valid dot-reference, we
|
||||||
|
// will look for the matching setter, in case it is needed.
|
||||||
|
Selector SetterSel =
|
||||||
|
SelectorTable::constructSetterName(PP.getIdentifierTable(),
|
||||||
|
PP.getSelectorTable(), &Member);
|
||||||
|
ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
|
||||||
|
if (!Setter) {
|
||||||
|
// If this reference is in an @implementation, also check for 'private'
|
||||||
|
// methods.
|
||||||
|
Setter = FindMethodInNestedImplementations(IFace, SetterSel);
|
||||||
|
}
|
||||||
|
// Look through local category implementations associated with the class.
|
||||||
|
if (!Setter) {
|
||||||
|
for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) {
|
||||||
|
if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
|
||||||
|
Setter = ObjCCategoryImpls[i]->getClassMethod(SetterSel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
|
if (Getter || Setter) {
|
||||||
|
QualType PType;
|
||||||
|
|
||||||
|
if (Getter)
|
||||||
|
PType = Getter->getResultType();
|
||||||
|
else {
|
||||||
|
for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
|
||||||
|
E = Setter->param_end(); PI != E; ++PI)
|
||||||
|
PType = (*PI)->getType();
|
||||||
|
}
|
||||||
|
// FIXME: we must check that the setter has property type.
|
||||||
|
return Owned(new (Context) ObjCKVCRefExpr(Getter, PType,
|
||||||
|
Setter, MemberLoc, BaseExpr));
|
||||||
|
}
|
||||||
|
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
|
||||||
|
<< &Member << BaseType);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Handle access to Objective-C instance variables, such as "Obj->ivar" and
|
// Handle access to Objective-C instance variables, such as "Obj->ivar" and
|
||||||
// (*Obj).ivar.
|
// (*Obj).ivar.
|
||||||
if (const ObjCInterfaceType *IFTy = BaseType->getAsObjCInterfaceType()) {
|
if ((OpKind == tok::arrow && BaseType->isObjCObjectPointerType()) ||
|
||||||
|
(OpKind == tok::period && BaseType->isObjCInterfaceType())) {
|
||||||
|
const ObjCObjectPointerType *OPT = BaseType->getAsObjCObjectPointerType();
|
||||||
|
const ObjCInterfaceType *IFaceT =
|
||||||
|
OPT ? OPT->getInterfaceType() : BaseType->getAsObjCInterfaceType();
|
||||||
|
ObjCInterfaceDecl *IDecl = IFaceT->getDecl();
|
||||||
ObjCInterfaceDecl *ClassDeclared;
|
ObjCInterfaceDecl *ClassDeclared;
|
||||||
if (ObjCIvarDecl *IV = IFTy->getDecl()->lookupInstanceVariable(&Member,
|
|
||||||
ClassDeclared)) {
|
if (ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(&Member,
|
||||||
|
ClassDeclared)) {
|
||||||
// If the decl being referenced had an error, return an error for this
|
// If the decl being referenced had an error, return an error for this
|
||||||
// sub-expr without emitting another error, in order to avoid cascading
|
// sub-expr without emitting another error, in order to avoid cascading
|
||||||
// error cases.
|
// error cases.
|
||||||
|
@ -2249,12 +2321,12 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IV->getAccessControl() == ObjCIvarDecl::Private) {
|
if (IV->getAccessControl() == ObjCIvarDecl::Private) {
|
||||||
if (ClassDeclared != IFTy->getDecl() ||
|
if (ClassDeclared != IDecl ||
|
||||||
ClassOfMethodDecl != ClassDeclared)
|
ClassOfMethodDecl != ClassDeclared)
|
||||||
Diag(MemberLoc, diag::error_private_ivar_access) << IV->getDeclName();
|
Diag(MemberLoc, diag::error_private_ivar_access) << IV->getDeclName();
|
||||||
}
|
}
|
||||||
// @protected
|
// @protected
|
||||||
else if (!IFTy->getDecl()->isSuperClassOf(ClassOfMethodDecl))
|
else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
|
||||||
Diag(MemberLoc, diag::error_protected_ivar_access) << IV->getDeclName();
|
Diag(MemberLoc, diag::error_protected_ivar_access) << IV->getDeclName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2263,18 +2335,46 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||||
OpKind == tok::arrow));
|
OpKind == tok::arrow));
|
||||||
}
|
}
|
||||||
return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
|
return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
|
||||||
<< IFTy->getDecl()->getDeclName() << &Member
|
<< IDecl->getDeclName() << &Member
|
||||||
<< BaseExpr->getSourceRange());
|
<< BaseExpr->getSourceRange());
|
||||||
}
|
}
|
||||||
|
// Handle properties on qualified "id" protocols.
|
||||||
|
const ObjCObjectPointerType *QIdTy;
|
||||||
|
if (OpKind == tok::period && (QIdTy = BaseType->getAsObjCQualifiedIdType())) {
|
||||||
|
// Check protocols on qualified interfaces.
|
||||||
|
Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
|
||||||
|
if (Decl *PMDecl = FindGetterNameDecl(QIdTy, Member, Sel, Context)) {
|
||||||
|
if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
|
||||||
|
// Check the use of this declaration
|
||||||
|
if (DiagnoseUseOfDecl(PD, MemberLoc))
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
|
return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
|
||||||
|
MemberLoc, BaseExpr));
|
||||||
|
}
|
||||||
|
if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
|
||||||
|
// Check the use of this method.
|
||||||
|
if (DiagnoseUseOfDecl(OMD, MemberLoc))
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
|
return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel,
|
||||||
|
OMD->getResultType(),
|
||||||
|
OMD, OpLoc, MemberLoc,
|
||||||
|
NULL, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
|
||||||
|
<< &Member << BaseType);
|
||||||
|
}
|
||||||
// Handle Objective-C property access, which is "Obj.property" where Obj is a
|
// Handle Objective-C property access, which is "Obj.property" where Obj is a
|
||||||
// pointer to a (potentially qualified) interface type.
|
// pointer to a (potentially qualified) interface type.
|
||||||
const PointerType *PTy;
|
const ObjCObjectPointerType *OPT;
|
||||||
const ObjCInterfaceType *IFTy;
|
if (OpKind == tok::period &&
|
||||||
if (OpKind == tok::period && (PTy = BaseType->getAsPointerType()) &&
|
(OPT = BaseType->getAsObjCInterfacePointerType())) {
|
||||||
(IFTy = PTy->getPointeeType()->getAsObjCInterfaceType())) {
|
const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
|
||||||
ObjCInterfaceDecl *IFace = IFTy->getDecl();
|
ObjCInterfaceDecl *IFace = IFaceT->getDecl();
|
||||||
|
|
||||||
// Search for a declared property first.
|
// Search for a declared property first.
|
||||||
if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(&Member)) {
|
if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(&Member)) {
|
||||||
// Check whether we can reference this property.
|
// Check whether we can reference this property.
|
||||||
|
@ -2288,10 +2388,9 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||||
return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
|
return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
|
||||||
MemberLoc, BaseExpr));
|
MemberLoc, BaseExpr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check protocols on qualified interfaces.
|
// Check protocols on qualified interfaces.
|
||||||
for (ObjCInterfaceType::qual_iterator I = IFTy->qual_begin(),
|
for (ObjCObjectPointerType::qual_iterator I = IFaceT->qual_begin(),
|
||||||
E = IFTy->qual_end(); I != E; ++I)
|
E = IFaceT->qual_end(); I != E; ++I)
|
||||||
if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) {
|
if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) {
|
||||||
// Check whether we can reference this property.
|
// Check whether we can reference this property.
|
||||||
if (DiagnoseUseOfDecl(PD, MemberLoc))
|
if (DiagnoseUseOfDecl(PD, MemberLoc))
|
||||||
|
@ -2300,7 +2399,16 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||||
return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
|
return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
|
||||||
MemberLoc, BaseExpr));
|
MemberLoc, BaseExpr));
|
||||||
}
|
}
|
||||||
|
for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
|
||||||
|
E = OPT->qual_end(); I != E; ++I)
|
||||||
|
if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) {
|
||||||
|
// Check whether we can reference this property.
|
||||||
|
if (DiagnoseUseOfDecl(PD, MemberLoc))
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
|
return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
|
||||||
|
MemberLoc, BaseExpr));
|
||||||
|
}
|
||||||
// If that failed, look for an "implicit" property by seeing if the nullary
|
// If that failed, look for an "implicit" property by seeing if the nullary
|
||||||
// selector is implemented.
|
// selector is implemented.
|
||||||
|
|
||||||
|
@ -2365,88 +2473,6 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||||
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
|
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
|
||||||
<< &Member << BaseType);
|
<< &Member << BaseType);
|
||||||
}
|
}
|
||||||
// Handle properties on qualified "id" protocols.
|
|
||||||
const ObjCObjectPointerType *QIdTy;
|
|
||||||
if (OpKind == tok::period && (QIdTy = BaseType->getAsObjCQualifiedIdType())) {
|
|
||||||
// Check protocols on qualified interfaces.
|
|
||||||
Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
|
|
||||||
if (Decl *PMDecl = FindGetterNameDecl(QIdTy, Member, Sel, Context)) {
|
|
||||||
if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
|
|
||||||
// Check the use of this declaration
|
|
||||||
if (DiagnoseUseOfDecl(PD, MemberLoc))
|
|
||||||
return ExprError();
|
|
||||||
|
|
||||||
return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
|
|
||||||
MemberLoc, BaseExpr));
|
|
||||||
}
|
|
||||||
if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
|
|
||||||
// Check the use of this method.
|
|
||||||
if (DiagnoseUseOfDecl(OMD, MemberLoc))
|
|
||||||
return ExprError();
|
|
||||||
|
|
||||||
return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel,
|
|
||||||
OMD->getResultType(),
|
|
||||||
OMD, OpLoc, MemberLoc,
|
|
||||||
NULL, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
|
|
||||||
<< &Member << BaseType);
|
|
||||||
}
|
|
||||||
// Handle properties on ObjC 'Class' types.
|
|
||||||
if (OpKind == tok::period && (BaseType == Context.getObjCClassType())) {
|
|
||||||
// Also must look for a getter name which uses property syntax.
|
|
||||||
Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
|
|
||||||
if (ObjCMethodDecl *MD = getCurMethodDecl()) {
|
|
||||||
ObjCInterfaceDecl *IFace = MD->getClassInterface();
|
|
||||||
ObjCMethodDecl *Getter;
|
|
||||||
// FIXME: need to also look locally in the implementation.
|
|
||||||
if ((Getter = IFace->lookupClassMethod(Sel))) {
|
|
||||||
// Check the use of this method.
|
|
||||||
if (DiagnoseUseOfDecl(Getter, MemberLoc))
|
|
||||||
return ExprError();
|
|
||||||
}
|
|
||||||
// If we found a getter then this may be a valid dot-reference, we
|
|
||||||
// will look for the matching setter, in case it is needed.
|
|
||||||
Selector SetterSel =
|
|
||||||
SelectorTable::constructSetterName(PP.getIdentifierTable(),
|
|
||||||
PP.getSelectorTable(), &Member);
|
|
||||||
ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
|
|
||||||
if (!Setter) {
|
|
||||||
// If this reference is in an @implementation, also check for 'private'
|
|
||||||
// methods.
|
|
||||||
Setter = FindMethodInNestedImplementations(IFace, SetterSel);
|
|
||||||
}
|
|
||||||
// Look through local category implementations associated with the class.
|
|
||||||
if (!Setter) {
|
|
||||||
for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) {
|
|
||||||
if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
|
|
||||||
Setter = ObjCCategoryImpls[i]->getClassMethod(SetterSel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
|
|
||||||
return ExprError();
|
|
||||||
|
|
||||||
if (Getter || Setter) {
|
|
||||||
QualType PType;
|
|
||||||
|
|
||||||
if (Getter)
|
|
||||||
PType = Getter->getResultType();
|
|
||||||
else {
|
|
||||||
for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
|
|
||||||
E = Setter->param_end(); PI != E; ++PI)
|
|
||||||
PType = (*PI)->getType();
|
|
||||||
}
|
|
||||||
// FIXME: we must check that the setter has property type.
|
|
||||||
return Owned(new (Context) ObjCKVCRefExpr(Getter, PType,
|
|
||||||
Setter, MemberLoc, BaseExpr));
|
|
||||||
}
|
|
||||||
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
|
|
||||||
<< &Member << BaseType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle 'field access' to vectors, such as 'V.xx'.
|
// Handle 'field access' to vectors, such as 'V.xx'.
|
||||||
if (BaseType->isExtVectorType()) {
|
if (BaseType->isExtVectorType()) {
|
||||||
|
@ -3069,13 +3095,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
|
||||||
// C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
|
// C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
|
||||||
// the type of the other operand."
|
// the type of the other operand."
|
||||||
if ((LHSTy->isPointerType() || LHSTy->isBlockPointerType() ||
|
if ((LHSTy->isPointerType() || LHSTy->isBlockPointerType() ||
|
||||||
Context.isObjCObjectPointerType(LHSTy)) &&
|
LHSTy->isObjCObjectPointerType()) &&
|
||||||
RHS->isNullPointerConstant(Context)) {
|
RHS->isNullPointerConstant(Context)) {
|
||||||
ImpCastExprToType(RHS, LHSTy); // promote the null to a pointer.
|
ImpCastExprToType(RHS, LHSTy); // promote the null to a pointer.
|
||||||
return LHSTy;
|
return LHSTy;
|
||||||
}
|
}
|
||||||
if ((RHSTy->isPointerType() || RHSTy->isBlockPointerType() ||
|
if ((RHSTy->isPointerType() || RHSTy->isBlockPointerType() ||
|
||||||
Context.isObjCObjectPointerType(RHSTy)) &&
|
RHSTy->isObjCObjectPointerType()) &&
|
||||||
LHS->isNullPointerConstant(Context)) {
|
LHS->isNullPointerConstant(Context)) {
|
||||||
ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer.
|
ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer.
|
||||||
return RHSTy;
|
return RHSTy;
|
||||||
|
@ -3119,46 +3145,15 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
|
||||||
ImpCastExprToType(RHS, LHSTy);
|
ImpCastExprToType(RHS, LHSTy);
|
||||||
return LHSTy;
|
return LHSTy;
|
||||||
}
|
}
|
||||||
// Need to handle "id<xx>" explicitly. Unlike "id", whose canonical type
|
|
||||||
// evaluates to "struct objc_object *" (and is handled above when comparing
|
|
||||||
// id with statically typed objects).
|
|
||||||
if (LHSTy->isObjCQualifiedIdType() || RHSTy->isObjCQualifiedIdType()) {
|
|
||||||
// GCC allows qualified id and any Objective-C type to devolve to
|
|
||||||
// id. Currently localizing to here until clear this should be
|
|
||||||
// part of ObjCQualifiedIdTypesAreCompatible.
|
|
||||||
if (ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true) ||
|
|
||||||
(LHSTy->isObjCQualifiedIdType() &&
|
|
||||||
Context.isObjCObjectPointerType(RHSTy)) ||
|
|
||||||
(RHSTy->isObjCQualifiedIdType() &&
|
|
||||||
Context.isObjCObjectPointerType(LHSTy))) {
|
|
||||||
// FIXME: This is not the correct composite type. This only happens to
|
|
||||||
// work because id can more or less be used anywhere, however this may
|
|
||||||
// change the type of method sends.
|
|
||||||
|
|
||||||
// FIXME: gcc adds some type-checking of the arguments and emits
|
|
||||||
// (confusing) incompatible comparison warnings in some
|
|
||||||
// cases. Investigate.
|
|
||||||
QualType compositeType = Context.getObjCIdType();
|
|
||||||
ImpCastExprToType(LHS, compositeType);
|
|
||||||
ImpCastExprToType(RHS, compositeType);
|
|
||||||
return compositeType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check constraints for Objective-C object pointers types.
|
// Check constraints for Objective-C object pointers types.
|
||||||
if (Context.isObjCObjectPointerType(LHSTy) &&
|
if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) {
|
||||||
Context.isObjCObjectPointerType(RHSTy)) {
|
|
||||||
|
|
||||||
if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
|
if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
|
||||||
// Two identical object pointer types are always compatible.
|
// Two identical object pointer types are always compatible.
|
||||||
return LHSTy;
|
return LHSTy;
|
||||||
}
|
}
|
||||||
// No need to check for block pointer types or qualified id types (they
|
const ObjCObjectPointerType *LHSOPT = LHSTy->getAsObjCObjectPointerType();
|
||||||
// were handled above).
|
const ObjCObjectPointerType *RHSOPT = RHSTy->getAsObjCObjectPointerType();
|
||||||
assert((LHSTy->isPointerType() && RHSTy->isPointerType()) &&
|
|
||||||
"Sema::CheckConditionalOperands(): Unexpected type");
|
|
||||||
QualType lhptee = LHSTy->getAsPointerType()->getPointeeType();
|
|
||||||
QualType rhptee = RHSTy->getAsPointerType()->getPointeeType();
|
|
||||||
|
|
||||||
QualType compositeType = LHSTy;
|
QualType compositeType = LHSTy;
|
||||||
|
|
||||||
// If both operands are interfaces and either operand can be
|
// If both operands are interfaces and either operand can be
|
||||||
|
@ -3174,16 +3169,19 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
|
||||||
|
|
||||||
// FIXME: Consider unifying with 'areComparableObjCPointerTypes'.
|
// FIXME: Consider unifying with 'areComparableObjCPointerTypes'.
|
||||||
// It could return the composite type.
|
// It could return the composite type.
|
||||||
const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType();
|
if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) {
|
||||||
const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType();
|
|
||||||
if (LHSIface && RHSIface &&
|
|
||||||
Context.canAssignObjCInterfaces(LHSIface, RHSIface)) {
|
|
||||||
compositeType = LHSTy;
|
compositeType = LHSTy;
|
||||||
} else if (LHSIface && RHSIface &&
|
} else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) {
|
||||||
Context.canAssignObjCInterfaces(RHSIface, LHSIface)) {
|
|
||||||
compositeType = RHSTy;
|
compositeType = RHSTy;
|
||||||
} else if (Context.isObjCIdStructType(lhptee) ||
|
} else if ((LHSTy->isObjCQualifiedIdType() ||
|
||||||
Context.isObjCIdStructType(rhptee)) {
|
RHSTy->isObjCQualifiedIdType()) &&
|
||||||
|
ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
|
||||||
|
// Need to handle "id<xx>" explicitly.
|
||||||
|
// GCC allows qualified id and any Objective-C type to devolve to
|
||||||
|
// id. Currently localizing to here until clear this should be
|
||||||
|
// part of ObjCQualifiedIdTypesAreCompatible.
|
||||||
|
compositeType = Context.getObjCIdType();
|
||||||
|
} else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) {
|
||||||
compositeType = Context.getObjCIdType();
|
compositeType = Context.getObjCIdType();
|
||||||
} else {
|
} else {
|
||||||
Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands)
|
Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands)
|
||||||
|
@ -3312,6 +3310,11 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
|
||||||
lhptee = lhsType->getAsPointerType()->getPointeeType();
|
lhptee = lhsType->getAsPointerType()->getPointeeType();
|
||||||
rhptee = rhsType->getAsPointerType()->getPointeeType();
|
rhptee = rhsType->getAsPointerType()->getPointeeType();
|
||||||
|
|
||||||
|
return CheckPointeeTypesForAssignment(lhptee, rhptee);
|
||||||
|
}
|
||||||
|
|
||||||
|
Sema::AssignConvertType
|
||||||
|
Sema::CheckPointeeTypesForAssignment(QualType lhptee, QualType rhptee) {
|
||||||
// make sure we operate on the canonical type
|
// make sure we operate on the canonical type
|
||||||
lhptee = Context.getCanonicalType(lhptee);
|
lhptee = Context.getCanonicalType(lhptee);
|
||||||
rhptee = Context.getCanonicalType(rhptee);
|
rhptee = Context.getCanonicalType(rhptee);
|
||||||
|
@ -3443,7 +3446,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
|
||||||
return Compatible;
|
return Compatible;
|
||||||
return Incompatible;
|
return Incompatible;
|
||||||
}
|
}
|
||||||
|
// FIXME: Look into removing. With ObjCObjectPointerType, I don't see a need.
|
||||||
if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) {
|
if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) {
|
||||||
if (ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType, false))
|
if (ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType, false))
|
||||||
return Compatible;
|
return Compatible;
|
||||||
|
@ -3454,7 +3457,6 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
|
||||||
return PointerToInt;
|
return PointerToInt;
|
||||||
return IncompatibleObjCQualifiedId;
|
return IncompatibleObjCQualifiedId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow scalar to ExtVector assignments, and assignments of an ExtVector type
|
// Allow scalar to ExtVector assignments, and assignments of an ExtVector type
|
||||||
// to the same ExtVector type.
|
// to the same ExtVector type.
|
||||||
if (lhsType->isExtVectorType()) {
|
if (lhsType->isExtVectorType()) {
|
||||||
|
@ -3486,13 +3488,18 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
|
||||||
if (isa<PointerType>(rhsType))
|
if (isa<PointerType>(rhsType))
|
||||||
return CheckPointerTypesForAssignment(lhsType, rhsType);
|
return CheckPointerTypesForAssignment(lhsType, rhsType);
|
||||||
|
|
||||||
|
if (isa<ObjCObjectPointerType>(rhsType)) {
|
||||||
|
QualType rhptee = rhsType->getAsObjCObjectPointerType()->getPointeeType();
|
||||||
|
QualType lhptee = lhsType->getAsPointerType()->getPointeeType();
|
||||||
|
return CheckPointeeTypesForAssignment(lhptee, rhptee);
|
||||||
|
}
|
||||||
|
|
||||||
if (rhsType->getAsBlockPointerType()) {
|
if (rhsType->getAsBlockPointerType()) {
|
||||||
if (lhsType->getAsPointerType()->getPointeeType()->isVoidType())
|
if (lhsType->getAsPointerType()->getPointeeType()->isVoidType())
|
||||||
return Compatible;
|
return Compatible;
|
||||||
|
|
||||||
// Treat block pointers as objects.
|
// Treat block pointers as objects.
|
||||||
if (getLangOptions().ObjC1 &&
|
if (getLangOptions().ObjC1 && lhsType->isObjCIdType())
|
||||||
lhsType == Context.getCanonicalType(Context.getObjCIdType()))
|
|
||||||
return Compatible;
|
return Compatible;
|
||||||
}
|
}
|
||||||
return Incompatible;
|
return Incompatible;
|
||||||
|
@ -3503,8 +3510,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
|
||||||
return IntToBlockPointer;
|
return IntToBlockPointer;
|
||||||
|
|
||||||
// Treat block pointers as objects.
|
// Treat block pointers as objects.
|
||||||
if (getLangOptions().ObjC1 &&
|
if (getLangOptions().ObjC1 && rhsType->isObjCIdType())
|
||||||
rhsType == Context.getCanonicalType(Context.getObjCIdType()))
|
|
||||||
return Compatible;
|
return Compatible;
|
||||||
|
|
||||||
if (rhsType->isBlockPointerType())
|
if (rhsType->isBlockPointerType())
|
||||||
|
@ -3517,6 +3523,29 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
|
||||||
return Incompatible;
|
return Incompatible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isa<ObjCObjectPointerType>(lhsType)) {
|
||||||
|
if (rhsType->isIntegerType())
|
||||||
|
return IntToPointer;
|
||||||
|
|
||||||
|
if (isa<PointerType>(rhsType)) {
|
||||||
|
QualType lhptee = lhsType->getAsObjCObjectPointerType()->getPointeeType();
|
||||||
|
QualType rhptee = rhsType->getAsPointerType()->getPointeeType();
|
||||||
|
return CheckPointeeTypesForAssignment(lhptee, rhptee);
|
||||||
|
}
|
||||||
|
if (rhsType->isObjCObjectPointerType()) {
|
||||||
|
QualType lhptee = lhsType->getAsObjCObjectPointerType()->getPointeeType();
|
||||||
|
QualType rhptee = rhsType->getAsObjCObjectPointerType()->getPointeeType();
|
||||||
|
return CheckPointeeTypesForAssignment(lhptee, rhptee);
|
||||||
|
}
|
||||||
|
if (const PointerType *RHSPT = rhsType->getAsPointerType()) {
|
||||||
|
if (RHSPT->getPointeeType()->isVoidType())
|
||||||
|
return Compatible;
|
||||||
|
}
|
||||||
|
// Treat block pointers as objects.
|
||||||
|
if (rhsType->isBlockPointerType())
|
||||||
|
return Compatible;
|
||||||
|
return Incompatible;
|
||||||
|
}
|
||||||
if (isa<PointerType>(rhsType)) {
|
if (isa<PointerType>(rhsType)) {
|
||||||
// C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
|
// C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
|
||||||
if (lhsType == Context.BoolTy)
|
if (lhsType == Context.BoolTy)
|
||||||
|
@ -3533,6 +3562,24 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
|
||||||
return Compatible;
|
return Compatible;
|
||||||
return Incompatible;
|
return Incompatible;
|
||||||
}
|
}
|
||||||
|
if (isa<ObjCObjectPointerType>(rhsType)) {
|
||||||
|
// C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
|
||||||
|
if (lhsType == Context.BoolTy)
|
||||||
|
return Compatible;
|
||||||
|
|
||||||
|
if (lhsType->isIntegerType())
|
||||||
|
return PointerToInt;
|
||||||
|
|
||||||
|
if (isa<PointerType>(lhsType)) {
|
||||||
|
QualType rhptee = lhsType->getAsObjCObjectPointerType()->getPointeeType();
|
||||||
|
QualType lhptee = rhsType->getAsPointerType()->getPointeeType();
|
||||||
|
return CheckPointeeTypesForAssignment(lhptee, rhptee);
|
||||||
|
}
|
||||||
|
if (isa<BlockPointerType>(lhsType) &&
|
||||||
|
rhsType->getAsPointerType()->getPointeeType()->isVoidType())
|
||||||
|
return Compatible;
|
||||||
|
return Incompatible;
|
||||||
|
}
|
||||||
|
|
||||||
if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) {
|
if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) {
|
||||||
if (Context.typesAreCompatible(lhsType, rhsType))
|
if (Context.typesAreCompatible(lhsType, rhsType))
|
||||||
|
@ -3628,7 +3675,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
|
||||||
// C99 6.5.16.1p1: the left operand is a pointer and the right is
|
// C99 6.5.16.1p1: the left operand is a pointer and the right is
|
||||||
// a null pointer constant.
|
// a null pointer constant.
|
||||||
if ((lhsType->isPointerType() ||
|
if ((lhsType->isPointerType() ||
|
||||||
lhsType->isObjCQualifiedIdType() ||
|
lhsType->isObjCObjectPointerType() ||
|
||||||
lhsType->isBlockPointerType())
|
lhsType->isBlockPointerType())
|
||||||
&& rExpr->isNullPointerConstant(Context)) {
|
&& rExpr->isNullPointerConstant(Context)) {
|
||||||
ImpCastExprToType(rExpr, lhsType);
|
ImpCastExprToType(rExpr, lhsType);
|
||||||
|
@ -3776,12 +3823,23 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
|
||||||
|
|
||||||
// Put any potential pointer into PExp
|
// Put any potential pointer into PExp
|
||||||
Expr* PExp = lex, *IExp = rex;
|
Expr* PExp = lex, *IExp = rex;
|
||||||
if (IExp->getType()->isPointerType())
|
if (IExp->getType()->isPointerType() ||
|
||||||
|
IExp->getType()->isObjCObjectPointerType())
|
||||||
std::swap(PExp, IExp);
|
std::swap(PExp, IExp);
|
||||||
|
|
||||||
if (const PointerType *PTy = PExp->getType()->getAsPointerType()) {
|
if (PExp->getType()->isPointerType() ||
|
||||||
|
PExp->getType()->isObjCObjectPointerType()) {
|
||||||
|
|
||||||
if (IExp->getType()->isIntegerType()) {
|
if (IExp->getType()->isIntegerType()) {
|
||||||
QualType PointeeTy = PTy->getPointeeType();
|
QualType PointeeTy;
|
||||||
|
const PointerType *PTy;
|
||||||
|
const ObjCObjectPointerType *OPT;
|
||||||
|
|
||||||
|
if ((PTy = PExp->getType()->getAsPointerType()))
|
||||||
|
PointeeTy = PTy->getPointeeType();
|
||||||
|
else if ((OPT = PExp->getType()->getAsObjCObjectPointerType()))
|
||||||
|
PointeeTy = OPT->getPointeeType();
|
||||||
|
|
||||||
// Check for arithmetic on pointers to incomplete types.
|
// Check for arithmetic on pointers to incomplete types.
|
||||||
if (PointeeTy->isVoidType()) {
|
if (PointeeTy->isVoidType()) {
|
||||||
if (getLangOptions().CPlusPlus) {
|
if (getLangOptions().CPlusPlus) {
|
||||||
|
@ -3803,7 +3861,7 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
|
||||||
// GNU extension: arithmetic on pointer to function
|
// GNU extension: arithmetic on pointer to function
|
||||||
Diag(Loc, diag::ext_gnu_ptr_func_arith)
|
Diag(Loc, diag::ext_gnu_ptr_func_arith)
|
||||||
<< lex->getType() << lex->getSourceRange();
|
<< lex->getType() << lex->getSourceRange();
|
||||||
} else if (!PTy->isDependentType() &&
|
} else if (((PTy && !PTy->isDependentType()) || OPT) &&
|
||||||
RequireCompleteType(Loc, PointeeTy,
|
RequireCompleteType(Loc, PointeeTy,
|
||||||
diag::err_typecheck_arithmetic_incomplete_type,
|
diag::err_typecheck_arithmetic_incomplete_type,
|
||||||
PExp->getSourceRange(), SourceRange(),
|
PExp->getSourceRange(), SourceRange(),
|
||||||
|
@ -3855,10 +3913,16 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
|
||||||
if (CompLHSTy) *CompLHSTy = compType;
|
if (CompLHSTy) *CompLHSTy = compType;
|
||||||
return compType;
|
return compType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Either ptr - int or ptr - ptr.
|
// Either ptr - int or ptr - ptr.
|
||||||
if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) {
|
if (lex->getType()->isPointerType() ||
|
||||||
QualType lpointee = LHSPTy->getPointeeType();
|
lex->getType()->isObjCObjectPointerType()) {
|
||||||
|
QualType lpointee;
|
||||||
|
if (const PointerType *LHSPTy = lex->getType()->getAsPointerType())
|
||||||
|
lpointee = LHSPTy->getPointeeType();
|
||||||
|
else if (const ObjCObjectPointerType *OPT =
|
||||||
|
lex->getType()->getAsObjCObjectPointerType())
|
||||||
|
lpointee = OPT->getPointeeType();
|
||||||
|
|
||||||
// The LHS must be an completely-defined object type.
|
// The LHS must be an completely-defined object type.
|
||||||
|
|
||||||
|
@ -4156,8 +4220,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
|
||||||
if (!LHSIsNull && !RHSIsNull && // C99 6.5.9p2
|
if (!LHSIsNull && !RHSIsNull && // C99 6.5.9p2
|
||||||
!LCanPointeeTy->isVoidType() && !RCanPointeeTy->isVoidType() &&
|
!LCanPointeeTy->isVoidType() && !RCanPointeeTy->isVoidType() &&
|
||||||
!Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
|
!Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
|
||||||
RCanPointeeTy.getUnqualifiedType()) &&
|
RCanPointeeTy.getUnqualifiedType())) {
|
||||||
!Context.areComparableObjCPointerTypes(lType, rType)) {
|
|
||||||
Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
|
Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
|
||||||
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
||||||
}
|
}
|
||||||
|
@ -4207,7 +4270,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
|
||||||
return ResultTy;
|
return ResultTy;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) {
|
if ((lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType())) {
|
||||||
if (lType->isPointerType() || rType->isPointerType()) {
|
if (lType->isPointerType() || rType->isPointerType()) {
|
||||||
const PointerType *LPT = lType->getAsPointerType();
|
const PointerType *LPT = lType->getAsPointerType();
|
||||||
const PointerType *RPT = rType->getAsPointerType();
|
const PointerType *RPT = rType->getAsPointerType();
|
||||||
|
@ -4226,19 +4289,27 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
|
||||||
ImpCastExprToType(rex, lType);
|
ImpCastExprToType(rex, lType);
|
||||||
return ResultTy;
|
return ResultTy;
|
||||||
}
|
}
|
||||||
if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
|
if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) {
|
||||||
|
if (!Context.areComparableObjCPointerTypes(lType, rType)) {
|
||||||
|
Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
|
||||||
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
||||||
|
}
|
||||||
|
if (lType->isObjCQualifiedIdType() && rType->isObjCQualifiedIdType()) {
|
||||||
|
if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
|
||||||
|
ImpCastExprToType(rex, lType);
|
||||||
|
return ResultTy;
|
||||||
|
} else {
|
||||||
|
Diag(Loc, diag::warn_incompatible_qualified_id_operands)
|
||||||
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
||||||
|
ImpCastExprToType(rex, lType);
|
||||||
|
return ResultTy;
|
||||||
|
}
|
||||||
|
}
|
||||||
ImpCastExprToType(rex, lType);
|
ImpCastExprToType(rex, lType);
|
||||||
return ResultTy;
|
return ResultTy;
|
||||||
} else {
|
|
||||||
if ((lType->isObjCQualifiedIdType() && rType->isObjCQualifiedIdType())) {
|
|
||||||
Diag(Loc, diag::warn_incompatible_qualified_id_operands)
|
|
||||||
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
|
||||||
ImpCastExprToType(rex, lType);
|
|
||||||
return ResultTy;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((lType->isPointerType() || lType->isObjCQualifiedIdType()) &&
|
if ((lType->isPointerType() || lType->isObjCObjectPointerType()) &&
|
||||||
rType->isIntegerType()) {
|
rType->isIntegerType()) {
|
||||||
if (isRelational)
|
if (isRelational)
|
||||||
Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer)
|
Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer)
|
||||||
|
@ -4250,7 +4321,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
|
||||||
return ResultTy;
|
return ResultTy;
|
||||||
}
|
}
|
||||||
if (lType->isIntegerType() &&
|
if (lType->isIntegerType() &&
|
||||||
(rType->isPointerType() || rType->isObjCQualifiedIdType())) {
|
(rType->isPointerType() || rType->isObjCObjectPointerType())) {
|
||||||
if (isRelational)
|
if (isRelational)
|
||||||
Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer)
|
Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer)
|
||||||
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
||||||
|
@ -4358,12 +4429,11 @@ static bool IsReadonlyProperty(Expr *E, Sema &S)
|
||||||
const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
|
const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
|
||||||
if (ObjCPropertyDecl *PDecl = PropExpr->getProperty()) {
|
if (ObjCPropertyDecl *PDecl = PropExpr->getProperty()) {
|
||||||
QualType BaseType = PropExpr->getBase()->getType();
|
QualType BaseType = PropExpr->getBase()->getType();
|
||||||
if (const PointerType *PTy = BaseType->getAsPointerType())
|
if (const ObjCObjectPointerType *OPT =
|
||||||
if (const ObjCInterfaceType *IFTy =
|
BaseType->getAsObjCInterfacePointerType())
|
||||||
PTy->getPointeeType()->getAsObjCInterfaceType())
|
if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
|
||||||
if (ObjCInterfaceDecl *IFace = IFTy->getDecl())
|
if (S.isPropertyReadonly(PDecl, IFace))
|
||||||
if (S.isPropertyReadonly(PDecl, IFace))
|
return true;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -4524,9 +4594,17 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
|
||||||
Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange();
|
Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange();
|
||||||
} else if (ResType->isRealType()) {
|
} else if (ResType->isRealType()) {
|
||||||
// OK!
|
// OK!
|
||||||
} else if (const PointerType *PT = ResType->getAsPointerType()) {
|
} else if (ResType->getAsPointerType() ||ResType->isObjCObjectPointerType()) {
|
||||||
|
QualType PointeeTy;
|
||||||
|
|
||||||
|
if (const PointerType *PTy = ResType->getAsPointerType())
|
||||||
|
PointeeTy = PTy->getPointeeType();
|
||||||
|
else if (const ObjCObjectPointerType *OPT =
|
||||||
|
ResType->getAsObjCObjectPointerType())
|
||||||
|
PointeeTy = OPT->getPointeeType();
|
||||||
|
|
||||||
// C99 6.5.2.4p2, 6.5.6p2
|
// C99 6.5.2.4p2, 6.5.6p2
|
||||||
if (PT->getPointeeType()->isVoidType()) {
|
if (PointeeTy->isVoidType()) {
|
||||||
if (getLangOptions().CPlusPlus) {
|
if (getLangOptions().CPlusPlus) {
|
||||||
Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type)
|
Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type)
|
||||||
<< Op->getSourceRange();
|
<< Op->getSourceRange();
|
||||||
|
@ -4535,7 +4613,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
|
||||||
|
|
||||||
// Pointer to void is a GNU extension in C.
|
// Pointer to void is a GNU extension in C.
|
||||||
Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange();
|
Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange();
|
||||||
} else if (PT->getPointeeType()->isFunctionType()) {
|
} else if (PointeeTy->isFunctionType()) {
|
||||||
if (getLangOptions().CPlusPlus) {
|
if (getLangOptions().CPlusPlus) {
|
||||||
Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type)
|
Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type)
|
||||||
<< Op->getType() << Op->getSourceRange();
|
<< Op->getType() << Op->getSourceRange();
|
||||||
|
@ -4544,7 +4622,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
|
||||||
|
|
||||||
Diag(OpLoc, diag::ext_gnu_ptr_func_arith)
|
Diag(OpLoc, diag::ext_gnu_ptr_func_arith)
|
||||||
<< ResType << Op->getSourceRange();
|
<< ResType << Op->getSourceRange();
|
||||||
} else if (RequireCompleteType(OpLoc, PT->getPointeeType(),
|
} else if (RequireCompleteType(OpLoc, PointeeTy,
|
||||||
diag::err_typecheck_arithmetic_incomplete_type,
|
diag::err_typecheck_arithmetic_incomplete_type,
|
||||||
Op->getSourceRange(), SourceRange(),
|
Op->getSourceRange(), SourceRange(),
|
||||||
ResType))
|
ResType))
|
||||||
|
@ -4741,6 +4819,9 @@ QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) {
|
||||||
if (const PointerType *PT = Ty->getAsPointerType())
|
if (const PointerType *PT = Ty->getAsPointerType())
|
||||||
return PT->getPointeeType();
|
return PT->getPointeeType();
|
||||||
|
|
||||||
|
if (const ObjCObjectPointerType *OPT = Ty->getAsObjCObjectPointerType())
|
||||||
|
return OPT->getPointeeType();
|
||||||
|
|
||||||
Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer)
|
Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer)
|
||||||
<< Ty << Op->getSourceRange();
|
<< Ty << Op->getSourceRange();
|
||||||
return QualType();
|
return QualType();
|
||||||
|
|
|
@ -1482,7 +1482,8 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
|
||||||
QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
|
QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
|
||||||
assert(getLangOptions().CPlusPlus && "This function assumes C++");
|
assert(getLangOptions().CPlusPlus && "This function assumes C++");
|
||||||
QualType T1 = E1->getType(), T2 = E2->getType();
|
QualType T1 = E1->getType(), T2 = E2->getType();
|
||||||
if(!T1->isPointerType() && !T2->isPointerType())
|
if(!T1->isPointerType() && !T2->isPointerType() &&
|
||||||
|
!T1->isObjCObjectPointerType() && !T2->isObjCObjectPointerType())
|
||||||
return QualType();
|
return QualType();
|
||||||
|
|
||||||
// C++0x 5.9p2
|
// C++0x 5.9p2
|
||||||
|
|
|
@ -74,14 +74,14 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
|
||||||
// interface private (even though it appears in the header files).
|
// interface private (even though it appears in the header files).
|
||||||
QualType Ty = Context.getObjCConstantStringInterface();
|
QualType Ty = Context.getObjCConstantStringInterface();
|
||||||
if (!Ty.isNull()) {
|
if (!Ty.isNull()) {
|
||||||
Ty = Context.getPointerType(Ty);
|
Ty = Context.getObjCObjectPointerType(Ty);
|
||||||
} else {
|
} else {
|
||||||
IdentifierInfo *NSIdent = &Context.Idents.get("NSString");
|
IdentifierInfo *NSIdent = &Context.Idents.get("NSString");
|
||||||
NamedDecl *IF = LookupName(TUScope, NSIdent, LookupOrdinaryName);
|
NamedDecl *IF = LookupName(TUScope, NSIdent, LookupOrdinaryName);
|
||||||
if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
|
if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
|
||||||
Context.setObjCConstantStringInterface(StrIF);
|
Context.setObjCConstantStringInterface(StrIF);
|
||||||
Ty = Context.getObjCConstantStringInterface();
|
Ty = Context.getObjCConstantStringInterface();
|
||||||
Ty = Context.getPointerType(Ty);
|
Ty = Context.getObjCObjectPointerType(Ty);
|
||||||
} else {
|
} else {
|
||||||
// If there is no NSString interface defined then treat constant
|
// If there is no NSString interface defined then treat constant
|
||||||
// strings as untyped objects and let the runtime figure it out later.
|
// strings as untyped objects and let the runtime figure it out later.
|
||||||
|
@ -156,7 +156,7 @@ Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
|
||||||
QualType Ty = Context.getObjCProtoType();
|
QualType Ty = Context.getObjCProtoType();
|
||||||
if (Ty.isNull())
|
if (Ty.isNull())
|
||||||
return true;
|
return true;
|
||||||
Ty = Context.getPointerType(Ty);
|
Ty = Context.getObjCObjectPointerType(Ty);
|
||||||
return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, RParenLoc);
|
return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, RParenLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,7 +390,7 @@ Sema::ExprResult Sema::ActOnClassMessage(
|
||||||
return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName();
|
return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName();
|
||||||
if (getCurMethodDecl()->isInstanceMethod()) {
|
if (getCurMethodDecl()->isInstanceMethod()) {
|
||||||
QualType superTy = Context.getObjCInterfaceType(ClassDecl);
|
QualType superTy = Context.getObjCInterfaceType(ClassDecl);
|
||||||
superTy = Context.getPointerType(superTy);
|
superTy = Context.getObjCObjectPointerType(superTy);
|
||||||
ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(),
|
ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(),
|
||||||
superTy);
|
superTy);
|
||||||
// We are really in an instance method, redirect.
|
// We are really in an instance method, redirect.
|
||||||
|
@ -527,7 +527,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
|
||||||
rbrac, ArgExprs, NumArgs);
|
rbrac, ArgExprs, NumArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle messages to id.
|
// Handle messages to id.
|
||||||
if (ReceiverCType == Context.getCanonicalType(Context.getObjCIdType()) ||
|
if (ReceiverCType == Context.getCanonicalType(Context.getObjCIdType()) ||
|
||||||
ReceiverCType->isBlockPointerType() ||
|
ReceiverCType->isBlockPointerType() ||
|
||||||
Context.isObjCNSObjectType(RExpr->getType())) {
|
Context.isObjCNSObjectType(RExpr->getType())) {
|
||||||
|
@ -602,11 +602,11 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
|
||||||
if (PDecl && (Method = PDecl->lookupClassMethod(Sel)))
|
if (PDecl && (Method = PDecl->lookupClassMethod(Sel)))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (const ObjCInterfaceType *OCIType =
|
} else if (const ObjCObjectPointerType *OCIType =
|
||||||
ReceiverCType->getAsPointerToObjCInterfaceType()) {
|
ReceiverCType->getAsObjCInterfacePointerType()) {
|
||||||
// We allow sending a message to a pointer to an interface (an object).
|
// We allow sending a message to a pointer to an interface (an object).
|
||||||
|
|
||||||
ClassDecl = OCIType->getDecl();
|
ClassDecl = OCIType->getInterfaceDecl();
|
||||||
// FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
|
// FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
|
||||||
// faster than the following method (which can do *many* linear searches).
|
// faster than the following method (which can do *many* linear searches).
|
||||||
// The idea is to add class info to InstanceMethodPool.
|
// The idea is to add class info to InstanceMethodPool.
|
||||||
|
@ -614,7 +614,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
|
||||||
|
|
||||||
if (!Method) {
|
if (!Method) {
|
||||||
// Search protocol qualifiers.
|
// Search protocol qualifiers.
|
||||||
for (ObjCQualifiedInterfaceType::qual_iterator QI = OCIType->qual_begin(),
|
for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(),
|
||||||
E = OCIType->qual_end(); QI != E; ++QI) {
|
E = OCIType->qual_end(); QI != E; ++QI) {
|
||||||
if ((Method = (*QI)->lookupInstanceMethod(Sel)))
|
if ((Method = (*QI)->lookupInstanceMethod(Sel)))
|
||||||
break;
|
break;
|
||||||
|
@ -631,9 +631,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
|
||||||
if (OCIType->qual_empty()) {
|
if (OCIType->qual_empty()) {
|
||||||
Method = LookupInstanceMethodInGlobalPool(
|
Method = LookupInstanceMethodInGlobalPool(
|
||||||
Sel, SourceRange(lbrac,rbrac));
|
Sel, SourceRange(lbrac,rbrac));
|
||||||
if (Method && !OCIType->getDecl()->isForwardDecl())
|
if (Method && !OCIType->getInterfaceDecl()->isForwardDecl())
|
||||||
Diag(lbrac, diag::warn_maynot_respond)
|
Diag(lbrac, diag::warn_maynot_respond)
|
||||||
<< OCIType->getDecl()->getIdentifier()->getName() << Sel;
|
<< OCIType->getInterfaceDecl()->getIdentifier()->getName() << Sel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -741,60 +741,36 @@ bool Sema::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) {
|
||||||
bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
|
bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
|
||||||
bool compare) {
|
bool compare) {
|
||||||
// Allow id<P..> and an 'id' or void* type in all cases.
|
// Allow id<P..> and an 'id' or void* type in all cases.
|
||||||
if (const PointerType *PT = lhs->getAsPointerType()) {
|
if (lhs->isVoidPointerType() ||
|
||||||
QualType PointeeTy = PT->getPointeeType();
|
lhs->isObjCIdType() || lhs->isObjCClassType())
|
||||||
if (PointeeTy->isVoidType() ||
|
return true;
|
||||||
Context.isObjCIdStructType(PointeeTy) ||
|
else if (rhs->isVoidPointerType() ||
|
||||||
Context.isObjCClassStructType(PointeeTy))
|
rhs->isObjCIdType() || rhs->isObjCClassType())
|
||||||
return true;
|
return true;
|
||||||
} else if (const PointerType *PT = rhs->getAsPointerType()) {
|
|
||||||
QualType PointeeTy = PT->getPointeeType();
|
|
||||||
if (PointeeTy->isVoidType() ||
|
|
||||||
Context.isObjCIdStructType(PointeeTy) ||
|
|
||||||
Context.isObjCClassStructType(PointeeTy))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) {
|
if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) {
|
||||||
const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType();
|
const ObjCObjectPointerType *rhsOPT = rhs->getAsObjCObjectPointerType();
|
||||||
const ObjCQualifiedInterfaceType *rhsQI = 0;
|
|
||||||
QualType rtype;
|
|
||||||
|
|
||||||
if (!rhsQID) {
|
if (!rhsOPT) return false;
|
||||||
// Not comparing two ObjCQualifiedIdType's?
|
|
||||||
if (!rhs->isPointerType()) return false;
|
if (rhsOPT->qual_empty()) {
|
||||||
|
// If the RHS is a unqualified interface pointer "NSString*",
|
||||||
rtype = rhs->getAsPointerType()->getPointeeType();
|
// make sure we check the class hierarchy.
|
||||||
rhsQI = rtype->getAsObjCQualifiedInterfaceType();
|
if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
|
||||||
if (rhsQI == 0) {
|
for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
|
||||||
// If the RHS is a unqualified interface pointer "NSString*",
|
E = lhsQID->qual_end(); I != E; ++I) {
|
||||||
// make sure we check the class hierarchy.
|
// when comparing an id<P> on lhs with a static type on rhs,
|
||||||
if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) {
|
// see if static class implements all of id's protocols, directly or
|
||||||
ObjCInterfaceDecl *rhsID = IT->getDecl();
|
// through its super class and categories.
|
||||||
for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
|
if (!ClassImplementsProtocol(*I, rhsID, true))
|
||||||
E = lhsQID->qual_end(); I != E; ++I) {
|
return false;
|
||||||
// when comparing an id<P> on lhs with a static type on rhs,
|
|
||||||
// see if static class implements all of id's protocols, directly or
|
|
||||||
// through its super class and categories.
|
|
||||||
if (!ClassImplementsProtocol(*I, rhsID, true))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
// If there are no qualifiers and no interface, we have an 'id'.
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
// Both the right and left sides have qualifiers.
|
||||||
ObjCObjectPointerType::qual_iterator RHSProtoI, RHSProtoE;
|
|
||||||
if (rhsQI) { // We have a qualified interface (e.g. "NSObject<Proto> *").
|
|
||||||
RHSProtoI = rhsQI->qual_begin();
|
|
||||||
RHSProtoE = rhsQI->qual_end();
|
|
||||||
} else if (rhsQID) { // We have a qualified id (e.g. "id<Proto> *").
|
|
||||||
RHSProtoI = rhsQID->qual_begin();
|
|
||||||
RHSProtoE = rhsQID->qual_end();
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
|
for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
|
||||||
E = lhsQID->qual_end(); I != E; ++I) {
|
E = lhsQID->qual_end(); I != E; ++I) {
|
||||||
ObjCProtocolDecl *lhsProto = *I;
|
ObjCProtocolDecl *lhsProto = *I;
|
||||||
|
@ -803,28 +779,26 @@ bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
|
||||||
// when comparing an id<P> on lhs with a static type on rhs,
|
// when comparing an id<P> on lhs with a static type on rhs,
|
||||||
// see if static class implements all of id's protocols, directly or
|
// see if static class implements all of id's protocols, directly or
|
||||||
// through its super class and categories.
|
// through its super class and categories.
|
||||||
for (; RHSProtoI != RHSProtoE; ++RHSProtoI) {
|
for (ObjCObjectPointerType::qual_iterator J = rhsOPT->qual_begin(),
|
||||||
ObjCProtocolDecl *rhsProto = *RHSProtoI;
|
E = rhsOPT->qual_end(); J != E; ++J) {
|
||||||
|
ObjCProtocolDecl *rhsProto = *J;
|
||||||
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
|
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
|
||||||
(compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
|
(compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
|
||||||
match = true;
|
match = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rhsQI) {
|
// If the RHS is a qualified interface pointer "NSString<P>*",
|
||||||
// If the RHS is a qualified interface pointer "NSString<P>*",
|
// make sure we check the class hierarchy.
|
||||||
// make sure we check the class hierarchy.
|
if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
|
||||||
if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) {
|
for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
|
||||||
ObjCInterfaceDecl *rhsID = IT->getDecl();
|
E = lhsQID->qual_end(); I != E; ++I) {
|
||||||
for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
|
// when comparing an id<P> on lhs with a static type on rhs,
|
||||||
E = lhsQID->qual_end(); I != E; ++I) {
|
// see if static class implements all of id's protocols, directly or
|
||||||
// when comparing an id<P> on lhs with a static type on rhs,
|
// through its super class and categories.
|
||||||
// see if static class implements all of id's protocols, directly or
|
if (ClassImplementsProtocol(*I, rhsID, true)) {
|
||||||
// through its super class and categories.
|
match = true;
|
||||||
if (ClassImplementsProtocol(*I, rhsID, true)) {
|
break;
|
||||||
match = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -837,7 +811,52 @@ bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
|
||||||
|
|
||||||
const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType();
|
const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType();
|
||||||
assert(rhsQID && "One of the LHS/RHS should be id<x>");
|
assert(rhsQID && "One of the LHS/RHS should be id<x>");
|
||||||
|
|
||||||
|
if (const ObjCObjectPointerType *lhsOPT =
|
||||||
|
lhs->getAsObjCInterfacePointerType()) {
|
||||||
|
if (lhsOPT->qual_empty()) {
|
||||||
|
bool match = false;
|
||||||
|
if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) {
|
||||||
|
for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(),
|
||||||
|
E = rhsQID->qual_end(); I != E; ++I) {
|
||||||
|
// when comparing an id<P> on lhs with a static type on rhs,
|
||||||
|
// see if static class implements all of id's protocols, directly or
|
||||||
|
// through its super class and categories.
|
||||||
|
if (ClassImplementsProtocol(*I, lhsID, true)) {
|
||||||
|
match = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!match)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Both the right and left sides have qualifiers.
|
||||||
|
for (ObjCObjectPointerType::qual_iterator I = lhsOPT->qual_begin(),
|
||||||
|
E = lhsOPT->qual_end(); I != E; ++I) {
|
||||||
|
ObjCProtocolDecl *lhsProto = *I;
|
||||||
|
bool match = false;
|
||||||
|
|
||||||
|
// when comparing an id<P> on lhs with a static type on rhs,
|
||||||
|
// see if static class implements all of id's protocols, directly or
|
||||||
|
// through its super class and categories.
|
||||||
|
for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(),
|
||||||
|
E = rhsQID->qual_end(); J != E; ++J) {
|
||||||
|
ObjCProtocolDecl *rhsProto = *J;
|
||||||
|
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
|
||||||
|
(compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
|
||||||
|
match = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!match)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// FIXME: The code below will be removed when ObjCQualifiedInterfaceType is
|
||||||
|
// removed.
|
||||||
if (!lhs->isPointerType())
|
if (!lhs->isPointerType())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -864,17 +883,6 @@ bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const ObjCInterfaceType *IT = ltype->getAsObjCInterfaceType()) {
|
|
||||||
// for static type vs. qualified 'id' type, check that class implements
|
|
||||||
// all of 'id's protocols.
|
|
||||||
ObjCInterfaceDecl *lhsID = IT->getDecl();
|
|
||||||
for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(),
|
|
||||||
E = rhsQID->qual_end(); I != E; ++I) {
|
|
||||||
if (!ClassImplementsProtocol(*I, lhsID, compare, true))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1005,77 +1005,64 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
|
||||||
if (!getLangOptions().ObjC1)
|
if (!getLangOptions().ObjC1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Conversions with Objective-C's id<...>.
|
// First, we handle all conversions on ObjC object pointer types.
|
||||||
if ((FromType->isObjCQualifiedIdType() || ToType->isObjCQualifiedIdType()) &&
|
const ObjCObjectPointerType* ToObjCPtr = ToType->getAsObjCObjectPointerType();
|
||||||
ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) {
|
const ObjCObjectPointerType *FromObjCPtr =
|
||||||
ConvertedType = ToType;
|
FromType->getAsObjCObjectPointerType();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Beyond this point, both types need to be pointers or block pointers.
|
if (ToObjCPtr && FromObjCPtr) {
|
||||||
|
// Objective C++: We're able to convert between "id" and a pointer
|
||||||
|
// to any interface (in both directions).
|
||||||
|
if (ToObjCPtr->isObjCIdType() && FromObjCPtr->isObjCIdType()) {
|
||||||
|
ConvertedType = ToType;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Objective C++: Allow conversions between the Objective-C "Class" and a
|
||||||
|
// pointer to any interface (in both directions).
|
||||||
|
if (ToObjCPtr->isObjCClassType() || FromObjCPtr->isObjCClassType()) {
|
||||||
|
ConvertedType = ToType;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Conversions with Objective-C's id<...>.
|
||||||
|
if ((FromObjCPtr->isObjCQualifiedIdType() ||
|
||||||
|
ToObjCPtr->isObjCQualifiedIdType()) &&
|
||||||
|
ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) {
|
||||||
|
ConvertedType = ToType;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Objective C++: We're able to convert from a pointer to an
|
||||||
|
// interface to a pointer to a different interface.
|
||||||
|
if (Context.canAssignObjCInterfaces(ToObjCPtr, FromObjCPtr)) {
|
||||||
|
ConvertedType = ToType;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Context.canAssignObjCInterfaces(FromObjCPtr, ToObjCPtr)) {
|
||||||
|
// Okay: this is some kind of implicit downcast of Objective-C
|
||||||
|
// interfaces, which is permitted. However, we're going to
|
||||||
|
// complain about it.
|
||||||
|
IncompatibleObjC = true;
|
||||||
|
ConvertedType = FromType;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Beyond this point, both types need to be C pointers or block pointers.
|
||||||
QualType ToPointeeType;
|
QualType ToPointeeType;
|
||||||
const PointerType* ToTypePtr = ToType->getAsPointerType();
|
if (const PointerType *ToCPtr = ToType->getAsPointerType())
|
||||||
if (ToTypePtr)
|
ToPointeeType = ToCPtr->getPointeeType();
|
||||||
ToPointeeType = ToTypePtr->getPointeeType();
|
|
||||||
else if (const BlockPointerType *ToBlockPtr = ToType->getAsBlockPointerType())
|
else if (const BlockPointerType *ToBlockPtr = ToType->getAsBlockPointerType())
|
||||||
ToPointeeType = ToBlockPtr->getPointeeType();
|
ToPointeeType = ToBlockPtr->getPointeeType();
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QualType FromPointeeType;
|
QualType FromPointeeType;
|
||||||
const PointerType *FromTypePtr = FromType->getAsPointerType();
|
if (const PointerType *FromCPtr = FromType->getAsPointerType())
|
||||||
if (FromTypePtr)
|
FromPointeeType = FromCPtr->getPointeeType();
|
||||||
FromPointeeType = FromTypePtr->getPointeeType();
|
else if (const BlockPointerType *FromBlockPtr = FromType->getAsBlockPointerType())
|
||||||
else if (const BlockPointerType *FromBlockPtr
|
|
||||||
= FromType->getAsBlockPointerType())
|
|
||||||
FromPointeeType = FromBlockPtr->getPointeeType();
|
FromPointeeType = FromBlockPtr->getPointeeType();
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Objective C++: We're able to convert from a pointer to an
|
|
||||||
// interface to a pointer to a different interface.
|
|
||||||
const ObjCInterfaceType* FromIface = FromPointeeType->getAsObjCInterfaceType();
|
|
||||||
const ObjCInterfaceType* ToIface = ToPointeeType->getAsObjCInterfaceType();
|
|
||||||
if (FromIface && ToIface &&
|
|
||||||
Context.canAssignObjCInterfaces(ToIface, FromIface)) {
|
|
||||||
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
|
|
||||||
ToPointeeType,
|
|
||||||
ToType, Context);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FromIface && ToIface &&
|
|
||||||
Context.canAssignObjCInterfaces(FromIface, ToIface)) {
|
|
||||||
// Okay: this is some kind of implicit downcast of Objective-C
|
|
||||||
// interfaces, which is permitted. However, we're going to
|
|
||||||
// complain about it.
|
|
||||||
IncompatibleObjC = true;
|
|
||||||
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
|
|
||||||
ToPointeeType,
|
|
||||||
ToType, Context);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Objective C++: We're able to convert between "id" and a pointer
|
|
||||||
// to any interface (in both directions).
|
|
||||||
if ((FromIface && Context.isObjCIdStructType(ToPointeeType))
|
|
||||||
|| (ToIface && Context.isObjCIdStructType(FromPointeeType))) {
|
|
||||||
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
|
|
||||||
ToPointeeType,
|
|
||||||
ToType, Context);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Objective C++: Allow conversions between the Objective-C "id" and
|
|
||||||
// "Class", in either direction.
|
|
||||||
if ((Context.isObjCIdStructType(FromPointeeType) &&
|
|
||||||
Context.isObjCClassStructType(ToPointeeType)) ||
|
|
||||||
(Context.isObjCClassStructType(FromPointeeType) &&
|
|
||||||
Context.isObjCIdStructType(ToPointeeType))) {
|
|
||||||
ConvertedType = ToType;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have pointers to pointers, recursively check whether this
|
// If we have pointers to pointers, recursively check whether this
|
||||||
// is an Objective-C conversion.
|
// is an Objective-C conversion.
|
||||||
if (FromPointeeType->isPointerType() && ToPointeeType->isPointerType() &&
|
if (FromPointeeType->isPointerType() && ToPointeeType->isPointerType() &&
|
||||||
|
@ -1086,7 +1073,6 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
|
||||||
ConvertedType = ToType;
|
ConvertedType = ToType;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have pointers to functions or blocks, check whether the only
|
// If we have pointers to functions or blocks, check whether the only
|
||||||
// differences in the argument and result types are in Objective-C
|
// differences in the argument and result types are in Objective-C
|
||||||
// pointer conversions. If so, we permit the conversion (but
|
// pointer conversions. If so, we permit the conversion (but
|
||||||
|
@ -1167,15 +1153,6 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType) {
|
||||||
QualType FromPointeeType = FromPtrType->getPointeeType(),
|
QualType FromPointeeType = FromPtrType->getPointeeType(),
|
||||||
ToPointeeType = ToPtrType->getPointeeType();
|
ToPointeeType = ToPtrType->getPointeeType();
|
||||||
|
|
||||||
// Objective-C++ conversions are always okay.
|
|
||||||
// FIXME: We should have a different class of conversions for the
|
|
||||||
// Objective-C++ implicit conversions.
|
|
||||||
if (Context.isObjCIdStructType(FromPointeeType) ||
|
|
||||||
Context.isObjCIdStructType(ToPointeeType) ||
|
|
||||||
Context.isObjCClassStructType(FromPointeeType) ||
|
|
||||||
Context.isObjCClassStructType(ToPointeeType))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (FromPointeeType->isRecordType() &&
|
if (FromPointeeType->isRecordType() &&
|
||||||
ToPointeeType->isRecordType()) {
|
ToPointeeType->isRecordType()) {
|
||||||
// We must have a derived-to-base conversion. Check an
|
// We must have a derived-to-base conversion. Check an
|
||||||
|
@ -1185,7 +1162,18 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType) {
|
||||||
From->getSourceRange());
|
From->getSourceRange());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (const ObjCObjectPointerType *FromPtrType =
|
||||||
|
FromType->getAsObjCObjectPointerType())
|
||||||
|
if (const ObjCObjectPointerType *ToPtrType =
|
||||||
|
ToType->getAsObjCObjectPointerType()) {
|
||||||
|
// Objective-C++ conversions are always okay.
|
||||||
|
// FIXME: We should have a different class of conversions for the
|
||||||
|
// Objective-C++ implicit conversions.
|
||||||
|
if (FromPtrType->isObjCIdType() || ToPtrType->isObjCIdType() ||
|
||||||
|
FromPtrType->isObjCClassType() || ToPtrType->isObjCClassType())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,8 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
|
||||||
case DeclSpec::TST_unspecified:
|
case DeclSpec::TST_unspecified:
|
||||||
// "<proto1,proto2>" is an objc qualified ID with a missing id.
|
// "<proto1,proto2>" is an objc qualified ID with a missing id.
|
||||||
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
|
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
|
||||||
Result = Context.getObjCObjectPointerType(0, (ObjCProtocolDecl**)PQ,
|
Result = Context.getObjCObjectPointerType(QualType(),
|
||||||
|
(ObjCProtocolDecl**)PQ,
|
||||||
DS.getNumProtocolQualifiers());
|
DS.getNumProtocolQualifiers());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -197,14 +198,16 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
|
||||||
// FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so we have
|
// FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so we have
|
||||||
// this "hack" for now...
|
// this "hack" for now...
|
||||||
if (const ObjCInterfaceType *Interface = Result->getAsObjCInterfaceType())
|
if (const ObjCInterfaceType *Interface = Result->getAsObjCInterfaceType())
|
||||||
|
// FIXME: Remove ObjCQualifiedInterfaceType (by moving the list of
|
||||||
|
// protocols 'up' to ObjCInterfaceType).
|
||||||
Result = Context.getObjCQualifiedInterfaceType(Interface->getDecl(),
|
Result = Context.getObjCQualifiedInterfaceType(Interface->getDecl(),
|
||||||
(ObjCProtocolDecl**)PQ,
|
(ObjCProtocolDecl**)PQ,
|
||||||
DS.getNumProtocolQualifiers());
|
DS.getNumProtocolQualifiers());
|
||||||
else if (Result == Context.getObjCIdType())
|
else if (Result->isObjCIdType())
|
||||||
// id<protocol-list>
|
// id<protocol-list>
|
||||||
Result = Context.getObjCObjectPointerType(0, (ObjCProtocolDecl**)PQ,
|
Result = Context.getObjCObjectPointerType(QualType(),
|
||||||
DS.getNumProtocolQualifiers());
|
(ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers());
|
||||||
else if (Result == Context.getObjCClassType()) {
|
else if (Result->isObjCClassType()) {
|
||||||
if (DeclLoc.isInvalid())
|
if (DeclLoc.isInvalid())
|
||||||
DeclLoc = DS.getSourceRange().getBegin();
|
DeclLoc = DS.getSourceRange().getBegin();
|
||||||
// Class<protocol-list>
|
// Class<protocol-list>
|
||||||
|
@ -886,6 +889,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
|
||||||
D.setInvalidType(true);
|
D.setInvalidType(true);
|
||||||
// Build the type anyway.
|
// Build the type anyway.
|
||||||
}
|
}
|
||||||
|
if (getLangOptions().ObjC1 && T->isObjCInterfaceType()) {
|
||||||
|
const ObjCInterfaceType *OIT = T->getAsObjCInterfaceType();
|
||||||
|
T = Context.getObjCObjectPointerType(T,
|
||||||
|
(ObjCProtocolDecl **)OIT->qual_begin(),
|
||||||
|
OIT->getNumProtocols());
|
||||||
|
break;
|
||||||
|
}
|
||||||
T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name);
|
T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name);
|
||||||
break;
|
break;
|
||||||
case DeclaratorChunk::Reference:
|
case DeclaratorChunk::Reference:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// RUN: clang-cc -triple=i686-apple-darwin9 -fnext-runtime -emit-llvm -o %t %s &&
|
// RUN: clang-cc -triple=i686-apple-darwin9 -fnext-runtime -emit-llvm -o %t %s &&
|
||||||
// RUN: grep -e "\^{Innermost=CC}" %t | count 1 &&
|
// RUN: grep -e "\^{Innermost=CC}" %t | count 1 &&
|
||||||
// RUN: grep -e "{Derived=#ib32b8b3b8sb16b8b8b2b8ccb6}" %t | count 1 &&
|
// RUN: grep -e "{Derived=^{objc_class}ib32b8b3b8sb16b8b8b2b8ccb6}" %t | count 1 &&
|
||||||
// RUN: grep -e "{B1=#@c}" %t | count 1 &&
|
// RUN: grep -e "{B1=^{objc_class}@c}" %t | count 1 &&
|
||||||
// RUN: grep -e "v12@0:4\[3\[4@]]8" %t | count 1 &&
|
// RUN: grep -e "v12@0:4\[3\[4@]]8" %t | count 1 &&
|
||||||
// RUN: grep -e "r\^{S=i}" %t | count 1 &&
|
// RUN: grep -e "r\^{S=i}" %t | count 1 &&
|
||||||
// RUN: grep -e "\^{Object=#}" %t | count 1
|
// RUN: grep -e "\^{Object=#}" %t | count 1
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
@class C;
|
@class C;
|
||||||
|
|
||||||
// RUN: grep _Z1fP11objc_object %t | count 1 &&
|
// RUN: grep _Z1fP2id %t | count 1 &&
|
||||||
void __attribute__((overloadable)) f(C *c) { }
|
void __attribute__((overloadable)) f(id c) { }
|
||||||
|
|
||||||
// RUN: grep _Z1fP1C %t | count 1
|
// RUN: grep _Z1fP1C %t | count 1
|
||||||
void __attribute__((overloadable)) f(id c) { }
|
void __attribute__((overloadable)) f(C *c) { }
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
// RUN: clang-cc -fblocks -include-pch %t -fsyntax-only -verify %s
|
// RUN: clang-cc -fblocks -include-pch %t -fsyntax-only -verify %s
|
||||||
|
|
||||||
// Expressions
|
// Expressions
|
||||||
int *A1 = (objc_string)0; // expected-warning {{'struct objc_object *'}}
|
int *A1 = (objc_string)0; // expected-warning {{aka 'id'}}
|
||||||
|
|
||||||
char A2 = (objc_encode){}; // expected-error {{not a compile-time constant}} \
|
char A2 = (objc_encode){}; // expected-error {{not a compile-time constant}} \
|
||||||
expected-warning {{char [2]}}
|
expected-warning {{char [2]}}
|
||||||
|
@ -15,8 +15,7 @@ int *A3 = (objc_protocol)0; // expected-warning {{aka 'Protocol *'}}
|
||||||
|
|
||||||
|
|
||||||
// Types.
|
// Types.
|
||||||
int *T0 = (objc_id_protocol_ty)0; // expected-error {{not a compile-time constant}} \
|
int *T0 = (objc_id_protocol_ty)0; // expected-warning {{aka 'id<foo>'}}
|
||||||
expected-warning {{aka 'id<foo>'}}
|
|
||||||
|
|
||||||
int *T1 = (objc_interface_ty)0; // expected-warning {{aka 'itf *'}}
|
int *T1 = (objc_interface_ty)0; // expected-warning {{aka 'itf *'}}
|
||||||
int *T2 = (objc_qual_interface_ty)0; // expected-warning {{aka 'itf<foo> *'}}
|
int *T2 = (objc_qual_interface_ty)0; // expected-warning {{aka 'itf<foo> *'}}
|
||||||
|
|
|
@ -26,8 +26,8 @@ int main()
|
||||||
MyOtherClass<MyProtocol> *obj_c_super_p_q = nil;
|
MyOtherClass<MyProtocol> *obj_c_super_p_q = nil;
|
||||||
MyClass<MyProtocol> *obj_c_cat_p_q = nil;
|
MyClass<MyProtocol> *obj_c_cat_p_q = nil;
|
||||||
|
|
||||||
obj_c_cat_p = obj_id_p; // expected-warning {{incompatible type assigning 'id<MyProtocol>', expected 'MyClass *'}}
|
obj_c_cat_p = obj_id_p;
|
||||||
obj_c_super_p = obj_id_p; // expected-warning {{incompatible type assigning 'id<MyProtocol>', expected 'MyOtherClass *'}}
|
obj_c_super_p = obj_id_p;
|
||||||
obj_id_p = obj_c_cat_p; /* Ok */
|
obj_id_p = obj_c_cat_p; /* Ok */
|
||||||
obj_id_p = obj_c_super_p; /* Ok */
|
obj_id_p = obj_c_super_p; /* Ok */
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ void f9(int cond, id<P0,P1> x0, id<P0,P2> x1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void f10(int cond, id<P0,P1> x0, id<P0,P2> x1) {
|
void f10(int cond, id<P0,P1> x0, id<P0,P2> x1) {
|
||||||
barP2(cond ? x0 : x1);
|
barP2(cond ? x0 : x1); // expected-warning {{incompatible type passing 'id<P0,P1>', expected 'id<P2>'}}
|
||||||
}
|
}
|
||||||
|
|
||||||
int f11(int cond, A* a, B* b) {
|
int f11(int cond, A* a, B* b) {
|
||||||
|
|
|
@ -15,6 +15,6 @@ void foo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test attempt to redefine 'id' in an incompatible fashion.
|
// Test attempt to redefine 'id' in an incompatible fashion.
|
||||||
typedef int id; // expected-error {{typedef redefinition with different types}}
|
typedef int id; // FIXME: Decide how we want to deal with this (now that 'id' is more of a built-in type).
|
||||||
id b;
|
id b;
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,6 @@ int test5(int X) {
|
||||||
void foo4() {
|
void foo4() {
|
||||||
struct objc_object X[10];
|
struct objc_object X[10];
|
||||||
|
|
||||||
[X rect];
|
[(id)X rect];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,5 @@ extern __strong id p5;
|
||||||
extern char* __strong p6; // expected-note {{previous definition is here}}
|
extern char* __strong p6; // expected-note {{previous definition is here}}
|
||||||
extern char* p6; // expected-error {{redefinition of 'p6' with a different type}}
|
extern char* p6; // expected-error {{redefinition of 'p6' with a different type}}
|
||||||
|
|
||||||
// FIXME. We do not issue error here because we don't put the attribute on the pointer type.
|
extern __strong char* p7; // expected-note {{previous definition is here}}
|
||||||
extern __strong char* p7;
|
extern char* p7; // expected-error {{redefinition of 'p7' with a different type}}
|
||||||
extern char* p7;
|
|
||||||
|
|
|
@ -17,6 +17,6 @@ void f2(id<NSCopying> o)
|
||||||
|
|
||||||
void f3(id o)
|
void f3(id o)
|
||||||
{
|
{
|
||||||
o.foo; // expected-error{{member reference base type 'id' is not a structure or union}}
|
o.foo; // expected-error{{property 'foo' not found on object of type 'id'}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// RUN: clang-cc -fsyntax-only -verify %s
|
// RUN: clang-cc -fsyntax-only -verify %s
|
||||||
|
// XFAIL
|
||||||
@interface Foo
|
@interface Foo
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче