diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 61 | ||||
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 3 | ||||
-rw-r--r-- | clang/lib/AST/DeclObjC.cpp | 30 | ||||
-rw-r--r-- | clang/lib/AST/Expr.cpp | 10 | ||||
-rw-r--r-- | clang/lib/AST/Type.cpp | 775 | ||||
-rw-r--r-- | clang/lib/AST/TypeLoc.cpp | 11 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGObjC.cpp | 34 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 26 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 32 | ||||
-rw-r--r-- | clang/lib/Parse/ParseInit.cpp | 25 | ||||
-rw-r--r-- | clang/lib/Parse/ParseObjc.cpp | 54 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 25 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 21 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprMember.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprObjC.cpp | 77 | ||||
-rw-r--r-- | clang/lib/Sema/SemaObjCProperty.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Sema/SemaPseudoObject.cpp | 36 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 14 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriterDecl.cpp | 1 |
21 files changed, 1092 insertions, 159 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index c7a66d74897..d04121ac2f3 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6893,9 +6893,13 @@ QualType ASTContext::areCommonBaseCompatible( const ObjCInterfaceDecl* RDecl = RHS->getInterface(); if (!LDecl || !RDecl || (declaresSameEntity(LDecl, RDecl))) return QualType(); - - do { - LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl)); + + while (!declaresSameEntity(LHS->getInterface(), RDecl)) { + // Strip protocols from the left-hand side. + if (LHS->getNumProtocols() > 0) + LHS = getObjCObjectType(LHS->getBaseType(), LHS->getTypeArgsAsWritten(), + { })->castAs<ObjCObjectType>(); + if (canAssignObjCInterfaces(LHS, RHS)) { SmallVector<ObjCProtocolDecl *, 8> Protocols; getIntersectionOfProtocols(*this, Lptr, Rptr, Protocols); @@ -6906,7 +6910,13 @@ QualType ASTContext::areCommonBaseCompatible( Result = getObjCObjectPointerType(Result); return Result; } - } while ((LDecl = LDecl->getSuperClass())); + + QualType LHSSuperType = LHS->getSuperClassType(); + if (LHSSuperType.isNull()) + break; + + LHS = LHSSuperType->castAs<ObjCObjectType>(); + } return QualType(); } @@ -6918,21 +6928,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. @@ -6957,9 +6961,28 @@ 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()) { + ArrayRef<QualType> LHSTypeArgs = LHS->getTypeArgs(); + ArrayRef<QualType> RHSTypeArgs = RHSSuper->getTypeArgs(); + for (unsigned i = 0, n = LHSTypeArgs.size(); i != n; ++i) { + if (!hasSameType(LHSTypeArgs[i], RHSTypeArgs[i])) + return false; + } + } + } + + return true; } bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) { diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index ff80ba1ce7e..f7bfcaacd7c 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1845,7 +1845,7 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { return QualType(); SmallVector<QualType, 4> TypeArgs; - for (auto TypeArg : T->getTypeArgs()) { + for (auto TypeArg : T->getTypeArgsAsWritten()) { QualType ImportedTypeArg = Importer.Import(TypeArg); if (ImportedTypeArg.isNull()) return QualType(); @@ -3452,6 +3452,7 @@ Decl *ASTNodeImporter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { ObjCTypeParamDecl *Result = ObjCTypeParamDecl::Create( Importer.getToContext(), DC, + D->getIndex(), Importer.Import(D->getLocation()), Name.getAsIdentifierInfo(), Importer.Import(D->getColonLoc()), diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index a93c8f61336..69ff33a60aa 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -1013,6 +1013,14 @@ SourceRange ObjCMethodDecl::getReturnTypeSourceRange() const { return SourceRange(); } +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, @@ -1190,17 +1198,18 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { void ObjCTypeParamDecl::anchor() { } ObjCTypeParamDecl *ObjCTypeParamDecl::Create(ASTContext &ctx, DeclContext *dc, + unsigned index, SourceLocation nameLoc, IdentifierInfo *name, SourceLocation colonLoc, TypeSourceInfo *boundInfo) { - return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, nameLoc, name, colonLoc, + return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, index, nameLoc, name, colonLoc, boundInfo); } ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx, unsigned ID) { - return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr, SourceLocation(), + return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr, 0, SourceLocation(), nullptr, SourceLocation(), nullptr); } @@ -1239,6 +1248,13 @@ ObjCTypeParamList *ObjCTypeParamList::create( 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 //===----------------------------------------------------------------------===// @@ -1606,6 +1622,11 @@ const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const { } } +QualType ObjCIvarDecl::getUsageType(QualType objectType) const { + return getType().substObjCMemberType(objectType, getDeclContext(), + ObjCSubstitutionContext::Property); +} + //===----------------------------------------------------------------------===// // ObjCAtDefsFieldDecl //===----------------------------------------------------------------------===// @@ -2012,6 +2033,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/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 87f9ffba78e..2e066b2c42c 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/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/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 48245f648bb..9b2bfc0cd9e 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -491,10 +491,13 @@ bool ObjCObjectType::isSpecialized() const { 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(); + // 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. @@ -506,16 +509,765 @@ ArrayRef<QualType> ObjCObjectType::getTypeArgs() const { 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(); + // 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 { }; } +namespace { + +/// 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) { + struct Visitor : public TypeVisitor<Visitor, QualType> { + ASTContext &Ctx; + F &&TheFunc; + + QualType recurse(QualType type) { + return simpleTransform(Ctx, type, std::move(TheFunc)); + } + + public: + Visitor(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())); + } + + 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 + }; + + // 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. + Visitor 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 'id' or 'Class', as appropriate. + + // If the underlying type is based on 'Class', substitute 'Class'. + if (typeParam->getUnderlyingType()->isObjCClassType() || + typeParam->getUnderlyingType()->isObjCQualifiedClassType()) { + return ctx.getQualifiedType(ctx.getObjCClassType(), + splitType.Quals); + } + + // Otherwise, substitute 'id'. + return ctx.getQualifiedType(ctx.getObjCIdType(), 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); + } + + anyChanged = true; + } + + newTypeArgs.push_back(newTypeArg); + } + + if (anyChanged) { + ArrayRef<ObjCProtocolDecl *> protocols( + objcObjectType->qual_begin(), + objcObjectType->getNumProtocols()); + return ctx.getObjCObjectType(objcObjectType->getBaseType(), + newTypeArgs, protocols); + } + } + + 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; +} + +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(); +} + +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); +} + +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 { // There is no sugar for ObjCObjectType's, just return the canonical @@ -551,6 +1303,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()) diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index 0d497aad8e4..02d0cec708c 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -312,6 +312,17 @@ 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); diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 747326e4c5b..4178d48f25a 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -31,10 +31,9 @@ using namespace CodeGen; typedef llvm::PointerIntPair<llvm::Value*,1,bool> TryEmitResult; static TryEmitResult tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e); -static RValue AdjustRelatedResultType(CodeGenFunction &CGF, - QualType ET, - const ObjCMethodDecl *Method, - RValue Result); +static RValue AdjustObjCObjectType(CodeGenFunction &CGF, + QualType ET, + RValue Result); /// Given the address of a variable of pointer type, find the correct /// null to store into it. @@ -248,23 +247,22 @@ llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) { return CGM.getObjCRuntime().GenerateProtocolRef(*this, E->getProtocol()); } -/// \brief Adjust the type of the result of an Objective-C message send -/// expression when the method has a related result type. -static RValue AdjustRelatedResultType(CodeGenFunction &CGF, - QualType ExpT, - const ObjCMethodDecl *Method, - RValue Result) { - if (!Method) +/// \brief Adjust the type of an Objective-C object that doesn't match up due +/// to type erasure at various points, e.g., related result types or the use +/// of parameterized classes. +static RValue AdjustObjCObjectType(CodeGenFunction &CGF, QualType ExpT, + RValue Result) { + if (!ExpT->isObjCRetainableType()) return Result; - if (!Method->hasRelatedResultType() || - CGF.getContext().hasSameType(ExpT, Method->getReturnType()) || - !Result.isScalar()) + // If the converted types are the same, we're done. + llvm::Type *ExpLLVMTy = CGF.ConvertType(ExpT); + if (ExpLLVMTy == Result.getScalarVal()->getType()) return Result; - - // We have applied a related result type. Cast the rvalue appropriately. + + // We have applied a substitution. Cast the rvalue appropriately. return RValue::get(CGF.Builder.CreateBitCast(Result.getScalarVal(), - CGF.ConvertType(ExpT))); + ExpLLVMTy)); } /// Decide whether to extend the lifetime of the receiver of a @@ -449,7 +447,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, Builder.CreateStore(newSelf, selfAddr); } - return AdjustRelatedResultType(*this, E->getType(), method, result); + return AdjustObjCObjectType(*this, E->getType(), result); } namespace { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 371c4970848..a1412bcee67 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2943,6 +2943,26 @@ private: SourceLocation Loc); public: +#ifndef NDEBUG + // Determine whether the given argument is an Objective-C method + // that may have type parameters in its signature. + static bool isObjCMethodWithTypeParams(const ObjCMethodDecl *method) { + const DeclContext *dc = method->getDeclContext(); + if (const ObjCInterfaceDecl *classDecl= dyn_cast<ObjCInterfaceDecl>(dc)) { + return classDecl->getTypeParamListAsWritten(); + } + + if (const ObjCCategoryDecl *catDecl = dyn_cast<ObjCCategoryDecl>(dc)) { + return catDecl->getTypeParamList(); + } + + return false; + } + + template<typename T> + static bool isObjCMethodWithTypeParams(const T *) { return false; } +#endif + /// EmitCallArgs - Emit call arguments for a function. template <typename T> void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo, @@ -2956,13 +2976,19 @@ public: assert((ParamsToSkip == 0 || CallArgTypeInfo) && "Can't skip parameters if type info is not provided"); if (CallArgTypeInfo) { +#ifndef NDEBUG + bool isGenericMethod = isObjCMethodWithTypeParams(CallArgTypeInfo); +#endif + // First, use the argument types that the type info knows about for (auto I = CallArgTypeInfo->param_type_begin() + ParamsToSkip, E = CallArgTypeInfo->param_type_end(); I != E; ++I, ++Arg) { assert(Arg != ArgEnd && "Running over edge of argument list!"); assert( + isGenericMethod || ((*I)->isVariablyModifiedType() || + (*I).getNonReferenceType()->isObjCRetainableType() || getContext() .getCanonicalType((*I).getNonReferenceType()) .getTypePtr() == diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index fdd10522ee5..231f6d4d97a 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2890,21 +2890,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // 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); - } - } + ParseObjCTypeArgsAndProtocolQualifiers(DS); } continue; @@ -3016,21 +3002,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // 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); - } - } + ParseObjCTypeArgsAndProtocolQualifiers(DS); } // Need to support trailing type qualifiers (e.g. "id<p> const"). diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp index 42287d68b33..f62c8be0769 100644 --- a/clang/lib/Parse/ParseInit.cpp +++ b/clang/lib/Parse/ParseInit.cpp @@ -258,20 +258,33 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { NextToken().is(tok::period), ReceiverType)) { case Sema::ObjCSuperMessage: + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + ConsumeToken(), + ParsedType(), + nullptr); + case Sema::ObjCClassMessage: CheckArrayDesignatorSyntax(*this, StartLoc, Desig); - if (Kind == Sema::ObjCSuperMessage) - return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, - ConsumeToken(), - ParsedType(), - nullptr); ConsumeToken(); // the identifier if (!ReceiverType) { SkipUntil(tok::r_square, StopAtSemi); return ExprError(); } - return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + // Parse type arguments and protocol qualifiers. + if (Tok.is(tok::less)) { + TypeResult NewReceiverType + = ParseObjCTypeArgsAndProtocolQualifiers(IILoc, ReceiverType); + if (!NewReceiverType.isUsable()) { + SkipUntil(tok::r_square, StopAtSemi); + return ExprError(); + } + + ReceiverType = NewReceiverType.get(); + } + + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, SourceLocation(), ReceiverType, nullptr); diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 0e4574056b0..669c0653df8 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -438,8 +438,10 @@ ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs( // type parameters. SmallVector<Decl *, 4> typeParams; auto makeProtocolIdentsIntoTypeParameters = [&]() { + unsigned index = 0; for (const auto &pair : protocolIdents) { DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(), + index++, pair.first, pair.second, SourceLocation(), @@ -502,6 +504,7 @@ ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs( // Create the type parameter. DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(), + typeParams.size(), paramName, paramLoc, colonLoc, @@ -1675,6 +1678,45 @@ void Parser::ParseObjCTypeArgsOrProtocolQualifiers( DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc); } +void Parser::ParseObjCTypeArgsAndProtocolQualifiers(DeclSpec &DS) { + assert(Tok.is(tok::less)); + + 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); + } + } +} + +TypeResult Parser::ParseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc, + ParsedType type) { + assert(Tok.is(tok::less)); + + // Create declaration specifiers and set the type as the type specifier. + DeclSpec DS(AttrFactory); + const char *prevSpec = nullptr; + unsigned diagID; + DS.SetTypeSpecType(TST_typename, loc, prevSpec, diagID, type, + Actions.getASTContext().getPrintingPolicy()); + + // Parse type arguments and protocol qualifiers. + ParseObjCTypeArgsAndProtocolQualifiers(DS); + + // Form a declarator to turn this into a type. + Declarator D(DS, Declarator::TypeNameContext); + return Actions.ActOnTypeName(getCurScope(), D); +} + void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc, BalancedDelimiterTracker &T, SmallVectorImpl<Decl *> &AllIvarDecls, @@ -2829,6 +2871,18 @@ ExprResult Parser::ParseObjCMessageExpression() { ConsumeToken(); // the type name + // Parse type arguments and protocol qualifiers. + if (Tok.is(tok::less)) { + TypeResult NewReceiverType + = ParseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType); + if (!NewReceiverType.isUsable()) { + SkipUntil(tok::r_square, StopAtSemi); + return ExprError(); + } + + ReceiverType = NewReceiverType.get(); + } + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), ReceiverType, nullptr); diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index ac1e3923afa..f28abf4c070 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -600,7 +600,8 @@ ActOnSuperClassOfClassInterface(Scope *S, } } -DeclResult Sema::actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName, +DeclResult Sema::actOnObjCTypeParam(Scope *S, unsigned index, + IdentifierInfo *paramName, SourceLocation paramLoc, SourceLocation colonLoc, ParsedType parsedTypeBound) { @@ -643,6 +644,23 @@ DeclResult Sema::actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName, // Forget the bound; we'll default to id later. typeBoundInfo = nullptr; } + + // Type bounds cannot have explicit nullability. + if (typeBoundInfo) { + // Type arguments cannot explicitly specify nullability. + if (auto nullability = AttributedType::stripOuterNullability(typeBound)) { + // Look at the type location information to find the nullability + // specifier so we can zap it. + SourceLocation nullabilityLoc + = typeBoundInfo->getTypeLoc().findNullabilityLoc(); + SourceLocation diagLoc + = nullabilityLoc.isValid()? nullabilityLoc + : typeBoundInfo->getTypeLoc().getLocStart(); + Diag(diagLoc, diag::err_type_param_bound_explicit_nullability) + << paramName << typeBoundInfo->getType() + << FixItHint::CreateRemoval(nullabilityLoc); + } + } } // If there was no explicit type bound (or we removed it due to an error), @@ -653,8 +671,8 @@ DeclResult Sema::actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName, } // Create the type parameter. - return ObjCTypeParamDecl::Create(Context, CurContext, paramLoc, paramName, - colonLoc, typeBoundInfo); + return ObjCTypeParamDecl::Create(Context, CurContext, index, paramLoc, + paramName, colonLoc, typeBoundInfo); } ObjCTypeParamList *Sema::actOnObjCTypeParamList(Scope *S, @@ -868,6 +886,7 @@ ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc, ObjCTypeParamDecl::Create( Context, CurContext, + typeParam->getIndex(), SourceLocation(), typeParam->getIdentifier(), SourceLocation(), diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c6b53d03890..afc9279cba1 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2466,8 +2466,8 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName(); ObjCIvarRefExpr *Result = new (Context) - ObjCIvarRefExpr(IV, IV->getType(), Loc, IV->getLocation(), - SelfExpr.get(), true, true); + ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc, + IV->getLocation(), SelfExpr.get(), true, true); if (getLangOpts().ObjCAutoRefCount) { if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { @@ -5185,17 +5185,17 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, } /// Do an explicit extend of the given block pointer if we're in ARC. -static void maybeExtendBlockObject(Sema &S, ExprResult &E) { +void Sema::maybeExtendBlockObject(ExprResult &E) { assert(E.get()->getType()->isBlockPointerType()); assert(E.get()->isRValue()); // Only do this in an r-value context. - if (!S.getLangOpts().ObjCAutoRefCount) return; + if (!getLangOpts().ObjCAutoRefCount) return; - E = ImplicitCastExpr::Create(S.Context, E.get()->getType(), + E = ImplicitCastExpr::Create(Context, E.get()->getType(), CK_ARCExtendBlockObject, E.get(), /*base path*/ nullptr, VK_RValue); - S.ExprNeedsCleanups = true; + ExprNeedsCleanups = true; } /// Prepare a conversion of the given expression to an ObjC object @@ -5205,7 +5205,7 @@ CastKind Sema::PrepareCastToObjCObjectPointer(ExprResult &E) { if (type->isObjCObjectPointerType()) { return CK_BitCast; } else if (type->isBlockPointerType()) { - maybeExtendBlockObject(*this, E); + maybeExtendBlockObject(E); return CK_BlockPointerToObjCPointerCast; } else { assert(type->isPointerType()); @@ -5247,7 +5247,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) { return CK_BitCast; if (SrcKind == Type::STK_CPointer) return CK_CPointerToObjCPointerCast; - maybeExtendBlockObject(*this, Src); + maybeExtendBlockObject(Src); return CK_BlockPointerToObjCPointerCast; case Type::STK_Bool: return CK_PointerToBoolean; @@ -6980,7 +6980,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, // Only under strict condition T^ is compatible with an Objective-C pointer. if (RHSType->isBlockPointerType() && LHSType->isBlockCompatibleObjCPointerType(Context)) { - maybeExtendBlockObject(*this, RHS); + maybeExtendBlockObject(RHS); Kind = CK_BlockPointerToObjCPointerCast; return Compatible; } @@ -8189,9 +8189,6 @@ static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) { // Get the LHS object's interface type. QualType InterfaceType = Type->getPointeeType(); - if (const ObjCObjectType *iQFaceTy = - InterfaceType->getAsObjCQualifiedInterfaceType()) - InterfaceType = iQFaceTy->getBaseType(); // If the RHS isn't an Objective-C object, bail out. if (!RHS->getType()->isObjCObjectPointerType()) diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index e421349338b..a9f1919e18a 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1378,7 +1378,8 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, } ObjCIvarRefExpr *Result = new (S.Context) ObjCIvarRefExpr( - IV, IV->getType(), MemberLoc, OpLoc, BaseExpr.get(), IsArrow); + IV, IV->getUsageType(BaseType), MemberLoc, OpLoc, BaseExpr.get(), + IsArrow); if (S.getLangOpts().ObjCAutoRefCount) { if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 7280f588c8b..51ab68a8ab1 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -1281,7 +1281,7 @@ static QualType getBaseMessageSendResultType(Sema &S, bool isSuperMessage) { assert(Method && "Must have a method"); if (!Method->hasRelatedResultType()) - return Method->getSendResultType(); + return Method->getSendResultType(ReceiverType); ASTContext &Context = S.Context; @@ -1289,7 +1289,8 @@ static QualType getBaseMessageSendResultType(Sema &S, // result type to the returned result. auto transferNullability = [&](QualType type) -> QualType { // If the method's result type has nullability, extract it. - if (auto nullability = Method->getSendResultType()->getNullability(Context)){ + if (auto nullability = Method->getSendResultType(ReceiverType) + ->getNullability(Context)){ // Strip off any outer nullability sugar from the provided type. (void)AttributedType::stripOuterNullability(type); @@ -1308,7 +1309,8 @@ static QualType getBaseMessageSendResultType(Sema &S, // was a class message send, T is the declared return type of the method // found if (Method->isInstanceMethod() && isClassMessage) - return stripObjCInstanceType(Context, Method->getSendResultType()); + return stripObjCInstanceType(Context, + Method->getSendResultType(ReceiverType)); // - if the receiver is super, T is a pointer to the class of the // enclosing method definition @@ -1322,14 +1324,14 @@ static QualType getBaseMessageSendResultType(Sema &S, } // - if the receiver is the name of a class U, T is a pointer to U - if (ReceiverType->getAs<ObjCInterfaceType>() || - ReceiverType->isObjCQualifiedInterfaceType()) + if (ReceiverType->getAsObjCInterfaceType()) return transferNullability(Context.getObjCObjectPointerType(ReceiverType)); // - if the receiver is of type Class or qualified Class type, // T is the declared return type of the method. if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) - return stripObjCInstanceType(Context, Method->getSendResultType()); + return stripObjCInstanceType(Context, + Method->getSendResultType(ReceiverType)); // - if the receiver is id, qualified id, Class, or qualified Class, T // is the receiver type, otherwise @@ -1592,6 +1594,10 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, return false; } + // Compute the set of type arguments to be substituted into each parameter + // type. + Optional<ArrayRef<QualType>> typeArgs + = ReceiverType->getObjCSubstitutions(Method->getDeclContext()); bool IsError = false; for (unsigned i = 0; i < NumNamedArgs; i++) { // We can't do any type-checking on a type-dependent argument. @@ -1625,18 +1631,37 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, continue; } + QualType origParamType = param->getType(); + QualType paramType = param->getType(); + if (typeArgs) + paramType = paramType.substObjCTypeArgs( + Context, + *typeArgs, + ObjCSubstitutionContext::Parameter); + if (RequireCompleteType(argExpr->getSourceRange().getBegin(), - param->getType(), + paramType, diag::err_call_incomplete_argument, argExpr)) return true; - InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, - param); + InitializedEntity Entity + = InitializedEntity::InitializeParameter(Context, param, paramType); ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), argExpr); if (ArgE.isInvalid()) IsError = true; - else + else { Args[i] = ArgE.getAs<Expr>(); + + // If we are type-erasing a block to a block-compatible + // Objective-C pointer type, we may need to extend the lifetime + // of the block object. + if (typeArgs && Args[i]->isRValue() && paramType->isBlockPointerType() && + origParamType->isBlockCompatibleObjCPointerType(Context)) { + ExprResult arg = Args[i]; + maybeExtendBlockObject(arg); + Args[i] = arg.get(); + } + } } // Promote additional arguments to variadic methods. @@ -1904,27 +1929,24 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr, receiverNameLoc); - bool IsSuper = false; + QualType SuperType; if (!IFace) { // If the "receiver" is 'super' in a method, handle it as an expression-like // property reference. if (receiverNamePtr->isStr("super")) { - IsSuper = true; - if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf(receiverNameLoc)) { - if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) { + if (auto classDecl = CurMethod->getClassInterface()) { + SuperType = QualType(classDecl->getSuperClassType(), 0); if (CurMethod->isInstanceMethod()) { - ObjCInterfaceDecl *Super = Class->getSuperClass(); - if (!Super) { + if (SuperType.isNull()) { // The current class does not have a superclass. Diag(receiverNameLoc, diag::error_root_class_cannot_use_super) - << Class->getIdentifier(); + << CurMethod->getClassInterface()->getIdentifier(); return ExprError(); } - QualType T = Context.getObjCInterfaceType(Super); - T = Context.getObjCObjectPointerType(T); + QualType T = Context.getObjCObjectPointerType(SuperType); - return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(), + return HandleExprPropertyRefExpr(T->castAs<ObjCObjectPointerType>(), /*BaseExpr*/nullptr, SourceLocation()/*OpLoc*/, &propertyName, @@ -1934,7 +1956,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, // Otherwise, if this is a class method, try dispatching to our // superclass. - IFace = Class->getSuperClass(); + IFace = CurMethod->getClassInterface()->getSuperClass(); } } } @@ -1964,7 +1986,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, // Look for the matching setter, in case it is needed. Selector SetterSel = SelectorTable::constructSetterSelector(PP.getIdentifierTable(), - PP.getSelectorTable(), + PP.getSelectorTable(), &propertyName); ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); @@ -1981,11 +2003,11 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, return ExprError(); if (Getter || Setter) { - if (IsSuper) + if (!SuperType.isNull()) return new (Context) ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty, propertyNameLoc, receiverNameLoc, - Context.getObjCInterfaceType(IFace)); + SuperType); return new (Context) ObjCPropertyRefExpr( Getter, Setter, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty, @@ -2132,8 +2154,8 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, return ExprError(); } - ObjCInterfaceDecl *Super = Class->getSuperClass(); - if (!Super) { + QualType SuperTy(Class->getSuperClassType(), 0); + if (SuperTy.isNull()) { // The current class does not have a superclass. Diag(SuperLoc, diag::error_root_class_cannot_use_super) << Class->getIdentifier(); @@ -2148,7 +2170,6 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, if (Method->isInstanceMethod()) { // Since we are in an instance method, this is an instance // message to the superclass instance. - QualType SuperTy = Context.getObjCInterfaceType(Super); SuperTy = Context.getObjCObjectPointerType(SuperTy); return BuildInstanceMessage(nullptr, SuperTy, SuperLoc, Sel, /*Method=*/nullptr, @@ -2158,7 +2179,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, // Since we are in a class method, this is a class message to // the superclass. return BuildClassMessage(/*ReceiverTypeInfo=*/nullptr, - Context.getObjCInterfaceType(Super), + SuperTy, SuperLoc, Sel, /*Method=*/nullptr, LBracLoc, SelectorLocs, RBracLoc, Args); } diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 0f88abcdf9e..f139c83c734 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -1157,7 +1157,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, CK_LValueToRValue, SelfExpr, nullptr, VK_RValue); Expr *IvarRefExpr = - new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc, + new (Context) ObjCIvarRefExpr(Ivar, + Ivar->getUsageType(SelfDecl->getType()), + PropertyDiagLoc, Ivar->getLocation(), LoadSelfExpr, true, true); ExprResult Res = PerformCopyInitialization( @@ -1207,7 +1209,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, CK_LValueToRValue, SelfExpr, nullptr, VK_RValue); Expr *lhs = - new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc, + new (Context) ObjCIvarRefExpr(Ivar, + Ivar->getUsageType(SelfDecl->getType()), + PropertyDiagLoc, Ivar->getLocation(), LoadSelfExpr, true, true); ObjCMethodDecl::param_iterator P = setterMethod->param_begin(); diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index 3e465af9632..fec97488f53 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -689,15 +689,7 @@ ExprResult ObjCPropertyOpBuilder::buildGet() { if (SyntacticRefExpr) SyntacticRefExpr->setIsMessagingGetter(); - QualType receiverType; - if (RefExpr->isClassReceiver()) { - receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver()); - } else if (RefExpr->isSuperReceiver()) { - receiverType = RefExpr->getSuperReceiverType(); - } else { - assert(InstanceReceiver); - receiverType = InstanceReceiver->getType(); - } + QualType receiverType = RefExpr->getReceiverType(S.Context); if (!Getter->isImplicit()) S.DiagnoseUseOfDecl(Getter, GenericLoc, nullptr, true); // Build a message-send. @@ -730,21 +722,17 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, if (SyntacticRefExpr) SyntacticRefExpr->setIsMessagingSetter(); - QualType receiverType; - if (RefExpr->isClassReceiver()) { - receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver()); - } else if (RefExpr->isSuperReceiver()) { - receiverType = RefExpr->getSuperReceiverType(); - } else { - assert(InstanceReceiver); - receiverType = InstanceReceiver->getType(); - } + QualType receiverType = RefExpr->getReceiverType(S.Context); // Use assignment constraints when possible; they give us better // diagnostics. "When possible" basically means anything except a // C++ class type. if (!S.getLangOpts().CPlusPlus || !op->getType()->isRecordType()) { - QualType paramType = (*Setter->param_begin())->getType(); + QualType paramType = (*Setter->param_begin())->getType() + .substObjCMemberType( + receiverType, + Setter->getDeclContext(), + ObjCSubstitutionContext::Parameter); if (!S.getLangOpts().CPlusPlus || !paramType->isRecordType()) { ExprResult opResult = op; Sema::AssignConvertType assignResult @@ -819,7 +807,9 @@ ExprResult ObjCPropertyOpBuilder::buildRValueOperation(Expr *op) { // As a special case, if the method returns 'id', try to get // a better type from the property. if (RefExpr->isExplicitProperty() && result.get()->isRValue()) { - QualType propType = RefExpr->getExplicitProperty()->getType(); + QualType receiverType = RefExpr->getReceiverType(S.Context); + QualType propType = RefExpr->getExplicitProperty() + ->getUsageType(receiverType); if (result.get()->getType()->isObjCIdType()) { if (const ObjCObjectPointerType *ptr = propType->getAs<ObjCObjectPointerType>()) { @@ -1119,9 +1109,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { if (const ObjCObjectPointerType *PTy = BaseT->getAs<ObjCObjectPointerType>()) { ResultType = PTy->getPointeeType(); - if (const ObjCObjectType *iQFaceTy = - ResultType->getAsObjCQualifiedInterfaceType()) - ResultType = iQFaceTy->getBaseType(); } Sema::ObjCSubscriptKind Res = S.CheckSubscriptingKind(RefExpr->getKeyExpr()); @@ -1228,9 +1215,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { if (const ObjCObjectPointerType *PTy = BaseT->getAs<ObjCObjectPointerType>()) { ResultType = PTy->getPointeeType(); - if (const ObjCObjectType *iQFaceTy = - ResultType->getAsObjCQualifiedInterfaceType()) - ResultType = iQFaceTy->getBaseType(); } Sema::ObjCSubscriptKind Res = diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 9170ac760d4..1257ae361f0 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -786,6 +786,19 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, for (unsigned i = 0, n = typeArgs.size(); i != n; ++i) { TypeSourceInfo *typeArgInfo = nullptr; QualType typeArg = S.GetTypeFromParser(typeArgs[i], &typeArgInfo); + + // Type arguments cannot explicitly specify nullability. + if (auto nullability = AttributedType::stripOuterNullability(typeArg)) { + SourceLocation nullabilityLoc + = typeArgInfo->getTypeLoc().findNullabilityLoc(); + SourceLocation diagLoc = nullabilityLoc.isValid()? nullabilityLoc + : typeArgInfo->getTypeLoc().getLocStart(); + S.Diag(diagLoc, + diag::err_type_arg_explicit_nullability) + << typeArg + << FixItHint::CreateRemoval(nullabilityLoc); + } + finalTypeArgs.push_back(typeArg); // Objective-C object pointer types must be substitutable for the bounds. @@ -3257,7 +3270,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case CAMN_Yes: checkNullabilityConsistency(state, pointerKind, pointerLoc); } - return nullptr; }; diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 69d173d3c85..c54c5697e59 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -904,6 +904,7 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { void ASTDeclReader::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { VisitTypedefNameDecl(D); + D->Index = Record[Idx++]; D->ColonLoc = ReadSourceLocation(Record, Idx); } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index dd56de38419..f54bc5f491e 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -421,8 +421,8 @@ 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()) + Record.push_back(T->getTypeArgsAsWritten().size()); + for (auto TypeArg : T->getTypeArgsAsWritten()) Writer.AddTypeRef(TypeArg, Record); Record.push_back(T->getNumProtocols()); for (const auto *I : T->quals()) diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 00f8daa676e..4d3fb78b080 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -581,6 +581,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { void ASTDeclWriter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { VisitTypedefNameDecl(D); + Record.push_back(D->Index); Writer.AddSourceLocation(D->ColonLoc, Record); Code = serialization::DECL_OBJC_TYPE_PARAM; |