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