Index: cfe/trunk/include/clang/AST/ASTContext.h =================================================================== --- cfe/trunk/include/clang/AST/ASTContext.h +++ cfe/trunk/include/clang/AST/ASTContext.h @@ -1030,6 +1030,14 @@ /// replaced. QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace) const; + /// \brief Apply Objective-C protocol qualifiers to the given type. + /// \param allowOnPointerType specifies if we can apply protocol + /// qualifiers on ObjCObjectPointerType. It can be set to true when + /// contructing the canonical type of a Objective-C type parameter. + QualType applyObjCProtocolQualifiers(QualType type, + ArrayRef protocols, bool &hasError, + bool allowOnPointerType = false) const; + /// \brief Return the uniqued reference to the type for an Objective-C /// gc-qualified type. /// Index: cfe/trunk/lib/AST/ASTContext.cpp =================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp +++ cfe/trunk/lib/AST/ASTContext.cpp @@ -3871,6 +3871,76 @@ return QualType(T, 0); } +/// Apply Objective-C protocol qualifiers to the given type. +/// If this is for the canonical type of a type parameter, we can apply +/// protocol qualifiers on the ObjCObjectPointerType. +QualType +ASTContext::applyObjCProtocolQualifiers(QualType type, + ArrayRef protocols, bool &hasError, + bool allowOnPointerType) const { + hasError = false; + + // Apply protocol qualifiers to ObjCObjectPointerType. + if (allowOnPointerType) { + if (const ObjCObjectPointerType *objPtr = + dyn_cast(type.getTypePtr())) { + const ObjCObjectType *objT = objPtr->getObjectType(); + // Merge protocol lists and construct ObjCObjectType. + SmallVector protocolsVec; + protocolsVec.append(objT->qual_begin(), + objT->qual_end()); + protocolsVec.append(protocols.begin(), protocols.end()); + ArrayRef protocols = protocolsVec; + type = getObjCObjectType( + objT->getBaseType(), + objT->getTypeArgsAsWritten(), + protocols, + objT->isKindOfTypeAsWritten()); + return getObjCObjectPointerType(type); + } + } + + // Apply protocol qualifiers to ObjCObjectType. + if (const ObjCObjectType *objT = dyn_cast(type.getTypePtr())){ + // FIXME: Check for protocols to which the class type is already + // known to conform. + + return getObjCObjectType(objT->getBaseType(), + objT->getTypeArgsAsWritten(), + protocols, + objT->isKindOfTypeAsWritten()); + } + + // If the canonical type is ObjCObjectType, ... + 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 getObjCObjectType(type, { }, protocols, false); + } + + // id + if (type->isObjCIdType()) { + const ObjCObjectPointerType *objPtr = type->castAs(); + type = getObjCObjectType(ObjCBuiltinIdTy, { }, protocols, + objPtr->isKindOfType()); + return getObjCObjectPointerType(type); + } + + // Class + if (type->isObjCClassType()) { + const ObjCObjectPointerType *objPtr = type->castAs(); + type = getObjCObjectType(ObjCBuiltinClassTy, { }, protocols, + objPtr->isKindOfType()); + return getObjCObjectPointerType(type); + } + + hasError = true; + return type; +} + /// ObjCObjectAdoptsQTypeProtocols - Checks that protocols in IC's /// protocol list adopt all protocols in QT's qualified-id protocol /// list. Index: cfe/trunk/lib/Sema/SemaType.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp +++ cfe/trunk/lib/Sema/SemaType.cpp @@ -1000,57 +1000,6 @@ return S.Context.getObjCObjectType(type, finalTypeArgs, { }, false); } -/// Apply Objective-C protocol qualifiers to the given type. -static QualType applyObjCProtocolQualifiers( - Sema &S, SourceLocation loc, SourceRange range, QualType type, - ArrayRef protocols, - const SourceLocation *protocolLocs, - bool failOnError = false) { - ASTContext &ctx = S.Context; - if (const ObjCObjectType *objT = dyn_cast(type.getTypePtr())){ - // FIXME: Check for protocols to which the class type is already - // known to conform. - - return ctx.getObjCObjectType(objT->getBaseType(), - objT->getTypeArgsAsWritten(), - protocols, - objT->isKindOfTypeAsWritten()); - } - - 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, false); - } - - // id - if (type->isObjCIdType()) { - const ObjCObjectPointerType *objPtr = type->castAs(); - type = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, protocols, - objPtr->isKindOfType()); - return ctx.getObjCObjectPointerType(type); - } - - // Class - if (type->isObjCClassType()) { - const ObjCObjectPointerType *objPtr = type->castAs(); - type = ctx.getObjCObjectType(ctx.ObjCBuiltinClassTy, { }, protocols, - objPtr->isKindOfType()); - return ctx.getObjCObjectPointerType(type); - } - - S.Diag(loc, diag::err_invalid_protocol_qualifiers) - << range; - - if (failOnError) - return QualType(); - - return type; -} - QualType Sema::BuildObjCObjectType(QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc, @@ -1072,12 +1021,14 @@ } if (!Protocols.empty()) { - Result = applyObjCProtocolQualifiers(*this, Loc, - SourceRange(ProtocolLAngleLoc, - ProtocolRAngleLoc), - Result, Protocols, - ProtocolLocs.data(), - FailOnError); + bool HasError; + Result = Context.applyObjCProtocolQualifiers(Result, Protocols, + HasError); + if (HasError) { + Diag(Loc, diag::err_invalid_protocol_qualifiers) + << SourceRange(ProtocolLAngleLoc, ProtocolRAngleLoc); + if (FailOnError) Result = QualType(); + } if (FailOnError && Result.isNull()) return QualType(); }