diff options
Diffstat (limited to 'lib/AST')
-rw-r--r-- | lib/AST/ASTContext.cpp | 504 | ||||
-rw-r--r-- | lib/AST/ASTDiagnostic.cpp | 15 | ||||
-rw-r--r-- | lib/AST/ASTDumper.cpp | 38 | ||||
-rw-r--r-- | lib/AST/ASTImporter.cpp | 92 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 16 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 1 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 6 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 214 | ||||
-rw-r--r-- | lib/AST/DeclPrinter.cpp | 58 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 10 | ||||
-rw-r--r-- | lib/AST/ItaniumMangle.cpp | 13 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 1034 | ||||
-rw-r--r-- | lib/AST/TypeLoc.cpp | 69 | ||||
-rw-r--r-- | lib/AST/TypePrinter.cpp | 82 |
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, |