summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ASTContext.cpp61
-rw-r--r--clang/lib/AST/ASTImporter.cpp3
-rw-r--r--clang/lib/AST/DeclObjC.cpp30
-rw-r--r--clang/lib/AST/Expr.cpp10
-rw-r--r--clang/lib/AST/Type.cpp775
-rw-r--r--clang/lib/AST/TypeLoc.cpp11
-rw-r--r--clang/lib/CodeGen/CGObjC.cpp34
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h26
-rw-r--r--clang/lib/Parse/ParseDecl.cpp32
-rw-r--r--clang/lib/Parse/ParseInit.cpp25
-rw-r--r--clang/lib/Parse/ParseObjc.cpp54
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp25
-rw-r--r--clang/lib/Sema/SemaExpr.cpp21
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp3
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp77
-rw-r--r--clang/lib/Sema/SemaObjCProperty.cpp8
-rw-r--r--clang/lib/Sema/SemaPseudoObject.cpp36
-rw-r--r--clang/lib/Sema/SemaType.cpp14
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp1
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp4
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp1
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;
OpenPOWER on IntegriCloud