aboutsummaryrefslogtreecommitdiff
path: root/lib/AST
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST')
-rw-r--r--lib/AST/ASTContext.cpp504
-rw-r--r--lib/AST/ASTDiagnostic.cpp15
-rw-r--r--lib/AST/ASTDumper.cpp38
-rw-r--r--lib/AST/ASTImporter.cpp92
-rw-r--r--lib/AST/Decl.cpp16
-rw-r--r--lib/AST/DeclBase.cpp1
-rw-r--r--lib/AST/DeclCXX.cpp6
-rw-r--r--lib/AST/DeclObjC.cpp214
-rw-r--r--lib/AST/DeclPrinter.cpp58
-rw-r--r--lib/AST/Expr.cpp10
-rw-r--r--lib/AST/ItaniumMangle.cpp13
-rw-r--r--lib/AST/Type.cpp1034
-rw-r--r--lib/AST/TypeLoc.cpp69
-rw-r--r--lib/AST/TypePrinter.cpp82
14 files changed, 1944 insertions, 208 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 5a91f074c4e1..fb9630180dca 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1917,11 +1917,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
// We can use protocol_iterator here instead of
// all_referenced_protocol_iterator since we are walking all categories.
for (auto *Proto : OI->all_referenced_protocols()) {
- Protocols.insert(Proto->getCanonicalDecl());
- for (auto *P : Proto->protocols()) {
- Protocols.insert(P->getCanonicalDecl());
- CollectInheritedProtocols(P, Protocols);
- }
+ CollectInheritedProtocols(Proto, Protocols);
}
// Categories of this Interface.
@@ -1935,16 +1931,16 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
}
} else if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) {
for (auto *Proto : OC->protocols()) {
- Protocols.insert(Proto->getCanonicalDecl());
- for (const auto *P : Proto->protocols())
- CollectInheritedProtocols(P, Protocols);
+ CollectInheritedProtocols(Proto, Protocols);
}
} else if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) {
- for (auto *Proto : OP->protocols()) {
- Protocols.insert(Proto->getCanonicalDecl());
- for (const auto *P : Proto->protocols())
- CollectInheritedProtocols(P, Protocols);
- }
+ // Insert the protocol.
+ if (!Protocols.insert(
+ const_cast<ObjCProtocolDecl *>(OP->getCanonicalDecl())).second)
+ return;
+
+ for (auto *Proto : OP->protocols())
+ CollectInheritedProtocols(Proto, Protocols);
}
}
@@ -3618,45 +3614,89 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **Protocols,
QualType ASTContext::getObjCObjectType(QualType BaseType,
ObjCProtocolDecl * const *Protocols,
unsigned NumProtocols) const {
- // If the base type is an interface and there aren't any protocols
- // to add, then the interface type will do just fine.
- if (!NumProtocols && isa<ObjCInterfaceType>(BaseType))
- return BaseType;
+ return getObjCObjectType(BaseType, { },
+ llvm::makeArrayRef(Protocols, NumProtocols),
+ /*isKindOf=*/false);
+}
+
+QualType ASTContext::getObjCObjectType(
+ QualType baseType,
+ ArrayRef<QualType> typeArgs,
+ 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() && !isKindOf &&
+ isa<ObjCInterfaceType>(baseType))
+ return baseType;
// Look in the folding set for an existing type.
llvm::FoldingSetNodeID ID;
- ObjCObjectTypeImpl::Profile(ID, BaseType, Protocols, NumProtocols);
+ ObjCObjectTypeImpl::Profile(ID, baseType, typeArgs, protocols, isKindOf);
void *InsertPos = nullptr;
if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(QT, 0);
- // Build the canonical type, which has the canonical base type and
- // a sorted-and-uniqued list of protocols.
- QualType Canonical;
- bool ProtocolsSorted = areSortedAndUniqued(Protocols, NumProtocols);
- if (!ProtocolsSorted || !BaseType.isCanonical()) {
- if (!ProtocolsSorted) {
- SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols,
- Protocols + NumProtocols);
- unsigned UniqueCount = NumProtocols;
-
- SortAndUniqueProtocols(&Sorted[0], UniqueCount);
- Canonical = getObjCObjectType(getCanonicalType(BaseType),
- &Sorted[0], UniqueCount);
+ // Determine the type arguments to be used for canonicalization,
+ // which may be explicitly specified here or written on the base
+ // type.
+ ArrayRef<QualType> effectiveTypeArgs = typeArgs;
+ if (effectiveTypeArgs.empty()) {
+ if (auto baseObject = baseType->getAs<ObjCObjectType>())
+ effectiveTypeArgs = baseObject->getTypeArgs();
+ }
+
+ // Build the canonical type, which has the canonical base type and a
+ // sorted-and-uniqued list of protocols and the type arguments
+ // canonicalized.
+ QualType canonical;
+ bool typeArgsAreCanonical = std::all_of(effectiveTypeArgs.begin(),
+ effectiveTypeArgs.end(),
+ [&](QualType type) {
+ return type.isCanonical();
+ });
+ bool protocolsSorted = areSortedAndUniqued(protocols.data(),
+ protocols.size());
+ if (!typeArgsAreCanonical || !protocolsSorted || !baseType.isCanonical()) {
+ // Determine the canonical type arguments.
+ ArrayRef<QualType> canonTypeArgs;
+ SmallVector<QualType, 4> canonTypeArgsVec;
+ if (!typeArgsAreCanonical) {
+ canonTypeArgsVec.reserve(effectiveTypeArgs.size());
+ for (auto typeArg : effectiveTypeArgs)
+ canonTypeArgsVec.push_back(getCanonicalType(typeArg));
+ canonTypeArgs = canonTypeArgsVec;
} else {
- Canonical = getObjCObjectType(getCanonicalType(BaseType),
- Protocols, NumProtocols);
+ canonTypeArgs = effectiveTypeArgs;
}
+ ArrayRef<ObjCProtocolDecl *> canonProtocols;
+ SmallVector<ObjCProtocolDecl*, 8> canonProtocolsVec;
+ if (!protocolsSorted) {
+ canonProtocolsVec.insert(canonProtocolsVec.begin(),
+ protocols.begin(),
+ protocols.end());
+ unsigned uniqueCount = protocols.size();
+ SortAndUniqueProtocols(&canonProtocolsVec[0], uniqueCount);
+ canonProtocols = llvm::makeArrayRef(&canonProtocolsVec[0], uniqueCount);
+ } else {
+ canonProtocols = protocols;
+ }
+
+ canonical = getObjCObjectType(getCanonicalType(baseType), canonTypeArgs,
+ canonProtocols, isKindOf);
+
// Regenerate InsertPos.
ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos);
}
- unsigned Size = sizeof(ObjCObjectTypeImpl);
- Size += NumProtocols * sizeof(ObjCProtocolDecl *);
- void *Mem = Allocate(Size, TypeAlignment);
+ unsigned size = sizeof(ObjCObjectTypeImpl);
+ size += typeArgs.size() * sizeof(QualType);
+ size += protocols.size() * sizeof(ObjCProtocolDecl *);
+ void *mem = Allocate(size, TypeAlignment);
ObjCObjectTypeImpl *T =
- new (Mem) ObjCObjectTypeImpl(Canonical, BaseType, Protocols, NumProtocols);
+ new (mem) ObjCObjectTypeImpl(canonical, baseType, typeArgs, protocols,
+ isKindOf);
Types.push_back(T);
ObjCObjectTypes.InsertNode(T, InsertPos);
@@ -5623,13 +5663,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
case Type::ObjCInterface: {
// Ignore protocol qualifiers when mangling at this level.
- T = T->castAs<ObjCObjectType>()->getBaseType();
-
- // The assumption seems to be that this assert will succeed
- // because nested levels will have filtered out 'id' and 'Class'.
- const ObjCInterfaceType *OIT = T->castAs<ObjCInterfaceType>();
// @encode(class_name)
- ObjCInterfaceDecl *OI = OIT->getDecl();
+ ObjCInterfaceDecl *OI = T->castAs<ObjCObjectType>()->getInterface();
S += '{';
S += OI->getObjCRuntimeNameAsString();
S += '=';
@@ -5921,7 +5956,7 @@ void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
TypedefDecl *ASTContext::getObjCIdDecl() const {
if (!ObjCIdDecl) {
- QualType T = getObjCObjectType(ObjCBuiltinIdTy, nullptr, 0);
+ QualType T = getObjCObjectType(ObjCBuiltinIdTy, { }, { });
T = getObjCObjectPointerType(T);
ObjCIdDecl = buildImplicitTypedef(T, "id");
}
@@ -5938,7 +5973,7 @@ TypedefDecl *ASTContext::getObjCSelDecl() const {
TypedefDecl *ASTContext::getObjCClassDecl() const {
if (!ObjCClassDecl) {
- QualType T = getObjCObjectType(ObjCBuiltinClassTy, nullptr, 0);
+ QualType T = getObjCObjectType(ObjCBuiltinClassTy, { }, { });
T = getObjCObjectPointerType(T);
ObjCClassDecl = buildImplicitTypedef(T, "Class");
}
@@ -5951,6 +5986,7 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const {
= ObjCInterfaceDecl::Create(*this, getTranslationUnitDecl(),
SourceLocation(),
&Idents.get("Protocol"),
+ /*typeParamList=*/nullptr,
/*PrevDecl=*/nullptr,
SourceLocation(), true);
}
@@ -6743,18 +6779,36 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
RHS->isObjCUnqualifiedIdOrClass())
return true;
- if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId())
- return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
- QualType(RHSOPT,0),
- false);
+ // 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 ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0),
- QualType(RHSOPT,0));
+ 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;
}
@@ -6768,26 +6822,46 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer(
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;
@@ -6795,78 +6869,253 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer(
return false;
}
+/// Comparison routine for Objective-C protocols to be used with
+/// llvm::array_pod_sort.
+static int compareObjCProtocolsByName(ObjCProtocolDecl * const *lhs,
+ ObjCProtocolDecl * const *rhs) {
+ return (*lhs)->getName().compare((*rhs)->getName());
+
+}
+
/// getIntersectionOfProtocols - This routine finds the intersection of set
-/// of protocols inherited from two distinct objective-c pointer objects.
+/// of protocols inherited from two distinct objective-c pointer objects with
+/// the given common base.
/// It is used to build composite qualifier list of the composite type of
/// the conditional expression involving two objective-c pointer objects.
static
void getIntersectionOfProtocols(ASTContext &Context,
+ const ObjCInterfaceDecl *CommonBase,
const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT,
- SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) {
+ SmallVectorImpl<ObjCProtocolDecl *> &IntersectionSet) {
const ObjCObjectType* LHS = LHSOPT->getObjectType();
const ObjCObjectType* RHS = RHSOPT->getObjectType();
assert(LHS->getInterface() && "LHS must have an interface base");
assert(RHS->getInterface() && "RHS must have an interface base");
-
- llvm::SmallPtrSet<ObjCProtocolDecl *, 8> InheritedProtocolSet;
- unsigned LHSNumProtocols = LHS->getNumProtocols();
- if (LHSNumProtocols > 0)
- InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end());
- else {
- llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols;
- Context.CollectInheritedProtocols(LHS->getInterface(),
- LHSInheritedProtocols);
- InheritedProtocolSet.insert(LHSInheritedProtocols.begin(),
- LHSInheritedProtocols.end());
+
+ // Add all of the protocols for the LHS.
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSProtocolSet;
+
+ // Start with the protocol qualifiers.
+ for (auto proto : LHS->quals()) {
+ Context.CollectInheritedProtocols(proto, LHSProtocolSet);
}
-
- unsigned RHSNumProtocols = RHS->getNumProtocols();
- if (RHSNumProtocols > 0) {
- ObjCProtocolDecl **RHSProtocols =
- const_cast<ObjCProtocolDecl **>(RHS->qual_begin());
- for (unsigned i = 0; i < RHSNumProtocols; ++i)
- if (InheritedProtocolSet.count(RHSProtocols[i]))
- IntersectionOfProtocols.push_back(RHSProtocols[i]);
- } else {
- llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols;
- Context.CollectInheritedProtocols(RHS->getInterface(),
- RHSInheritedProtocols);
- for (ObjCProtocolDecl *ProtDecl : RHSInheritedProtocols)
- if (InheritedProtocolSet.count(ProtDecl))
- IntersectionOfProtocols.push_back(ProtDecl);
+
+ // Also add the protocols associated with the LHS interface.
+ Context.CollectInheritedProtocols(LHS->getInterface(), LHSProtocolSet);
+
+ // Add all of the protocls for the RHS.
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSProtocolSet;
+
+ // Start with the protocol qualifiers.
+ for (auto proto : RHS->quals()) {
+ Context.CollectInheritedProtocols(proto, RHSProtocolSet);
+ }
+
+ // Also add the protocols associated with the RHS interface.
+ Context.CollectInheritedProtocols(RHS->getInterface(), RHSProtocolSet);
+
+ // Compute the intersection of the collected protocol sets.
+ for (auto proto : LHSProtocolSet) {
+ if (RHSProtocolSet.count(proto))
+ IntersectionSet.push_back(proto);
}
+
+ // Compute the set of protocols that is implied by either the common type or
+ // the protocols within the intersection.
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ImpliedProtocols;
+ Context.CollectInheritedProtocols(CommonBase, ImpliedProtocols);
+
+ // Remove any implied protocols from the list of inherited protocols.
+ if (!ImpliedProtocols.empty()) {
+ IntersectionSet.erase(
+ std::remove_if(IntersectionSet.begin(),
+ IntersectionSet.end(),
+ [&](ObjCProtocolDecl *proto) -> bool {
+ return ImpliedProtocols.count(proto) > 0;
+ }),
+ IntersectionSet.end());
+ }
+
+ // Sort the remaining protocols by name.
+ llvm::array_pod_sort(IntersectionSet.begin(), IntersectionSet.end(),
+ compareObjCProtocolsByName);
+}
+
+/// Determine whether the first type is a subtype of the second.
+static bool canAssignObjCObjectTypes(ASTContext &ctx, QualType lhs,
+ QualType rhs) {
+ // Common case: two object pointers.
+ const ObjCObjectPointerType *lhsOPT = lhs->getAs<ObjCObjectPointerType>();
+ const ObjCObjectPointerType *rhsOPT = rhs->getAs<ObjCObjectPointerType>();
+ if (lhsOPT && rhsOPT)
+ return ctx.canAssignObjCInterfaces(lhsOPT, rhsOPT);
+
+ // Two block pointers.
+ const BlockPointerType *lhsBlock = lhs->getAs<BlockPointerType>();
+ const BlockPointerType *rhsBlock = rhs->getAs<BlockPointerType>();
+ if (lhsBlock && rhsBlock)
+ return ctx.typesAreBlockPointerCompatible(lhs, rhs);
+
+ // If either is an unqualified 'id' and the other is a block, it's
+ // acceptable.
+ if ((lhsOPT && lhsOPT->isObjCIdType() && rhsBlock) ||
+ (rhsOPT && rhsOPT->isObjCIdType() && lhsBlock))
+ return true;
+
+ return false;
+}
+
+// Check that the given Objective-C type argument lists are equivalent.
+static bool sameObjCTypeArgs(ASTContext &ctx,
+ const ObjCInterfaceDecl *iface,
+ ArrayRef<QualType> lhsArgs,
+ ArrayRef<QualType> rhsArgs,
+ bool stripKindOf) {
+ if (lhsArgs.size() != rhsArgs.size())
+ return false;
+
+ ObjCTypeParamList *typeParams = iface->getTypeParamList();
+ for (unsigned i = 0, n = lhsArgs.size(); i != n; ++i) {
+ if (ctx.hasSameType(lhsArgs[i], rhsArgs[i]))
+ continue;
+
+ switch (typeParams->begin()[i]->getVariance()) {
+ case ObjCTypeParamVariance::Invariant:
+ if (!stripKindOf ||
+ !ctx.hasSameType(lhsArgs[i].stripObjCKindOfType(ctx),
+ rhsArgs[i].stripObjCKindOfType(ctx))) {
+ return false;
+ }
+ break;
+
+ case ObjCTypeParamVariance::Covariant:
+ if (!canAssignObjCObjectTypes(ctx, lhsArgs[i], rhsArgs[i]))
+ return false;
+ break;
+
+ case ObjCTypeParamVariance::Contravariant:
+ if (!canAssignObjCObjectTypes(ctx, rhsArgs[i], lhsArgs[i]))
+ return false;
+ break;
+ }
+ }
+
+ return true;
}
-/// areCommonBaseCompatible - Returns common base class of the two classes if
-/// one found. Note that this is O'2 algorithm. But it will be called as the
-/// last type comparison in a ?-exp of ObjC pointer types before a
-/// warning is issued. So, its invokation is extremely rare.
QualType ASTContext::areCommonBaseCompatible(
- const ObjCObjectPointerType *Lptr,
- const ObjCObjectPointerType *Rptr) {
+ const ObjCObjectPointerType *Lptr,
+ const ObjCObjectPointerType *Rptr) {
const ObjCObjectType *LHS = Lptr->getObjectType();
const ObjCObjectType *RHS = Rptr->getObjectType();
const ObjCInterfaceDecl* LDecl = LHS->getInterface();
const ObjCInterfaceDecl* RDecl = RHS->getInterface();
- if (!LDecl || !RDecl || (declaresSameEntity(LDecl, RDecl)))
+
+ if (!LDecl || !RDecl)
return QualType();
-
- do {
- LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl));
- if (canAssignObjCInterfaces(LHS, RHS)) {
+
+ // Follow the left-hand side up the class hierarchy until we either hit a
+ // root or find the RHS. Record the ancestors in case we don't find it.
+ llvm::SmallDenseMap<const ObjCInterfaceDecl *, const ObjCObjectType *, 4>
+ LHSAncestors;
+ while (true) {
+ // Record this ancestor. We'll need this if the common type isn't in the
+ // path from the LHS to the root.
+ LHSAncestors[LHS->getInterface()->getCanonicalDecl()] = LHS;
+
+ if (declaresSameEntity(LHS->getInterface(), RDecl)) {
+ // Get the type arguments.
+ ArrayRef<QualType> LHSTypeArgs = LHS->getTypeArgsAsWritten();
+ bool anyChanges = false;
+ if (LHS->isSpecialized() && RHS->isSpecialized()) {
+ // Both have type arguments, compare them.
+ if (!sameObjCTypeArgs(*this, LHS->getInterface(),
+ 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
+ // arguments.
+ LHSTypeArgs = { };
+ anyChanges = true;
+ }
+
+ // Compute the intersection of protocols.
SmallVector<ObjCProtocolDecl *, 8> Protocols;
- getIntersectionOfProtocols(*this, Lptr, Rptr, Protocols);
+ getIntersectionOfProtocols(*this, LHS->getInterface(), Lptr, Rptr,
+ Protocols);
+ if (!Protocols.empty())
+ anyChanges = true;
+
+ // 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,
+ LHS->isKindOfType());
+ return getObjCObjectPointerType(Result);
+ }
+
+ return getObjCObjectPointerType(QualType(LHS, 0));
+ }
+
+ // Find the superclass.
+ QualType LHSSuperType = LHS->getSuperClassType();
+ if (LHSSuperType.isNull())
+ break;
- QualType Result = QualType(LHS, 0);
+ LHS = LHSSuperType->castAs<ObjCObjectType>();
+ }
+
+ // We didn't find anything by following the LHS to its root; now check
+ // the RHS against the cached set of ancestors.
+ while (true) {
+ auto KnownLHS = LHSAncestors.find(RHS->getInterface()->getCanonicalDecl());
+ if (KnownLHS != LHSAncestors.end()) {
+ LHS = KnownLHS->second;
+
+ // Get the type arguments.
+ ArrayRef<QualType> RHSTypeArgs = RHS->getTypeArgsAsWritten();
+ bool anyChanges = false;
+ if (LHS->isSpecialized() && RHS->isSpecialized()) {
+ // Both have type arguments, compare them.
+ if (!sameObjCTypeArgs(*this, LHS->getInterface(),
+ 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
+ // arguments.
+ RHSTypeArgs = { };
+ anyChanges = true;
+ }
+
+ // Compute the intersection of protocols.
+ SmallVector<ObjCProtocolDecl *, 8> Protocols;
+ getIntersectionOfProtocols(*this, RHS->getInterface(), Lptr, Rptr,
+ Protocols);
if (!Protocols.empty())
- Result = getObjCObjectType(Result, Protocols.data(), Protocols.size());
- Result = getObjCObjectPointerType(Result);
- return Result;
+ anyChanges = true;
+
+ if (anyChanges) {
+ QualType Result = getObjCInterfaceType(RHS->getInterface());
+ Result = getObjCObjectType(Result, RHSTypeArgs, Protocols,
+ RHS->isKindOfType());
+ return getObjCObjectPointerType(Result);
+ }
+
+ return getObjCObjectPointerType(QualType(RHS, 0));
}
- } while ((LDecl = LDecl->getSuperClass()));
-
+
+ // Find the superclass of the RHS.
+ QualType RHSSuperType = RHS->getSuperClassType();
+ if (RHSSuperType.isNull())
+ break;
+
+ RHS = RHSSuperType->castAs<ObjCObjectType>();
+ }
+
return QualType();
}
@@ -6877,21 +7126,15 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
// Verify that the base decls are compatible: the RHS must be a subclass of
// the LHS.
- if (!LHS->getInterface()->isSuperClassOf(RHS->getInterface()))
+ ObjCInterfaceDecl *LHSInterface = LHS->getInterface();
+ bool IsSuperClass = LHSInterface->isSuperClassOf(RHS->getInterface());
+ if (!IsSuperClass)
return false;
- // RHS must have a superset of the protocols in the LHS. If the LHS is not
- // protocol qualified at all, then we are good.
- if (LHS->getNumProtocols() == 0)
- return true;
-
- // Okay, we know the LHS has protocol qualifiers. But RHS may or may not.
- // More detailed analysis is required.
- // OK, if LHS is same or a superclass of RHS *and*
- // this LHS, or as RHS's super class is assignment compatible with LHS.
- bool IsSuperClass =
- LHS->getInterface()->isSuperClassOf(RHS->getInterface());
- if (IsSuperClass) {
+ // If the LHS has protocol qualifiers, determine whether all of them are
+ // satisfied by the RHS (i.e., the RHS has a superset of the protocols in the
+ // LHS).
+ if (LHS->getNumProtocols() > 0) {
// OK if conversion of LHS to SuperClass results in narrowing of types
// ; i.e., SuperClass may implement at least one of the protocols
// in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok.
@@ -6901,7 +7144,7 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
// Also, if RHS has explicit quelifiers, include them for comparing with LHS's
// qualifiers.
for (auto *RHSPI : RHS->quals())
- SuperClassInheritedProtocols.insert(RHSPI->getCanonicalDecl());
+ CollectInheritedProtocols(RHSPI, SuperClassInheritedProtocols);
// If there is no protocols associated with RHS, it is not a match.
if (SuperClassInheritedProtocols.empty())
return false;
@@ -6916,9 +7159,26 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
if (!SuperImplementsProtocol)
return false;
}
- return true;
}
- return false;
+
+ // If the LHS is specialized, we may need to check type arguments.
+ if (LHS->isSpecialized()) {
+ // Follow the superclass chain until we've matched the LHS class in the
+ // hierarchy. This substitutes type arguments through.
+ const ObjCObjectType *RHSSuper = RHS;
+ while (!declaresSameEntity(RHSSuper->getInterface(), LHSInterface))
+ RHSSuper = RHSSuper->getSuperClassType()->castAs<ObjCObjectType>();
+
+ // If the RHS is specializd, compare type arguments.
+ if (RHSSuper->isSpecialized() &&
+ !sameObjCTypeArgs(*this, LHS->getInterface(),
+ LHS->getTypeArgs(), RHSSuper->getTypeArgs(),
+ /*stripKindOf=*/true)) {
+ return false;
+ }
+ }
+
+ return true;
}
bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 000588face96..dddaa5af6fb0 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -125,12 +125,23 @@ break; \
if (const PointerType *Ty = QT->getAs<PointerType>()) {
QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(),
ShouldAKA));
+ } else if (const auto *Ty = QT->getAs<ObjCObjectPointerType>()) {
+ QT = Context.getObjCObjectPointerType(Desugar(Context, Ty->getPointeeType(),
+ ShouldAKA));
} else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) {
QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(),
ShouldAKA));
} else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) {
QT = Context.getRValueReferenceType(Desugar(Context, Ty->getPointeeType(),
ShouldAKA));
+ } else if (const auto *Ty = QT->getAs<ObjCObjectType>()) {
+ if (Ty->getBaseType().getTypePtr() != Ty && !ShouldAKA) {
+ QualType BaseType = Desugar(Context, Ty->getBaseType(), ShouldAKA);
+ QT = Context.getObjCObjectType(BaseType, Ty->getTypeArgsAsWritten(),
+ llvm::makeArrayRef(Ty->qual_begin(),
+ Ty->getNumProtocols()),
+ Ty->isKindOfTypeAsWritten());
+ }
}
return QC.apply(Context, QT);
@@ -181,8 +192,8 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
if (CompareCanTy == CanTy)
continue; // Same canonical types
std::string CompareS = CompareTy.getAsString(Context.getPrintingPolicy());
- bool aka;
- QualType CompareDesugar = Desugar(Context, CompareTy, aka);
+ bool ShouldAKA = false;
+ QualType CompareDesugar = Desugar(Context, CompareTy, ShouldAKA);
std::string CompareDesugarStr =
CompareDesugar.getAsString(Context.getPrintingPolicy());
if (CompareS != S && CompareDesugarStr != S)
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 90da4167197a..c95922b141e0 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -240,6 +240,9 @@ namespace {
void dumpTemplateArgument(const TemplateArgument &A,
SourceRange R = SourceRange());
+ // Objective-C utilities.
+ void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams);
+
// Types
void VisitComplexType(const ComplexType *T) {
dumpTypeAsChild(T->getElementType());
@@ -463,6 +466,7 @@ namespace {
// ObjC Decls
void VisitObjCIvarDecl(const ObjCIvarDecl *D);
void VisitObjCMethodDecl(const ObjCMethodDecl *D);
+ void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D);
void VisitObjCCategoryDecl(const ObjCCategoryDecl *D);
void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D);
void VisitObjCProtocolDecl(const ObjCProtocolDecl *D);
@@ -955,6 +959,18 @@ void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) {
}
//===----------------------------------------------------------------------===//
+// Objective-C Utilities
+//===----------------------------------------------------------------------===//
+void ASTDumper::dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) {
+ if (!typeParams)
+ return;
+
+ for (auto typeParam : *typeParams) {
+ dumpDecl(typeParam);
+ }
+}
+
+//===----------------------------------------------------------------------===//
// Decl dumping methods.
//===----------------------------------------------------------------------===//
@@ -1457,9 +1473,30 @@ void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
dumpStmt(D->getBody());
}
+void ASTDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) {
+ dumpName(D);
+ switch (D->getVariance()) {
+ case ObjCTypeParamVariance::Invariant:
+ break;
+
+ case ObjCTypeParamVariance::Covariant:
+ OS << " covariant";
+ break;
+
+ case ObjCTypeParamVariance::Contravariant:
+ OS << " contravariant";
+ break;
+ }
+
+ if (D->hasExplicitBound())
+ OS << " bounded";
+ dumpType(D->getUnderlyingType());
+}
+
void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
dumpName(D);
dumpDeclRef(D->getClassInterface());
+ dumpObjCTypeParamList(D->getTypeParamList());
dumpDeclRef(D->getImplementation());
for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
E = D->protocol_end();
@@ -1482,6 +1519,7 @@ void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
dumpName(D);
+ dumpObjCTypeParamList(D->getTypeParamListAsWritten());
dumpDeclRef(D->getSuperClass(), "super");
dumpDeclRef(D->getImplementation());
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 76e4e1191501..35c0f690db82 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -150,9 +150,12 @@ namespace clang {
Decl *VisitImplicitParamDecl(ImplicitParamDecl *D);
Decl *VisitParmVarDecl(ParmVarDecl *D);
Decl *VisitObjCMethodDecl(ObjCMethodDecl *D);
+ Decl *VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D);
Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D);
Decl *VisitLinkageSpecDecl(LinkageSpecDecl *D);
+
+ ObjCTypeParamList *ImportObjCTypeParamList(ObjCTypeParamList *list);
Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D);
@@ -1841,6 +1844,15 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) {
if (ToBaseType.isNull())
return QualType();
+ SmallVector<QualType, 4> TypeArgs;
+ for (auto TypeArg : T->getTypeArgsAsWritten()) {
+ QualType ImportedTypeArg = Importer.Import(TypeArg);
+ if (ImportedTypeArg.isNull())
+ return QualType();
+
+ TypeArgs.push_back(ImportedTypeArg);
+ }
+
SmallVector<ObjCProtocolDecl *, 4> Protocols;
for (auto *P : T->quals()) {
ObjCProtocolDecl *Protocol
@@ -1850,9 +1862,9 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) {
Protocols.push_back(Protocol);
}
- return Importer.getToContext().getObjCObjectType(ToBaseType,
- Protocols.data(),
- Protocols.size());
+ return Importer.getToContext().getObjCObjectType(ToBaseType, TypeArgs,
+ Protocols,
+ T->isKindOfTypeAsWritten());
}
QualType
@@ -3423,6 +3435,35 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
return ToMethod;
}
+Decl *ASTNodeImporter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
+ // Import the major distinguishing characteristics of a category.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ NamedDecl *ToD;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc))
+ return nullptr;
+ if (ToD)
+ return ToD;
+
+ TypeSourceInfo *BoundInfo = Importer.Import(D->getTypeSourceInfo());
+ if (!BoundInfo)
+ return nullptr;
+
+ ObjCTypeParamDecl *Result = ObjCTypeParamDecl::Create(
+ Importer.getToContext(), DC,
+ D->getVariance(),
+ Importer.Import(D->getVarianceLoc()),
+ D->getIndex(),
+ Importer.Import(D->getLocation()),
+ Name.getAsIdentifierInfo(),
+ Importer.Import(D->getColonLoc()),
+ BoundInfo);
+ Importer.Imported(D, Result);
+ Result->setLexicalDeclContext(LexicalDC);
+ return Result;
+}
+
Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
// Import the major distinguishing characteristics of a category.
DeclContext *DC, *LexicalDC;
@@ -3450,11 +3491,16 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
Importer.Import(D->getCategoryNameLoc()),
Name.getAsIdentifierInfo(),
ToInterface,
+ /*TypeParamList=*/nullptr,
Importer.Import(D->getIvarLBraceLoc()),
Importer.Import(D->getIvarRBraceLoc()));
ToCategory->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToCategory);
Importer.Imported(D, ToCategory);
+ // Import the type parameter list after calling Imported, to avoid
+ // loops when bringing in their DeclContext.
+ ToCategory->setTypeParamList(ImportObjCTypeParamList(
+ D->getTypeParamList()));
// Import protocols
SmallVector<ObjCProtocolDecl *, 4> Protocols;
@@ -3663,13 +3709,11 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From,
// If this class has a superclass, import it.
if (From->getSuperClass()) {
- ObjCInterfaceDecl *Super = cast_or_null<ObjCInterfaceDecl>(
- Importer.Import(From->getSuperClass()));
- if (!Super)
+ TypeSourceInfo *SuperTInfo = Importer.Import(From->getSuperClassTInfo());
+ if (!SuperTInfo)
return true;
-
- To->setSuperClass(Super);
- To->setSuperClassLoc(Importer.Import(From->getSuperClassLoc()));
+
+ To->setSuperClass(SuperTInfo);
}
// Import protocols
@@ -3716,6 +3760,27 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From,
return false;
}
+ObjCTypeParamList *
+ASTNodeImporter::ImportObjCTypeParamList(ObjCTypeParamList *list) {
+ if (!list)
+ return nullptr;
+
+ SmallVector<ObjCTypeParamDecl *, 4> toTypeParams;
+ for (auto fromTypeParam : *list) {
+ auto toTypeParam = cast_or_null<ObjCTypeParamDecl>(
+ Importer.Import(fromTypeParam));
+ if (!toTypeParam)
+ return nullptr;
+
+ toTypeParams.push_back(toTypeParam);
+ }
+
+ return ObjCTypeParamList::create(Importer.getToContext(),
+ Importer.Import(list->getLAngleLoc()),
+ toTypeParams,
+ Importer.Import(list->getRAngleLoc()));
+}
+
Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
// If this class has a definition in the translation unit we're coming from,
// but this particular declaration is not that definition, import the
@@ -3756,13 +3821,18 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
if (!ToIface) {
ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getAtStartLoc()),
- Name.getAsIdentifierInfo(),
+ Name.getAsIdentifierInfo(),
+ /*TypeParamList=*/nullptr,
/*PrevDecl=*/nullptr, Loc,
D->isImplicitInterfaceDecl());
ToIface->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToIface);
}
Importer.Imported(D, ToIface);
+ // Import the type parameter list after calling Imported, to avoid
+ // loops when bringing in their DeclContext.
+ ToIface->setTypeParamList(ImportObjCTypeParamList(
+ D->getTypeParamListAsWritten()));
if (D->isThisDeclarationADefinition() && ImportDefinition(D, ToIface))
return nullptr;
@@ -5313,7 +5383,7 @@ TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) {
return nullptr;
return ToContext.getTrivialTypeSourceInfo(T,
- FromTSI->getTypeLoc().getLocStart());
+ Import(FromTSI->getTypeLoc().getLocStart()));
}
Decl *ASTImporter::GetAlreadyImportedOrNull(Decl *FromD) {
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index d9a3389c58f3..ea4b2f517cd0 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1803,15 +1803,19 @@ void VarDecl::setStorageClass(StorageClass SC) {
VarDecl::TLSKind VarDecl::getTLSKind() const {
switch (VarDeclBits.TSCSpec) {
case TSCS_unspecified:
- if (!hasAttr<ThreadAttr>())
+ if (!hasAttr<ThreadAttr>() &&
+ !(getASTContext().getLangOpts().OpenMPUseTLS &&
+ getASTContext().getTargetInfo().isTLSSupported() &&
+ hasAttr<OMPThreadPrivateDeclAttr>()))
return TLS_None;
- return getASTContext().getLangOpts().isCompatibleWithMSVC(
- LangOptions::MSVC2015)
+ return ((getASTContext().getLangOpts().isCompatibleWithMSVC(
+ LangOptions::MSVC2015)) ||
+ hasAttr<OMPThreadPrivateDeclAttr>())
? TLS_Dynamic
: TLS_Static;
case TSCS___thread: // Fall through.
case TSCS__Thread_local:
- return TLS_Static;
+ return TLS_Static;
case TSCS_thread_local:
return TLS_Dynamic;
}
@@ -2712,7 +2716,7 @@ bool FunctionDecl::isMSExternInline() const {
for (const FunctionDecl *FD = getMostRecentDecl(); FD;
FD = FD->getPreviousDecl())
- if (FD->getStorageClass() == SC_Extern)
+ if (!FD->isImplicit() && FD->getStorageClass() == SC_Extern)
return true;
return false;
@@ -2724,7 +2728,7 @@ static bool redeclForcesDefMSVC(const FunctionDecl *Redecl) {
for (const FunctionDecl *FD = Redecl->getPreviousDecl(); FD;
FD = FD->getPreviousDecl())
- if (FD->getStorageClass() == SC_Extern)
+ if (!FD->isImplicit() && FD->getStorageClass() == SC_Extern)
return false;
return true;
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index d20451d1badc..4fcec53d6eb9 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -561,6 +561,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case TypeAliasTemplate:
case UnresolvedUsingTypename:
case TemplateTypeParm:
+ case ObjCTypeParam:
return IDNS_Ordinary | IDNS_Type;
case UsingShadow:
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index b00b8a0ea9cc..d905fcf13a45 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -1272,7 +1272,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
break;
CTD = NewCTD;
}
- return CTD->getTemplatedDecl();
+ return CTD->getTemplatedDecl()->getDefinition();
}
if (auto *CTPSD =
From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
@@ -1281,7 +1281,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
break;
CTPSD = NewCTPSD;
}
- return CTPSD;
+ return CTPSD->getDefinition();
}
}
@@ -1290,7 +1290,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
const CXXRecordDecl *RD = this;
while (auto *NewRD = RD->getInstantiatedFromMemberClass())
RD = NewRD;
- return RD;
+ return RD->getDefinition();
}
}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index a1600cb11014..280c412ae8ff 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -239,6 +239,62 @@ ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration(
void ObjCInterfaceDecl::anchor() { }
+ObjCTypeParamList *ObjCInterfaceDecl::getTypeParamList() const {
+ // If this particular declaration has a type parameter list, return it.
+ if (ObjCTypeParamList *written = getTypeParamListAsWritten())
+ return written;
+
+ // If there is a definition, return its type parameter list.
+ if (const ObjCInterfaceDecl *def = getDefinition())
+ return def->getTypeParamListAsWritten();
+
+ // Otherwise, look at previous declarations to determine whether any
+ // of them has a type parameter list, skipping over those
+ // declarations that do not.
+ for (auto decl = getMostRecentDecl(); decl; decl = decl->getPreviousDecl()) {
+ if (ObjCTypeParamList *written = decl->getTypeParamListAsWritten())
+ return written;
+ }
+
+ return nullptr;
+}
+
+void ObjCInterfaceDecl::setTypeParamList(ObjCTypeParamList *TPL) {
+ TypeParamList = TPL;
+ if (!TPL)
+ return;
+ // Set the declaration context of each of the type parameters.
+ for (auto typeParam : *TypeParamList)
+ typeParam->setDeclContext(this);
+}
+
+ObjCInterfaceDecl *ObjCInterfaceDecl::getSuperClass() const {
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return nullptr;
+
+ if (data().ExternallyCompleted)
+ LoadExternalDefinition();
+
+ if (const ObjCObjectType *superType = getSuperClassType()) {
+ if (ObjCInterfaceDecl *superDecl = superType->getInterface()) {
+ if (ObjCInterfaceDecl *superDef = superDecl->getDefinition())
+ return superDef;
+
+ return superDecl;
+ }
+ }
+
+ return nullptr;
+}
+
+SourceLocation ObjCInterfaceDecl::getSuperClassLoc() const {
+ if (TypeSourceInfo *superTInfo = getSuperClassTInfo())
+ return superTInfo->getTypeLoc().getLocStart();
+
+ return SourceLocation();
+}
+
/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property
/// with name 'PropertyId' in the primary class; including those in protocols
/// (direct or indirect) used by the primary class.
@@ -889,9 +945,13 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
return family;
}
-void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
- const ObjCInterfaceDecl *OID) {
+QualType ObjCMethodDecl::getSelfType(ASTContext &Context,
+ const ObjCInterfaceDecl *OID,
+ bool &selfIsPseudoStrong,
+ bool &selfIsConsumed) {
QualType selfTy;
+ selfIsPseudoStrong = false;
+ selfIsConsumed = false;
if (isInstanceMethod()) {
// There may be no interface context due to error in declaration
// of the interface (which has been reported). Recover gracefully.
@@ -904,9 +964,6 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
} else // we have a factory method.
selfTy = Context.getObjCClassType();
- bool selfIsPseudoStrong = false;
- bool selfIsConsumed = false;
-
if (Context.getLangOpts().ObjCAutoRefCount) {
if (isInstanceMethod()) {
selfIsConsumed = hasAttr<NSConsumesSelfAttr>();
@@ -930,7 +987,14 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
selfIsPseudoStrong = true;
}
}
+ return selfTy;
+}
+void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
+ const ObjCInterfaceDecl *OID) {
+ bool selfIsPseudoStrong, selfIsConsumed;
+ QualType selfTy =
+ getSelfType(Context, OID, selfIsPseudoStrong, selfIsConsumed);
ImplicitParamDecl *self
= ImplicitParamDecl::Create(Context, this, SourceLocation(),
&Context.Idents.get("self"), selfTy);
@@ -966,6 +1030,20 @@ SourceRange ObjCMethodDecl::getReturnTypeSourceRange() const {
return SourceRange();
}
+QualType ObjCMethodDecl::getSendResultType() const {
+ ASTContext &Ctx = getASTContext();
+ return getReturnType().getNonLValueExprType(Ctx)
+ .substObjCTypeArgs(Ctx, {}, ObjCSubstitutionContext::Result);
+}
+
+QualType ObjCMethodDecl::getSendResultType(QualType receiverType) const {
+ // FIXME: Handle related result types here.
+
+ return getReturnType().getNonLValueExprType(getASTContext())
+ .substObjCMemberType(receiverType, getDeclContext(),
+ ObjCSubstitutionContext::Result);
+}
+
static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
const ObjCMethodDecl *Method,
SmallVectorImpl<const ObjCMethodDecl *> &Methods,
@@ -1137,6 +1215,81 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
}
//===----------------------------------------------------------------------===//
+// ObjCTypeParamDecl
+//===----------------------------------------------------------------------===//
+
+void ObjCTypeParamDecl::anchor() { }
+
+ObjCTypeParamDecl *ObjCTypeParamDecl::Create(ASTContext &ctx, DeclContext *dc,
+ ObjCTypeParamVariance variance,
+ SourceLocation varianceLoc,
+ unsigned index,
+ SourceLocation nameLoc,
+ IdentifierInfo *name,
+ SourceLocation colonLoc,
+ TypeSourceInfo *boundInfo) {
+ return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, variance, varianceLoc, index,
+ nameLoc, name, colonLoc, boundInfo);
+}
+
+ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx,
+ unsigned ID) {
+ return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr,
+ ObjCTypeParamVariance::Invariant,
+ SourceLocation(), 0, SourceLocation(),
+ nullptr, SourceLocation(), nullptr);
+}
+
+SourceRange ObjCTypeParamDecl::getSourceRange() const {
+ SourceLocation startLoc = VarianceLoc;
+ if (startLoc.isInvalid())
+ startLoc = getLocation();
+
+ if (hasExplicitBound()) {
+ return SourceRange(startLoc,
+ getTypeSourceInfo()->getTypeLoc().getEndLoc());
+ }
+
+ return SourceRange(startLoc);
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCTypeParamList
+//===----------------------------------------------------------------------===//
+ObjCTypeParamList::ObjCTypeParamList(SourceLocation lAngleLoc,
+ ArrayRef<ObjCTypeParamDecl *> typeParams,
+ SourceLocation rAngleLoc)
+ : NumParams(typeParams.size())
+{
+ Brackets.Begin = lAngleLoc.getRawEncoding();
+ Brackets.End = rAngleLoc.getRawEncoding();
+ std::copy(typeParams.begin(), typeParams.end(), begin());
+}
+
+
+ObjCTypeParamList *ObjCTypeParamList::create(
+ ASTContext &ctx,
+ SourceLocation lAngleLoc,
+ ArrayRef<ObjCTypeParamDecl *> typeParams,
+ SourceLocation rAngleLoc) {
+ unsigned size = sizeof(ObjCTypeParamList)
+ + sizeof(ObjCTypeParamDecl *) * typeParams.size();
+ static_assert(llvm::AlignOf<ObjCTypeParamList>::Alignment >=
+ llvm::AlignOf<ObjCTypeParamDecl *>::Alignment,
+ "type parameter list needs greater alignment");
+ unsigned align = llvm::alignOf<ObjCTypeParamList>();
+ void *mem = ctx.Allocate(size, align);
+ return new (mem) ObjCTypeParamList(lAngleLoc, typeParams, rAngleLoc);
+}
+
+void ObjCTypeParamList::gatherDefaultTypeArgs(
+ SmallVectorImpl<QualType> &typeArgs) const {
+ typeArgs.reserve(size());
+ for (auto typeParam : *this)
+ typeArgs.push_back(typeParam->getUnderlyingType());
+}
+
+//===----------------------------------------------------------------------===//
// ObjCInterfaceDecl
//===----------------------------------------------------------------------===//
@@ -1144,11 +1297,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
DeclContext *DC,
SourceLocation atLoc,
IdentifierInfo *Id,
+ ObjCTypeParamList *typeParamList,
ObjCInterfaceDecl *PrevDecl,
SourceLocation ClassLoc,
bool isInternal){
ObjCInterfaceDecl *Result = new (C, DC)
- ObjCInterfaceDecl(C, DC, atLoc, Id, ClassLoc, PrevDecl, isInternal);
+ ObjCInterfaceDecl(C, DC, atLoc, Id, typeParamList, ClassLoc, PrevDecl,
+ isInternal);
Result->Data.setInt(!C.getLangOpts().Modules);
C.getObjCInterfaceType(Result, PrevDecl);
return Result;
@@ -1159,6 +1314,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C,
ObjCInterfaceDecl *Result = new (C, ID) ObjCInterfaceDecl(C, nullptr,
SourceLocation(),
nullptr,
+ nullptr,
SourceLocation(),
nullptr, false);
Result->Data.setInt(!C.getLangOpts().Modules);
@@ -1167,11 +1323,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C,
ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
SourceLocation AtLoc, IdentifierInfo *Id,
+ ObjCTypeParamList *typeParamList,
SourceLocation CLoc,
ObjCInterfaceDecl *PrevDecl,
bool IsInternal)
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc),
- redeclarable_base(C), TypeForDecl(nullptr), Data() {
+ redeclarable_base(C), TypeForDecl(nullptr), TypeParamList(nullptr),
+ Data() {
setPreviousDecl(PrevDecl);
// Copy the 'data' pointer over.
@@ -1179,6 +1337,8 @@ ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
Data = PrevDecl->Data;
setImplicit(IsInternal);
+
+ setTypeParamList(typeParamList);
}
void ObjCInterfaceDecl::LoadExternalDefinition() const {
@@ -1492,6 +1652,11 @@ const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
}
}
+QualType ObjCIvarDecl::getUsageType(QualType objectType) const {
+ return getType().substObjCMemberType(objectType, getDeclContext(),
+ ObjCSubstitutionContext::Property);
+}
+
//===----------------------------------------------------------------------===//
// ObjCAtDefsFieldDecl
//===----------------------------------------------------------------------===//
@@ -1648,17 +1813,34 @@ ObjCProtocolDecl::getObjCRuntimeNameAsString() const {
void ObjCCategoryDecl::anchor() { }
+ObjCCategoryDecl::ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
+ SourceLocation ClassNameLoc,
+ SourceLocation CategoryNameLoc,
+ IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
+ ObjCTypeParamList *typeParamList,
+ SourceLocation IvarLBraceLoc,
+ SourceLocation IvarRBraceLoc)
+ : ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
+ ClassInterface(IDecl), TypeParamList(nullptr),
+ NextClassCategory(nullptr), CategoryNameLoc(CategoryNameLoc),
+ IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc)
+{
+ setTypeParamList(typeParamList);
+}
+
ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation AtLoc,
SourceLocation ClassNameLoc,
SourceLocation CategoryNameLoc,
IdentifierInfo *Id,
ObjCInterfaceDecl *IDecl,
+ ObjCTypeParamList *typeParamList,
SourceLocation IvarLBraceLoc,
SourceLocation IvarRBraceLoc) {
ObjCCategoryDecl *CatDecl =
new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id,
- IDecl, IvarLBraceLoc, IvarRBraceLoc);
+ IDecl, typeParamList, IvarLBraceLoc,
+ IvarRBraceLoc);
if (IDecl) {
// Link this category into its class's category list.
CatDecl->NextClassCategory = IDecl->getCategoryListRaw();
@@ -1676,7 +1858,7 @@ ObjCCategoryDecl *ObjCCategoryDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
return new (C, ID) ObjCCategoryDecl(nullptr, SourceLocation(),
SourceLocation(), SourceLocation(),
- nullptr, nullptr);
+ nullptr, nullptr, nullptr);
}
ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const {
@@ -1688,6 +1870,15 @@ void ObjCCategoryDecl::setImplementation(ObjCCategoryImplDecl *ImplD) {
getASTContext().setObjCImplementation(this, ImplD);
}
+void ObjCCategoryDecl::setTypeParamList(ObjCTypeParamList *TPL) {
+ TypeParamList = TPL;
+ if (!TPL)
+ return;
+ // Set the declaration context of each of the type parameters.
+ for (auto typeParam : *TypeParamList)
+ typeParam->setDeclContext(this);
+}
+
//===----------------------------------------------------------------------===//
// ObjCCategoryImplDecl
@@ -1876,6 +2067,11 @@ ObjCPropertyDecl *ObjCPropertyDecl::CreateDeserialized(ASTContext &C,
QualType(), nullptr, None);
}
+QualType ObjCPropertyDecl::getUsageType(QualType objectType) const {
+ return DeclType.substObjCMemberType(objectType, getDeclContext(),
+ ObjCSubstitutionContext::Property);
+}
+
//===----------------------------------------------------------------------===//
// ObjCPropertyImplDecl
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index d33093b8b5e1..3202d8c75436 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -44,6 +44,8 @@ namespace {
void PrintObjCMethodType(ASTContext &Ctx, Decl::ObjCDeclQualifier Quals,
QualType T);
+ void PrintObjCTypeParams(ObjCTypeParamList *Params);
+
public:
DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
unsigned Indentation = 0, bool PrintInstantiation = false)
@@ -962,6 +964,38 @@ void DeclPrinter::PrintObjCMethodType(ASTContext &Ctx,
Out << ')';
}
+void DeclPrinter::PrintObjCTypeParams(ObjCTypeParamList *Params) {
+ Out << "<";
+ unsigned First = true;
+ for (auto *Param : *Params) {
+ if (First) {
+ First = false;
+ } else {
+ Out << ", ";
+ }
+
+ switch (Param->getVariance()) {
+ case ObjCTypeParamVariance::Invariant:
+ break;
+
+ case ObjCTypeParamVariance::Covariant:
+ Out << "__covariant ";
+ break;
+
+ case ObjCTypeParamVariance::Contravariant:
+ Out << "__contravariant ";
+ break;
+ }
+
+ Out << Param->getDeclName().getAsString();
+
+ if (Param->hasExplicitBound()) {
+ Out << " : " << Param->getUnderlyingType().getAsString(Policy);
+ }
+ }
+ Out << ">";
+}
+
void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
if (OMD->isInstanceMethod())
Out << "- ";
@@ -1037,14 +1071,24 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
ObjCInterfaceDecl *SID = OID->getSuperClass();
if (!OID->isThisDeclarationADefinition()) {
- Out << "@class " << I << ";";
+ Out << "@class " << I;
+
+ if (auto TypeParams = OID->getTypeParamListAsWritten()) {
+ PrintObjCTypeParams(TypeParams);
+ }
+
+ Out << ";";
return;
}
bool eolnOut = false;
+ Out << "@interface " << I;
+
+ if (auto TypeParams = OID->getTypeParamListAsWritten()) {
+ PrintObjCTypeParams(TypeParams);
+ }
+
if (SID)
- Out << "@interface " << I << " : " << *SID;
- else
- Out << "@interface " << I;
+ Out << " : " << OID->getSuperClass()->getName();
// Protocols?
const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
@@ -1107,7 +1151,11 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
}
void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
- Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n";
+ Out << "@interface " << *PID->getClassInterface();
+ if (auto TypeParams = PID->getTypeParamList()) {
+ PrintObjCTypeParams(TypeParams);
+ }
+ Out << "(" << *PID << ")\n";
if (PID->ivar_size() > 0) {
Out << "{\n";
Indentation += Policy.Indentation;
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 87f9ffba78e3..2e066b2c42c6 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -3748,6 +3748,16 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
return nullptr;
}
+QualType ObjCPropertyRefExpr::getReceiverType(const ASTContext &ctx) const {
+ if (isClassReceiver())
+ return ctx.getObjCInterfaceType(getClassReceiver());
+
+ if (isSuperReceiver())
+ return getSuperReceiverType();
+
+ return getBase()->getType();
+}
+
StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
switch (getBridgeKind()) {
case OBC_Bridge:
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 0134c090d67e..dac803e5d2ff 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -2379,6 +2379,10 @@ void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
}
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 ObjCObjectType *T) {
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) {
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 541bd1ebdf88..cee5fee83913 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -466,18 +466,976 @@ const RecordType *Type::getAsUnionType() const {
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,
- ObjCProtocolDecl * const *Protocols,
- unsigned NumProtocols)
- : Type(ObjCObject, Canonical, false, false, false, false),
+ ArrayRef<QualType> typeArgs,
+ ArrayRef<ObjCProtocolDecl *> protocols,
+ bool isKindOf)
+ : Type(ObjCObject, Canonical, Base->isDependentType(),
+ Base->isInstantiationDependentType(),
+ Base->isVariablyModifiedType(),
+ Base->containsUnexpandedParameterPack()),
BaseType(Base)
{
- ObjCObjectTypeBits.NumProtocols = NumProtocols;
- assert(getNumProtocols() == NumProtocols &&
+ ObjCObjectTypeBits.IsKindOf = isKindOf;
+
+ ObjCObjectTypeBits.NumTypeArgs = typeArgs.size();
+ assert(getTypeArgsAsWritten().size() == typeArgs.size() &&
+ "bitfield overflow in type argument count");
+ ObjCObjectTypeBits.NumProtocols = protocols.size();
+ assert(getNumProtocols() == protocols.size() &&
"bitfield overflow in protocol count");
- if (NumProtocols)
- memcpy(getProtocolStorage(), Protocols,
- NumProtocols * sizeof(ObjCProtocolDecl*));
+ if (!typeArgs.empty())
+ memcpy(getTypeArgStorage(), typeArgs.data(),
+ typeArgs.size() * sizeof(QualType));
+ if (!protocols.empty())
+ memcpy(getProtocolStorage(), protocols.data(),
+ protocols.size() * sizeof(ObjCProtocolDecl*));
+
+ for (auto typeArg : typeArgs) {
+ if (typeArg->isDependentType())
+ setDependent();
+ else if (typeArg->isInstantiationDependentType())
+ setInstantiationDependent();
+
+ if (typeArg->containsUnexpandedParameterPack())
+ setContainsUnexpandedParameterPack();
+ }
+}
+
+bool ObjCObjectType::isSpecialized() const {
+ // If we have type arguments written here, the type is specialized.
+ if (ObjCObjectTypeBits.NumTypeArgs > 0)
+ return true;
+
+ // Otherwise, check whether the base type is specialized.
+ if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) {
+ // Terminate when we reach an interface type.
+ if (isa<ObjCInterfaceType>(objcObject))
+ return false;
+
+ return objcObject->isSpecialized();
+ }
+
+ // Not specialized.
+ return false;
+}
+
+ArrayRef<QualType> ObjCObjectType::getTypeArgs() const {
+ // We have type arguments written on this type.
+ if (isSpecializedAsWritten())
+ return getTypeArgsAsWritten();
+
+ // 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 { };
+
+ return objcObject->getTypeArgs();
+ }
+
+ // No type arguments.
+ 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 {
+
+template<typename F>
+QualType simpleTransform(ASTContext &ctx, QualType type, F &&f);
+
+/// Visitor used by simpleTransform() to perform the transformation.
+template<typename F>
+struct SimpleTransformVisitor
+ : public TypeVisitor<SimpleTransformVisitor<F>, QualType> {
+ ASTContext &Ctx;
+ F &&TheFunc;
+
+ QualType recurse(QualType type) {
+ return simpleTransform(Ctx, type, std::move(TheFunc));
+ }
+
+public:
+ SimpleTransformVisitor(ASTContext &ctx, F &&f) : Ctx(ctx), TheFunc(std::move(f)) { }
+
+ // None of the clients of this transformation can occur where
+ // there are dependent types, so skip dependent types.
+#define TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) \
+ QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); }
+#include "clang/AST/TypeNodes.def"
+
+#define TRIVIAL_TYPE_CLASS(Class) \
+ QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); }
+
+ TRIVIAL_TYPE_CLASS(Builtin)
+
+ QualType VisitComplexType(const ComplexType *T) {
+ QualType elementType = recurse(T->getElementType());
+ if (elementType.isNull())
+ return QualType();
+
+ if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getComplexType(elementType);
+ }
+
+ QualType VisitPointerType(const PointerType *T) {
+ QualType pointeeType = recurse(T->getPointeeType());
+ if (pointeeType.isNull())
+ return QualType();
+
+ if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getPointerType(pointeeType);
+ }
+
+ QualType VisitBlockPointerType(const BlockPointerType *T) {
+ QualType pointeeType = recurse(T->getPointeeType());
+ if (pointeeType.isNull())
+ return QualType();
+
+ if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getBlockPointerType(pointeeType);
+ }
+
+ QualType VisitLValueReferenceType(const LValueReferenceType *T) {
+ QualType pointeeType = recurse(T->getPointeeTypeAsWritten());
+ if (pointeeType.isNull())
+ return QualType();
+
+ if (pointeeType.getAsOpaquePtr()
+ == T->getPointeeTypeAsWritten().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getLValueReferenceType(pointeeType, T->isSpelledAsLValue());
+ }
+
+ QualType VisitRValueReferenceType(const RValueReferenceType *T) {
+ QualType pointeeType = recurse(T->getPointeeTypeAsWritten());
+ if (pointeeType.isNull())
+ return QualType();
+
+ if (pointeeType.getAsOpaquePtr()
+ == T->getPointeeTypeAsWritten().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getRValueReferenceType(pointeeType);
+ }
+
+ QualType VisitMemberPointerType(const MemberPointerType *T) {
+ QualType pointeeType = recurse(T->getPointeeType());
+ if (pointeeType.isNull())
+ return QualType();
+
+ if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getMemberPointerType(pointeeType, T->getClass());
+ }
+
+ QualType VisitConstantArrayType(const ConstantArrayType *T) {
+ QualType elementType = recurse(T->getElementType());
+ if (elementType.isNull())
+ return QualType();
+
+ if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getConstantArrayType(elementType, T->getSize(),
+ T->getSizeModifier(),
+ T->getIndexTypeCVRQualifiers());
+ }
+
+ QualType VisitVariableArrayType(const VariableArrayType *T) {
+ QualType elementType = recurse(T->getElementType());
+ if (elementType.isNull())
+ return QualType();
+
+ if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getVariableArrayType(elementType, T->getSizeExpr(),
+ T->getSizeModifier(),
+ T->getIndexTypeCVRQualifiers(),
+ T->getBracketsRange());
+ }
+
+ QualType VisitIncompleteArrayType(const IncompleteArrayType *T) {
+ QualType elementType = recurse(T->getElementType());
+ if (elementType.isNull())
+ return QualType();
+
+ if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getIncompleteArrayType(elementType, T->getSizeModifier(),
+ T->getIndexTypeCVRQualifiers());
+ }
+
+ QualType VisitVectorType(const VectorType *T) {
+ QualType elementType = recurse(T->getElementType());
+ if (elementType.isNull())
+ return QualType();
+
+ if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getVectorType(elementType, T->getNumElements(),
+ T->getVectorKind());
+ }
+
+ QualType VisitExtVectorType(const ExtVectorType *T) {
+ QualType elementType = recurse(T->getElementType());
+ if (elementType.isNull())
+ return QualType();
+
+ if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getExtVectorType(elementType, T->getNumElements());
+ }
+
+ QualType VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
+ QualType returnType = recurse(T->getReturnType());
+ if (returnType.isNull())
+ return QualType();
+
+ if (returnType.getAsOpaquePtr() == T->getReturnType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getFunctionNoProtoType(returnType, T->getExtInfo());
+ }
+
+ QualType VisitFunctionProtoType(const FunctionProtoType *T) {
+ QualType returnType = recurse(T->getReturnType());
+ if (returnType.isNull())
+ return QualType();
+
+ // Transform parameter types.
+ SmallVector<QualType, 4> paramTypes;
+ bool paramChanged = false;
+ for (auto paramType : T->getParamTypes()) {
+ QualType newParamType = recurse(paramType);
+ if (newParamType.isNull())
+ return QualType();
+
+ if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr())
+ paramChanged = true;
+
+ paramTypes.push_back(newParamType);
+ }
+
+ // Transform extended info.
+ FunctionProtoType::ExtProtoInfo info = T->getExtProtoInfo();
+ bool exceptionChanged = false;
+ if (info.ExceptionSpec.Type == EST_Dynamic) {
+ SmallVector<QualType, 4> exceptionTypes;
+ for (auto exceptionType : info.ExceptionSpec.Exceptions) {
+ QualType newExceptionType = recurse(exceptionType);
+ if (newExceptionType.isNull())
+ return QualType();
+
+ if (newExceptionType.getAsOpaquePtr()
+ != exceptionType.getAsOpaquePtr())
+ exceptionChanged = true;
+
+ exceptionTypes.push_back(newExceptionType);
+ }
+
+ if (exceptionChanged) {
+ unsigned size = sizeof(QualType) * exceptionTypes.size();
+ void *mem = Ctx.Allocate(size, llvm::alignOf<QualType>());
+ memcpy(mem, exceptionTypes.data(), size);
+ info.ExceptionSpec.Exceptions
+ = llvm::makeArrayRef((QualType *)mem, exceptionTypes.size());
+ }
+ }
+
+ if (returnType.getAsOpaquePtr() == T->getReturnType().getAsOpaquePtr() &&
+ !paramChanged && !exceptionChanged)
+ return QualType(T, 0);
+
+ return Ctx.getFunctionType(returnType, paramTypes, info);
+ }
+
+ QualType VisitParenType(const ParenType *T) {
+ QualType innerType = recurse(T->getInnerType());
+ if (innerType.isNull())
+ return QualType();
+
+ if (innerType.getAsOpaquePtr() == T->getInnerType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getParenType(innerType);
+ }
+
+ TRIVIAL_TYPE_CLASS(Typedef)
+
+ QualType VisitAdjustedType(const AdjustedType *T) {
+ QualType originalType = recurse(T->getOriginalType());
+ if (originalType.isNull())
+ return QualType();
+
+ QualType adjustedType = recurse(T->getAdjustedType());
+ if (adjustedType.isNull())
+ return QualType();
+
+ if (originalType.getAsOpaquePtr()
+ == T->getOriginalType().getAsOpaquePtr() &&
+ adjustedType.getAsOpaquePtr() == T->getAdjustedType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getAdjustedType(originalType, adjustedType);
+ }
+
+ QualType VisitDecayedType(const DecayedType *T) {
+ QualType originalType = recurse(T->getOriginalType());
+ if (originalType.isNull())
+ return QualType();
+
+ if (originalType.getAsOpaquePtr()
+ == T->getOriginalType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getDecayedType(originalType);
+ }
+
+ TRIVIAL_TYPE_CLASS(TypeOfExpr)
+ TRIVIAL_TYPE_CLASS(TypeOf)
+ TRIVIAL_TYPE_CLASS(Decltype)
+ TRIVIAL_TYPE_CLASS(UnaryTransform)
+ TRIVIAL_TYPE_CLASS(Record)
+ TRIVIAL_TYPE_CLASS(Enum)
+
+ // FIXME: Non-trivial to implement, but important for C++
+ TRIVIAL_TYPE_CLASS(Elaborated)
+
+ QualType VisitAttributedType(const AttributedType *T) {
+ QualType modifiedType = recurse(T->getModifiedType());
+ if (modifiedType.isNull())
+ return QualType();
+
+ QualType equivalentType = recurse(T->getEquivalentType());
+ if (equivalentType.isNull())
+ return QualType();
+
+ if (modifiedType.getAsOpaquePtr()
+ == T->getModifiedType().getAsOpaquePtr() &&
+ equivalentType.getAsOpaquePtr()
+ == T->getEquivalentType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getAttributedType(T->getAttrKind(), modifiedType,
+ equivalentType);
+ }
+
+ QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
+ QualType replacementType = recurse(T->getReplacementType());
+ if (replacementType.isNull())
+ return QualType();
+
+ if (replacementType.getAsOpaquePtr()
+ == T->getReplacementType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getSubstTemplateTypeParmType(T->getReplacedParameter(),
+ replacementType);
+ }
+
+ // FIXME: Non-trivial to implement, but important for C++
+ TRIVIAL_TYPE_CLASS(TemplateSpecialization)
+
+ QualType VisitAutoType(const AutoType *T) {
+ if (!T->isDeduced())
+ return QualType(T, 0);
+
+ QualType deducedType = recurse(T->getDeducedType());
+ if (deducedType.isNull())
+ return QualType();
+
+ if (deducedType.getAsOpaquePtr()
+ == T->getDeducedType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getAutoType(deducedType, T->isDecltypeAuto(),
+ T->isDependentType());
+ }
+
+ // FIXME: Non-trivial to implement, but important for C++
+ TRIVIAL_TYPE_CLASS(PackExpansion)
+
+ QualType VisitObjCObjectType(const ObjCObjectType *T) {
+ QualType baseType = recurse(T->getBaseType());
+ if (baseType.isNull())
+ return QualType();
+
+ // Transform type arguments.
+ bool typeArgChanged = false;
+ SmallVector<QualType, 4> typeArgs;
+ for (auto typeArg : T->getTypeArgsAsWritten()) {
+ QualType newTypeArg = recurse(typeArg);
+ if (newTypeArg.isNull())
+ return QualType();
+
+ if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr())
+ typeArgChanged = true;
+
+ typeArgs.push_back(newTypeArg);
+ }
+
+ if (baseType.getAsOpaquePtr() == T->getBaseType().getAsOpaquePtr() &&
+ !typeArgChanged)
+ return QualType(T, 0);
+
+ return Ctx.getObjCObjectType(baseType, typeArgs,
+ llvm::makeArrayRef(T->qual_begin(),
+ T->getNumProtocols()),
+ T->isKindOfTypeAsWritten());
+ }
+
+ TRIVIAL_TYPE_CLASS(ObjCInterface)
+
+ QualType VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
+ QualType pointeeType = recurse(T->getPointeeType());
+ if (pointeeType.isNull())
+ return QualType();
+
+ if (pointeeType.getAsOpaquePtr()
+ == T->getPointeeType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getObjCObjectPointerType(pointeeType);
+ }
+
+ QualType VisitAtomicType(const AtomicType *T) {
+ QualType valueType = recurse(T->getValueType());
+ if (valueType.isNull())
+ return QualType();
+
+ if (valueType.getAsOpaquePtr()
+ == T->getValueType().getAsOpaquePtr())
+ return QualType(T, 0);
+
+ return Ctx.getAtomicType(valueType);
+ }
+
+#undef TRIVIAL_TYPE_CLASS
+};
+
+/// Perform a simple type transformation that does not change the
+/// semantics of the type.
+template<typename F>
+QualType simpleTransform(ASTContext &ctx, QualType type, F &&f) {
+ // Transform the type. If it changed, return the transformed result.
+ QualType transformed = f(type);
+ if (transformed.getAsOpaquePtr() != type.getAsOpaquePtr())
+ return transformed;
+
+ // Split out the qualifiers from the type.
+ SplitQualType splitType = type.split();
+
+ // Visit the type itself.
+ SimpleTransformVisitor<F> visitor(ctx, std::move(f));
+ QualType result = visitor.Visit(splitType.Ty);
+ if (result.isNull())
+ return result;
+
+ // Reconstruct the transformed type by applying the local qualifiers
+ // from the split type.
+ return ctx.getQualifiedType(result, splitType.Quals);
+}
+
+} // end anonymous namespace
+
+/// Substitute the given type arguments for Objective-C type
+/// parameters within the given type, recursively.
+QualType QualType::substObjCTypeArgs(
+ ASTContext &ctx,
+ ArrayRef<QualType> typeArgs,
+ ObjCSubstitutionContext context) const {
+ return simpleTransform(ctx, *this,
+ [&](QualType type) -> QualType {
+ SplitQualType splitType = type.split();
+
+ // Replace an Objective-C type parameter reference with the corresponding
+ // type argument.
+ if (const auto *typedefTy = dyn_cast<TypedefType>(splitType.Ty)) {
+ if (auto *typeParam = dyn_cast<ObjCTypeParamDecl>(typedefTy->getDecl())) {
+ // If we have type arguments, use them.
+ if (!typeArgs.empty()) {
+ // FIXME: Introduce SubstObjCTypeParamType ?
+ QualType argType = typeArgs[typeParam->getIndex()];
+ return ctx.getQualifiedType(argType, splitType.Quals);
+ }
+
+ switch (context) {
+ case ObjCSubstitutionContext::Ordinary:
+ case ObjCSubstitutionContext::Parameter:
+ case ObjCSubstitutionContext::Superclass:
+ // Substitute the bound.
+ return ctx.getQualifiedType(typeParam->getUnderlyingType(),
+ splitType.Quals);
+
+ case ObjCSubstitutionContext::Result:
+ 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);
+
+ // 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);
+ }
+ }
+ }
+ }
+
+ // If we have a function type, update the context appropriately.
+ if (const auto *funcType = dyn_cast<FunctionType>(splitType.Ty)) {
+ // Substitute result type.
+ QualType returnType = funcType->getReturnType().substObjCTypeArgs(
+ ctx,
+ typeArgs,
+ ObjCSubstitutionContext::Result);
+ if (returnType.isNull())
+ return QualType();
+
+ // Handle non-prototyped functions, which only substitute into the result
+ // type.
+ if (isa<FunctionNoProtoType>(funcType)) {
+ // If the return type was unchanged, do nothing.
+ if (returnType.getAsOpaquePtr()
+ == funcType->getReturnType().getAsOpaquePtr())
+ return type;
+
+ // Otherwise, build a new type.
+ return ctx.getFunctionNoProtoType(returnType, funcType->getExtInfo());
+ }
+
+ const auto *funcProtoType = cast<FunctionProtoType>(funcType);
+
+ // Transform parameter types.
+ SmallVector<QualType, 4> paramTypes;
+ bool paramChanged = false;
+ for (auto paramType : funcProtoType->getParamTypes()) {
+ QualType newParamType = paramType.substObjCTypeArgs(
+ ctx,
+ typeArgs,
+ ObjCSubstitutionContext::Parameter);
+ if (newParamType.isNull())
+ return QualType();
+
+ if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr())
+ paramChanged = true;
+
+ paramTypes.push_back(newParamType);
+ }
+
+ // Transform extended info.
+ FunctionProtoType::ExtProtoInfo info = funcProtoType->getExtProtoInfo();
+ bool exceptionChanged = false;
+ if (info.ExceptionSpec.Type == EST_Dynamic) {
+ SmallVector<QualType, 4> exceptionTypes;
+ for (auto exceptionType : info.ExceptionSpec.Exceptions) {
+ QualType newExceptionType = exceptionType.substObjCTypeArgs(
+ ctx,
+ typeArgs,
+ ObjCSubstitutionContext::Ordinary);
+ if (newExceptionType.isNull())
+ return QualType();
+
+ if (newExceptionType.getAsOpaquePtr()
+ != exceptionType.getAsOpaquePtr())
+ exceptionChanged = true;
+
+ exceptionTypes.push_back(newExceptionType);
+ }
+
+ if (exceptionChanged) {
+ unsigned size = sizeof(QualType) * exceptionTypes.size();
+ void *mem = ctx.Allocate(size, llvm::alignOf<QualType>());
+ memcpy(mem, exceptionTypes.data(), size);
+ info.ExceptionSpec.Exceptions
+ = llvm::makeArrayRef((QualType *)mem, exceptionTypes.size());
+ }
+ }
+
+ if (returnType.getAsOpaquePtr()
+ == funcProtoType->getReturnType().getAsOpaquePtr() &&
+ !paramChanged && !exceptionChanged)
+ return type;
+
+ return ctx.getFunctionType(returnType, paramTypes, info);
+ }
+
+ // Substitute into the type arguments of a specialized Objective-C object
+ // type.
+ if (const auto *objcObjectType = dyn_cast<ObjCObjectType>(splitType.Ty)) {
+ if (objcObjectType->isSpecializedAsWritten()) {
+ SmallVector<QualType, 4> newTypeArgs;
+ bool anyChanged = false;
+ for (auto typeArg : objcObjectType->getTypeArgsAsWritten()) {
+ QualType newTypeArg = typeArg.substObjCTypeArgs(
+ ctx, typeArgs,
+ ObjCSubstitutionContext::Ordinary);
+ if (newTypeArg.isNull())
+ return QualType();
+
+ if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) {
+ // If we're substituting based on an unspecialized context type,
+ // produce an unspecialized type.
+ ArrayRef<ObjCProtocolDecl *> protocols(
+ objcObjectType->qual_begin(),
+ objcObjectType->getNumProtocols());
+ if (typeArgs.empty() &&
+ context != ObjCSubstitutionContext::Superclass) {
+ return ctx.getObjCObjectType(
+ objcObjectType->getBaseType(), { },
+ protocols,
+ objcObjectType->isKindOfTypeAsWritten());
+ }
+
+ anyChanged = true;
+ }
+
+ newTypeArgs.push_back(newTypeArg);
+ }
+
+ if (anyChanged) {
+ ArrayRef<ObjCProtocolDecl *> protocols(
+ objcObjectType->qual_begin(),
+ objcObjectType->getNumProtocols());
+ return ctx.getObjCObjectType(objcObjectType->getBaseType(),
+ newTypeArgs, protocols,
+ objcObjectType->isKindOfTypeAsWritten());
+ }
+ }
+
+ return type;
+ }
+
+ return type;
+ });
+}
+
+QualType QualType::substObjCMemberType(QualType objectType,
+ const DeclContext *dc,
+ ObjCSubstitutionContext context) const {
+ if (auto subs = objectType->getObjCSubstitutions(dc))
+ return substObjCTypeArgs(dc->getParentASTContext(), *subs, context);
+
+ 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.
+ if (auto method = dyn_cast<ObjCMethodDecl>(dc))
+ dc = method->getDeclContext();
+
+ // Find the class or category in which the type we're substituting
+ // was declared.
+ const ObjCInterfaceDecl *dcClassDecl = dyn_cast<ObjCInterfaceDecl>(dc);
+ const ObjCCategoryDecl *dcCategoryDecl = nullptr;
+ ObjCTypeParamList *dcTypeParams = nullptr;
+ if (dcClassDecl) {
+ // If the class does not have any type parameters, there's no
+ // substitution to do.
+ dcTypeParams = dcClassDecl->getTypeParamList();
+ if (!dcTypeParams)
+ return None;
+ } else {
+ // If we are in neither a class mor a category, there's no
+ // substitution to perform.
+ dcCategoryDecl = dyn_cast<ObjCCategoryDecl>(dc);
+ if (!dcCategoryDecl)
+ return None;
+
+ // If the category does not have any type parameters, there's no
+ // substitution to do.
+ dcTypeParams = dcCategoryDecl->getTypeParamList();
+ if (!dcTypeParams)
+ return None;
+
+ dcClassDecl = dcCategoryDecl->getClassInterface();
+ if (!dcClassDecl)
+ return None;
+ }
+ assert(dcTypeParams && "No substitutions to perform");
+ assert(dcClassDecl && "No class context");
+
+ // Find the underlying object type.
+ const ObjCObjectType *objectType;
+ if (const auto *objectPointerType = getAs<ObjCObjectPointerType>()) {
+ objectType = objectPointerType->getObjectType();
+ } else if (getAs<BlockPointerType>()) {
+ ASTContext &ctx = dc->getParentASTContext();
+ objectType = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, { })
+ ->castAs<ObjCObjectType>();;
+ } else {
+ objectType = getAs<ObjCObjectType>();
+ }
+
+ /// Extract the class from the receiver object type.
+ ObjCInterfaceDecl *curClassDecl = objectType ? objectType->getInterface()
+ : nullptr;
+ if (!curClassDecl) {
+ // If we don't have a context type (e.g., this is "id" or some
+ // variant thereof), substitute the bounds.
+ return llvm::ArrayRef<QualType>();
+ }
+
+ // Follow the superclass chain until we've mapped the receiver type
+ // to the same class as the context.
+ while (curClassDecl != dcClassDecl) {
+ // Map to the superclass type.
+ QualType superType = objectType->getSuperClassType();
+ if (superType.isNull()) {
+ objectType = nullptr;
+ break;
+ }
+
+ objectType = superType->castAs<ObjCObjectType>();
+ curClassDecl = objectType->getInterface();
+ }
+
+ // If we don't have a receiver type, or the receiver type does not
+ // have type arguments, substitute in the defaults.
+ if (!objectType || objectType->isUnspecialized()) {
+ return llvm::ArrayRef<QualType>();
+ }
+
+ // The receiver type has the type arguments we want.
+ return objectType->getTypeArgs();
+}
+
+bool Type::acceptsObjCTypeParams() const {
+ if (auto *IfaceT = getAsObjCInterfaceType()) {
+ if (auto *ID = IfaceT->getInterface()) {
+ if (ID->getTypeParamList())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ObjCObjectType::computeSuperClassTypeSlow() const {
+ // Retrieve the class declaration for this type. If there isn't one
+ // (e.g., this is some variant of "id" or "Class"), then there is no
+ // superclass type.
+ ObjCInterfaceDecl *classDecl = getInterface();
+ if (!classDecl) {
+ CachedSuperClassType.setInt(true);
+ return;
+ }
+
+ // Extract the superclass type.
+ const ObjCObjectType *superClassObjTy = classDecl->getSuperClassType();
+ if (!superClassObjTy) {
+ CachedSuperClassType.setInt(true);
+ return;
+ }
+
+ ObjCInterfaceDecl *superClassDecl = superClassObjTy->getInterface();
+ if (!superClassDecl) {
+ CachedSuperClassType.setInt(true);
+ return;
+ }
+
+ // If the superclass doesn't have type parameters, then there is no
+ // substitution to perform.
+ QualType superClassType(superClassObjTy, 0);
+ ObjCTypeParamList *superClassTypeParams = superClassDecl->getTypeParamList();
+ if (!superClassTypeParams) {
+ CachedSuperClassType.setPointerAndInt(
+ superClassType->castAs<ObjCObjectType>(), true);
+ return;
+ }
+
+ // If the superclass reference is unspecialized, return it.
+ if (superClassObjTy->isUnspecialized()) {
+ CachedSuperClassType.setPointerAndInt(superClassObjTy, true);
+ return;
+ }
+
+ // If the subclass is not parameterized, there aren't any type
+ // parameters in the superclass reference to substitute.
+ ObjCTypeParamList *typeParams = classDecl->getTypeParamList();
+ if (!typeParams) {
+ CachedSuperClassType.setPointerAndInt(
+ superClassType->castAs<ObjCObjectType>(), true);
+ return;
+ }
+
+ // If the subclass type isn't specialized, return the unspecialized
+ // superclass.
+ if (isUnspecialized()) {
+ QualType unspecializedSuper
+ = classDecl->getASTContext().getObjCInterfaceType(
+ superClassObjTy->getInterface());
+ CachedSuperClassType.setPointerAndInt(
+ unspecializedSuper->castAs<ObjCObjectType>(),
+ true);
+ return;
+ }
+
+ // Substitute the provided type arguments into the superclass type.
+ ArrayRef<QualType> typeArgs = getTypeArgs();
+ assert(typeArgs.size() == typeParams->size());
+ CachedSuperClassType.setPointerAndInt(
+ superClassType.substObjCTypeArgs(classDecl->getASTContext(), typeArgs,
+ ObjCSubstitutionContext::Superclass)
+ ->castAs<ObjCObjectType>(),
+ true);
+}
+
+const ObjCInterfaceType *ObjCObjectPointerType::getInterfaceType() const {
+ if (auto interfaceDecl = getObjectType()->getInterface()) {
+ return interfaceDecl->getASTContext().getObjCInterfaceType(interfaceDecl)
+ ->castAs<ObjCInterfaceType>();
+ }
+
+ return nullptr;
+}
+
+QualType ObjCObjectPointerType::getSuperClassType() const {
+ QualType superObjectType = getObjectType()->getSuperClassType();
+ if (superObjectType.isNull())
+ return superObjectType;
+
+ ASTContext &ctx = getInterfaceDecl()->getASTContext();
+ return ctx.getObjCObjectPointerType(superObjectType);
}
const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const {
@@ -514,6 +1472,13 @@ const ObjCObjectPointerType *Type::getAsObjCQualifiedClassType() const {
return nullptr;
}
+const ObjCObjectType *Type::getAsObjCInterfaceType() const {
+ if (const ObjCObjectType *OT = getAs<ObjCObjectType>()) {
+ if (OT->getInterface())
+ return OT;
+ }
+ return nullptr;
+}
const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) {
if (OPT->getInterfaceType())
@@ -1927,7 +2892,9 @@ bool AttributedType::isCallingConv() const {
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:
@@ -2076,15 +3043,23 @@ QualifierCollector::apply(const ASTContext &Context, const Type *T) const {
void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID,
QualType BaseType,
- ObjCProtocolDecl * const *Protocols,
- unsigned NumProtocols) {
+ ArrayRef<QualType> typeArgs,
+ ArrayRef<ObjCProtocolDecl *> protocols,
+ bool isKindOf) {
ID.AddPointer(BaseType.getAsOpaquePtr());
- for (unsigned i = 0; i != NumProtocols; i++)
- ID.AddPointer(Protocols[i]);
+ ID.AddInteger(typeArgs.size());
+ for (auto typeArg : typeArgs)
+ ID.AddPointer(typeArg.getAsOpaquePtr());
+ ID.AddInteger(protocols.size());
+ for (auto proto : protocols)
+ ID.AddPointer(proto);
+ ID.AddBoolean(isKindOf);
}
void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getBaseType(), qual_begin(), getNumProtocols());
+ Profile(ID, getBaseType(), getTypeArgsAsWritten(),
+ llvm::makeArrayRef(qual_begin(), getNumProtocols()),
+ isKindOfTypeAsWritten());
}
namespace {
@@ -2495,6 +3470,39 @@ Optional<NullabilityKind> AttributedType::stripOuterNullability(QualType &T) {
return None;
}
+bool Type::isBlockCompatibleObjCPointerType(ASTContext &ctx) const {
+ const ObjCObjectPointerType *objcPtr = getAs<ObjCObjectPointerType>();
+ if (!objcPtr)
+ return false;
+
+ if (objcPtr->isObjCIdType()) {
+ // id is always okay.
+ return true;
+ }
+
+ // Blocks are NSObjects.
+ if (ObjCInterfaceDecl *iface = objcPtr->getInterfaceDecl()) {
+ if (iface->getIdentifier() != ctx.getNSObjectName())
+ return false;
+
+ // Continue to check qualifiers, below.
+ } else if (objcPtr->isObjCQualifiedIdType()) {
+ // Continue to check qualifiers, below.
+ } else {
+ return false;
+ }
+
+ // Check protocol qualifiers.
+ for (ObjCProtocolDecl *proto : objcPtr->quals()) {
+ // Blocks conform to NSObject and NSCopying.
+ if (proto->getIdentifier() != ctx.getNSObjectName() &&
+ proto->getIdentifier() != ctx.getNSCopyingName())
+ return false;
+ }
+
+ return true;
+}
+
Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const {
if (isObjCARCImplicitlyUnretainedType())
return Qualifiers::OCL_ExplicitNone;
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index c069eb061739..85bda6a06d97 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -19,6 +19,8 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+static const unsigned TypeLocMaxDataAlign = llvm::alignOf<void *>();
+
//===----------------------------------------------------------------------===//
// TypeLoc Implementation
//===----------------------------------------------------------------------===//
@@ -125,6 +127,46 @@ void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL,
}
}
+namespace {
+ class TypeLocCopier : public TypeLocVisitor<TypeLocCopier> {
+ TypeLoc Source;
+ public:
+ TypeLocCopier(TypeLoc source) : Source(source) { }
+
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ void Visit##CLASS##TypeLoc(CLASS##TypeLoc dest) { \
+ dest.copyLocal(Source.castAs<CLASS##TypeLoc>()); \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ };
+}
+
+
+void TypeLoc::copy(TypeLoc other) {
+ assert(getFullDataSize() == other.getFullDataSize());
+
+ // If both data pointers are aligned to the maximum alignment, we
+ // can memcpy because getFullDataSize() accurately reflects the
+ // layout of the data.
+ if (reinterpret_cast<uintptr_t>(Data)
+ == llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(Data),
+ TypeLocMaxDataAlign) &&
+ reinterpret_cast<uintptr_t>(other.Data)
+ == llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(other.Data),
+ TypeLocMaxDataAlign)) {
+ memcpy(Data, other.Data, getFullDataSize());
+ return;
+ }
+
+ // Copy each of the pieces.
+ TypeLoc TL(getType(), Data);
+ do {
+ TypeLocCopier(other).Visit(TL);
+ other = other.getNextTypeLoc();
+ } while ((TL = TL.getNextTypeLoc()));
+}
+
SourceLocation TypeLoc::getBeginLoc() const {
TypeLoc Cur = *this;
TypeLoc LeftMost = Cur;
@@ -312,6 +354,33 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
return TL;
}
+SourceLocation TypeLoc::findNullabilityLoc() const {
+ if (auto attributedLoc = getAs<AttributedTypeLoc>()) {
+ if (attributedLoc.getAttrKind() == AttributedType::attr_nullable ||
+ attributedLoc.getAttrKind() == AttributedType::attr_nonnull ||
+ attributedLoc.getAttrKind() == AttributedType::attr_null_unspecified)
+ return attributedLoc.getAttrNameLoc();
+ }
+
+ return SourceLocation();
+}
+
+void ObjCObjectTypeLoc::initializeLocal(ASTContext &Context,
+ SourceLocation Loc) {
+ setHasBaseTypeAsWritten(true);
+ setTypeArgsLAngleLoc(Loc);
+ setTypeArgsRAngleLoc(Loc);
+ for (unsigned i = 0, e = getNumTypeArgs(); i != e; ++i) {
+ setTypeArgTInfo(i,
+ Context.getTrivialTypeSourceInfo(
+ getTypePtr()->getTypeArgsAsWritten()[i], Loc));
+ }
+ setProtocolLAngleLoc(Loc);
+ setProtocolRAngleLoc(Loc);
+ for (unsigned i = 0, e = getNumProtocols(); i != e; ++i)
+ setProtocolLoc(i, Loc);
+}
+
void TypeOfTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo>
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 9938170c321a..0bb50c6ba815 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -1129,6 +1129,9 @@ void TypePrinter::printAttributedBefore(const AttributedType *T,
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(const AttributedType *T,
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,59 +1316,61 @@ void TypePrinter::printObjCInterfaceAfter(const ObjCInterfaceType *T,
void TypePrinter::printObjCObjectBefore(const ObjCObjectType *T,
raw_ostream &OS) {
- if (T->qual_empty())
+ if (T->qual_empty() && T->isUnspecializedAsWritten() &&
+ !T->isKindOfTypeAsWritten())
return printBefore(T->getBaseType(), OS);
+ if (T->isKindOfTypeAsWritten())
+ OS << "__kindof ";
+
print(T->getBaseType(), OS, StringRef());
- OS << '<';
- bool isFirst = true;
- for (const auto *I : T->quals()) {
- if (isFirst)
- isFirst = false;
- else
- OS << ',';
- OS << I->getName();
+
+ if (T->isSpecializedAsWritten()) {
+ bool isFirst = true;
+ OS << '<';
+ for (auto typeArg : T->getTypeArgsAsWritten()) {
+ if (isFirst)
+ isFirst = false;
+ else
+ OS << ",";
+
+ print(typeArg, OS, StringRef());
+ }
+ OS << '>';
}
- OS << '>';
+
+ if (!T->qual_empty()) {
+ bool isFirst = true;
+ OS << '<';
+ for (const auto *I : T->quals()) {
+ if (isFirst)
+ isFirst = false;
+ else
+ OS << ',';
+ OS << I->getName();
+ }
+ OS << '>';
+ }
+
spaceBeforePlaceHolder(OS);
}
void TypePrinter::printObjCObjectAfter(const ObjCObjectType *T,
raw_ostream &OS) {
- if (T->qual_empty())
+ if (T->qual_empty() && T->isUnspecializedAsWritten() &&
+ !T->isKindOfTypeAsWritten())
return printAfter(T->getBaseType(), OS);
}
void TypePrinter::printObjCObjectPointerBefore(const ObjCObjectPointerType *T,
raw_ostream &OS) {
- T->getPointeeType().getLocalQualifiers().print(OS, Policy,
- /*appendSpaceIfNonEmpty=*/true);
-
- assert(!T->isObjCSelType());
+ printBefore(T->getPointeeType(), OS);
- if (T->isObjCIdType() || T->isObjCQualifiedIdType())
- OS << "id";
- else if (T->isObjCClassType() || T->isObjCQualifiedClassType())
- OS << "Class";
- else
- OS << T->getInterfaceDecl()->getName();
-
- if (!T->qual_empty()) {
- OS << '<';
- for (ObjCObjectPointerType::qual_iterator I = T->qual_begin(),
- E = T->qual_end();
- I != E; ++I) {
- OS << (*I)->getName();
- if (I+1 != E)
- OS << ',';
- }
- OS << '>';
- }
-
+ // If we need to print the pointer, print it now.
if (!T->isObjCIdType() && !T->isObjCQualifiedIdType() &&
!T->isObjCClassType() && !T->isObjCQualifiedClassType()) {
- OS << " *"; // Don't forget the implicit pointer.
- } else {
- spaceBeforePlaceHolder(OS);
+ if (HasEmptyPlaceHolder)
+ OS << ' ';
+ OS << '*';
}
}
void TypePrinter::printObjCObjectPointerAfter(const ObjCObjectPointerType *T,