diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 92 | ||||
| -rw-r--r-- | clang/lib/AST/ASTDiagnostic.cpp | 10 | ||||
| -rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 27 | ||||
| -rw-r--r-- | clang/lib/AST/DeclObjC.cpp | 27 | ||||
| -rw-r--r-- | clang/lib/AST/Type.cpp | 99 | ||||
| -rw-r--r-- | clang/lib/AST/TypeLoc.cpp | 16 | ||||
| -rw-r--r-- | clang/lib/AST/TypePrinter.cpp | 71 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 50 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseObjc.cpp | 146 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseTentative.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/DeclSpec.cpp | 11 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 549 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 34 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExprObjC.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 230 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 14 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 11 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTWriterDecl.cpp | 3 |
19 files changed, 1127 insertions, 274 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 61b7c5db8e1..c7a66d74897 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3618,45 +3618,85 @@ 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)); +} + +QualType ASTContext::getObjCObjectType( + QualType baseType, + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols) const { + // If the base type is an interface and there aren't any protocols or + // type arguments to add, then the interface type will do just fine. + if (typeArgs.empty() && protocols.empty() && isa<ObjCInterfaceType>(baseType)) + 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); 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); + // 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); Types.push_back(T); ObjCObjectTypes.InsertNode(T, InsertPos); @@ -5921,7 +5961,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 +5978,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"); } diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index 000588face9..d6de4548466 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -125,12 +125,22 @@ 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())); + } } return QC.apply(Context, QT); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 88cca6d5924..ff80ba1ce7e 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1844,6 +1844,16 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { if (ToBaseType.isNull()) return QualType(); + SmallVector<QualType, 4> TypeArgs; + for (auto TypeArg : T->getTypeArgs()) { + 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 @@ -1853,9 +1863,8 @@ 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); } QualType @@ -3694,13 +3703,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 @@ -5367,7 +5374,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/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 79054c7862f..a93c8f61336 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -259,6 +259,33 @@ ObjCTypeParamList *ObjCInterfaceDecl::getTypeParamList() const { return nullptr; } +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. diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 541bd1ebdf8..48245f648bb 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -467,19 +467,56 @@ const RecordType *Type::getAsUnionType() const { } ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, - ObjCProtocolDecl * const *Protocols, - unsigned NumProtocols) + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols) : Type(ObjCObject, Canonical, false, false, false, false), BaseType(Base) { - ObjCObjectTypeBits.NumProtocols = NumProtocols; - assert(getNumProtocols() == NumProtocols && + 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*)); } +bool ObjCObjectType::isSpecialized() const { + // If we have type arguments written here, the type is specialized. + if (ObjCObjectTypeBits.NumTypeArgs > 0) + return true; + + if (!qual_empty()) { + // Otherwise, check whether the base type is specialized. + if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) + return objcObject->isSpecialized(); + } + + // Not specialized. + return false; +} + +ArrayRef<QualType> ObjCObjectType::getTypeArgs() const { + // We have type arguments written on this type. + if (isSpecializedAsWritten()) + return getTypeArgsAsWritten(); + + if (!qual_empty()) { + // Look at the base type, which might have type arguments. + if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) + return objcObject->getTypeArgs(); + } + + // No type arguments. + return { }; +} + + const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const { // There is no sugar for ObjCObjectType's, just return the canonical // type pointer if it is the right class. There is no typedef information to @@ -2076,15 +2113,20 @@ 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) { 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); } void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getBaseType(), qual_begin(), getNumProtocols()); + Profile(ID, getBaseType(), getTypeArgs(), + llvm::makeArrayRef(qual_begin(), getNumProtocols())); } namespace { @@ -2495,6 +2537,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/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index c069eb06173..0d497aad8e4 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -312,6 +312,22 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) { return TL; } +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/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 9938170c321..ab63babf3f5 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1310,59 +1310,56 @@ 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()) return printBefore(T->getBaseType(), OS); 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()) 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, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index d843e801b63..fdd10522ee5 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2886,11 +2886,26 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); // The typename - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); + // Objective-C supports type arguments and protocol references + // following an Objective-C object pointer type. Handle either + // one of them. + if (Tok.is(tok::less) && getLangOpts().ObjC1) { + ParseObjCTypeArgsOrProtocolQualifiers( + DS, /*warnOnIncompleteProtocols=*/false); + + // An Objective-C object pointer followed by type arguments + // can then be followed again by a set of protocol references, e.g., + // \c NSArray<NSView><NSTextDelegate> + if (Tok.is(tok::less)) { + if (DS.getProtocolQualifiers()) { + Diag(Tok, diag::err_objc_type_args_after_protocols) + << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd()); + SkipUntil(tok::greater, tok::greatergreater); + } else { + ParseObjCProtocolQualifiers(DS); + } + } + } continue; } @@ -2997,11 +3012,26 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); // The identifier - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); + // Objective-C supports type arguments and protocol references + // following an Objective-C object pointer type. Handle either + // one of them. + if (Tok.is(tok::less) && getLangOpts().ObjC1) { + ParseObjCTypeArgsOrProtocolQualifiers( + DS, /*warnOnIncompleteProtocols=*/false); + + // An Objective-C object pointer followed by type arguments + // can then be followed again by a set of protocol references, e.g., + // \c NSArray<NSView><NSTextDelegate> + if (Tok.is(tok::less)) { + if (DS.getProtocolQualifiers()) { + Diag(Tok, diag::err_objc_type_args_after_protocols) + << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd()); + SkipUntil(tok::greater, tok::greatergreater); + } else { + ParseObjCProtocolQualifiers(DS); + } + } + } // Need to support trailing type qualifiers (e.g. "id<p> const"). // If a type specifier follows, it will be diagnosed elsewhere. diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 3ef187af8d7..0e4574056b0 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -179,7 +179,7 @@ void Parser::CheckNestedObjCContexts(SourceLocation AtLoc) /// @end /// /// objc-superclass: -/// ':' identifier +/// ':' identifier objc-type-arguments[opt] /// /// objc-class-interface-attributes: /// __attribute__((visibility("default"))) @@ -293,6 +293,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, // Parse a class interface. IdentifierInfo *superClassId = nullptr; SourceLocation superClassLoc; + DeclSpec superClassDS(AttrFactory); if (Tok.is(tok::colon)) { // a super class is specified. ConsumeToken(); @@ -311,18 +312,12 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, } superClassId = Tok.getIdentifierInfo(); superClassLoc = ConsumeToken(); - } else if (typeParameterList) { - // An objc-type-parameter-list is ambiguous with an objc-protocol-refs - // in an @interface without a specified superclass, so such classes - // are ill-formed. We have determined that we have an - // objc-type-parameter-list but no superclass, so complain and record - // as if we inherited from NSObject. - SourceLocation insertLoc = PP.getLocForEndOfToken(PrevTokLocation); - Diag(insertLoc, diag::err_objc_parameterized_class_without_base) - << nameId - << FixItHint::CreateInsertion(insertLoc, " : NSObject"); - superClassId = PP.getIdentifierInfo("NSObject"); - superClassLoc = Tok.getLocation(); + + // Type arguments for the superclass or protocol conformances. + if (Tok.is(tok::less)) { + ParseObjCTypeArgsOrProtocolQualifiers(superClassDS, + /*warnOnIncompleteProtocols=*/true); + } } // Next, we need to check for any protocol references. @@ -338,6 +333,16 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, /*ForObjCContainer=*/true, &ProtocolIdents[0], ProtocolIdents.size(), ProtocolRefs); + } else if (auto protocols = superClassDS.getProtocolQualifiers()) { + // We already parsed the protocols named when we thought we had a + // type argument list (for a specialized superclass). Treat them + // as actual protocol references. + unsigned numProtocols = superClassDS.getNumProtocolQualifiers(); + ProtocolRefs.append(protocols, protocols + numProtocols); + ProtocolLocs.append(superClassDS.getProtocolLocs(), + superClassDS.getProtocolLocs() + numProtocols); + LAngleLoc = superClassDS.getProtocolLAngleLoc(); + EndProtoLoc = superClassDS.getLocEnd(); } else if (Tok.is(tok::less) && ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true, LAngleLoc, EndProtoLoc)) { @@ -348,8 +353,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc); Decl *ClsType = - Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, typeParameterList, - superClassId, superClassLoc, + Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc, + typeParameterList, superClassId, + superClassLoc, + superClassDS.getObjCTypeArgs(), + superClassDS.getObjCTypeArgsRange(), ProtocolRefs.data(), ProtocolRefs.size(), ProtocolLocs.data(), EndProtoLoc, attrs.getList()); @@ -1554,8 +1562,7 @@ bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) { SmallVector<Decl *, 8> ProtocolDecl; SmallVector<SourceLocation, 8> ProtocolLocs; bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, - false, - LAngleLoc, EndProtoLoc); + false, LAngleLoc, EndProtoLoc); DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), ProtocolLocs.data(), LAngleLoc); if (EndProtoLoc.isValid()) @@ -1563,6 +1570,111 @@ bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) { return Result; } +/// Parse Objective-C type arguments or protocol qualifiers. +/// +/// objc-type-arguments: +/// '<' type-name (',' type-name)* '>' +/// +void Parser::ParseObjCTypeArgsOrProtocolQualifiers( + DeclSpec &DS, + bool warnOnIncompleteProtocols) { + assert(Tok.is(tok::less) && "Not at the start of type args or protocols"); + SourceLocation lAngleLoc = ConsumeToken(); + + // Whether all of the elements we've parsed thus far are single + // identifiers, which might be types or might be protocols. + bool allSingleIdentifiers = true; + SmallVector<IdentifierInfo *, 4> identifiers; + SmallVector<SourceLocation, 4> identifierLocs; + + // Parse a list of comma-separated identifiers, bailing out if we + // see something different. + do { + // Parse a single identifier. + if (Tok.is(tok::identifier) && + (NextToken().is(tok::comma) || + NextToken().is(tok::greater) || + NextToken().is(tok::greatergreater))) { + identifiers.push_back(Tok.getIdentifierInfo()); + identifierLocs.push_back(ConsumeToken()); + continue; + } + + if (Tok.is(tok::code_completion)) { + // FIXME: Also include types here. + SmallVector<IdentifierLocPair, 4> identifierLocPairs; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + identifierLocPairs.push_back(IdentifierLocPair(identifiers[i], + identifierLocs[i])); + } + + Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs.data(), + identifierLocPairs.size()); + cutOffParsing(); + return; + } + + allSingleIdentifiers = false; + break; + } while (TryConsumeToken(tok::comma)); + + // If we parsed an identifier list, semantic analysis sorts out + // whether it refers to protocols or to type arguments. + if (allSingleIdentifiers) { + // Parse the closing '>'. + SourceLocation rAngleLoc; + (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true, + /*ObjCGenericList=*/true); + + // Let Sema figure out what we parsed. + Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(), + DS, + lAngleLoc, + identifiers, + identifierLocs, + rAngleLoc, + warnOnIncompleteProtocols); + return; + } + + // We syntactically matched a type argument, so commit to parsing + // type arguments. + SmallVector<ParsedType, 4> typeArgs; + + // Convert the identifiers into type arguments. + bool invalid = false; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + ParsedType typeArg + = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope()); + if (typeArg) { + typeArgs.push_back(typeArg); + } else { + invalid = true; + } + } + + // Continue parsing type-names. + do { + TypeResult typeArg = ParseTypeName(); + if (typeArg.isUsable()) { + typeArgs.push_back(typeArg.get()); + } else { + invalid = true; + } + } while (TryConsumeToken(tok::comma)); + + // Parse the closing '>'. + SourceLocation rAngleLoc; + (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true, + /*ObjCGenericList=*/true); + + if (invalid) + return; + + // Update the DeclSpec appropriately. + DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc); +} + void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc, BalancedDelimiterTracker &T, SmallVectorImpl<Decl *> &AllIvarDecls, diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 368cb934bba..3fdd902f07c 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1384,7 +1384,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case_typename: // In Objective-C, we might have a protocol-qualified type. if (getLangOpts().ObjC1 && NextToken().is(tok::less)) { - // Tentatively parse the + // Tentatively parse the protocol qualifiers. TentativeParsingAction PA(*this); ConsumeToken(); // The type token diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index d5c8871cac8..5c75536e94a 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -893,6 +893,7 @@ bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec, return false; } + bool DeclSpec::SetConceptSpec(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { if (Concept_specified) { @@ -905,6 +906,16 @@ bool DeclSpec::SetConceptSpec(SourceLocation Loc, const char *&PrevSpec, return false; } +void DeclSpec::setObjCTypeArgs(SourceLocation lAngleLoc, + ArrayRef<ParsedType> args, + SourceLocation rAngleLoc) { + ParsedType *argsCopy = new ParsedType[args.size()]; + memcpy(argsCopy, args.data(), args.size() * sizeof(ParsedType)); + ObjCTypeArgs = llvm::makeArrayRef(argsCopy, args.size()); + ObjCTypeArgsLAngleLoc = lAngleLoc; + ObjCTypeArgsRAngleLoc = rAngleLoc; +} + void DeclSpec::setProtocolQualifiers(Decl * const *Protos, unsigned NP, SourceLocation *ProtoLocs, diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 574a7c8857c..ac1e3923afa 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -464,6 +464,142 @@ static void diagnoseUseOfProtocols(Sema &TheSema, } } +void Sema:: +ActOnSuperClassOfClassInterface(Scope *S, + SourceLocation AtInterfaceLoc, + ObjCInterfaceDecl *IDecl, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperName, + SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange) { + // Check if a different kind of symbol declared in this scope. + NamedDecl *PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc, + LookupOrdinaryName); + + if (!PrevDecl) { + // Try to correct for a typo in the superclass name without correcting + // to the class we're defining. + if (TypoCorrection Corrected = CorrectTypo( + DeclarationNameInfo(SuperName, SuperLoc), + LookupOrdinaryName, TUScope, + NULL, llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl), + CTK_ErrorRecovery)) { + diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest) + << SuperName << ClassName); + PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>(); + } + } + + if (declaresSameEntity(PrevDecl, IDecl)) { + Diag(SuperLoc, diag::err_recursive_superclass) + << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); + IDecl->setEndOfDefinitionLoc(ClassLoc); + } else { + ObjCInterfaceDecl *SuperClassDecl = + dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); + QualType SuperClassType; + + // Diagnose classes that inherit from deprecated classes. + if (SuperClassDecl) { + (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); + SuperClassType = Context.getObjCInterfaceType(SuperClassDecl); + } + + if (PrevDecl && SuperClassDecl == 0) { + // The previous declaration was not a class decl. Check if we have a + // typedef. If we do, get the underlying class type. + if (const TypedefNameDecl *TDecl = + dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { + QualType T = TDecl->getUnderlyingType(); + if (T->isObjCObjectType()) { + if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { + SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); + SuperClassType = Context.getTypeDeclType(TDecl); + + // This handles the following case: + // @interface NewI @end + // typedef NewI DeprI __attribute__((deprecated("blah"))) + // @interface SI : DeprI /* warn here */ @end + (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), SuperLoc); + } + } + } + + // This handles the following case: + // + // typedef int SuperClass; + // @interface MyClass : SuperClass {} @end + // + if (!SuperClassDecl) { + Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + } + } + + if (!dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { + if (!SuperClassDecl) + Diag(SuperLoc, diag::err_undef_superclass) + << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); + else if (RequireCompleteType(SuperLoc, + SuperClassType, + diag::err_forward_superclass, + SuperClassDecl->getDeclName(), + ClassName, + SourceRange(AtInterfaceLoc, ClassLoc))) { + SuperClassDecl = 0; + SuperClassType = QualType(); + } + } + + if (SuperClassType.isNull()) { + assert(!SuperClassDecl && "Failed to set SuperClassType?"); + return; + } + + // Handle type arguments on the superclass. + TypeSourceInfo *SuperClassTInfo = nullptr; + if (!SuperTypeArgs.empty()) { + // Form declaration specifiers naming this superclass type with + // type arguments. + AttributeFactory attrFactory; + DeclSpec DS(attrFactory); + const char* prevSpec; // unused + unsigned diagID; // unused + TypeSourceInfo *parsedTSInfo + = Context.getTrivialTypeSourceInfo(SuperClassType, SuperLoc); + ParsedType parsedType = CreateParsedType(SuperClassType, parsedTSInfo); + + DS.SetTypeSpecType(DeclSpec::TST_typename, SuperLoc, prevSpec, diagID, + parsedType, Context.getPrintingPolicy()); + DS.SetRangeStart(SuperLoc); + DS.SetRangeEnd(SuperLoc); + DS.setObjCTypeArgs(SuperTypeArgsRange.getBegin(), + SuperTypeArgs, + SuperTypeArgsRange.getEnd()); + + // Form the declarator. + Declarator D(DS, Declarator::TypeNameContext); + + TypeResult fullSuperClassType = ActOnTypeName(S, D); + if (!fullSuperClassType.isUsable()) + return; + + SuperClassType = GetTypeFromParser(fullSuperClassType.get(), + &SuperClassTInfo); + } + + if (!SuperClassTInfo) { + SuperClassTInfo = Context.getTrivialTypeSourceInfo(SuperClassType, + SuperLoc); + } + + IDecl->setSuperClass(SuperClassTInfo); + IDecl->setEndOfDefinitionLoc(SuperClassTInfo->getTypeLoc().getLocEnd()); + } +} + DeclResult Sema::actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName, SourceLocation paramLoc, SourceLocation colonLoc, @@ -499,7 +635,7 @@ DeclResult Sema::actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName, // Form the new type source information. typeBoundInfo = builder.getTypeSourceInfo(Context, typeBound); } else { - // Not a + // Not a valid type bound. Diag(typeBoundInfo->getTypeLoc().getBeginLoc(), diag::err_objc_type_param_bound_nonobject) << typeBound << paramName; @@ -669,10 +805,12 @@ static bool checkTypeParamListConsistency(Sema &S, } Decl *Sema:: -ActOnStartClassInterface(SourceLocation AtInterfaceLoc, +ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, IdentifierInfo *SuperName, SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange, Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { @@ -767,84 +905,13 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IDecl->startDefinition(); if (SuperName) { - // Check if a different kind of symbol declared in this scope. - PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc, - LookupOrdinaryName); - - if (!PrevDecl) { - // Try to correct for a typo in the superclass name without correcting - // to the class we're defining. - if (TypoCorrection Corrected = - CorrectTypo(DeclarationNameInfo(SuperName, SuperLoc), - LookupOrdinaryName, TUScope, nullptr, - llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl), - CTK_ErrorRecovery)) { - diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest) - << SuperName << ClassName); - PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>(); - } - } - - if (declaresSameEntity(PrevDecl, IDecl)) { - Diag(SuperLoc, diag::err_recursive_superclass) - << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); - IDecl->setEndOfDefinitionLoc(ClassLoc); - } else { - ObjCInterfaceDecl *SuperClassDecl = - dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); - - // Diagnose availability in the context of the @interface. - ContextRAII SavedContext(*this, IDecl); - // Diagnose classes that inherit from deprecated classes. - if (SuperClassDecl) - (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); - - if (PrevDecl && !SuperClassDecl) { - // The previous declaration was not a class decl. Check if we have a - // typedef. If we do, get the underlying class type. - if (const TypedefNameDecl *TDecl = - dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { - QualType T = TDecl->getUnderlyingType(); - if (T->isObjCObjectType()) { - if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { - SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); - // This handles the following case: - // @interface NewI @end - // typedef NewI DeprI __attribute__((deprecated("blah"))) - // @interface SI : DeprI /* warn here */ @end - (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), SuperLoc); - } - } - } - - // This handles the following case: - // - // typedef int SuperClass; - // @interface MyClass : SuperClass {} @end - // - if (!SuperClassDecl) { - Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName; - Diag(PrevDecl->getLocation(), diag::note_previous_definition); - } - } + // Diagnose availability in the context of the @interface. + ContextRAII SavedContext(*this, IDecl); - if (!dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { - if (!SuperClassDecl) - Diag(SuperLoc, diag::err_undef_superclass) - << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); - else if (RequireCompleteType(SuperLoc, - Context.getObjCInterfaceType(SuperClassDecl), - diag::err_forward_superclass, - SuperClassDecl->getDeclName(), - ClassName, - SourceRange(AtInterfaceLoc, ClassLoc))) { - SuperClassDecl = nullptr; - } - } - IDecl->setSuperClass(SuperClassDecl); - IDecl->setSuperClassLoc(SuperLoc); - IDecl->setEndOfDefinitionLoc(SuperLoc); - } + ActOnSuperClassOfClassInterface(S, AtInterfaceLoc, IDecl, + ClassName, ClassLoc, + SuperName, SuperLoc, SuperTypeArgs, + SuperTypeArgsRange); } else { // we have a root class. IDecl->setEndOfDefinitionLoc(ClassLoc); } @@ -1091,6 +1158,325 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer, } } +// Callback to only accept typo corrections that are either +// Objective-C protocols or valid Objective-C type arguments. +class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback { + ASTContext &Context; + Sema::LookupNameKind LookupKind; + public: + ObjCTypeArgOrProtocolValidatorCCC(ASTContext &context, + Sema::LookupNameKind lookupKind) + : Context(context), LookupKind(lookupKind) { } + + bool ValidateCandidate(const TypoCorrection &candidate) override { + // If we're allowed to find protocols and we have a protocol, accept it. + if (LookupKind != Sema::LookupOrdinaryName) { + if (candidate.getCorrectionDeclAs<ObjCProtocolDecl>()) + return true; + } + + // If we're allowed to find type names and we have one, accept it. + if (LookupKind != Sema::LookupObjCProtocolName) { + // If we have a type declaration, we might accept this result. + if (auto typeDecl = candidate.getCorrectionDeclAs<TypeDecl>()) { + // If we found a tag declaration outside of C++, skip it. This + // can happy because we look for any name when there is no + // bias to protocol or type names. + if (isa<RecordDecl>(typeDecl) && !Context.getLangOpts().CPlusPlus) + return false; + + // Make sure the type is something we would accept as a type + // argument. + auto type = Context.getTypeDeclType(typeDecl); + if (type->isObjCObjectPointerType() || + type->isBlockPointerType() || + type->isDependentType() || + type->isObjCObjectType()) + return true; + + return false; + } + + // If we have an Objective-C class type, accept it; there will + // be another fix to add the '*'. + if (candidate.getCorrectionDeclAs<ObjCInterfaceDecl>()) + return true; + + return false; + } + + return false; + } +}; + +void Sema::actOnObjCTypeArgsOrProtocolQualifiers( + Scope *S, + DeclSpec &DS, + SourceLocation lAngleLoc, + ArrayRef<IdentifierInfo *> identifiers, + ArrayRef<SourceLocation> identifierLocs, + SourceLocation rAngleLoc, + bool warnOnIncompleteProtocols) { + // Local function that updates the declaration specifiers with + // protocol information. + SmallVector<ObjCProtocolDecl *, 4> protocols; + unsigned numProtocolsResolved = 0; + auto resolvedAsProtocols = [&] { + assert(numProtocolsResolved == identifiers.size() && "Unresolved protocols"); + + for (unsigned i = 0, n = protocols.size(); i != n; ++i) { + ObjCProtocolDecl *&proto = protocols[i]; + // For an objc container, delay protocol reference checking until after we + // can set the objc decl as the availability context, otherwise check now. + if (!warnOnIncompleteProtocols) { + (void)DiagnoseUseOfDecl(proto, identifierLocs[i]); + } + + // If this is a forward protocol declaration, get its definition. + if (!proto->isThisDeclarationADefinition() && proto->getDefinition()) + proto = proto->getDefinition(); + + // If this is a forward declaration and we are supposed to warn in this + // case, do it. + // FIXME: Recover nicely in the hidden case. + ObjCProtocolDecl *forwardDecl = nullptr; + if (warnOnIncompleteProtocols && + NestedProtocolHasNoDefinition(proto, forwardDecl)) { + Diag(identifierLocs[i], diag::warn_undef_protocolref) + << proto->getDeclName(); + Diag(forwardDecl->getLocation(), diag::note_protocol_decl_undefined) + << forwardDecl; + } + } + + DS.setProtocolQualifiers((Decl * const *)(protocols.data()), + protocols.size(), + const_cast<SourceLocation *>(identifierLocs.data()), + lAngleLoc); + if (rAngleLoc.isValid()) + DS.SetRangeEnd(rAngleLoc); + }; + + // Attempt to resolve all of the identifiers as protocols. + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + ObjCProtocolDecl *proto = LookupProtocol(identifiers[i], identifierLocs[i]); + protocols.push_back(proto); + if (proto) + ++numProtocolsResolved; + } + + // If all of the names were protocols, these were protocol qualifiers. + if (numProtocolsResolved == identifiers.size()) + return resolvedAsProtocols(); + + // Attempt to resolve all of the identifiers as type names or + // Objective-C class names. The latter is technically ill-formed, + // but is probably something like \c NSArray<NSView *> missing the + // \c*. + typedef llvm::PointerUnion<TypeDecl *, ObjCInterfaceDecl *> TypeOrClassDecl; + SmallVector<TypeOrClassDecl, 4> typeDecls; + unsigned numTypeDeclsResolved = 0; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + NamedDecl *decl = LookupSingleName(S, identifiers[i], identifierLocs[i], + LookupOrdinaryName); + if (!decl) { + typeDecls.push_back(TypeOrClassDecl()); + continue; + } + + if (auto typeDecl = dyn_cast<TypeDecl>(decl)) { + typeDecls.push_back(typeDecl); + ++numTypeDeclsResolved; + continue; + } + + if (auto objcClass = dyn_cast<ObjCInterfaceDecl>(decl)) { + typeDecls.push_back(objcClass); + ++numTypeDeclsResolved; + continue; + } + + typeDecls.push_back(TypeOrClassDecl()); + } + + AttributeFactory attrFactory; + + // Local function that forms a reference to the given type or + // Objective-C class declaration. + auto resolveTypeReference = [&](TypeOrClassDecl typeDecl, SourceLocation loc) + -> TypeResult { + // Form declaration specifiers. They simply refer to the type. + DeclSpec DS(attrFactory); + const char* prevSpec; // unused + unsigned diagID; // unused + QualType type; + if (auto *actualTypeDecl = typeDecl.dyn_cast<TypeDecl *>()) + type = Context.getTypeDeclType(actualTypeDecl); + else + type = Context.getObjCInterfaceType(typeDecl.get<ObjCInterfaceDecl *>()); + TypeSourceInfo *parsedTSInfo = Context.getTrivialTypeSourceInfo(type, loc); + ParsedType parsedType = CreateParsedType(type, parsedTSInfo); + DS.SetTypeSpecType(DeclSpec::TST_typename, loc, prevSpec, diagID, + parsedType, Context.getPrintingPolicy()); + // Use the identifier location for the type source range. + DS.SetRangeStart(loc); + DS.SetRangeEnd(loc); + + // Form the declarator. + Declarator D(DS, Declarator::TypeNameContext); + + // If we have a typedef of an Objective-C class type that is missing a '*', + // add the '*'. + if (type->getAs<ObjCInterfaceType>()) { + SourceLocation starLoc = PP.getLocForEndOfToken(loc); + ParsedAttributes parsedAttrs(attrFactory); + D.AddTypeInfo(DeclaratorChunk::getPointer(/*typeQuals=*/0, starLoc, + SourceLocation(), + SourceLocation(), + SourceLocation(), + SourceLocation()), + parsedAttrs, + starLoc); + + // Diagnose the missing '*'. + Diag(loc, diag::err_objc_type_arg_missing_star) + << type + << FixItHint::CreateInsertion(starLoc, " *"); + } + + // Convert this to a type. + return ActOnTypeName(S, D); + }; + + // Local function that updates the declaration specifiers with + // type argument information. + auto resolvedAsTypeDecls = [&] { + assert(numTypeDeclsResolved == identifiers.size() && "Unresolved type decl"); + // Map type declarations to type arguments. + SmallVector<ParsedType, 4> typeArgs; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + // Map type reference to a type. + TypeResult type = resolveTypeReference(typeDecls[i], identifierLocs[i]); + if (!type.isUsable()) + return; + + typeArgs.push_back(type.get()); + } + + // Record the Objective-C type arguments. + DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc); + }; + + // If all of the identifiers can be resolved as type names or + // Objective-C class names, we have type arguments. + if (numTypeDeclsResolved == identifiers.size()) + return resolvedAsTypeDecls(); + + // Error recovery: some names weren't found, or we have a mix of + // type and protocol names. Go resolve all of the unresolved names + // and complain if we can't find a consistent answer. + LookupNameKind lookupKind = LookupAnyName; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + // If we already have a protocol or type. Check whether it is the + // right thing. + if (protocols[i] || typeDecls[i]) { + // If we haven't figured out whether we want types or protocols + // yet, try to figure it out from this name. + if (lookupKind == LookupAnyName) { + // If this name refers to both a protocol and a type (e.g., \c + // NSObject), don't conclude anything yet. + if (protocols[i] && typeDecls[i]) + continue; + + // Otherwise, let this name decide whether we'll be correcting + // toward types or protocols. + lookupKind = protocols[i] ? LookupObjCProtocolName + : LookupOrdinaryName; + continue; + } + + // If we want protocols and we have a protocol, there's nothing + // more to do. + if (lookupKind == LookupObjCProtocolName && protocols[i]) + continue; + + // If we want types and we have a type declaration, there's + // nothing more to do. + if (lookupKind == LookupOrdinaryName && typeDecls[i]) + continue; + + // We have a conflict: some names refer to protocols and others + // refer to types. + Diag(identifierLocs[i], diag::err_objc_type_args_and_protocols) + << (protocols[i] != nullptr) + << identifiers[i] + << identifiers[0] + << SourceRange(identifierLocs[0]); + + return; + } + + // Perform typo correction on the name. + TypoCorrection corrected = CorrectTypo( + DeclarationNameInfo(identifiers[i], identifierLocs[i]), lookupKind, S, + nullptr, + llvm::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(Context, + lookupKind), + CTK_ErrorRecovery); + if (corrected) { + // Did we find a protocol? + if (auto proto = corrected.getCorrectionDeclAs<ObjCProtocolDecl>()) { + diagnoseTypo(corrected, + PDiag(diag::err_undeclared_protocol_suggest) + << identifiers[i]); + lookupKind = LookupObjCProtocolName; + protocols[i] = proto; + ++numProtocolsResolved; + continue; + } + + // Did we find a type? + if (auto typeDecl = corrected.getCorrectionDeclAs<TypeDecl>()) { + diagnoseTypo(corrected, + PDiag(diag::err_unknown_typename_suggest) + << identifiers[i]); + lookupKind = LookupOrdinaryName; + typeDecls[i] = typeDecl; + ++numTypeDeclsResolved; + continue; + } + + // Did we find an Objective-C class? + if (auto objcClass = corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) { + diagnoseTypo(corrected, + PDiag(diag::err_unknown_type_or_class_name_suggest) + << identifiers[i] << true); + lookupKind = LookupOrdinaryName; + typeDecls[i] = objcClass; + ++numTypeDeclsResolved; + continue; + } + } + + // We couldn't find anything. + Diag(identifierLocs[i], + (lookupKind == LookupAnyName ? diag::err_objc_type_arg_missing + : lookupKind == LookupObjCProtocolName ? diag::err_undeclared_protocol + : diag::err_unknown_typename)) + << identifiers[i]; + return; + } + + // If all of the names were (corrected to) protocols, these were + // protocol qualifiers. + if (numProtocolsResolved == identifiers.size()) + return resolvedAsProtocols(); + + // Otherwise, all of the names were (corrected to) types. + assert(numTypeDeclsResolved == identifiers.size() && "Not all types?"); + return resolvedAsTypeDecls(); +} + /// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of /// a class method in its extension. /// @@ -1374,8 +1760,9 @@ Decl *Sema::ActOnStartClassImplementation( true); IDecl->startDefinition(); if (SDecl) { - IDecl->setSuperClass(SDecl); - IDecl->setSuperClassLoc(SuperClassLoc); + IDecl->setSuperClass(Context.getTrivialTypeSourceInfo( + Context.getObjCInterfaceType(SDecl), + SuperClassLoc)); IDecl->setEndOfDefinitionLoc(SuperClassLoc); } else { IDecl->setEndOfDefinitionLoc(ClassLoc); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 01a4d488057..c6b53d03890 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5826,36 +5826,6 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, return ResultTy; } -/// \brief Returns true if QT is quelified-id and implements 'NSObject' and/or -/// 'NSCopying' protocols (and nothing else); or QT is an NSObject and optionally -/// implements 'NSObject' and/or NSCopying' protocols (and nothing else). -static bool isObjCPtrBlockCompatible(Sema &S, ASTContext &C, QualType QT) { - if (QT->isObjCIdType()) - return true; - - const ObjCObjectPointerType *OPT = QT->getAs<ObjCObjectPointerType>(); - if (!OPT) - return false; - - if (ObjCInterfaceDecl *ID = OPT->getInterfaceDecl()) - if (ID->getIdentifier() != &C.Idents.get("NSObject")) - return false; - - ObjCProtocolDecl* PNSCopying = - S.LookupProtocol(&C.Idents.get("NSCopying"), SourceLocation()); - ObjCProtocolDecl* PNSObject = - S.LookupProtocol(&C.Idents.get("NSObject"), SourceLocation()); - - for (auto *Proto : OPT->quals()) { - if ((PNSCopying && declaresSameEntity(Proto, PNSCopying)) || - (PNSObject && declaresSameEntity(Proto, PNSObject))) - ; - else - return false; - } - return true; -} - /// \brief Return the resulting type when the operands are both block pointers. static QualType checkConditionalBlockPointerCompatibility(Sema &S, ExprResult &LHS, @@ -7008,8 +6978,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, } // Only under strict condition T^ is compatible with an Objective-C pointer. - if (RHSType->isBlockPointerType() && - isObjCPtrBlockCompatible(*this, Context, LHSType)) { + if (RHSType->isBlockPointerType() && + LHSType->isBlockCompatibleObjCPointerType(Context)) { maybeExtendBlockObject(*this, RHS); Kind = CK_BlockPointerToObjCPointerCast; return Compatible; diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 0e1751a503b..7280f588c8b 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -959,8 +959,10 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) { ObjCProtocolDecl *PQ[] = {NSCopyingPDecl}; QIDNSCopying = - Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl**) PQ,1); + Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { }, + llvm::makeArrayRef( + (ObjCProtocolDecl**) PQ, + 1)); QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying); } } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 8d76f692025..9170ac760d4 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -738,6 +738,160 @@ static void diagnoseAndRemoveTypeQualifiers(Sema &S, const DeclSpec &DS, } } +/// Apply Objective-C type arguments to the given type. +static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, + ArrayRef<ParsedType> typeArgs, + SourceRange typeArgsRange) { + // We can only apply type arguments to an Objective-C class type. + const auto *objcObjectType = type->getAs<ObjCObjectType>(); + if (!objcObjectType || !objcObjectType->getInterface()) { + S.Diag(loc, diag::err_objc_type_args_non_class) + << type + << typeArgsRange; + return type; + } + + // The class type must be parameterized. + ObjCInterfaceDecl *objcClass = objcObjectType->getInterface(); + ObjCTypeParamList *typeParams = objcClass->getTypeParamList(); + if (!typeParams) { + S.Diag(loc, diag::err_objc_type_args_non_parameterized_class) + << objcClass->getDeclName() + << FixItHint::CreateRemoval(typeArgsRange); + return type; + } + + // The type must not already be specialized. + if (objcObjectType->isSpecialized()) { + S.Diag(loc, diag::err_objc_type_args_specialized_class) + << type + << FixItHint::CreateRemoval(typeArgsRange); + return type; + } + + // Make sure that we have the right number of type arguments. + if (typeArgs.size() != typeParams->size()) { + S.Diag(loc, diag::err_objc_type_args_wrong_arity) + << (typeArgs.size() < typeParams->size()) + << objcClass->getDeclName() + << (unsigned)typeArgs.size() + << (unsigned)typeParams->size(); + S.Diag(objcClass->getLocation(), diag::note_previous_decl) + << objcClass; + return type; + } + + // Check the type arguments. + SmallVector<QualType, 4> finalTypeArgs; + for (unsigned i = 0, n = typeArgs.size(); i != n; ++i) { + TypeSourceInfo *typeArgInfo = nullptr; + QualType typeArg = S.GetTypeFromParser(typeArgs[i], &typeArgInfo); + finalTypeArgs.push_back(typeArg); + + // Objective-C object pointer types must be substitutable for the bounds. + if (const auto *typeArgObjC = typeArg->getAs<ObjCObjectPointerType>()) { + // Retrieve the bound. + ObjCTypeParamDecl *typeParam = typeParams->begin()[i]; + QualType bound = typeParam->getUnderlyingType(); + const auto *boundObjC = bound->getAs<ObjCObjectPointerType>(); + + // Determine whether the type argument is substitutable for the bound. + if (typeArgObjC->isObjCIdType()) { + // When the type argument is 'id', the only acceptable type + // parameter bound is 'id'. + if (boundObjC->isObjCIdType()) + continue; + } else if (S.Context.canAssignObjCInterfaces(boundObjC, typeArgObjC)) { + // Otherwise, we follow the assignability rules. + continue; + } + + // Diagnose the mismatch. + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), + diag::err_objc_type_arg_does_not_match_bound) + << typeArg << bound << typeParam->getDeclName(); + S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here) + << typeParam->getDeclName(); + + return type; + } + + // Block pointer types are permitted for unqualified 'id' bounds. + if (typeArg->isBlockPointerType()) { + // Retrieve the bound. + ObjCTypeParamDecl *typeParam = typeParams->begin()[i]; + QualType bound = typeParam->getUnderlyingType(); + if (bound->isBlockCompatibleObjCPointerType(S.Context)) + continue; + + // Diagnose the mismatch. + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), + diag::err_objc_type_arg_does_not_match_bound) + << typeArg << bound << typeParam->getDeclName(); + S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here) + << typeParam->getDeclName(); + + return type; + } + + // Dependent types will be checked at instantiation time. + if (typeArg->isDependentType()) { + continue; + } + + // Diagnose non-id-compatible type arguments. + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), + diag::err_objc_type_arg_not_id_compatible) + << typeArg + << typeArgInfo->getTypeLoc().getSourceRange(); + return type; + } + + // Success. Form the specialized type. + return S.Context.getObjCObjectType(type, finalTypeArgs, { }); +} + +/// Apply Objective-C protocol qualifiers to the given type. +static QualType applyObjCProtocolQualifiers( + Sema &S, SourceLocation loc, SourceRange range, QualType type, + ArrayRef<ObjCProtocolDecl *> protocols, + const SourceLocation *protocolLocs) { + ASTContext &ctx = S.Context; + if (const ObjCObjectType *objT = dyn_cast<ObjCObjectType>(type.getTypePtr())){ + // FIXME: Check for protocols to which the class type is already + // known to conform. + + return ctx.getObjCObjectType(objT->getBaseType(), + objT->getTypeArgsAsWritten(), + protocols); + } + + if (type->isObjCObjectType()) { + // Silently overwrite any existing protocol qualifiers. + // TODO: determine whether that's the right thing to do. + + // FIXME: Check for protocols to which the class type is already + // known to conform. + return ctx.getObjCObjectType(type, { }, protocols); + } + + // id<protocol-list> + if (type->isObjCIdType()) { + type = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, protocols); + return ctx.getObjCObjectPointerType(type); + } + + // Class<protocol-list> + if (type->isObjCClassType()) { + type = ctx.getObjCObjectType(ctx.ObjCBuiltinClassTy, { }, protocols); + return ctx.getObjCObjectPointerType(type); + } + + S.Diag(loc, diag::err_invalid_protocol_qualifiers) + << range; + return type; +} + /// \brief Convert the specified declspec to the appropriate type /// object. /// \param state Specifies the declarator containing the declaration specifier @@ -803,9 +957,10 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { case DeclSpec::TST_unspecified: // "<proto1,proto2>" is an objc qualified ID with a missing id. if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl*const*)PQ, - DS.getNumProtocolQualifiers()); + Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { }, + llvm::makeArrayRef( + (ObjCProtocolDecl*const*)PQ, + DS.getNumProtocolQualifiers())); Result = Context.getObjCObjectPointerType(Result); break; } @@ -967,37 +1122,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); Result = S.GetTypeFromParser(DS.getRepAsType()); - if (Result.isNull()) + if (Result.isNull()) { declarator.setInvalidType(true); - else if (DeclSpec::ProtocolQualifierListTy PQ - = DS.getProtocolQualifiers()) { - if (const ObjCObjectType *ObjT = Result->getAs<ObjCObjectType>()) { - // Silently drop any existing protocol qualifiers. - // TODO: determine whether that's the right thing to do. - if (ObjT->getNumProtocols()) - Result = ObjT->getBaseType(); - - if (DS.getNumProtocolQualifiers()) - Result = Context.getObjCObjectType(Result, - (ObjCProtocolDecl*const*) PQ, - DS.getNumProtocolQualifiers()); - } else if (Result->isObjCIdType()) { - // id<protocol-list> - Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl*const*) PQ, - DS.getNumProtocolQualifiers()); - Result = Context.getObjCObjectPointerType(Result); - } else if (Result->isObjCClassType()) { - // Class<protocol-list> - Result = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, - (ObjCProtocolDecl*const*) PQ, - DS.getNumProtocolQualifiers()); - Result = Context.getObjCObjectPointerType(Result); - } else { - S.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) - << DS.getSourceRange(); - declarator.setInvalidType(true); - } } else if (S.getLangOpts().OpenCL) { if (const AtomicType *AT = Result->getAs<AtomicType>()) { const BuiltinType *BT = AT->getValueType()->getAs<BuiltinType>(); @@ -1022,6 +1148,21 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { declarator.setInvalidType(true); } } + } else { + // Apply Objective-C type arguments. + if (DS.hasObjCTypeArgs()) { + Result = applyObjCTypeArgs(S, DeclLoc, Result, DS.getObjCTypeArgs(), + DS.getObjCTypeArgsRange()); + } + + // Apply Objective-C protocol qualifiers. + if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { + Result = applyObjCProtocolQualifiers( + S, DeclLoc, DS.getSourceRange(), Result, + llvm::makeArrayRef((ObjCProtocolDecl * const *)PQ, + DS.getNumProtocolQualifiers()), + DS.getProtocolLocs()); + } } // TypeQuals handled by caller. @@ -4138,18 +4279,33 @@ namespace { Visit(TL.getBaseLoc()); } + // Type arguments. + if (TL.getNumTypeArgs() > 0) { + assert(TL.getNumTypeArgs() == DS.getObjCTypeArgs().size()); + TL.setTypeArgsLAngleLoc(DS.getObjCTypeArgsLAngleLoc()); + TL.setTypeArgsRAngleLoc(DS.getObjCTypeArgsRAngleLoc()); + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) { + TypeSourceInfo *typeArgInfo = nullptr; + (void)Sema::GetTypeFromParser(DS.getObjCTypeArgs()[i], &typeArgInfo); + TL.setTypeArgTInfo(i, typeArgInfo); + } + } else { + TL.setTypeArgsLAngleLoc(SourceLocation()); + TL.setTypeArgsRAngleLoc(SourceLocation()); + } + // Protocol qualifiers. if (DS.getProtocolQualifiers()) { assert(TL.getNumProtocols() > 0); assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); - TL.setLAngleLoc(DS.getProtocolLAngleLoc()); - TL.setRAngleLoc(DS.getSourceRange().getEnd()); + TL.setProtocolLAngleLoc(DS.getProtocolLAngleLoc()); + TL.setProtocolRAngleLoc(DS.getSourceRange().getEnd()); for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i) TL.setProtocolLoc(i, DS.getProtocolLocs()[i]); } else { assert(TL.getNumProtocols() == 0); - TL.setLAngleLoc(SourceLocation()); - TL.setRAngleLoc(SourceLocation()); + TL.setProtocolLAngleLoc(SourceLocation()); + TL.setProtocolRAngleLoc(SourceLocation()); } } void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 48a898cb30d..89464c443e8 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -5263,11 +5263,15 @@ QualType ASTReader::readTypeRecord(unsigned Index) { case TYPE_OBJC_OBJECT: { unsigned Idx = 0; QualType Base = readType(*Loc.F, Record, Idx); + unsigned NumTypeArgs = Record[Idx++]; + SmallVector<QualType, 4> TypeArgs; + for (unsigned I = 0; I != NumTypeArgs; ++I) + TypeArgs.push_back(readType(*Loc.F, Record, Idx)); unsigned NumProtos = Record[Idx++]; SmallVector<ObjCProtocolDecl*, 4> Protos; for (unsigned I = 0; I != NumProtos; ++I) Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx)); - return Context.getObjCObjectType(Base, Protos.data(), NumProtos); + return Context.getObjCObjectType(Base, TypeArgs, Protos); } case TYPE_OBJC_OBJECT_POINTER: { @@ -5646,8 +5650,12 @@ void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { } void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { TL.setHasBaseTypeAsWritten(Record[Idx++]); - TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); - TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setTypeArgsLAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setTypeArgsRAngleLoc(ReadSourceLocation(Record, Idx)); + for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) + TL.setTypeArgTInfo(i, Reader.GetTypeSourceInfo(F, Record, Idx)); + TL.setProtocolLAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setProtocolRAngleLoc(ReadSourceLocation(Record, Idx)); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) TL.setProtocolLoc(i, ReadSourceLocation(Record, Idx)); } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index e01ea2b8a59..69d173d3c85 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -953,8 +953,7 @@ void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { ObjCInterfaceDecl::DefinitionData &Data = ID->data(); // Read the superclass. - Data.SuperClass = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx); - Data.SuperClassLoc = ReadSourceLocation(Record, Idx); + Data.SuperClassTInfo = GetTypeSourceInfo(Record, Idx); Data.EndLoc = ReadSourceLocation(Record, Idx); Data.HasDesignatedInitializers = Record[Idx++]; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 0d15b17c7ce..dd56de38419 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -421,6 +421,9 @@ void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) { Writer.AddTypeRef(T->getBaseType(), Record); + Record.push_back(T->getTypeArgs().size()); + for (auto TypeArg : T->getTypeArgs()) + Writer.AddTypeRef(TypeArg, Record); Record.push_back(T->getNumProtocols()); for (const auto *I : T->quals()) Writer.AddDeclRef(I, Record); @@ -648,8 +651,12 @@ void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { } void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { Record.push_back(TL.hasBaseTypeAsWritten()); - Writer.AddSourceLocation(TL.getLAngleLoc(), Record); - Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + Writer.AddSourceLocation(TL.getTypeArgsLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getTypeArgsRAngleLoc(), Record); + for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) + Writer.AddTypeSourceInfo(TL.getTypeArgTInfo(i), Record); + Writer.AddSourceLocation(TL.getProtocolLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getProtocolRAngleLoc(), Record); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) Writer.AddSourceLocation(TL.getProtocolLoc(i), Record); } diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 5e9151eed5e..00f8daa676e 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -604,8 +604,7 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { // Write the DefinitionData ObjCInterfaceDecl::DefinitionData &Data = D->data(); - Writer.AddDeclRef(D->getSuperClass(), Record); - Writer.AddSourceLocation(D->getSuperClassLoc(), Record); + Writer.AddTypeSourceInfo(D->getSuperClassTInfo(), Record); Writer.AddSourceLocation(D->getEndOfDefinitionLoc(), Record); Record.push_back(Data.HasDesignatedInitializers); |

