Skip to content

Commit ab209d8

Browse files
committedJul 7, 2015
Implement the Objective-C __kindof type qualifier.
The __kindof type qualifier can be applied to Objective-C object (pointer) types to indicate id-like behavior, which includes implicit "downcasting" of __kindof types to subclasses and id-like message-send behavior. __kindof types provide better type bounds for substitutions into unspecified generic types, which preserves more type information. llvm-svn: 241548
1 parent 10dc9d8 commit ab209d8

26 files changed

+841
-97
lines changed
 

‎clang/include/clang/AST/ASTContext.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -1195,14 +1195,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
11951195
QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
11961196
ObjCInterfaceDecl *PrevDecl = nullptr) const;
11971197

1198-
/// Legacy interface: cannot provide type arguments.
1198+
/// Legacy interface: cannot provide type arguments or __kindof.
11991199
QualType getObjCObjectType(QualType Base,
12001200
ObjCProtocolDecl * const *Protocols,
12011201
unsigned NumProtocols) const;
12021202

12031203
QualType getObjCObjectType(QualType Base,
12041204
ArrayRef<QualType> typeArgs,
1205-
ArrayRef<ObjCProtocolDecl *> protocols) const;
1205+
ArrayRef<ObjCProtocolDecl *> protocols,
1206+
bool isKindOf) const;
12061207

12071208
bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl);
12081209
/// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in

‎clang/include/clang/AST/Type.h

+66-6
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,9 @@ class QualType {
10541054
const DeclContext *dc,
10551055
ObjCSubstitutionContext context) const;
10561056

1057+
/// Strip Objective-C "__kindof" types from the given type.
1058+
QualType stripObjCKindOfType(const ASTContext &ctx) const;
1059+
10571060
private:
10581061
// These methods are implemented in a separate translation unit;
10591062
// "static"-ize them to avoid creating temporary QualTypes in the
@@ -1353,9 +1356,12 @@ class Type : public ExtQualsTypeCommonBase {
13531356

13541357
/// NumProtocols - The number of protocols stored directly on this
13551358
/// object type.
1356-
unsigned NumProtocols : 7;
1359+
unsigned NumProtocols : 6;
1360+
1361+
/// Whether this is a "kindof" type.
1362+
unsigned IsKindOf : 1;
13571363
};
1358-
static_assert(NumTypeBits + 7 + 7 <= 32, "Does not fit in an unsigned");
1364+
static_assert(NumTypeBits + 7 + 6 + 1 <= 32, "Does not fit in an unsigned");
13591365

13601366
class ReferenceTypeBitfields {
13611367
friend class ReferenceType;
@@ -1649,7 +1655,27 @@ class Type : public ExtQualsTypeCommonBase {
16491655
bool isObjCQualifiedClassType() const; // Class<foo>
16501656
bool isObjCObjectOrInterfaceType() const;
16511657
bool isObjCIdType() const; // id
1658+
1659+
/// Whether the type is Objective-C 'id' or a __kindof type of an
1660+
/// object type, e.g., __kindof NSView * or __kindof id
1661+
/// <NSCopying>.
1662+
///
1663+
/// \param bound Will be set to the bound on non-id subtype types,
1664+
/// which will be (possibly specialized) Objective-C class type, or
1665+
/// null for 'id.
1666+
bool isObjCIdOrObjectKindOfType(const ASTContext &ctx,
1667+
const ObjCObjectType *&bound) const;
1668+
16521669
bool isObjCClassType() const; // Class
1670+
1671+
/// Whether the type is Objective-C 'Class' or a __kindof type of an
1672+
/// Class type, e.g., __kindof Class <NSCopying>.
1673+
///
1674+
/// Unlike \c isObjCIdOrObjectKindOfType, there is no relevant bound
1675+
/// here because Objective-C's type system cannot express "a class
1676+
/// object for a subclass of NSFoo".
1677+
bool isObjCClassOrClassKindOfType() const;
1678+
16531679
bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const;
16541680
bool isObjCSelType() const; // Class
16551681
bool isObjCBuiltinType() const; // 'id' or 'Class'
@@ -3581,6 +3607,7 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
35813607
attr_nonnull,
35823608
attr_nullable,
35833609
attr_null_unspecified,
3610+
attr_objc_kindof,
35843611
};
35853612

35863613
private:
@@ -4514,14 +4541,16 @@ class ObjCObjectType : public Type {
45144541
protected:
45154542
ObjCObjectType(QualType Canonical, QualType Base,
45164543
ArrayRef<QualType> typeArgs,
4517-
ArrayRef<ObjCProtocolDecl *> protocols);
4544+
ArrayRef<ObjCProtocolDecl *> protocols,
4545+
bool isKindOf);
45184546

45194547
enum Nonce_ObjCInterface { Nonce_ObjCInterface };
45204548
ObjCObjectType(enum Nonce_ObjCInterface)
45214549
: Type(ObjCInterface, QualType(), false, false, false, false),
45224550
BaseType(QualType(this_(), 0)) {
45234551
ObjCObjectTypeBits.NumProtocols = 0;
45244552
ObjCObjectTypeBits.NumTypeArgs = 0;
4553+
ObjCObjectTypeBits.IsKindOf = 0;
45254554
}
45264555

45274556
void computeSuperClassTypeSlow() const;
@@ -4603,6 +4632,17 @@ class ObjCObjectType : public Type {
46034632
return qual_begin()[I];
46044633
}
46054634

4635+
/// Retrieve all of the protocol qualifiers.
4636+
ArrayRef<ObjCProtocolDecl *> getProtocols() const {
4637+
return ArrayRef<ObjCProtocolDecl *>(qual_begin(), getNumProtocols());
4638+
}
4639+
4640+
/// Whether this is a "__kindof" type as written.
4641+
bool isKindOfTypeAsWritten() const { return ObjCObjectTypeBits.IsKindOf; }
4642+
4643+
/// Whether this ia a "__kindof" type (semantically).
4644+
bool isKindOfType() const;
4645+
46064646
/// Retrieve the type of the superclass of this object type.
46074647
///
46084648
/// This operation substitutes any type arguments into the
@@ -4617,6 +4657,10 @@ class ObjCObjectType : public Type {
46174657
return QualType(CachedSuperClassType.getPointer(), 0);
46184658
}
46194659

4660+
/// Strip off the Objective-C "kindof" type and (with it) any
4661+
/// protocol qualifiers.
4662+
QualType stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const;
4663+
46204664
bool isSugared() const { return false; }
46214665
QualType desugar() const { return QualType(this, 0); }
46224666

@@ -4638,15 +4682,17 @@ class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode {
46384682

46394683
ObjCObjectTypeImpl(QualType Canonical, QualType Base,
46404684
ArrayRef<QualType> typeArgs,
4641-
ArrayRef<ObjCProtocolDecl *> protocols)
4642-
: ObjCObjectType(Canonical, Base, typeArgs, protocols) {}
4685+
ArrayRef<ObjCProtocolDecl *> protocols,
4686+
bool isKindOf)
4687+
: ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {}
46434688

46444689
public:
46454690
void Profile(llvm::FoldingSetNodeID &ID);
46464691
static void Profile(llvm::FoldingSetNodeID &ID,
46474692
QualType Base,
46484693
ArrayRef<QualType> typeArgs,
4649-
ArrayRef<ObjCProtocolDecl *> protocols);
4694+
ArrayRef<ObjCProtocolDecl *> protocols,
4695+
bool isKindOf);
46504696
};
46514697

46524698
inline QualType *ObjCObjectType::getTypeArgStorage() {
@@ -4798,6 +4844,12 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
47984844
return getObjectType()->isObjCUnqualifiedClass();
47994845
}
48004846

4847+
/// isObjCIdOrClassType - True if this is equivalent to the 'id' or
4848+
/// 'Class' type,
4849+
bool isObjCIdOrClassType() const {
4850+
return getObjectType()->isObjCUnqualifiedIdOrClass();
4851+
}
4852+
48014853
/// isObjCQualifiedIdType - True if this is equivalent to 'id<P>' for some
48024854
/// non-empty set of protocols.
48034855
bool isObjCQualifiedIdType() const {
@@ -4810,6 +4862,9 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
48104862
return getObjectType()->isObjCQualifiedClass();
48114863
}
48124864

4865+
/// Whether this is a "__kindof" type.
4866+
bool isKindOfType() const { return getObjectType()->isKindOfType(); }
4867+
48134868
/// Whether this type is specialized, meaning that it has type arguments.
48144869
bool isSpecialized() const { return getObjectType()->isSpecialized(); }
48154870

@@ -4873,6 +4928,11 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
48734928
/// null type if there is no superclass.
48744929
QualType getSuperClassType() const;
48754930

4931+
/// Strip off the Objective-C "kindof" type and (with it) any
4932+
/// protocol qualifiers.
4933+
const ObjCObjectPointerType *stripObjCKindOfTypeAndQuals(
4934+
const ASTContext &ctx) const;
4935+
48764936
void Profile(llvm::FoldingSetNodeID &ID) {
48774937
Profile(ID, getPointeeType());
48784938
}

‎clang/include/clang/Basic/Attr.td

+5
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,11 @@ def TypeNullUnspecified : TypeAttr {
976976
let Documentation = [TypeNullUnspecifiedDocs];
977977
}
978978

979+
def ObjCKindOf : TypeAttr {
980+
let Spellings = [Keyword<"__kindof">];
981+
let Documentation = [Undocumented];
982+
}
983+
979984
def AssumeAligned : InheritableAttr {
980985
let Spellings = [GCC<"assume_aligned">];
981986
let Subjects = SubjectList<[ObjCMethod, Function]>;

‎clang/include/clang/Basic/DiagnosticSemaKinds.td

+6
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,12 @@ def warning_multiple_selectors: Warning<
978978
"several methods with selector %0 of mismatched types are found "
979979
"for the @selector expression">,
980980
InGroup<SelectorTypeMismatch>, DefaultIgnore;
981+
982+
def err_objc_kindof_nonobject : Error<
983+
"'__kindof' specifier cannot be applied to non-object type %0">;
984+
def err_objc_kindof_wrong_position : Error<
985+
"'__kindof' type specifier must precede the declarator">;
986+
981987
// C++ declarations
982988
def err_static_assert_expression_is_not_constant : Error<
983989
"static_assert expression is not an integral constant expression">;

‎clang/include/clang/Basic/TokenKinds.def

+3
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,9 @@ KEYWORD(__bridge_transfer , KEYARC)
526526
KEYWORD(__bridge_retained , KEYARC)
527527
KEYWORD(__bridge_retain , KEYARC)
528528

529+
// Objective-C keywords.
530+
KEYWORD(__kindof , KEYOBJC2)
531+
529532
// Alternate spelling for various tokens. There are GCC extensions in all
530533
// languages, but should not be disabled in strict conformance mode.
531534
ALIAS("__alignof__" , __alignof , KEYALL)

‎clang/include/clang/Sema/Sema.h

+4
Original file line numberDiff line numberDiff line change
@@ -7240,6 +7240,10 @@ class Sema {
72407240
SourceLocation ProtocolRAngleLoc,
72417241
bool FailOnError = false);
72427242

7243+
/// Check the application of the Objective-C '__kindof' qualifier to
7244+
/// the given type.
7245+
bool checkObjCKindOfType(QualType &type, SourceLocation loc);
7246+
72437247
/// Ensure attributes are consistent with type.
72447248
/// \param [in, out] Attributes The attributes to check; they will
72457249
/// be modified to be consistent with \p PropertyTy.

0 commit comments

Comments
 (0)