r241548 - Implement the Objective-C __kindof type qualifier.
Douglas Gregor
dgregor at apple.com
Mon Jul 6 20:58:43 PDT 2015
Author: dgregor
Date: Mon Jul 6 22:58:42 2015
New Revision: 241548
URL: http://llvm.org/viewvc/llvm-project?rev=241548&view=rev
Log:
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.
Added:
cfe/trunk/test/PCH/objc_kindof.m
cfe/trunk/test/SemaObjC/kindof.m
Modified:
cfe/trunk/include/clang/AST/ASTContext.h
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/include/clang/Basic/Attr.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Basic/TokenKinds.def
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/AST/ASTDiagnostic.cpp
cfe/trunk/lib/AST/ASTImporter.cpp
cfe/trunk/lib/AST/ItaniumMangle.cpp
cfe/trunk/lib/AST/Type.cpp
cfe/trunk/lib/AST/TypePrinter.cpp
cfe/trunk/lib/Basic/IdentifierTable.cpp
cfe/trunk/lib/Lex/PPMacroExpansion.cpp
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseTentative.cpp
cfe/trunk/lib/Sema/SemaExprObjC.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/lib/Serialization/ASTReader.cpp
cfe/trunk/lib/Serialization/ASTWriter.cpp
cfe/trunk/test/CodeGenObjCXX/mangle.mm
cfe/trunk/test/SemaObjC/parameterized_classes_subst.m
cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm
Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Mon Jul 6 22:58:42 2015
@@ -1195,14 +1195,15 @@ public:
QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
ObjCInterfaceDecl *PrevDecl = nullptr) const;
- /// Legacy interface: cannot provide type arguments.
+ /// Legacy interface: cannot provide type arguments or __kindof.
QualType getObjCObjectType(QualType Base,
ObjCProtocolDecl * const *Protocols,
unsigned NumProtocols) const;
QualType getObjCObjectType(QualType Base,
ArrayRef<QualType> typeArgs,
- ArrayRef<ObjCProtocolDecl *> protocols) const;
+ ArrayRef<ObjCProtocolDecl *> protocols,
+ bool isKindOf) const;
bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl);
/// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Mon Jul 6 22:58:42 2015
@@ -1054,6 +1054,9 @@ public:
const DeclContext *dc,
ObjCSubstitutionContext context) const;
+ /// Strip Objective-C "__kindof" types from the given type.
+ QualType stripObjCKindOfType(const ASTContext &ctx) const;
+
private:
// These methods are implemented in a separate translation unit;
// "static"-ize them to avoid creating temporary QualTypes in the
@@ -1353,9 +1356,12 @@ protected:
/// NumProtocols - The number of protocols stored directly on this
/// object type.
- unsigned NumProtocols : 7;
+ unsigned NumProtocols : 6;
+
+ /// Whether this is a "kindof" type.
+ unsigned IsKindOf : 1;
};
- static_assert(NumTypeBits + 7 + 7 <= 32, "Does not fit in an unsigned");
+ static_assert(NumTypeBits + 7 + 6 + 1 <= 32, "Does not fit in an unsigned");
class ReferenceTypeBitfields {
friend class ReferenceType;
@@ -1649,7 +1655,27 @@ public:
bool isObjCQualifiedClassType() const; // Class<foo>
bool isObjCObjectOrInterfaceType() const;
bool isObjCIdType() const; // id
+
+ /// Whether the type is Objective-C 'id' or a __kindof type of an
+ /// object type, e.g., __kindof NSView * or __kindof id
+ /// <NSCopying>.
+ ///
+ /// \param bound Will be set to the bound on non-id subtype types,
+ /// which will be (possibly specialized) Objective-C class type, or
+ /// null for 'id.
+ bool isObjCIdOrObjectKindOfType(const ASTContext &ctx,
+ const ObjCObjectType *&bound) const;
+
bool isObjCClassType() const; // Class
+
+ /// Whether the type is Objective-C 'Class' or a __kindof type of an
+ /// Class type, e.g., __kindof Class <NSCopying>.
+ ///
+ /// Unlike \c isObjCIdOrObjectKindOfType, there is no relevant bound
+ /// here because Objective-C's type system cannot express "a class
+ /// object for a subclass of NSFoo".
+ bool isObjCClassOrClassKindOfType() const;
+
bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const;
bool isObjCSelType() const; // Class
bool isObjCBuiltinType() const; // 'id' or 'Class'
@@ -3581,6 +3607,7 @@ public:
attr_nonnull,
attr_nullable,
attr_null_unspecified,
+ attr_objc_kindof,
};
private:
@@ -4514,7 +4541,8 @@ class ObjCObjectType : public Type {
protected:
ObjCObjectType(QualType Canonical, QualType Base,
ArrayRef<QualType> typeArgs,
- ArrayRef<ObjCProtocolDecl *> protocols);
+ ArrayRef<ObjCProtocolDecl *> protocols,
+ bool isKindOf);
enum Nonce_ObjCInterface { Nonce_ObjCInterface };
ObjCObjectType(enum Nonce_ObjCInterface)
@@ -4522,6 +4550,7 @@ protected:
BaseType(QualType(this_(), 0)) {
ObjCObjectTypeBits.NumProtocols = 0;
ObjCObjectTypeBits.NumTypeArgs = 0;
+ ObjCObjectTypeBits.IsKindOf = 0;
}
void computeSuperClassTypeSlow() const;
@@ -4603,6 +4632,17 @@ public:
return qual_begin()[I];
}
+ /// Retrieve all of the protocol qualifiers.
+ ArrayRef<ObjCProtocolDecl *> getProtocols() const {
+ return ArrayRef<ObjCProtocolDecl *>(qual_begin(), getNumProtocols());
+ }
+
+ /// Whether this is a "__kindof" type as written.
+ bool isKindOfTypeAsWritten() const { return ObjCObjectTypeBits.IsKindOf; }
+
+ /// Whether this ia a "__kindof" type (semantically).
+ bool isKindOfType() const;
+
/// Retrieve the type of the superclass of this object type.
///
/// This operation substitutes any type arguments into the
@@ -4617,6 +4657,10 @@ public:
return QualType(CachedSuperClassType.getPointer(), 0);
}
+ /// Strip off the Objective-C "kindof" type and (with it) any
+ /// protocol qualifiers.
+ QualType stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const;
+
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
@@ -4638,15 +4682,17 @@ class ObjCObjectTypeImpl : public ObjCOb
ObjCObjectTypeImpl(QualType Canonical, QualType Base,
ArrayRef<QualType> typeArgs,
- ArrayRef<ObjCProtocolDecl *> protocols)
- : ObjCObjectType(Canonical, Base, typeArgs, protocols) {}
+ ArrayRef<ObjCProtocolDecl *> protocols,
+ bool isKindOf)
+ : ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {}
public:
void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID,
QualType Base,
ArrayRef<QualType> typeArgs,
- ArrayRef<ObjCProtocolDecl *> protocols);
+ ArrayRef<ObjCProtocolDecl *> protocols,
+ bool isKindOf);
};
inline QualType *ObjCObjectType::getTypeArgStorage() {
@@ -4798,6 +4844,12 @@ public:
return getObjectType()->isObjCUnqualifiedClass();
}
+ /// isObjCIdOrClassType - True if this is equivalent to the 'id' or
+ /// 'Class' type,
+ bool isObjCIdOrClassType() const {
+ return getObjectType()->isObjCUnqualifiedIdOrClass();
+ }
+
/// isObjCQualifiedIdType - True if this is equivalent to 'id<P>' for some
/// non-empty set of protocols.
bool isObjCQualifiedIdType() const {
@@ -4810,6 +4862,9 @@ public:
return getObjectType()->isObjCQualifiedClass();
}
+ /// Whether this is a "__kindof" type.
+ bool isKindOfType() const { return getObjectType()->isKindOfType(); }
+
/// Whether this type is specialized, meaning that it has type arguments.
bool isSpecialized() const { return getObjectType()->isSpecialized(); }
@@ -4873,6 +4928,11 @@ public:
/// null type if there is no superclass.
QualType getSuperClassType() const;
+ /// Strip off the Objective-C "kindof" type and (with it) any
+ /// protocol qualifiers.
+ const ObjCObjectPointerType *stripObjCKindOfTypeAndQuals(
+ const ASTContext &ctx) const;
+
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getPointeeType());
}
Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Mon Jul 6 22:58:42 2015
@@ -976,6 +976,11 @@ def TypeNullUnspecified : TypeAttr {
let Documentation = [TypeNullUnspecifiedDocs];
}
+def ObjCKindOf : TypeAttr {
+ let Spellings = [Keyword<"__kindof">];
+ let Documentation = [Undocumented];
+}
+
def AssumeAligned : InheritableAttr {
let Spellings = [GCC<"assume_aligned">];
let Subjects = SubjectList<[ObjCMethod, Function]>;
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jul 6 22:58:42 2015
@@ -978,6 +978,12 @@ def warning_multiple_selectors: Warning<
"several methods with selector %0 of mismatched types are found "
"for the @selector expression">,
InGroup<SelectorTypeMismatch>, DefaultIgnore;
+
+def err_objc_kindof_nonobject : Error<
+ "'__kindof' specifier cannot be applied to non-object type %0">;
+def err_objc_kindof_wrong_position : Error<
+ "'__kindof' type specifier must precede the declarator">;
+
// C++ declarations
def err_static_assert_expression_is_not_constant : Error<
"static_assert expression is not an integral constant expression">;
Modified: cfe/trunk/include/clang/Basic/TokenKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TokenKinds.def?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TokenKinds.def (original)
+++ cfe/trunk/include/clang/Basic/TokenKinds.def Mon Jul 6 22:58:42 2015
@@ -526,6 +526,9 @@ KEYWORD(__bridge_transfer , K
KEYWORD(__bridge_retained , KEYARC)
KEYWORD(__bridge_retain , KEYARC)
+// Objective-C keywords.
+KEYWORD(__kindof , KEYOBJC2)
+
// Alternate spelling for various tokens. There are GCC extensions in all
// languages, but should not be disabled in strict conformance mode.
ALIAS("__alignof__" , __alignof , KEYALL)
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Jul 6 22:58:42 2015
@@ -7240,6 +7240,10 @@ public:
SourceLocation ProtocolRAngleLoc,
bool FailOnError = false);
+ /// Check the application of the Objective-C '__kindof' qualifier to
+ /// the given type.
+ bool checkObjCKindOfType(QualType &type, SourceLocation loc);
+
/// Ensure attributes are consistent with type.
/// \param [in, out] Attributes The attributes to check; they will
/// be modified to be consistent with \p PropertyTy.
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Mon Jul 6 22:58:42 2015
@@ -3615,21 +3615,24 @@ QualType ASTContext::getObjCObjectType(Q
ObjCProtocolDecl * const *Protocols,
unsigned NumProtocols) const {
return getObjCObjectType(BaseType, { },
- llvm::makeArrayRef(Protocols, NumProtocols));
+ llvm::makeArrayRef(Protocols, NumProtocols),
+ /*isKindOf=*/false);
}
QualType ASTContext::getObjCObjectType(
QualType baseType,
ArrayRef<QualType> typeArgs,
- ArrayRef<ObjCProtocolDecl *> protocols) const {
+ ArrayRef<ObjCProtocolDecl *> protocols,
+ bool isKindOf) const {
// If the base type is an interface and there aren't any protocols or
// type arguments to add, then the interface type will do just fine.
- if (typeArgs.empty() && protocols.empty() && isa<ObjCInterfaceType>(baseType))
+ if (typeArgs.empty() && protocols.empty() && !isKindOf &&
+ isa<ObjCInterfaceType>(baseType))
return baseType;
// Look in the folding set for an existing type.
llvm::FoldingSetNodeID ID;
- ObjCObjectTypeImpl::Profile(ID, baseType, typeArgs, protocols);
+ ObjCObjectTypeImpl::Profile(ID, baseType, typeArgs, protocols, isKindOf);
void *InsertPos = nullptr;
if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(QT, 0);
@@ -3681,7 +3684,7 @@ QualType ASTContext::getObjCObjectType(
}
canonical = getObjCObjectType(getCanonicalType(baseType), canonTypeArgs,
- canonProtocols);
+ canonProtocols, isKindOf);
// Regenerate InsertPos.
ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -3692,7 +3695,8 @@ QualType ASTContext::getObjCObjectType(
size += protocols.size() * sizeof(ObjCProtocolDecl *);
void *mem = Allocate(size, TypeAlignment);
ObjCObjectTypeImpl *T =
- new (mem) ObjCObjectTypeImpl(canonical, baseType, typeArgs, protocols);
+ new (mem) ObjCObjectTypeImpl(canonical, baseType, typeArgs, protocols,
+ isKindOf);
Types.push_back(T);
ObjCObjectTypes.InsertNode(T, InsertPos);
@@ -6775,18 +6779,36 @@ bool ASTContext::canAssignObjCInterfaces
RHS->isObjCUnqualifiedIdOrClass())
return true;
- if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId())
- return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
- QualType(RHSOPT,0),
- false);
-
- if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass())
- return ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0),
- QualType(RHSOPT,0));
+ // Function object that propagates a successful result or handles
+ // __kindof types.
+ auto finish = [&](bool succeeded) -> bool {
+ if (succeeded)
+ return true;
+
+ if (!RHS->isKindOfType())
+ return false;
+
+ // Strip off __kindof and protocol qualifiers, then check whether
+ // we can assign the other way.
+ return canAssignObjCInterfaces(RHSOPT->stripObjCKindOfTypeAndQuals(*this),
+ LHSOPT->stripObjCKindOfTypeAndQuals(*this));
+ };
+
+ if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId()) {
+ return finish(ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
+ QualType(RHSOPT,0),
+ false));
+ }
+
+ if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass()) {
+ return finish(ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0),
+ QualType(RHSOPT,0)));
+ }
// If we have 2 user-defined types, fall into that path.
- if (LHS->getInterface() && RHS->getInterface())
- return canAssignObjCInterfaces(LHS, RHS);
+ if (LHS->getInterface() && RHS->getInterface()) {
+ return finish(canAssignObjCInterfaces(LHS, RHS));
+ }
return false;
}
@@ -6800,26 +6822,46 @@ bool ASTContext::canAssignObjCInterfaces
const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT,
bool BlockReturnType) {
+
+ // Function object that propagates a successful result or handles
+ // __kindof types.
+ auto finish = [&](bool succeeded) -> bool {
+ if (succeeded)
+ return true;
+
+ const ObjCObjectPointerType *Expected = BlockReturnType ? RHSOPT : LHSOPT;
+ if (!Expected->isKindOfType())
+ return false;
+
+ // Strip off __kindof and protocol qualifiers, then check whether
+ // we can assign the other way.
+ return canAssignObjCInterfacesInBlockPointer(
+ RHSOPT->stripObjCKindOfTypeAndQuals(*this),
+ LHSOPT->stripObjCKindOfTypeAndQuals(*this),
+ BlockReturnType);
+ };
+
if (RHSOPT->isObjCBuiltinType() || LHSOPT->isObjCIdType())
return true;
if (LHSOPT->isObjCBuiltinType()) {
- return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType();
+ return finish(RHSOPT->isObjCBuiltinType() ||
+ RHSOPT->isObjCQualifiedIdType());
}
if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
- return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
- QualType(RHSOPT,0),
- false);
+ return finish(ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
+ QualType(RHSOPT,0),
+ false));
const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
if (LHS && RHS) { // We have 2 user-defined types.
if (LHS != RHS) {
if (LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
- return BlockReturnType;
+ return finish(BlockReturnType);
if (RHS->getDecl()->isSuperClassOf(LHS->getDecl()))
- return !BlockReturnType;
+ return finish(!BlockReturnType);
}
else
return true;
@@ -6903,13 +6945,19 @@ void getIntersectionOfProtocols(ASTConte
// Check that the given Objective-C type argument lists are equivalent.
static bool sameObjCTypeArgs(const ASTContext &ctx, ArrayRef<QualType> lhsArgs,
- ArrayRef<QualType> rhsArgs) {
+ ArrayRef<QualType> rhsArgs,
+ bool stripKindOf) {
if (lhsArgs.size() != rhsArgs.size())
return false;
for (unsigned i = 0, n = lhsArgs.size(); i != n; ++i) {
- if (!ctx.hasSameType(lhsArgs[i], rhsArgs[i]))
- return false;
+ if (!ctx.hasSameType(lhsArgs[i], rhsArgs[i])) {
+ if (!stripKindOf ||
+ !ctx.hasSameType(lhsArgs[i].stripObjCKindOfType(ctx),
+ rhsArgs[i].stripObjCKindOfType(ctx))) {
+ return false;
+ }
+ }
}
return true;
@@ -6941,7 +6989,8 @@ QualType ASTContext::areCommonBaseCompat
bool anyChanges = false;
if (LHS->isSpecialized() && RHS->isSpecialized()) {
// Both have type arguments, compare them.
- if (!sameObjCTypeArgs(*this, LHS->getTypeArgs(), RHS->getTypeArgs()))
+ if (!sameObjCTypeArgs(*this, LHS->getTypeArgs(), RHS->getTypeArgs(),
+ /*stripKindOf=*/true))
return QualType();
} else if (LHS->isSpecialized() != RHS->isSpecialized()) {
// If only one has type arguments, the result will not have type
@@ -6960,7 +7009,8 @@ QualType ASTContext::areCommonBaseCompat
// If anything in the LHS will have changed, build a new result type.
if (anyChanges) {
QualType Result = getObjCInterfaceType(LHS->getInterface());
- Result = getObjCObjectType(Result, LHSTypeArgs, Protocols);
+ Result = getObjCObjectType(Result, LHSTypeArgs, Protocols,
+ LHS->isKindOfType());
return getObjCObjectPointerType(Result);
}
@@ -6987,7 +7037,8 @@ QualType ASTContext::areCommonBaseCompat
bool anyChanges = false;
if (LHS->isSpecialized() && RHS->isSpecialized()) {
// Both have type arguments, compare them.
- if (!sameObjCTypeArgs(*this, LHS->getTypeArgs(), RHS->getTypeArgs()))
+ if (!sameObjCTypeArgs(*this, LHS->getTypeArgs(), RHS->getTypeArgs(),
+ /*stripKindOf=*/true))
return QualType();
} else if (LHS->isSpecialized() != RHS->isSpecialized()) {
// If only one has type arguments, the result will not have type
@@ -7005,7 +7056,8 @@ QualType ASTContext::areCommonBaseCompat
if (anyChanges) {
QualType Result = getObjCInterfaceType(RHS->getInterface());
- Result = getObjCObjectType(Result, RHSTypeArgs, Protocols);
+ Result = getObjCObjectType(Result, RHSTypeArgs, Protocols,
+ RHS->isKindOfType());
return getObjCObjectPointerType(Result);
}
@@ -7075,7 +7127,8 @@ bool ASTContext::canAssignObjCInterfaces
// If the RHS is specializd, compare type arguments.
if (RHSSuper->isSpecialized() &&
- !sameObjCTypeArgs(*this, LHS->getTypeArgs(), RHSSuper->getTypeArgs())) {
+ !sameObjCTypeArgs(*this, LHS->getTypeArgs(), RHSSuper->getTypeArgs(),
+ /*stripKindOf=*/true)) {
return false;
}
}
Modified: cfe/trunk/lib/AST/ASTDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDiagnostic.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTDiagnostic.cpp (original)
+++ cfe/trunk/lib/AST/ASTDiagnostic.cpp Mon Jul 6 22:58:42 2015
@@ -139,7 +139,8 @@ break; \
QualType BaseType = Desugar(Context, Ty->getBaseType(), ShouldAKA);
QT = Context.getObjCObjectType(BaseType, Ty->getTypeArgsAsWritten(),
llvm::makeArrayRef(Ty->qual_begin(),
- Ty->getNumProtocols()));
+ Ty->getNumProtocols()),
+ Ty->isKindOfTypeAsWritten());
}
}
Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Mon Jul 6 22:58:42 2015
@@ -1853,7 +1853,6 @@ QualType ASTNodeImporter::VisitObjCObjec
TypeArgs.push_back(ImportedTypeArg);
}
-
SmallVector<ObjCProtocolDecl *, 4> Protocols;
for (auto *P : T->quals()) {
ObjCProtocolDecl *Protocol
@@ -1864,7 +1863,8 @@ QualType ASTNodeImporter::VisitObjCObjec
}
return Importer.getToContext().getObjCObjectType(ToBaseType, TypeArgs,
- Protocols);
+ Protocols,
+ T->isKindOfTypeAsWritten());
}
QualType
Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Mon Jul 6 22:58:42 2015
@@ -2379,6 +2379,10 @@ void CXXNameMangler::mangleType(const Ob
}
void CXXNameMangler::mangleType(const ObjCObjectType *T) {
+ // Treat __kindof as a vendor extended type qualifier.
+ if (T->isKindOfType())
+ Out << "U8__kindof";
+
if (!T->qual_empty()) {
// Mangle protocol qualifiers.
SmallString<64> QualStr;
@@ -2391,7 +2395,16 @@ void CXXNameMangler::mangleType(const Ob
QualOS.flush();
Out << 'U' << QualStr.size() << QualStr;
}
+
mangleType(T->getBaseType());
+
+ if (T->isSpecialized()) {
+ // Mangle type arguments as I <type>+ E
+ Out << 'I';
+ for (auto typeArg : T->getTypeArgs())
+ mangleType(typeArg);
+ Out << 'E';
+ }
}
void CXXNameMangler::mangleType(const BlockPointerType *T) {
Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Mon Jul 6 22:58:42 2015
@@ -466,15 +466,61 @@ const RecordType *Type::getAsUnionType()
return nullptr;
}
+bool Type::isObjCIdOrObjectKindOfType(const ASTContext &ctx,
+ const ObjCObjectType *&bound) const {
+ bound = nullptr;
+
+ const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>();
+ if (!OPT)
+ return false;
+
+ // Easy case: id.
+ if (OPT->isObjCIdType())
+ return true;
+
+ // If it's not a __kindof type, reject it now.
+ if (!OPT->isKindOfType())
+ return false;
+
+ // If it's Class or qualified Class, it's not an object type.
+ if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType())
+ return false;
+
+ // Figure out the type bound for the __kindof type.
+ bound = OPT->getObjectType()->stripObjCKindOfTypeAndQuals(ctx)
+ ->getAs<ObjCObjectType>();
+ return true;
+}
+
+bool Type::isObjCClassOrClassKindOfType() const {
+ const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>();
+ if (!OPT)
+ return false;
+
+ // Easy case: Class.
+ if (OPT->isObjCClassType())
+ return true;
+
+ // If it's not a __kindof type, reject it now.
+ if (!OPT->isKindOfType())
+ return false;
+
+ // If it's Class or qualified Class, it's a class __kindof type.
+ return OPT->isObjCClassType() || OPT->isObjCQualifiedClassType();
+}
+
ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
ArrayRef<QualType> typeArgs,
- ArrayRef<ObjCProtocolDecl *> protocols)
+ ArrayRef<ObjCProtocolDecl *> protocols,
+ bool isKindOf)
: Type(ObjCObject, Canonical, Base->isDependentType(),
Base->isInstantiationDependentType(),
Base->isVariablyModifiedType(),
Base->containsUnexpandedParameterPack()),
BaseType(Base)
{
+ ObjCObjectTypeBits.IsKindOf = isKindOf;
+
ObjCObjectTypeBits.NumTypeArgs = typeArgs.size();
assert(getTypeArgsAsWritten().size() == typeArgs.size() &&
"bitfield overflow in type argument count");
@@ -535,6 +581,52 @@ ArrayRef<QualType> ObjCObjectType::getTy
return { };
}
+bool ObjCObjectType::isKindOfType() const {
+ if (isKindOfTypeAsWritten())
+ return true;
+
+ // Look at the base type, which might have type arguments.
+ if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) {
+ // Terminate when we reach an interface type.
+ if (isa<ObjCInterfaceType>(objcObject))
+ return false;
+
+ return objcObject->isKindOfType();
+ }
+
+ // Not a "__kindof" type.
+ return false;
+}
+
+QualType ObjCObjectType::stripObjCKindOfTypeAndQuals(
+ const ASTContext &ctx) const {
+ if (!isKindOfType() && qual_empty())
+ return QualType(this, 0);
+
+ // Recursively strip __kindof.
+ SplitQualType splitBaseType = getBaseType().split();
+ QualType baseType(splitBaseType.Ty, 0);
+ if (const ObjCObjectType *baseObj
+ = splitBaseType.Ty->getAs<ObjCObjectType>()) {
+ baseType = baseObj->stripObjCKindOfTypeAndQuals(ctx);
+ }
+
+ return ctx.getObjCObjectType(ctx.getQualifiedType(baseType,
+ splitBaseType.Quals),
+ getTypeArgsAsWritten(),
+ /*protocols=*/{ },
+ /*isKindOf=*/false);
+}
+
+const ObjCObjectPointerType *ObjCObjectPointerType::stripObjCKindOfTypeAndQuals(
+ const ASTContext &ctx) const {
+ if (!isKindOfType() && qual_empty())
+ return this;
+
+ QualType obj = getObjectType()->stripObjCKindOfTypeAndQuals(ctx);
+ return ctx.getObjCObjectPointerType(obj)->castAs<ObjCObjectPointerType>();
+}
+
namespace {
/// Perform a simple type transformation that does not change the
@@ -888,7 +980,8 @@ QualType simpleTransform(ASTContext &ctx
return Ctx.getObjCObjectType(baseType, typeArgs,
llvm::makeArrayRef(T->qual_begin(),
- T->getNumProtocols()));
+ T->getNumProtocols()),
+ T->isKindOfTypeAsWritten());
}
TRIVIAL_TYPE_CLASS(ObjCInterface)
@@ -971,18 +1064,28 @@ QualType QualType::substObjCTypeArgs(
splitType.Quals);
case ObjCSubstitutionContext::Result:
- case ObjCSubstitutionContext::Property:
- // Substitute 'id' or 'Class', as appropriate.
-
- // If the underlying type is based on 'Class', substitute 'Class'.
- if (typeParam->getUnderlyingType()->isObjCClassType() ||
- typeParam->getUnderlyingType()->isObjCQualifiedClassType()) {
- return ctx.getQualifiedType(ctx.getObjCClassType(),
+ case ObjCSubstitutionContext::Property: {
+ // Substitute the __kindof form of the underlying type.
+ const auto *objPtr = typeParam->getUnderlyingType()
+ ->castAs<ObjCObjectPointerType>();
+
+ // __kindof types, id, and Class don't need an additional
+ // __kindof.
+ if (objPtr->isKindOfType() || objPtr->isObjCIdOrClassType())
+ return ctx.getQualifiedType(typeParam->getUnderlyingType(),
splitType.Quals);
- }
- // Otherwise, substitute 'id'.
- return ctx.getQualifiedType(ctx.getObjCIdType(), splitType.Quals);
+ // Add __kindof.
+ const auto *obj = objPtr->getObjectType();
+ QualType resultTy = ctx.getObjCObjectType(obj->getBaseType(),
+ obj->getTypeArgsAsWritten(),
+ obj->getProtocols(),
+ /*isKindOf=*/true);
+
+ // Rebuild object pointer type.
+ resultTy = ctx.getObjCObjectPointerType(resultTy);
+ return ctx.getQualifiedType(resultTy, splitType.Quals);
+ }
}
}
}
@@ -1086,8 +1189,10 @@ QualType QualType::substObjCTypeArgs(
objcObjectType->getNumProtocols());
if (typeArgs.empty() &&
context != ObjCSubstitutionContext::Superclass) {
- return ctx.getObjCObjectType(objcObjectType->getBaseType(), { },
- protocols);
+ return ctx.getObjCObjectType(
+ objcObjectType->getBaseType(), { },
+ protocols,
+ objcObjectType->isKindOfTypeAsWritten());
}
anyChanged = true;
@@ -1101,7 +1206,8 @@ QualType QualType::substObjCTypeArgs(
objcObjectType->qual_begin(),
objcObjectType->getNumProtocols());
return ctx.getObjCObjectType(objcObjectType->getBaseType(),
- newTypeArgs, protocols);
+ newTypeArgs, protocols,
+ objcObjectType->isKindOfTypeAsWritten());
}
}
@@ -1121,6 +1227,30 @@ QualType QualType::substObjCMemberType(Q
return *this;
}
+QualType QualType::stripObjCKindOfType(const ASTContext &constCtx) const {
+ // FIXME: Because ASTContext::getAttributedType() is non-const.
+ auto &ctx = const_cast<ASTContext &>(constCtx);
+ return simpleTransform(ctx, *this,
+ [&](QualType type) -> QualType {
+ SplitQualType splitType = type.split();
+ if (auto *objType = splitType.Ty->getAs<ObjCObjectType>()) {
+ if (!objType->isKindOfType())
+ return type;
+
+ QualType baseType
+ = objType->getBaseType().stripObjCKindOfType(ctx);
+ return ctx.getQualifiedType(
+ ctx.getObjCObjectType(baseType,
+ objType->getTypeArgsAsWritten(),
+ objType->getProtocols(),
+ /*isKindOf=*/false),
+ splitType.Quals);
+ }
+
+ return type;
+ });
+}
+
Optional<ArrayRef<QualType>> Type::getObjCSubstitutions(
const DeclContext *dc) const {
// Look through method scopes.
@@ -2745,7 +2875,9 @@ bool AttributedType::isCallingConv() con
case attr_nonnull:
case attr_nullable:
case attr_null_unspecified:
+ case attr_objc_kindof:
return false;
+
case attr_pcs:
case attr_pcs_vfp:
case attr_cdecl:
@@ -2895,7 +3027,8 @@ QualifierCollector::apply(const ASTConte
void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID,
QualType BaseType,
ArrayRef<QualType> typeArgs,
- ArrayRef<ObjCProtocolDecl *> protocols) {
+ ArrayRef<ObjCProtocolDecl *> protocols,
+ bool isKindOf) {
ID.AddPointer(BaseType.getAsOpaquePtr());
ID.AddInteger(typeArgs.size());
for (auto typeArg : typeArgs)
@@ -2903,11 +3036,13 @@ void ObjCObjectTypeImpl::Profile(llvm::F
ID.AddInteger(protocols.size());
for (auto proto : protocols)
ID.AddPointer(proto);
+ ID.AddBoolean(isKindOf);
}
void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getBaseType(), getTypeArgs(),
- llvm::makeArrayRef(qual_begin(), getNumProtocols()));
+ Profile(ID, getBaseType(), getTypeArgsAsWritten(),
+ llvm::makeArrayRef(qual_begin(), getNumProtocols()),
+ isKindOfTypeAsWritten());
}
namespace {
Modified: cfe/trunk/lib/AST/TypePrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypePrinter.cpp (original)
+++ cfe/trunk/lib/AST/TypePrinter.cpp Mon Jul 6 22:58:42 2015
@@ -1129,6 +1129,9 @@ void TypePrinter::printAttributedBefore(
T->getAttrKind() == AttributedType::attr_objc_ownership)
return printBefore(T->getEquivalentType(), OS);
+ if (T->getAttrKind() == AttributedType::attr_objc_kindof)
+ OS << "__kindof ";
+
printBefore(T->getModifiedType(), OS);
if (T->isMSTypeSpec()) {
@@ -1165,6 +1168,9 @@ void TypePrinter::printAttributedAfter(c
T->getAttrKind() == AttributedType::attr_objc_ownership)
return printAfter(T->getEquivalentType(), OS);
+ if (T->getAttrKind() == AttributedType::attr_objc_kindof)
+ return;
+
// TODO: not all attributes are GCC-style attributes.
if (T->isMSTypeSpec())
return;
@@ -1310,9 +1316,13 @@ void TypePrinter::printObjCInterfaceAfte
void TypePrinter::printObjCObjectBefore(const ObjCObjectType *T,
raw_ostream &OS) {
- if (T->qual_empty() && T->isUnspecializedAsWritten())
+ if (T->qual_empty() && T->isUnspecializedAsWritten() &&
+ !T->isKindOfTypeAsWritten())
return printBefore(T->getBaseType(), OS);
+ if (T->isKindOfTypeAsWritten())
+ OS << "__kindof ";
+
print(T->getBaseType(), OS, StringRef());
if (T->isSpecializedAsWritten()) {
@@ -1346,7 +1356,8 @@ void TypePrinter::printObjCObjectBefore(
}
void TypePrinter::printObjCObjectAfter(const ObjCObjectType *T,
raw_ostream &OS) {
- if (T->qual_empty() && T->isUnspecializedAsWritten())
+ if (T->qual_empty() && T->isUnspecializedAsWritten() &&
+ !T->isKindOfTypeAsWritten())
return printAfter(T->getBaseType(), OS);
}
Modified: cfe/trunk/lib/Basic/IdentifierTable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/IdentifierTable.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/IdentifierTable.cpp (original)
+++ cfe/trunk/lib/Basic/IdentifierTable.cpp Mon Jul 6 22:58:42 2015
@@ -109,7 +109,8 @@ namespace {
WCHARSUPPORT = 0x04000,
HALFSUPPORT = 0x08000,
KEYCONCEPTS = 0x10000,
- KEYALL = (0x1ffff & ~KEYNOMS18 &
+ KEYOBJC2 = 0x20000,
+ KEYALL = (0x3ffff & ~KEYNOMS18 &
~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude.
};
@@ -144,6 +145,7 @@ static KeywordStatus getKeywordStatus(co
// in non-arc mode.
if (LangOpts.ObjC2 && (Flags & KEYARC)) return KS_Enabled;
if (LangOpts.ConceptsTS && (Flags & KEYCONCEPTS)) return KS_Enabled;
+ if (LangOpts.ObjC2 && (Flags & KEYOBJC2)) return KS_Enabled;
if (LangOpts.CPlusPlus && (Flags & KEYCXX11)) return KS_Future;
return KS_Disabled;
}
Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Mon Jul 6 22:58:42 2015
@@ -1088,6 +1088,7 @@ static bool HasFeature(const Preprocesso
.Case("objc_default_synthesize_properties", LangOpts.ObjC2)
.Case("objc_fixed_enum", LangOpts.ObjC2)
.Case("objc_instancetype", LangOpts.ObjC2)
+ .Case("objc_kindof", LangOpts.ObjC2)
.Case("objc_modules", LangOpts.ObjC2 && LangOpts.Modules)
.Case("objc_nonfragile_abi", LangOpts.ObjCRuntime.isNonFragile())
.Case("objc_property_explicit_atomic",
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jul 6 22:58:42 2015
@@ -2601,6 +2601,7 @@ Parser::DiagnoseMissingSemiAfterTagDefin
/// [C11] alignment-specifier declaration-specifiers[opt]
/// [GNU] attributes declaration-specifiers[opt]
/// [Clang] '__module_private__' declaration-specifiers[opt]
+/// [ObjC1] '__kindof' declaration-specifiers[opt]
///
/// storage-class-specifier: [C99 6.7.1]
/// 'typedef'
@@ -3083,6 +3084,13 @@ void Parser::ParseDeclarationSpecifiers(
ParseNullabilityTypeSpecifiers(DS.getAttributes());
continue;
+ // Objective-C 'kindof' types.
+ case tok::kw___kindof:
+ DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc,
+ nullptr, 0, AttributeList::AS_Keyword);
+ (void)ConsumeToken();
+ continue;
+
// storage-class-specifier
case tok::kw_typedef:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_typedef, Loc,
@@ -4345,6 +4353,8 @@ bool Parser::isTypeSpecifierQualifier()
case tok::kw__Nullable:
case tok::kw__Null_unspecified:
+ case tok::kw___kindof:
+
case tok::kw___private:
case tok::kw___local:
case tok::kw___global:
@@ -4525,6 +4535,8 @@ bool Parser::isDeclarationSpecifier(bool
case tok::kw__Nullable:
case tok::kw__Null_unspecified:
+ case tok::kw___kindof:
+
case tok::kw___private:
case tok::kw___local:
case tok::kw___global:
@@ -4762,6 +4774,13 @@ void Parser::ParseTypeQualifierListOpt(D
ParseNullabilityTypeSpecifiers(DS.getAttributes());
continue;
+ // Objective-C 'kindof' types.
+ case tok::kw___kindof:
+ DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc,
+ nullptr, 0, AttributeList::AS_Keyword);
+ (void)ConsumeToken();
+ continue;
+
case tok::kw___attribute:
if (AttrReqs & AR_GNUAttributesParsedAndRejected)
// When GNU attributes are expressly forbidden, diagnose their usage.
Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Mon Jul 6 22:58:42 2015
@@ -1281,6 +1281,7 @@ Parser::isCXXDeclarationSpecifier(Parser
case tok::kw__Nonnull:
case tok::kw__Nullable:
case tok::kw__Null_unspecified:
+ case tok::kw___kindof:
return TPResult::True;
// Borland
Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Mon Jul 6 22:58:42 2015
@@ -962,7 +962,8 @@ ExprResult Sema::BuildObjCDictionaryLite
Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { },
llvm::makeArrayRef(
(ObjCProtocolDecl**) PQ,
- 1));
+ 1),
+ false);
QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying);
}
}
@@ -2620,35 +2621,41 @@ ExprResult Sema::BuildInstanceMessage(Ex
// of the more detailed type-checking on the receiver.
if (!Method) {
- // Handle messages to id.
- bool receiverIsId = ReceiverType->isObjCIdType();
- if (receiverIsId || ReceiverType->isBlockPointerType() ||
+ // Handle messages to id and __kindof types (where we use the
+ // global method pool).
+ // FIXME: The type bound is currently ignored by lookup in the
+ // global pool.
+ const ObjCObjectType *typeBound = nullptr;
+ bool receiverIsIdLike = ReceiverType->isObjCIdOrObjectKindOfType(Context,
+ typeBound);
+ if (receiverIsIdLike || ReceiverType->isBlockPointerType() ||
(Receiver && Context.isObjCNSObjectType(Receiver->getType()))) {
Method = LookupInstanceMethodInGlobalPool(Sel,
SourceRange(LBracLoc, RBracLoc),
- receiverIsId);
+ receiverIsIdLike);
if (!Method)
Method = LookupFactoryMethodInGlobalPool(Sel,
SourceRange(LBracLoc,RBracLoc),
- receiverIsId);
+ receiverIsIdLike);
if (Method) {
if (ObjCMethodDecl *BestMethod =
SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod()))
Method = BestMethod;
if (!AreMultipleMethodsInGlobalPool(Sel, Method,
SourceRange(LBracLoc, RBracLoc),
- receiverIsId)) {
+ receiverIsIdLike)) {
DiagnoseUseOfDecl(Method, SelLoc);
}
}
- } else if (ReceiverType->isObjCClassType() ||
+ } else if (ReceiverType->isObjCClassOrClassKindOfType() ||
ReceiverType->isObjCQualifiedClassType()) {
// Handle messages to Class.
// We allow sending a message to a qualified Class ("Class<foo>"), which
// is ok as long as one of the protocols implements the selector (if not,
// warn).
- if (const ObjCObjectPointerType *QClassTy
- = ReceiverType->getAsObjCQualifiedClassType()) {
+ if (!ReceiverType->isObjCClassOrClassKindOfType()) {
+ const ObjCObjectPointerType *QClassTy
+ = ReceiverType->getAsObjCQualifiedClassType();
// Search protocols for class methods.
Method = LookupMethodInQualifiedType(Sel, QClassTy, false);
if (!Method) {
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Jul 6 22:58:42 2015
@@ -2152,23 +2152,7 @@ bool Sema::isObjCPointerConversion(QualT
FromObjCPtr->getPointeeType()))
return false;
- // Check for compatible
- // Objective C++: We're able to convert between "id" or "Class" and a
- // pointer to any interface (in both directions).
- if (ToObjCPtr->isObjCBuiltinType() && FromObjCPtr->isObjCBuiltinType()) {
- ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers);
- return true;
- }
- // Conversions with Objective-C's id<...>.
- if ((FromObjCPtr->isObjCQualifiedIdType() ||
- ToObjCPtr->isObjCQualifiedIdType()) &&
- Context.ObjCQualifiedIdTypesAreCompatible(ToType, FromType,
- /*compare=*/false)) {
- ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers);
- return true;
- }
- // Objective C++: We're able to convert from a pointer to an
- // interface to a pointer to a different interface.
+ // Conversion between Objective-C pointers.
if (Context.canAssignObjCInterfaces(ToObjCPtr, FromObjCPtr)) {
const ObjCInterfaceType* LHS = ToObjCPtr->getInterfaceType();
const ObjCInterfaceType* RHS = FromObjCPtr->getInterfaceType();
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Jul 6 22:58:42 2015
@@ -643,6 +643,9 @@ static void distributeTypeAttrsFromDecla
NULLABILITY_TYPE_ATTRS_CASELIST:
// Nullability specifiers cannot go after the declarator-id.
+
+ // Objective-C __kindof does not get distributed.
+ case AttributeList::AT_ObjCKindOf:
continue;
default:
@@ -928,7 +931,7 @@ static QualType applyObjCTypeArgs(Sema &
}
// Success. Form the specialized type.
- return S.Context.getObjCObjectType(type, finalTypeArgs, { });
+ return S.Context.getObjCObjectType(type, finalTypeArgs, { }, false);
}
/// Apply Objective-C protocol qualifiers to the given type.
@@ -944,7 +947,8 @@ static QualType applyObjCProtocolQualifi
return ctx.getObjCObjectType(objT->getBaseType(),
objT->getTypeArgsAsWritten(),
- protocols);
+ protocols,
+ objT->isKindOfTypeAsWritten());
}
if (type->isObjCObjectType()) {
@@ -953,18 +957,22 @@ static QualType applyObjCProtocolQualifi
// FIXME: Check for protocols to which the class type is already
// known to conform.
- return ctx.getObjCObjectType(type, { }, protocols);
+ return ctx.getObjCObjectType(type, { }, protocols, false);
}
// id<protocol-list>
if (type->isObjCIdType()) {
- type = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, protocols);
+ const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>();
+ type = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, protocols,
+ objPtr->isKindOfType());
return ctx.getObjCObjectPointerType(type);
}
// Class<protocol-list>
if (type->isObjCClassType()) {
- type = ctx.getObjCObjectType(ctx.ObjCBuiltinClassTy, { }, protocols);
+ const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>();
+ type = ctx.getObjCObjectType(ctx.ObjCBuiltinClassTy, { }, protocols,
+ objPtr->isKindOfType());
return ctx.getObjCObjectPointerType(type);
}
@@ -1021,7 +1029,8 @@ TypeResult Sema::actOnObjCProtocolQualif
Context.ObjCBuiltinIdTy, { },
llvm::makeArrayRef(
(ObjCProtocolDecl * const *)protocols.data(),
- protocols.size()));
+ protocols.size()),
+ false);
Result = Context.getObjCObjectPointerType(Result);
TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result);
@@ -4430,6 +4439,8 @@ static AttributeList::Kind getAttrListKi
return AttributeList::AT_TypeNullable;
case AttributedType::attr_null_unspecified:
return AttributeList::AT_TypeNullUnspecified;
+ case AttributedType::attr_objc_kindof:
+ return AttributeList::AT_ObjCKindOf;
}
llvm_unreachable("unexpected attribute kind!");
}
@@ -5514,6 +5525,44 @@ bool Sema::checkNullabilityTypeSpecifier
return false;
}
+bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) {
+ // Find out if it's an Objective-C object or object pointer type;
+ const ObjCObjectPointerType *ptrType = type->getAs<ObjCObjectPointerType>();
+ const ObjCObjectType *objType = ptrType ? ptrType->getObjectType()
+ : type->getAs<ObjCObjectType>();
+
+ // If not, we can't apply __kindof.
+ if (!objType) {
+ // FIXME: Handle dependent types that aren't yet object types.
+ Diag(loc, diag::err_objc_kindof_nonobject)
+ << type;
+ return true;
+ }
+
+ // Rebuild the "equivalent" type, which pushes __kindof down into
+ // the object type.
+ QualType equivType = Context.getObjCObjectType(objType->getBaseType(),
+ objType->getTypeArgsAsWritten(),
+ objType->getProtocols(),
+ /*isKindOf=*/true);
+
+ // If we started with an object pointer type, rebuild it.
+ if (ptrType) {
+ equivType = Context.getObjCObjectPointerType(equivType);
+ if (auto nullability = type->getNullability(Context)) {
+ auto attrKind = AttributedType::getNullabilityAttrKind(*nullability);
+ equivType = Context.getAttributedType(attrKind, equivType, equivType);
+ }
+ }
+
+ // Build the attributed type to record where __kindof occurred.
+ type = Context.getAttributedType(AttributedType::attr_objc_kindof,
+ type,
+ equivType);
+
+ return false;
+}
+
/// Map a nullability attribute kind to a nullability kind.
static NullabilityKind mapNullabilityAttrKind(AttributeList::Kind kind) {
switch (kind) {
@@ -6124,6 +6173,7 @@ static void processTypeAttrs(TypeProcess
attr.setUsedAsTypeAttr();
break;
+
NULLABILITY_TYPE_ATTRS_CASELIST:
// Either add nullability here or try to distribute it. We
// don't want to distribute the nullability specifier past any
@@ -6142,6 +6192,28 @@ static void processTypeAttrs(TypeProcess
}
break;
+ case AttributeList::AT_ObjCKindOf:
+ // '__kindof' must be part of the decl-specifiers.
+ switch (TAL) {
+ case TAL_DeclSpec:
+ break;
+
+ case TAL_DeclChunk:
+ case TAL_DeclName:
+ state.getSema().Diag(attr.getLoc(),
+ diag::err_objc_kindof_wrong_position)
+ << FixItHint::CreateRemoval(attr.getLoc())
+ << FixItHint::CreateInsertion(
+ state.getDeclarator().getDeclSpec().getLocStart(), "__kindof ");
+ break;
+ }
+
+ // Apply it regardless.
+ if (state.getSema().checkObjCKindOfType(type, attr.getLoc()))
+ attr.setInvalid();
+ attr.setUsedAsTypeAttr();
+ break;
+
case AttributeList::AT_NSReturnsRetained:
if (!state.getSema().getLangOpts().ObjCAutoRefCount)
break;
Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Mon Jul 6 22:58:42 2015
@@ -5271,7 +5271,8 @@ QualType ASTReader::readTypeRecord(unsig
SmallVector<ObjCProtocolDecl*, 4> Protos;
for (unsigned I = 0; I != NumProtos; ++I)
Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx));
- return Context.getObjCObjectType(Base, TypeArgs, Protos);
+ bool IsKindOf = Record[Idx++];
+ return Context.getObjCObjectType(Base, TypeArgs, Protos, IsKindOf);
}
case TYPE_OBJC_OBJECT_POINTER: {
Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon Jul 6 22:58:42 2015
@@ -427,6 +427,7 @@ void ASTTypeWriter::VisitObjCObjectType(
Record.push_back(T->getNumProtocols());
for (const auto *I : T->quals())
Writer.AddDeclRef(I, Record);
+ Record.push_back(T->isKindOfTypeAsWritten());
Code = TYPE_OBJC_OBJECT;
}
Modified: cfe/trunk/test/CodeGenObjCXX/mangle.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/mangle.mm?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/mangle.mm (original)
+++ cfe/trunk/test/CodeGenObjCXX/mangle.mm Mon Jul 6 22:58:42 2015
@@ -98,3 +98,18 @@ template<> void X<A*>::f() {}
// CHECK-LABEL: define void @_ZN1XIP1AE1fEv
template<> void X<A<P>*>::f() {}
// CHECK-LABEL: define void @_ZN1XIPU11objcproto1P1AE1fEv
+
+// CHECK-LABEL: define void @_Z12kindof_test2PU8__kindof5Test2
+void kindof_test2(__kindof Test2 *t2) { }
+
+ at interface Parameterized<T, U> : A
+ at end
+
+// CHECK-LABEL: define void @_Z19parameterized_test1P13ParameterizedIP1AP4TestE
+void parameterized_test1(Parameterized<A *, Test *> *p) {}
+
+// CHECK-LABEL: define void @_Z19parameterized_test2PU8__kindof13ParameterizedIP1AP4TestE
+void parameterized_test2(__kindof Parameterized<A *, Test *> *p) {}
+
+// CHECK-LABEL: define void @_Z19parameterized_test3P13Parameterized
+void parameterized_test3(Parameterized *p) {}
Added: cfe/trunk/test/PCH/objc_kindof.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/objc_kindof.m?rev=241548&view=auto
==============================================================================
--- cfe/trunk/test/PCH/objc_kindof.m (added)
+++ cfe/trunk/test/PCH/objc_kindof.m Mon Jul 6 22:58:42 2015
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -emit-pch %s -o %t
+// RUN: %clang_cc1 -include-pch %t -verify %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+ at protocol NSObject
+ at end
+
+ at protocol NSCopying
+ at end
+
+__attribute__((objc_root_class))
+ at interface NSObject <NSObject>
+ at end
+
+ at interface NSString : NSObject <NSCopying>
+ at end
+
+ at interface NSMutableString : NSString
+ at end
+
+ at interface NSNumber : NSObject <NSCopying>
+ at end
+
+extern __kindof NSObject <NSCopying> *kindof_NSObject_NSCopying;
+
+#else
+void testPrettyPrint(int *ip) {
+ ip = kindof_NSObject_NSCopying; // expected-warning{{from '__kindof NSObject<NSCopying> *'}}
+}
+
+#endif
Added: cfe/trunk/test/SemaObjC/kindof.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/kindof.m?rev=241548&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/kindof.m (added)
+++ cfe/trunk/test/SemaObjC/kindof.m Mon Jul 6 22:58:42 2015
@@ -0,0 +1,304 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only %s -verify
+
+// Tests Objective-C 'kindof' types.
+
+#if !__has_feature(objc_kindof)
+#error does not support __kindof
+#endif
+
+ at protocol NSObject
+ at end
+
+ at protocol NSCopying
+- (id)copy;
++ (Class)classCopy;
+ at end
+
+ at protocol NSRandomProto
+- (void)randomMethod;
++ (void)randomClassMethod;
+ at end
+
+__attribute__((objc_root_class))
+ at interface NSObject <NSObject>
+- (NSObject *)retain;
+ at end
+
+ at interface NSString : NSObject <NSCopying>
+- (NSString *)stringByAppendingString:(NSString *)string;
++ (instancetype)string;
+ at end
+
+ at interface NSMutableString : NSString
+- (void)appendString:(NSString *)string;
+ at end
+
+ at interface NSNumber : NSObject <NSCopying>
+- (NSNumber *)numberByAddingNumber:(NSNumber *)number;
+ at end
+
+// ---------------------------------------------------------------------------
+// Parsing and semantic analysis for __kindof
+// ---------------------------------------------------------------------------
+
+// Test proper application of __kindof.
+typedef __kindof NSObject *typedef1;
+typedef NSObject __kindof *typedef2;
+typedef __kindof NSObject<NSCopying> typedef3;
+typedef NSObject<NSCopying> __kindof *typedef4;
+typedef __kindof id<NSCopying> typedef5;
+typedef __kindof Class<NSCopying> typedef6;
+
+// Test redundancy of __kindof.
+typedef __kindof id __kindof redundant_typedef1;
+typedef __kindof NSObject __kindof *redundant_typedef2;
+
+// Test application of __kindof to typedefs.
+typedef NSObject *NSObject_ptr_typedef;
+typedef NSObject NSObject_typedef;
+typedef __kindof NSObject_ptr_typedef typedef_typedef1;
+typedef __kindof NSObject_typedef typedef_typedef2;
+
+// Test application of __kindof to non-object types.
+typedef __kindof int nonobject_typedef1; // expected-error{{'__kindof' specifier cannot be applied to non-object type 'int'}}
+typedef NSObject **NSObject_ptr_ptr;
+typedef __kindof NSObject_ptr_ptr nonobject_typedef2; // expected-error{{'__kindof' specifier cannot be applied to non-object type 'NSObject_ptr_ptr' (aka 'NSObject **')}}
+
+// Test application of __kindof outside of the decl-specifiers.
+typedef NSObject * __kindof bad_specifier_location1; // expected-error{{'__kindof' type specifier must precede the declarator}}
+typedef NSObject bad_specifier_location2 __kindof; // expected-error{{expected ';' after top level declarator}}
+// expected-warning at -1{{declaration does not declare anything}}
+
+// ---------------------------------------------------------------------------
+// Pretty printing of __kindof
+// ---------------------------------------------------------------------------
+void test_pretty_print(int *ip) {
+ __kindof NSObject *kindof_NSObject;
+ ip = kindof_NSObject; // expected-warning{{from '__kindof NSObject *'}}
+
+ __kindof NSObject_ptr_typedef kindof_NSObject_ptr;
+ ip = kindof_NSObject_ptr; // expected-warning{{from '__kindof NSObject_ptr_typedef'}}
+
+ __kindof id <NSCopying> *kindof_NSCopying;
+ ip = kindof_NSCopying; // expected-warning{{from '__kindof id<NSCopying> *'}}
+
+ __kindof NSObject_ptr_typedef *kindof_NSObject_ptr_typedef;
+ ip = kindof_NSObject_ptr_typedef; // expected-warning{{from '__kindof NSObject_ptr_typedef *'}}
+}
+
+// ---------------------------------------------------------------------------
+// Basic implicit conversions (dropping __kindof, upcasts, etc.)
+// ---------------------------------------------------------------------------
+void test_add_remove_kindof_conversions(void) {
+ __kindof NSObject *kindof_NSObject_obj;
+ NSObject *NSObject_obj;
+
+ // Conversion back and forth
+ kindof_NSObject_obj = NSObject_obj;
+ NSObject_obj = kindof_NSObject_obj;
+
+ // Qualified-id conversion back and forth.
+ __kindof id <NSCopying> kindof_id_NSCopying_obj;
+ id <NSCopying> id_NSCopying_obj;
+ kindof_id_NSCopying_obj = id_NSCopying_obj;
+ id_NSCopying_obj = kindof_id_NSCopying_obj;
+}
+
+void test_upcast_conversions(void) {
+ __kindof NSObject *kindof_NSObject_obj;
+ NSObject *NSObject_obj;
+
+ // Upcasts
+ __kindof NSString *kindof_NSString_obj;
+ NSString *NSString_obj;
+ kindof_NSObject_obj = kindof_NSString_obj;
+ kindof_NSObject_obj = NSString_obj;
+ NSObject_obj = kindof_NSString_obj;
+ NSObject_obj = NSString_obj;
+
+ // "Upcasts" with qualified-id.
+ __kindof id <NSCopying> kindof_id_NSCopying_obj;
+ id <NSCopying> id_NSCopying_obj;
+ kindof_id_NSCopying_obj = kindof_NSString_obj;
+ kindof_id_NSCopying_obj = NSString_obj;
+ id_NSCopying_obj = kindof_NSString_obj;
+ id_NSCopying_obj = NSString_obj;
+}
+
+
+void test_ptr_object_conversions(void) {
+ __kindof NSObject **ptr_kindof_NSObject_obj;
+ NSObject **ptr_NSObject_obj;
+
+ // Conversions back and forth.
+ ptr_kindof_NSObject_obj = ptr_NSObject_obj;
+ ptr_NSObject_obj = ptr_kindof_NSObject_obj;
+
+ // Conversions back and forth with qualified-id.
+ __kindof id <NSCopying> *ptr_kindof_id_NSCopying_obj;
+ id <NSCopying> *ptr_id_NSCopying_obj;
+ ptr_kindof_id_NSCopying_obj = ptr_id_NSCopying_obj;
+ ptr_id_NSCopying_obj = ptr_kindof_id_NSCopying_obj;
+
+ // Upcasts.
+ __kindof NSString **ptr_kindof_NSString_obj;
+ NSString **ptr_NSString_obj;
+ ptr_kindof_NSObject_obj = ptr_kindof_NSString_obj;
+ ptr_kindof_NSObject_obj = ptr_NSString_obj;
+ ptr_NSObject_obj = ptr_kindof_NSString_obj;
+ ptr_NSObject_obj = ptr_NSString_obj;
+}
+
+// ---------------------------------------------------------------------------
+// Implicit downcasting
+// ---------------------------------------------------------------------------
+void test_downcast_conversions(void) {
+ __kindof NSObject *kindof_NSObject_obj;
+ NSObject *NSObject_obj;
+ __kindof NSString *kindof_NSString_obj;
+ NSString *NSString_obj;
+
+ // Implicit downcasting.
+ kindof_NSString_obj = kindof_NSObject_obj;
+ kindof_NSString_obj = NSObject_obj; // expected-warning{{assigning to '__kindof NSString *' from 'NSObject *'}}
+ NSString_obj = kindof_NSObject_obj;
+ NSString_obj = NSObject_obj; // expected-warning{{assigning to 'NSString *' from 'NSObject *'}}
+
+ // Implicit downcasting with qualified id.
+ __kindof id <NSCopying> kindof_NSCopying_obj;
+ id <NSCopying> NSCopying_obj;
+ kindof_NSString_obj = kindof_NSCopying_obj;
+ kindof_NSString_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}}
+ NSString_obj = kindof_NSCopying_obj;
+ NSString_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}}
+ kindof_NSObject_obj = kindof_NSCopying_obj;
+ kindof_NSObject_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}}
+ NSObject_obj = kindof_NSCopying_obj;
+ NSObject_obj = NSCopying_obj; // expected-warning{{from incompatible type 'id<NSCopying>'}}
+}
+
+void test_crosscast_conversions(void) {
+ __kindof NSString *kindof_NSString_obj;
+ NSString *NSString_obj;
+ __kindof NSNumber *kindof_NSNumber_obj;
+ NSNumber *NSNumber_obj;
+
+ NSString_obj = kindof_NSNumber_obj; // expected-warning{{from '__kindof NSNumber *'}}
+}
+
+// ---------------------------------------------------------------------------
+// Blocks
+// ---------------------------------------------------------------------------
+void test_block_conversions(void) {
+ // Adding/removing __kindof from return type.
+ __kindof NSString *(^kindof_NSString_void_block)(void);
+ NSString *(^NSString_void_block)(void);
+ kindof_NSString_void_block = NSString_void_block;
+ NSString_void_block = kindof_NSString_void_block;
+
+ // Covariant return type.
+ __kindof NSMutableString *(^kindof_NSMutableString_void_block)(void);
+ NSMutableString *(^NSMutableString_void_block)(void);
+ kindof_NSString_void_block = NSMutableString_void_block;
+ NSString_void_block = kindof_NSMutableString_void_block;
+ kindof_NSString_void_block = NSMutableString_void_block;
+ NSString_void_block = kindof_NSMutableString_void_block;
+
+ // "Covariant" return type via downcasting rule.
+ kindof_NSMutableString_void_block = NSString_void_block; // expected-error{{from 'NSString *(^)(void)'}}
+ NSMutableString_void_block = kindof_NSString_void_block;
+ kindof_NSMutableString_void_block = NSString_void_block; // expected-error{{from 'NSString *(^)(void)'}}
+ NSMutableString_void_block = kindof_NSString_void_block;
+
+ // Cross-casted return type.
+ __kindof NSNumber *(^kindof_NSNumber_void_block)(void);
+ NSNumber *(^NSNumber_void_block)(void);
+ kindof_NSString_void_block = NSNumber_void_block; // expected-error{{from 'NSNumber *(^)(void)'}}
+ NSString_void_block = kindof_NSNumber_void_block; // expected-error{{'__kindof NSNumber *(^)(void)'}}
+ kindof_NSString_void_block = NSNumber_void_block; // expected-error{{from 'NSNumber *(^)(void)'}}
+ NSString_void_block = kindof_NSNumber_void_block; // expected-error{{'__kindof NSNumber *(^)(void)'}}
+
+ // Adding/removing __kindof from argument type.
+ void (^void_kindof_NSString_block)(__kindof NSString *);
+ void (^void_NSString_block)(NSString *);
+ void_kindof_NSString_block = void_NSString_block;
+ void_NSString_block = void_kindof_NSString_block;
+
+ // Contravariant argument type.
+ void (^void_kindof_NSMutableString_block)(__kindof NSMutableString *);
+ void (^void_NSMutableString_block)(NSMutableString *);
+ void_kindof_NSMutableString_block = void_kindof_NSString_block;
+ void_kindof_NSMutableString_block = void_NSString_block;
+ void_NSMutableString_block = void_kindof_NSString_block;
+ void_NSMutableString_block = void_NSString_block;
+
+ // "Contravariant" argument type via downcasting rule.
+ void_kindof_NSString_block = void_kindof_NSMutableString_block;
+ void_kindof_NSString_block = void_NSMutableString_block;
+ void_NSString_block = void_kindof_NSMutableString_block; // expected-error{{from 'void (^)(__kindof NSMutableString *)'}}
+ void_NSString_block = void_NSMutableString_block; // expected-error{{from 'void (^)(NSMutableString *)'}}
+}
+
+// ---------------------------------------------------------------------------
+// Messaging __kindof types.
+// ---------------------------------------------------------------------------
+void message_kindof_object(__kindof NSString *kindof_NSString) {
+ [kindof_NSString retain]; // in superclass
+ [kindof_NSString stringByAppendingString:0]; // in class
+ [kindof_NSString appendString:0]; // in subclass
+ [kindof_NSString numberByAddingNumber: 0]; // FIXME: in unrelated class
+ [kindof_NSString randomMethod]; // in protocol
+}
+
+void message_kindof_qualified_id(__kindof id <NSCopying> kindof_NSCopying) {
+ [kindof_NSCopying copy]; // in protocol
+ [kindof_NSCopying stringByAppendingString:0]; // in some class
+ [kindof_NSCopying randomMethod]; // in unrelated protocol
+}
+
+void message_kindof_qualified_class(
+ __kindof Class <NSCopying> kindof_NSCopying) {
+ [kindof_NSCopying classCopy]; // in protocol
+ [kindof_NSCopying string]; // in some class
+ [kindof_NSCopying randomClassMethod]; // in unrelated protocol
+}
+
+// ---------------------------------------------------------------------------
+// __kindof within specialized types
+// ---------------------------------------------------------------------------
+ at interface NSArray<T> : NSObject
+ at end
+
+void implicit_convert_array(NSArray<__kindof NSString *> *kindofStringsArray,
+ NSArray<NSString *> *stringsArray,
+ NSArray<__kindof NSMutableString *>
+ *kindofMutStringsArray,
+ NSArray<NSMutableString *> *mutStringsArray) {
+ // Adding/removing __kindof is okay.
+ kindofStringsArray = stringsArray;
+ stringsArray = kindofStringsArray;
+
+ // Other covariant and contravariant conversions still not permitted.
+ kindofStringsArray = mutStringsArray; // expected-warning{{incompatible pointer types}}
+ stringsArray = kindofMutStringsArray; // expected-warning{{incompatible pointer types}}
+ mutStringsArray = kindofStringsArray; // expected-warning{{incompatible pointer types}}
+
+ // Adding/removing nested __kindof is okay.
+ NSArray<NSArray<__kindof NSString *> *> *kindofStringsArrayArray;
+ NSArray<NSArray<NSString *> *> *stringsArrayArray;
+ kindofStringsArrayArray = stringsArrayArray;
+ stringsArrayArray = kindofStringsArrayArray;
+}
+
+// ---------------------------------------------------------------------------
+// __kindof + nullability
+// ---------------------------------------------------------------------------
+
+void testNullability() {
+ // The base type being a pointer type tickles the bug.
+ extern __kindof id <NSCopying> __nonnull getSomeCopyable();
+ NSString *string = getSomeCopyable(); // no-warning
+
+ void processCopyable(__typeof(getSomeCopyable()) string);
+ processCopyable(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
+}
Modified: cfe/trunk/test/SemaObjC/parameterized_classes_subst.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/parameterized_classes_subst.m?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/parameterized_classes_subst.m (original)
+++ cfe/trunk/test/SemaObjC/parameterized_classes_subst.m Mon Jul 6 22:58:42 2015
@@ -18,6 +18,9 @@ __attribute__((objc_root_class))
@interface NSString : NSObject <NSCopying>
@end
+ at interface NSMutableString : NSString
+ at end
+
@interface NSNumber : NSObject <NSCopying>
@end
@@ -144,6 +147,7 @@ void test_message_send_result(
NSMutableSet *mutSet,
MutableSetOfArrays *mutArraySet,
NSArray<NSString *> *stringArray,
+ NSArray<__kindof NSString *> *kindofStringArray,
void (^block)(void)) {
int *ip;
ip = [stringSet firstObject]; // expected-warning{{from 'NSString *'}}
@@ -171,6 +175,12 @@ void test_message_send_result(
[[NSMutableArray alloc] initWithArray: stringArray]; // okay
[[NSMutableArray<NSString *> alloc] initWithArray: stringArray]; // okay
[[NSMutableArray<NSNumber *> alloc] initWithArray: stringArray]; // expected-warning{{sending 'NSArray<NSString *> *' to parameter of type 'NSArray<NSNumber *> *'}}
+
+ ip = [[[NSViewController alloc] init] view]; // expected-warning{{from '__kindof NSView *'}}
+ [[[[NSViewController alloc] init] view] toggle];
+
+ NSMutableString *mutStr = kindofStringArray[0];
+ NSNumber *number = kindofStringArray[0]; // expected-warning{{of type '__kindof NSString *'}}
}
void test_message_send_param(
@@ -215,7 +225,9 @@ void test_property_read(
ip = mutSet.allObjects; // expected-warning{{from 'NSArray *'}}
ip = mutArraySet.allObjects; // expected-warning{{from 'NSArray *'}}
- ip = mutDict.someRandomKey; // expected-warning{{from 'id'}}
+ ip = mutDict.someRandomKey; // expected-warning{{from '__kindof id<NSCopying>'}}
+
+ ip = [[NSViewController alloc] init].view; // expected-warning{{from '__kindof NSView *'}}
}
void test_property_write(
Modified: cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm?rev=241548&r1=241547&r2=241548&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm (original)
+++ cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm Mon Jul 6 22:58:42 2015
@@ -172,7 +172,7 @@ void test_property_read(
ip = mutSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
ip = mutArraySet.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
- ip = mutDict.someRandomKey; // expected-error{{from incompatible type 'id'}}
+ ip = mutDict.someRandomKey; // expected-error{{from incompatible type '__kindof id<NSCopying>'}}
}
void test_property_write(
More information about the cfe-commits
mailing list