C++ support for Objective-C lightweight generics.

Teach C++'s tentative parsing to handle specializations of Objective-C
class types (e.g., NSArray<NSString *>) as well as Objective-C
protocol qualifiers (id<NSCopying>) by extending type-annotation
tokens to handle this case. As part of this, remove Objective-C
protocol qualifiers from the declaration specifiers, which never
really made sense: instead, provide Sema entry points to make them
part of the type annotation token. Among other things, this properly
diagnoses bogus types such as "<NSCopying> id" which should have been
written as "id <NSCopying>".

Implements template instantiation support for, e.g., NSArray<T>*
in C++. Note that parameterized classes are not templates in the C++
sense, so that cannot (for example) be used as a template argument for
a template template parameter. Part of rdar://problem/6294649.

llvm-svn: 241545
This commit is contained in:
Douglas Gregor 2015-07-07 03:58:14 +00:00
parent c5e07f5c11
commit 9bda6cff20
26 changed files with 1374 additions and 362 deletions

View File

@ -4730,7 +4730,11 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
QualType PointeeType;
ObjCObjectPointerType(QualType Canonical, QualType Pointee)
: Type(ObjCObjectPointer, Canonical, false, false, false, false),
: Type(ObjCObjectPointer, Canonical,
Pointee->isDependentType(),
Pointee->isInstantiationDependentType(),
Pointee->isVariablyModifiedType(),
Pointee->containsUnexpandedParameterPack()),
PointeeType(Pointee) {}
friend class ASTContext; // ASTContext creates these.

View File

@ -177,6 +177,9 @@ public:
memcpy(getOpaqueData(), Other.getOpaqueData(), Size);
}
/// Copies the other type loc into this one.
void copy(TypeLoc other);
friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) {
return LHS.Ty == RHS.Ty && LHS.Data == RHS.Data;
}
@ -253,6 +256,10 @@ public:
// do nothing
}
void copyLocal(TypeLoc other) {
// do nothing
}
TypeLoc getNextTypeLoc() const {
return getUnqualifiedLoc();
}
@ -343,6 +350,20 @@ public:
return size;
}
void copyLocal(Derived other) {
// Some subclasses have no data to copy.
if (asDerived()->getLocalDataSize() == 0) return;
// Copy the fixed-sized local data.
memcpy(getLocalData(), other.getLocalData(), sizeof(LocalData));
// Copy the variable-sized local data. We need to do this
// separately because the padding in the source and the padding in
// the destination might be different.
memcpy(getExtraLocalData(), other.getExtraLocalData(),
asDerived()->getExtraLocalDataSize());
}
TypeLoc getNextTypeLoc() const {
return getNextTypeLoc(asDerived()->getInnerType());
}
@ -892,6 +913,11 @@ public:
return *(this->getTypePtr()->qual_begin() + i);
}
ArrayRef<SourceLocation> getProtocolLocs() const {
return llvm::makeArrayRef(getProtocolLocArray(), getNumProtocols());
}
bool hasBaseTypeAsWritten() const {
return getLocalData()->HasBaseTypeAsWritten;
}

View File

@ -7817,6 +7817,6 @@ def err_objc_type_arg_not_id_compatible : Error<
"type argument %0 is neither an Objective-C object nor a block type">;
def err_objc_type_arg_does_not_match_bound : Error<
"type argument %0 does not satisy the bound (%1) of type parameter %2">;
"type argument %0 does not satisfy the bound (%1) of type parameter %2">;
} // end of sema component.

View File

@ -1267,19 +1267,45 @@ private:
bool WarnOnDeclarations,
bool ForObjCContainer,
SourceLocation &LAngleLoc,
SourceLocation &EndProtoLoc);
bool ParseObjCProtocolQualifiers(DeclSpec &DS);
void ParseObjCTypeArgsOrProtocolQualifiers(DeclSpec &DS,
bool warnOnIncompleteProtocols);
SourceLocation &EndProtoLoc,
bool consumeLastToken);
/// Parse the first angle-bracket-delimited clause for an
/// Objective-C object or object pointer type, which may be either
/// type arguments or protocol qualifiers.
void parseObjCTypeArgsOrProtocolQualifiers(
SourceLocation &typeArgsLAngleLoc,
SmallVectorImpl<ParsedType> &typeArgs,
SourceLocation &typeArgsRAngleLoc,
SourceLocation &protocolLAngleLoc,
SmallVectorImpl<Decl *> &protocols,
SmallVectorImpl<SourceLocation> &protocolLocs,
SourceLocation &protocolRAngleLoc,
bool consumeLastToken,
bool warnOnIncompleteProtocols);
/// Parse either Objective-C type arguments or protocol qualifiers; if the
/// former, also parse protocol qualifiers afterward.
void ParseObjCTypeArgsAndProtocolQualifiers(DeclSpec &DS);
void parseObjCTypeArgsAndProtocolQualifiers(
SourceLocation &typeArgsLAngleLoc,
SmallVectorImpl<ParsedType> &typeArgs,
SourceLocation &typeArgsRAngleLoc,
SourceLocation &protocolLAngleLoc,
SmallVectorImpl<Decl *> &protocols,
SmallVectorImpl<SourceLocation> &protocolLocs,
SourceLocation &protocolRAngleLoc,
bool consumeLastToken);
/// Parse a protocol qualifier type such as '<NSCopying>', which is
/// an anachronistic way of writing 'id<NSCopying>'.
TypeResult parseObjCProtocolQualifierType(SourceLocation &rAngleLoc);
/// Parse Objective-C type arguments and protocol qualifiers, extending the
/// current type with the parsed result.
TypeResult ParseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,
ParsedType type);
TypeResult parseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,
ParsedType type,
bool consumeLastToken,
SourceLocation &endLoc);
void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
Decl *CDecl);

View File

@ -373,22 +373,6 @@ private:
// Scope specifier for the type spec, if applicable.
CXXScopeSpec TypeScope;
/// List of Objective-C type arguments, e.g., in \c NSArray<NSView *>.
ArrayRef<ParsedType> ObjCTypeArgs;
/// Location of the '<' that starts a list of Objective-C type arguments.
SourceLocation ObjCTypeArgsLAngleLoc;
/// Location of the '>' that ends a list of Objective-C type arguments.
SourceLocation ObjCTypeArgsRAngleLoc;
// List of protocol qualifiers for objective-c classes. Used for
// protocol-qualified interfaces "NString<foo>" and protocol-qualified id
// "id<foo>".
Decl * const *ProtocolQualifiers;
unsigned NumProtocolQualifiers;
SourceLocation ProtocolLAngleLoc;
SourceLocation *ProtocolLocs;
// SourceLocation info. These are null if the item wasn't specified or if
// the setting was synthesized.
SourceRange Range;
@ -450,17 +434,10 @@ public:
Constexpr_specified(false),
Concept_specified(false),
Attrs(attrFactory),
ProtocolQualifiers(nullptr),
NumProtocolQualifiers(0),
ProtocolLocs(nullptr),
writtenBS(),
ObjCQualifiers(nullptr) {
}
~DeclSpec() {
delete [] ObjCTypeArgs.data();
delete [] ProtocolQualifiers;
delete [] ProtocolLocs;
}
// storage-class-specifier
SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
TSCS getThreadStorageClassSpec() const {
@ -499,6 +476,8 @@ public:
bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; }
bool isTypeAltiVecBool() const { return TypeAltiVecBool; }
bool isTypeSpecOwned() const { return TypeSpecOwned; }
bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); }
ParsedType getRepAsType() const {
assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");
return TypeRep;
@ -760,38 +739,6 @@ public:
Attrs.takeAllFrom(attrs);
}
/// Determine whether the declaration specifiers contain Objective-C
/// type arguments.
bool hasObjCTypeArgs() const { return !ObjCTypeArgs.empty(); }
ArrayRef<ParsedType> getObjCTypeArgs() const { return ObjCTypeArgs; }
SourceLocation getObjCTypeArgsLAngleLoc() const {
return ObjCTypeArgsLAngleLoc;
}
SourceLocation getObjCTypeArgsRAngleLoc() const {
return ObjCTypeArgsRAngleLoc;
}
SourceRange getObjCTypeArgsRange() const {
return SourceRange(ObjCTypeArgsLAngleLoc, ObjCTypeArgsRAngleLoc);
}
void setObjCTypeArgs(SourceLocation lAngleLoc,
ArrayRef<ParsedType> args,
SourceLocation rAngleLoc);
typedef Decl * const *ProtocolQualifierListTy;
ProtocolQualifierListTy getProtocolQualifiers() const {
return ProtocolQualifiers;
}
SourceLocation *getProtocolLocs() const { return ProtocolLocs; }
unsigned getNumProtocolQualifiers() const {
return NumProtocolQualifiers;
}
SourceLocation getProtocolLAngleLoc() const { return ProtocolLAngleLoc; }
void setProtocolQualifiers(Decl * const *Protos, unsigned NP,
SourceLocation *ProtoLocs,
SourceLocation LAngleLoc);
/// Finish - This does final analysis of the declspec, issuing diagnostics for
/// things like "_Imaginary" (lacking an FP type). After calling this method,
/// DeclSpec is guaranteed self-consistent, even if an error occurred.

View File

@ -7191,17 +7191,54 @@ public:
/// Given a list of identifiers (and their locations), resolve the
/// names to either Objective-C protocol qualifiers or type
/// arguments, as appropriate. The result will be attached to the
/// given declaration specifiers.
/// arguments, as appropriate.
void actOnObjCTypeArgsOrProtocolQualifiers(
Scope *S,
DeclSpec &DS,
SourceLocation lAngleLoc,
ArrayRef<IdentifierInfo *> identifiers,
ArrayRef<SourceLocation> identifierLocs,
SourceLocation rAngleLoc,
SourceLocation &typeArgsLAngleLoc,
SmallVectorImpl<ParsedType> &typeArgs,
SourceLocation &typeArgsRAngleLoc,
SourceLocation &protocolLAngleLoc,
SmallVectorImpl<Decl *> &protocols,
SourceLocation &protocolRAngleLoc,
bool warnOnIncompleteProtocols);
/// Build a an Objective-C protocol-qualified 'id' type where no
/// base type was specified.
TypeResult actOnObjCProtocolQualifierType(
SourceLocation lAngleLoc,
ArrayRef<Decl *> protocols,
ArrayRef<SourceLocation> protocolLocs,
SourceLocation rAngleLoc);
/// Build a specialized and/or protocol-qualified Objective-C type.
TypeResult actOnObjCTypeArgsAndProtocolQualifiers(
Scope *S,
SourceLocation Loc,
ParsedType BaseType,
SourceLocation TypeArgsLAngleLoc,
ArrayRef<ParsedType> TypeArgs,
SourceLocation TypeArgsRAngleLoc,
SourceLocation ProtocolLAngleLoc,
ArrayRef<Decl *> Protocols,
ArrayRef<SourceLocation> ProtocolLocs,
SourceLocation ProtocolRAngleLoc);
/// Build an Objective-C object pointer type.
QualType BuildObjCObjectType(QualType BaseType,
SourceLocation Loc,
SourceLocation TypeArgsLAngleLoc,
ArrayRef<TypeSourceInfo *> TypeArgs,
SourceLocation TypeArgsRAngleLoc,
SourceLocation ProtocolLAngleLoc,
ArrayRef<ObjCProtocolDecl *> Protocols,
ArrayRef<SourceLocation> ProtocolLocs,
SourceLocation ProtocolRAngleLoc,
bool FailOnError = false);
/// Ensure attributes are consistent with type.
/// \param [in, out] Attributes The attributes to check; they will
/// be modified to be consistent with \p PropertyTy.

View File

@ -469,7 +469,10 @@ const RecordType *Type::getAsUnionType() const {
ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
ArrayRef<QualType> typeArgs,
ArrayRef<ObjCProtocolDecl *> protocols)
: Type(ObjCObject, Canonical, false, false, false, false),
: Type(ObjCObject, Canonical, Base->isDependentType(),
Base->isInstantiationDependentType(),
Base->isVariablyModifiedType(),
Base->containsUnexpandedParameterPack()),
BaseType(Base)
{
ObjCObjectTypeBits.NumTypeArgs = typeArgs.size();
@ -484,6 +487,16 @@ ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
if (!protocols.empty())
memcpy(getProtocolStorage(), protocols.data(),
protocols.size() * sizeof(ObjCProtocolDecl*));
for (auto typeArg : typeArgs) {
if (typeArg->isDependentType())
setDependent();
else if (typeArg->isInstantiationDependentType())
setInstantiationDependent();
if (typeArg->containsUnexpandedParameterPack())
setContainsUnexpandedParameterPack();
}
}
bool ObjCObjectType::isSpecialized() const {

View File

@ -19,6 +19,8 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
static const unsigned TypeLocMaxDataAlign = llvm::alignOf<void *>();
//===----------------------------------------------------------------------===//
// TypeLoc Implementation
//===----------------------------------------------------------------------===//
@ -125,6 +127,46 @@ void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL,
}
}
namespace {
class TypeLocCopier : public TypeLocVisitor<TypeLocCopier> {
TypeLoc Source;
public:
TypeLocCopier(TypeLoc source) : Source(source) { }
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
void Visit##CLASS##TypeLoc(CLASS##TypeLoc dest) { \
dest.copyLocal(Source.castAs<CLASS##TypeLoc>()); \
}
#include "clang/AST/TypeLocNodes.def"
};
}
void TypeLoc::copy(TypeLoc other) {
assert(getFullDataSize() == other.getFullDataSize());
// If both data pointers are aligned to the maximum alignment, we
// can memcpy because getFullDataSize() accurately reflects the
// layout of the data.
if (reinterpret_cast<uintptr_t>(Data)
== llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(Data),
TypeLocMaxDataAlign) &&
reinterpret_cast<uintptr_t>(other.Data)
== llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(other.Data),
TypeLocMaxDataAlign)) {
memcpy(Data, other.Data, getFullDataSize());
return;
}
// Copy each of the pieces.
TypeLoc TL(getType(), Data);
do {
TypeLocCopier(other).Visit(TL);
other = other.getNextTypeLoc();
} while ((TL = TL.getNextTypeLoc()));
}
SourceLocation TypeLoc::getBeginLoc() const {
TypeLoc Cur = *this;
TypeLoc LeftMost = Cur;

View File

@ -1106,6 +1106,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("arc_cf_code_audited", true)
.Case("objc_bridge_id", true)
.Case("objc_bridge_id_on_typedefs", true)
.Case("objc_generics", LangOpts.ObjC2)
// C11 features
.Case("c_alignas", LangOpts.C11)
.Case("c_alignof", LangOpts.C11)

View File

@ -2144,8 +2144,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
if (isTypeSpecifier(DSC) && !DS.hasTypeSpecifier()) {
Diag(Tok, diag::err_expected_type);
DS.SetTypeSpecError();
} else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() &&
!DS.hasAttributes()) {
} else if (Specs == DeclSpec::PQ_None && !DS.hasAttributes()) {
Diag(Tok, diag::err_typename_requires_specqual);
if (!DS.hasTypeSpecifier())
DS.SetTypeSpecError();
@ -2886,13 +2885,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
ConsumeToken(); // The typename
// 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) {
ParseObjCTypeArgsAndProtocolQualifiers(DS);
}
continue;
}
@ -2999,10 +2991,17 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ConsumeToken(); // The identifier
// Objective-C supports type arguments and protocol references
// following an Objective-C object pointer type. Handle either
// one of them.
// following an Objective-C object or object pointer
// type. Handle either one of them.
if (Tok.is(tok::less) && getLangOpts().ObjC1) {
ParseObjCTypeArgsAndProtocolQualifiers(DS);
SourceLocation NewEndLoc;
TypeResult NewTypeRep = parseObjCTypeArgsAndProtocolQualifiers(
Loc, TypeRep, /*consumeLastToken=*/true,
NewEndLoc);
if (NewTypeRep.isUsable()) {
DS.UpdateTypeRep(NewTypeRep.get());
DS.SetRangeEnd(NewEndLoc);
}
}
// Need to support trailing type qualifiers (e.g. "id<p> const").
@ -3420,10 +3419,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (DS.hasTypeSpecifier() || !getLangOpts().ObjC1)
goto DoneWithDeclSpec;
if (!ParseObjCProtocolQualifiers(DS))
Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id)
<< FixItHint::CreateInsertion(Loc, "id")
<< SourceRange(Loc, DS.getSourceRange().getEnd());
SourceLocation StartLoc = Tok.getLocation();
SourceLocation EndLoc;
TypeResult Type = parseObjCProtocolQualifierType(EndLoc);
if (Type.isUsable()) {
if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, StartLoc,
PrevSpec, DiagID, Type.get(),
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
DS.SetRangeEnd(EndLoc);
} else {
DS.SetTypeSpecError();
}
// Need to support trailing type qualifiers (e.g. "id<p> const").
// If a type specifier follows, it will be diagnosed elsewhere.

View File

@ -1805,13 +1805,6 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
ConsumeToken();
// 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 we don't have Objective-C or a '<', this is
// just a normal reference to a typedef name.
if (Tok.is(tok::less) && getLangOpts().ObjC1)
ParseObjCProtocolQualifiers(DS);
DS.Finish(Diags, PP, Policy);
return;
}

View File

@ -274,8 +274,11 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
// Parse type arguments and protocol qualifiers.
if (Tok.is(tok::less)) {
SourceLocation NewEndLoc;
TypeResult NewReceiverType
= ParseObjCTypeArgsAndProtocolQualifiers(IILoc, ReceiverType);
= parseObjCTypeArgsAndProtocolQualifiers(IILoc, ReceiverType,
/*consumeLastToken=*/true,
NewEndLoc);
if (!NewReceiverType.isUsable()) {
SkipUntil(tok::r_square, StopAtSemi);
return ExprError();

View File

@ -267,7 +267,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
LAngleLoc, EndProtoLoc))
LAngleLoc, EndProtoLoc,
/*consumeLastToken=*/true))
return nullptr;
Decl *CategoryType =
@ -293,8 +294,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
// Parse a class interface.
IdentifierInfo *superClassId = nullptr;
SourceLocation superClassLoc;
DeclSpec superClassDS(AttrFactory);
SourceLocation typeArgsLAngleLoc;
SmallVector<ParsedType, 4> typeArgs;
SourceLocation typeArgsRAngleLoc;
SmallVector<Decl *, 4> protocols;
SmallVector<SourceLocation, 4> protocolLocs;
if (Tok.is(tok::colon)) { // a super class is specified.
ConsumeToken();
@ -315,51 +319,50 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
// Type arguments for the superclass or protocol conformances.
if (Tok.is(tok::less)) {
ParseObjCTypeArgsOrProtocolQualifiers(superClassDS,
parseObjCTypeArgsOrProtocolQualifiers(typeArgsLAngleLoc,
typeArgs,
typeArgsRAngleLoc,
LAngleLoc,
protocols,
protocolLocs,
EndProtoLoc,
/*consumeLastToken=*/true,
/*warnOnIncompleteProtocols=*/true);
}
}
// Next, we need to check for any protocol references.
SmallVector<Decl *, 8> ProtocolRefs;
SmallVector<SourceLocation, 8> ProtocolLocs;
if (LAngleLoc.isValid()) {
// We already parsed the protocols named when we thought we had a
// type parameter list. Translate them into actual protocol references.
for (const auto &pair : ProtocolIdents) {
ProtocolLocs.push_back(pair.second);
if (!ProtocolIdents.empty()) {
// We already parsed the protocols named when we thought we had a
// type parameter list. Translate them into actual protocol references.
for (const auto &pair : ProtocolIdents) {
protocolLocs.push_back(pair.second);
}
Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true,
/*ForObjCContainer=*/true,
&ProtocolIdents[0], ProtocolIdents.size(),
protocols);
}
Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true,
/*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)) {
} else if (protocols.empty() && Tok.is(tok::less) &&
ParseObjCProtocolReferences(protocols, protocolLocs, true, true,
LAngleLoc, EndProtoLoc,
/*consumeLastToken=*/true)) {
return nullptr;
}
if (Tok.isNot(tok::less))
Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
Actions.ActOnTypedefedProtocols(protocols, superClassId, superClassLoc);
Decl *ClsType =
Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc,
typeParameterList, superClassId,
superClassLoc,
superClassDS.getObjCTypeArgs(),
superClassDS.getObjCTypeArgsRange(),
ProtocolRefs.data(), ProtocolRefs.size(),
ProtocolLocs.data(),
typeArgs,
SourceRange(typeArgsLAngleLoc,
typeArgsRAngleLoc),
protocols.data(), protocols.size(),
protocolLocs.data(),
EndProtoLoc, attrs.getList());
if (Tok.is(tok::l_brace))
@ -1515,7 +1518,8 @@ bool Parser::
ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
SmallVectorImpl<SourceLocation> &ProtocolLocs,
bool WarnOnDeclarations, bool ForObjCContainer,
SourceLocation &LAngleLoc, SourceLocation &EndLoc) {
SourceLocation &LAngleLoc, SourceLocation &EndLoc,
bool consumeLastToken) {
assert(Tok.is(tok::less) && "expected <");
LAngleLoc = ConsumeToken(); // the "<"
@ -1545,7 +1549,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
}
// Consume the '>'.
if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true,
if (ParseGreaterThanInTemplateList(EndLoc, consumeLastToken,
/*ObjCGenericList=*/false))
return true;
@ -1556,30 +1560,43 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
return false;
}
/// \brief Parse the Objective-C protocol qualifiers that follow a typename
/// in a decl-specifier-seq, starting at the '<'.
bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) {
assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'");
assert(getLangOpts().ObjC1 && "Protocol qualifiers only exist in Objective-C");
SourceLocation LAngleLoc, EndProtoLoc;
SmallVector<Decl *, 8> ProtocolDecl;
SmallVector<SourceLocation, 8> ProtocolLocs;
bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
false, LAngleLoc, EndProtoLoc);
DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
ProtocolLocs.data(), LAngleLoc);
if (EndProtoLoc.isValid())
DS.SetRangeEnd(EndProtoLoc);
return Result;
SourceLocation lAngleLoc;
SmallVector<Decl *, 8> protocols;
SmallVector<SourceLocation, 8> protocolLocs;
(void)ParseObjCProtocolReferences(protocols, protocolLocs, false, false,
lAngleLoc, rAngleLoc,
/*consumeLastToken=*/true);
TypeResult result = Actions.actOnObjCProtocolQualifierType(lAngleLoc,
protocols,
protocolLocs,
rAngleLoc);
if (result.isUsable()) {
Diag(lAngleLoc, diag::warn_objc_protocol_qualifier_missing_id)
<< FixItHint::CreateInsertion(lAngleLoc, "id")
<< SourceRange(lAngleLoc, rAngleLoc);
}
return result;
}
/// Parse Objective-C type arguments or protocol qualifiers.
///
/// objc-type-arguments:
/// '<' type-name (',' type-name)* '>'
/// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>'
///
void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
DeclSpec &DS,
void Parser::parseObjCTypeArgsOrProtocolQualifiers(
SourceLocation &typeArgsLAngleLoc,
SmallVectorImpl<ParsedType> &typeArgs,
SourceLocation &typeArgsRAngleLoc,
SourceLocation &protocolLAngleLoc,
SmallVectorImpl<Decl *> &protocols,
SmallVectorImpl<SourceLocation> &protocolLocs,
SourceLocation &protocolRAngleLoc,
bool consumeLastToken,
bool warnOnIncompleteProtocols) {
assert(Tok.is(tok::less) && "Not at the start of type args or protocols");
SourceLocation lAngleLoc = ConsumeToken();
@ -1588,7 +1605,7 @@ void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
// identifiers, which might be types or might be protocols.
bool allSingleIdentifiers = true;
SmallVector<IdentifierInfo *, 4> identifiers;
SmallVector<SourceLocation, 4> identifierLocs;
SmallVectorImpl<SourceLocation> &identifierLocs = protocolLocs;
// Parse a list of comma-separated identifiers, bailing out if we
// see something different.
@ -1626,23 +1643,27 @@ void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
if (allSingleIdentifiers) {
// Parse the closing '>'.
SourceLocation rAngleLoc;
(void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true,
(void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken,
/*ObjCGenericList=*/true);
// Let Sema figure out what we parsed.
Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(),
DS,
lAngleLoc,
identifiers,
identifierLocs,
rAngleLoc,
typeArgsLAngleLoc,
typeArgs,
typeArgsRAngleLoc,
protocolLAngleLoc,
protocols,
protocolRAngleLoc,
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;
@ -1650,7 +1671,19 @@ void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
ParsedType typeArg
= Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope());
if (typeArg) {
typeArgs.push_back(typeArg);
DeclSpec DS(AttrFactory);
const char *prevSpec = nullptr;
unsigned diagID;
DS.SetTypeSpecType(TST_typename, identifierLocs[i], prevSpec, diagID,
typeArg, Actions.getASTContext().getPrintingPolicy());
// Form a declarator to turn this into a type.
Declarator D(DS, Declarator::TypeNameContext);
TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D);
if (fullTypeArg.isUsable())
typeArgs.push_back(fullTypeArg.get());
else
invalid = true;
} else {
invalid = true;
}
@ -1659,6 +1692,14 @@ void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
// Continue parsing type-names.
do {
TypeResult typeArg = ParseTypeName();
// Consume the '...' for a pack expansion.
SourceLocation ellipsisLoc;
TryConsumeToken(tok::ellipsis, ellipsisLoc);
if (typeArg.isUsable() && ellipsisLoc.isValid()) {
typeArg = Actions.ActOnPackExpansion(typeArg.get(), ellipsisLoc);
}
if (typeArg.isUsable()) {
typeArgs.push_back(typeArg.get());
} else {
@ -1668,53 +1709,105 @@ void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
// Parse the closing '>'.
SourceLocation rAngleLoc;
(void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true,
(void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken,
/*ObjCGenericList=*/true);
if (invalid)
if (invalid) {
typeArgs.clear();
return;
}
// Update the DeclSpec appropriately.
DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc);
// Record left/right angle locations.
typeArgsLAngleLoc = lAngleLoc;
typeArgsRAngleLoc = rAngleLoc;
}
void Parser::ParseObjCTypeArgsAndProtocolQualifiers(DeclSpec &DS) {
void Parser::parseObjCTypeArgsAndProtocolQualifiers(
SourceLocation &typeArgsLAngleLoc,
SmallVectorImpl<ParsedType> &typeArgs,
SourceLocation &typeArgsRAngleLoc,
SourceLocation &protocolLAngleLoc,
SmallVectorImpl<Decl *> &protocols,
SmallVectorImpl<SourceLocation> &protocolLocs,
SourceLocation &protocolRAngleLoc,
bool consumeLastToken) {
assert(Tok.is(tok::less));
ParseObjCTypeArgsOrProtocolQualifiers(DS,
// Parse the first angle-bracket-delimited clause.
parseObjCTypeArgsOrProtocolQualifiers(typeArgsLAngleLoc,
typeArgs,
typeArgsRAngleLoc,
protocolLAngleLoc,
protocols,
protocolLocs,
protocolRAngleLoc,
consumeLastToken,
/*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()) {
if ((consumeLastToken && Tok.is(tok::less)) ||
(!consumeLastToken && NextToken().is(tok::less))) {
// If we aren't consuming the last token, the prior '>' is still hanging
// there. Consume it before we parse the protocol qualifiers.
if (!consumeLastToken)
ConsumeToken();
if (!protocols.empty()) {
SkipUntilFlags skipFlags = SkipUntilFlags();
if (!consumeLastToken)
skipFlags = skipFlags | StopBeforeMatch;
Diag(Tok, diag::err_objc_type_args_after_protocols)
<< SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd());
SkipUntil(tok::greater, tok::greatergreater);
<< SourceRange(protocolLAngleLoc, protocolRAngleLoc);
SkipUntil(tok::greater, tok::greatergreater, skipFlags);
} else {
ParseObjCProtocolQualifiers(DS);
ParseObjCProtocolReferences(protocols, protocolLocs,
/*WarnOnDeclarations=*/false,
/*ForObjCContainer=*/false,
protocolLAngleLoc, protocolRAngleLoc,
consumeLastToken);
}
}
}
TypeResult Parser::ParseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,
ParsedType type) {
TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers(
SourceLocation loc,
ParsedType type,
bool consumeLastToken,
SourceLocation &endLoc) {
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());
SourceLocation typeArgsLAngleLoc;
SmallVector<ParsedType, 4> typeArgs;
SourceLocation typeArgsRAngleLoc;
SourceLocation protocolLAngleLoc;
SmallVector<Decl *, 4> protocols;
SmallVector<SourceLocation, 4> protocolLocs;
SourceLocation protocolRAngleLoc;
// Parse type arguments and protocol qualifiers.
ParseObjCTypeArgsAndProtocolQualifiers(DS);
parseObjCTypeArgsAndProtocolQualifiers(typeArgsLAngleLoc, typeArgs,
typeArgsRAngleLoc, protocolLAngleLoc,
protocols, protocolLocs,
protocolRAngleLoc, consumeLastToken);
// Form a declarator to turn this into a type.
Declarator D(DS, Declarator::TypeNameContext);
return Actions.ActOnTypeName(getCurScope(), D);
// Compute the location of the last token.
if (consumeLastToken)
endLoc = PrevTokLocation;
else
endLoc = Tok.getLocation();
return Actions.actOnObjCTypeArgsAndProtocolQualifiers(
getCurScope(),
loc,
type,
typeArgsLAngleLoc,
typeArgs,
typeArgsRAngleLoc,
protocolLAngleLoc,
protocols,
protocolLocs,
protocolRAngleLoc);
}
void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
@ -1926,7 +2019,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true,
LAngleLoc, EndProtoLoc))
LAngleLoc, EndProtoLoc,
/*consumeLastToken=*/true))
return DeclGroupPtrTy();
Decl *ProtoType =
@ -2020,9 +2114,14 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
rparenLoc = ConsumeParen();
if (Tok.is(tok::less)) { // we have illegal '<' try to recover
Diag(Tok, diag::err_unexpected_protocol_qualifier);
AttributeFactory attr;
DeclSpec DS(attr);
(void)ParseObjCProtocolQualifiers(DS);
SourceLocation protocolLAngleLoc, protocolRAngleLoc;
SmallVector<Decl *, 4> protocols;
SmallVector<SourceLocation, 4> protocolLocs;
(void)ParseObjCProtocolReferences(protocols, protocolLocs,
/*warnOnIncompleteProtocols=*/false,
/*ForObjCContainer=*/false,
protocolLAngleLoc, protocolRAngleLoc,
/*consumeLastToken=*/true);
}
ObjCImpDecl = Actions.ActOnStartCategoryImplementation(
AtLoc, nameId, nameLoc, categoryId,
@ -2050,10 +2149,15 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc);
else if (Tok.is(tok::less)) { // we have illegal '<' try to recover
Diag(Tok, diag::err_unexpected_protocol_qualifier);
// try to recover.
AttributeFactory attr;
DeclSpec DS(attr);
(void)ParseObjCProtocolQualifiers(DS);
SourceLocation protocolLAngleLoc, protocolRAngleLoc;
SmallVector<Decl *, 4> protocols;
SmallVector<SourceLocation, 4> protocolLocs;
(void)ParseObjCProtocolReferences(protocols, protocolLocs,
/*warnOnIncompleteProtocols=*/false,
/*ForObjCContainer=*/false,
protocolLAngleLoc, protocolRAngleLoc,
/*consumeLastToken=*/true);
}
}
assert(ObjCImpDecl);
@ -2873,8 +2977,11 @@ ExprResult Parser::ParseObjCMessageExpression() {
// Parse type arguments and protocol qualifiers.
if (Tok.is(tok::less)) {
SourceLocation NewEndLoc;
TypeResult NewReceiverType
= ParseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType);
= parseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType,
/*consumeLastToken=*/true,
NewEndLoc);
if (!NewReceiverType.isUsable()) {
SkipUntil(tok::r_square, StopAtSemi);
return ExprError();

View File

@ -1413,14 +1413,35 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
// It's not something we know about. Leave it unannotated.
break;
case Sema::NC_Type:
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Classification.getType());
Tok.setAnnotationEndLoc(NameLoc);
case Sema::NC_Type: {
SourceLocation BeginLoc = NameLoc;
if (SS.isNotEmpty())
Tok.setLocation(SS.getBeginLoc());
BeginLoc = SS.getBeginLoc();
/// An Objective-C object type followed by '<' is a specialization of
/// a parameterized class type or a protocol-qualified type.
ParsedType Ty = Classification.getType();
if (getLangOpts().ObjC1 && NextToken().is(tok::less) &&
(Ty.get()->isObjCObjectType() ||
Ty.get()->isObjCObjectPointerType())) {
// Consume the name.
SourceLocation IdentifierLoc = ConsumeToken();
SourceLocation NewEndLoc;
TypeResult NewType
= parseObjCTypeArgsAndProtocolQualifiers(IdentifierLoc, Ty,
/*consumeLastToken=*/false,
NewEndLoc);
if (NewType.isUsable())
Ty = NewType.get();
}
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Ty);
Tok.setAnnotationEndLoc(Tok.getLocation());
Tok.setLocation(BeginLoc);
PP.AnnotateCachedTokens(Tok);
return ANK_Success;
}
case Sema::NC_Expression:
Tok.setKind(tok::annot_primary_expr);
@ -1627,13 +1648,33 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext,
// A FixIt was applied as a result of typo correction
if (CorrectedII)
Tok.setIdentifierInfo(CorrectedII);
SourceLocation BeginLoc = Tok.getLocation();
if (SS.isNotEmpty()) // it was a C++ qualified type name.
BeginLoc = SS.getBeginLoc();
/// An Objective-C object type followed by '<' is a specialization of
/// a parameterized class type or a protocol-qualified type.
if (getLangOpts().ObjC1 && NextToken().is(tok::less) &&
(Ty.get()->isObjCObjectType() ||
Ty.get()->isObjCObjectPointerType())) {
// Consume the name.
SourceLocation IdentifierLoc = ConsumeToken();
SourceLocation NewEndLoc;
TypeResult NewType
= parseObjCTypeArgsAndProtocolQualifiers(IdentifierLoc, Ty,
/*consumeLastToken=*/false,
NewEndLoc);
if (NewType.isUsable())
Ty = NewType.get();
}
// This is a typename. Replace the current token in-place with an
// annotation type token.
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Ty);
Tok.setAnnotationEndLoc(Tok.getLocation());
if (SS.isNotEmpty()) // it was a C++ qualified type name.
Tok.setLocation(SS.getBeginLoc());
Tok.setLocation(BeginLoc);
// In case the tokens were cached, have Preprocessor replace
// them with the annotation token.

View File

@ -893,7 +893,6 @@ bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec,
return false;
}
bool DeclSpec::SetConceptSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID) {
if (Concept_specified) {
@ -906,30 +905,6 @@ 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,
SourceLocation LAngleLoc) {
if (NP == 0) return;
Decl **ProtoQuals = new Decl*[NP];
memcpy(ProtoQuals, Protos, sizeof(Decl*)*NP);
ProtocolQualifiers = ProtoQuals;
ProtocolLocs = new SourceLocation[NP];
memcpy(ProtocolLocs, ProtoLocs, sizeof(SourceLocation)*NP);
NumProtocolQualifiers = NP;
ProtocolLAngleLoc = LAngleLoc;
}
void DeclSpec::SaveWrittenBuiltinSpecs() {
writtenBS.Sign = getTypeSpecSign();
writtenBS.Width = getTypeSpecWidth();

View File

@ -560,29 +560,19 @@ ActOnSuperClassOfClassInterface(Scope *S,
// 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 (!SuperTypeArgs.empty()) {
TypeResult fullSuperClassType = actOnObjCTypeArgsAndProtocolQualifiers(
S,
SuperLoc,
CreateParsedType(SuperClassType,
nullptr),
SuperTypeArgsRange.getBegin(),
SuperTypeArgs,
SuperTypeArgsRange.getEnd(),
SourceLocation(),
{ },
{ },
SourceLocation());
if (!fullSuperClassType.isUsable())
return;
@ -1230,21 +1220,26 @@ class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback {
void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
Scope *S,
DeclSpec &DS,
SourceLocation lAngleLoc,
ArrayRef<IdentifierInfo *> identifiers,
ArrayRef<SourceLocation> identifierLocs,
SourceLocation rAngleLoc,
SourceLocation &typeArgsLAngleLoc,
SmallVectorImpl<ParsedType> &typeArgs,
SourceLocation &typeArgsRAngleLoc,
SourceLocation &protocolLAngleLoc,
SmallVectorImpl<Decl *> &protocols,
SourceLocation &protocolRAngleLoc,
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];
ObjCProtocolDecl *&proto
= reinterpret_cast<ObjCProtocolDecl *&>(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) {
@ -1268,12 +1263,9 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
}
}
DS.setProtocolQualifiers((Decl * const *)(protocols.data()),
protocols.size(),
const_cast<SourceLocation *>(identifierLocs.data()),
lAngleLoc);
if (rAngleLoc.isValid())
DS.SetRangeEnd(rAngleLoc);
protocolLAngleLoc = lAngleLoc;
protocolRAngleLoc = rAngleLoc;
assert(protocols.size() == identifierLocs.size());
};
// Attempt to resolve all of the identifiers as protocols.
@ -1370,20 +1362,24 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
// Local function that updates the declaration specifiers with
// type argument information.
auto resolvedAsTypeDecls = [&] {
// We did not resolve these as protocols.
protocols.clear();
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())
if (!type.isUsable()) {
typeArgs.clear();
return;
}
typeArgs.push_back(type.get());
}
// Record the Objective-C type arguments.
DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc);
typeArgsLAngleLoc = lAngleLoc;
typeArgsRAngleLoc = rAngleLoc;
};
// If all of the identifiers can be resolved as type names or
@ -1432,6 +1428,8 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
<< identifiers[0]
<< SourceRange(identifierLocs[0]);
protocols.clear();
typeArgs.clear();
return;
}
@ -1483,6 +1481,8 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
: lookupKind == LookupObjCProtocolName ? diag::err_undeclared_protocol
: diag::err_unknown_typename))
<< identifiers[i];
protocols.clear();
typeArgs.clear();
return;
}

View File

@ -740,14 +740,18 @@ 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) {
ArrayRef<TypeSourceInfo *> typeArgs,
SourceRange typeArgsRange,
bool failOnError = false) {
// 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;
if (failOnError)
return QualType();
return type;
}
@ -758,6 +762,10 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
S.Diag(loc, diag::err_objc_type_args_non_parameterized_class)
<< objcClass->getDeclName()
<< FixItHint::CreateRemoval(typeArgsRange);
if (failOnError)
return QualType();
return type;
}
@ -766,26 +774,20 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
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;
if (failOnError)
return QualType();
return type;
}
// Check the type arguments.
SmallVector<QualType, 4> finalTypeArgs;
unsigned numTypeParams = typeParams->size();
bool anyPackExpansions = false;
for (unsigned i = 0, n = typeArgs.size(); i != n; ++i) {
TypeSourceInfo *typeArgInfo = nullptr;
QualType typeArg = S.GetTypeFromParser(typeArgs[i], &typeArgInfo);
TypeSourceInfo *typeArgInfo = typeArgs[i];
QualType typeArg = typeArgInfo->getType();
// Type arguments cannot explicitly specify nullability.
if (auto nullability = AttributedType::stripOuterNullability(typeArg)) {
@ -801,10 +803,42 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
finalTypeArgs.push_back(typeArg);
if (typeArg->getAs<PackExpansionType>())
anyPackExpansions = true;
// Find the corresponding type parameter, if there is one.
ObjCTypeParamDecl *typeParam = nullptr;
if (!anyPackExpansions) {
if (i < numTypeParams) {
typeParam = typeParams->begin()[i];
} else {
// Too many arguments.
S.Diag(loc, diag::err_objc_type_args_wrong_arity)
<< false
<< objcClass->getDeclName()
<< (unsigned)typeArgs.size()
<< numTypeParams;
S.Diag(objcClass->getLocation(), diag::note_previous_decl)
<< objcClass;
if (failOnError)
return QualType();
return type;
}
}
// Objective-C object pointer types must be substitutable for the bounds.
if (const auto *typeArgObjC = typeArg->getAs<ObjCObjectPointerType>()) {
// If we don't have a type parameter to match against, assume
// everything is fine. There was a prior pack expansion that
// means we won't be able to match anything.
if (!typeParam) {
assert(anyPackExpansions && "Too many arguments?");
continue;
}
// Retrieve the bound.
ObjCTypeParamDecl *typeParam = typeParams->begin()[i];
QualType bound = typeParam->getUnderlyingType();
const auto *boundObjC = bound->getAs<ObjCObjectPointerType>();
@ -826,13 +860,23 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here)
<< typeParam->getDeclName();
if (failOnError)
return QualType();
return type;
}
// Block pointer types are permitted for unqualified 'id' bounds.
if (typeArg->isBlockPointerType()) {
// If we don't have a type parameter to match against, assume
// everything is fine. There was a prior pack expansion that
// means we won't be able to match anything.
if (!typeParam) {
assert(anyPackExpansions && "Too many arguments?");
continue;
}
// Retrieve the bound.
ObjCTypeParamDecl *typeParam = typeParams->begin()[i];
QualType bound = typeParam->getUnderlyingType();
if (bound->isBlockCompatibleObjCPointerType(S.Context))
continue;
@ -844,6 +888,9 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here)
<< typeParam->getDeclName();
if (failOnError)
return QualType();
return type;
}
@ -857,6 +904,26 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
diag::err_objc_type_arg_not_id_compatible)
<< typeArg
<< typeArgInfo->getTypeLoc().getSourceRange();
if (failOnError)
return QualType();
return type;
}
// Make sure we didn't have the wrong number of arguments.
if (!anyPackExpansions && finalTypeArgs.size() != numTypeParams) {
S.Diag(loc, diag::err_objc_type_args_wrong_arity)
<< (typeArgs.size() < typeParams->size())
<< objcClass->getDeclName()
<< (unsigned)finalTypeArgs.size()
<< (unsigned)numTypeParams;
S.Diag(objcClass->getLocation(), diag::note_previous_decl)
<< objcClass;
if (failOnError)
return QualType();
return type;
}
@ -868,7 +935,8 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
static QualType applyObjCProtocolQualifiers(
Sema &S, SourceLocation loc, SourceRange range, QualType type,
ArrayRef<ObjCProtocolDecl *> protocols,
const SourceLocation *protocolLocs) {
const SourceLocation *protocolLocs,
bool failOnError = false) {
ASTContext &ctx = S.Context;
if (const ObjCObjectType *objT = dyn_cast<ObjCObjectType>(type.getTypePtr())){
// FIXME: Check for protocols to which the class type is already
@ -902,9 +970,185 @@ static QualType applyObjCProtocolQualifiers(
S.Diag(loc, diag::err_invalid_protocol_qualifiers)
<< range;
if (failOnError)
return QualType();
return type;
}
QualType Sema::BuildObjCObjectType(QualType BaseType,
SourceLocation Loc,
SourceLocation TypeArgsLAngleLoc,
ArrayRef<TypeSourceInfo *> TypeArgs,
SourceLocation TypeArgsRAngleLoc,
SourceLocation ProtocolLAngleLoc,
ArrayRef<ObjCProtocolDecl *> Protocols,
ArrayRef<SourceLocation> ProtocolLocs,
SourceLocation ProtocolRAngleLoc,
bool FailOnError) {
QualType Result = BaseType;
if (!TypeArgs.empty()) {
Result = applyObjCTypeArgs(*this, Loc, Result, TypeArgs,
SourceRange(TypeArgsLAngleLoc,
TypeArgsRAngleLoc),
FailOnError);
if (FailOnError && Result.isNull())
return QualType();
}
if (!Protocols.empty()) {
Result = applyObjCProtocolQualifiers(*this, Loc,
SourceRange(ProtocolLAngleLoc,
ProtocolRAngleLoc),
Result, Protocols,
ProtocolLocs.data(),
FailOnError);
if (FailOnError && Result.isNull())
return QualType();
}
return Result;
}
TypeResult Sema::actOnObjCProtocolQualifierType(
SourceLocation lAngleLoc,
ArrayRef<Decl *> protocols,
ArrayRef<SourceLocation> protocolLocs,
SourceLocation rAngleLoc) {
// Form id<protocol-list>.
QualType Result = Context.getObjCObjectType(
Context.ObjCBuiltinIdTy, { },
llvm::makeArrayRef(
(ObjCProtocolDecl * const *)protocols.data(),
protocols.size()));
Result = Context.getObjCObjectPointerType(Result);
TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result);
TypeLoc ResultTL = ResultTInfo->getTypeLoc();
auto ObjCObjectPointerTL = ResultTL.castAs<ObjCObjectPointerTypeLoc>();
ObjCObjectPointerTL.setStarLoc(SourceLocation()); // implicit
auto ObjCObjectTL = ObjCObjectPointerTL.getPointeeLoc()
.castAs<ObjCObjectTypeLoc>();
ObjCObjectTL.setHasBaseTypeAsWritten(false);
ObjCObjectTL.getBaseLoc().initialize(Context, SourceLocation());
// No type arguments.
ObjCObjectTL.setTypeArgsLAngleLoc(SourceLocation());
ObjCObjectTL.setTypeArgsRAngleLoc(SourceLocation());
// Fill in protocol qualifiers.
ObjCObjectTL.setProtocolLAngleLoc(lAngleLoc);
ObjCObjectTL.setProtocolRAngleLoc(rAngleLoc);
for (unsigned i = 0, n = protocols.size(); i != n; ++i)
ObjCObjectTL.setProtocolLoc(i, protocolLocs[i]);
// We're done. Return the completed type to the parser.
return CreateParsedType(Result, ResultTInfo);
}
TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers(
Scope *S,
SourceLocation Loc,
ParsedType BaseType,
SourceLocation TypeArgsLAngleLoc,
ArrayRef<ParsedType> TypeArgs,
SourceLocation TypeArgsRAngleLoc,
SourceLocation ProtocolLAngleLoc,
ArrayRef<Decl *> Protocols,
ArrayRef<SourceLocation> ProtocolLocs,
SourceLocation ProtocolRAngleLoc) {
TypeSourceInfo *BaseTypeInfo = nullptr;
QualType T = GetTypeFromParser(BaseType, &BaseTypeInfo);
if (T.isNull())
return true;
// Handle missing type-source info.
if (!BaseTypeInfo)
BaseTypeInfo = Context.getTrivialTypeSourceInfo(T, Loc);
// Extract type arguments.
SmallVector<TypeSourceInfo *, 4> ActualTypeArgInfos;
for (unsigned i = 0, n = TypeArgs.size(); i != n; ++i) {
TypeSourceInfo *TypeArgInfo = nullptr;
QualType TypeArg = GetTypeFromParser(TypeArgs[i], &TypeArgInfo);
if (TypeArg.isNull()) {
ActualTypeArgInfos.clear();
break;
}
assert(TypeArgInfo && "No type source info?");
ActualTypeArgInfos.push_back(TypeArgInfo);
}
// Build the object type.
QualType Result = BuildObjCObjectType(
T,
BaseTypeInfo->getTypeLoc().getSourceRange().getBegin(),
TypeArgsLAngleLoc,
ActualTypeArgInfos,
TypeArgsRAngleLoc,
ProtocolLAngleLoc,
llvm::makeArrayRef((ObjCProtocolDecl **)Protocols.data(),
Protocols.size()),
ProtocolLocs,
ProtocolRAngleLoc,
/*FailOnError=*/false);
if (Result == T)
return BaseType;
// Create source information for this type.
TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result);
TypeLoc ResultTL = ResultTInfo->getTypeLoc();
// For id<Proto1, Proto2> or Class<Proto1, Proto2>, we'll have an
// object pointer type. Fill in source information for it.
if (auto ObjCObjectPointerTL = ResultTL.getAs<ObjCObjectPointerTypeLoc>()) {
// The '*' is implicit.
ObjCObjectPointerTL.setStarLoc(SourceLocation());
ResultTL = ObjCObjectPointerTL.getPointeeLoc();
}
auto ObjCObjectTL = ResultTL.castAs<ObjCObjectTypeLoc>();
// Type argument information.
if (ObjCObjectTL.getNumTypeArgs() > 0) {
assert(ObjCObjectTL.getNumTypeArgs() == ActualTypeArgInfos.size());
ObjCObjectTL.setTypeArgsLAngleLoc(TypeArgsLAngleLoc);
ObjCObjectTL.setTypeArgsRAngleLoc(TypeArgsRAngleLoc);
for (unsigned i = 0, n = ActualTypeArgInfos.size(); i != n; ++i)
ObjCObjectTL.setTypeArgTInfo(i, ActualTypeArgInfos[i]);
} else {
ObjCObjectTL.setTypeArgsLAngleLoc(SourceLocation());
ObjCObjectTL.setTypeArgsRAngleLoc(SourceLocation());
}
// Protocol qualifier information.
if (ObjCObjectTL.getNumProtocols() > 0) {
assert(ObjCObjectTL.getNumProtocols() == Protocols.size());
ObjCObjectTL.setProtocolLAngleLoc(ProtocolLAngleLoc);
ObjCObjectTL.setProtocolRAngleLoc(ProtocolRAngleLoc);
for (unsigned i = 0, n = Protocols.size(); i != n; ++i)
ObjCObjectTL.setProtocolLoc(i, ProtocolLocs[i]);
} else {
ObjCObjectTL.setProtocolLAngleLoc(SourceLocation());
ObjCObjectTL.setProtocolRAngleLoc(SourceLocation());
}
// Base type.
ObjCObjectTL.setHasBaseTypeAsWritten(true);
if (ObjCObjectTL.getType() == T)
ObjCObjectTL.getBaseLoc().initializeFullCopy(BaseTypeInfo->getTypeLoc());
else
ObjCObjectTL.getBaseLoc().initialize(Context, Loc);
// We're done. Return the completed type to the parser.
return CreateParsedType(Result, ResultTInfo);
}
/// \brief Convert the specified declspec to the appropriate type
/// object.
/// \param state Specifies the declarator containing the declaration specifier
@ -968,16 +1212,6 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = Context.Char32Ty;
break;
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, { },
llvm::makeArrayRef(
(ObjCProtocolDecl*const*)PQ,
DS.getNumProtocolQualifiers()));
Result = Context.getObjCObjectPointerType(Result);
break;
}
// If this is a missing declspec in a block literal return context, then it
// is inferred from the return statements inside the block.
// The declspec is always missing in a lambda expr context; it is either
@ -1161,21 +1395,6 @@ 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.
@ -4282,47 +4501,14 @@ namespace {
TL.setNameEndLoc(DS.getLocEnd());
}
void VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
// Handle the base type, which might not have been written explicitly.
if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
TL.setHasBaseTypeAsWritten(false);
TL.getBaseLoc().initialize(Context, SourceLocation());
} else {
TL.setHasBaseTypeAsWritten(true);
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.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.setProtocolLAngleLoc(SourceLocation());
TL.setProtocolRAngleLoc(SourceLocation());
}
TypeSourceInfo *RepTInfo = nullptr;
Sema::GetTypeFromParser(DS.getRepAsType(), &RepTInfo);
TL.copy(RepTInfo->getTypeLoc());
}
void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
TL.setStarLoc(SourceLocation());
Visit(TL.getPointeeLoc());
TypeSourceInfo *RepTInfo = nullptr;
Sema::GetTypeFromParser(DS.getRepAsType(), &RepTInfo);
TL.copy(RepTInfo->getTypeLoc());
}
void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
TypeSourceInfo *TInfo = nullptr;

View File

@ -685,6 +685,27 @@ public:
QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType,
SourceLocation Sigil);
/// \brief Build an Objective-C object type.
///
/// By default, performs semantic analysis when building the object type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildObjCObjectType(QualType BaseType,
SourceLocation Loc,
SourceLocation TypeArgsLAngleLoc,
ArrayRef<TypeSourceInfo *> TypeArgs,
SourceLocation TypeArgsRAngleLoc,
SourceLocation ProtocolLAngleLoc,
ArrayRef<ObjCProtocolDecl *> Protocols,
ArrayRef<SourceLocation> ProtocolLocs,
SourceLocation ProtocolRAngleLoc);
/// \brief Build a new Objective-C object pointer type given the pointee type.
///
/// By default, directly builds the pointer type, with no additional semantic
/// analysis.
QualType RebuildObjCObjectPointerType(QualType PointeeType,
SourceLocation Star);
/// \brief Build a new array type given the element type, size
/// modifier, size of the array (if known), size expression, and index type
/// qualifiers.
@ -5606,18 +5627,153 @@ template<typename Derived>
QualType
TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB,
ObjCObjectTypeLoc TL) {
// ObjCObjectType is never dependent.
TLB.pushFullCopy(TL);
return TL.getType();
// Transform base type.
QualType BaseType = getDerived().TransformType(TLB, TL.getBaseLoc());
if (BaseType.isNull())
return QualType();
bool AnyChanged = BaseType != TL.getBaseLoc().getType();
// Transform type arguments.
SmallVector<TypeSourceInfo *, 4> NewTypeArgInfos;
for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) {
TypeSourceInfo *TypeArgInfo = TL.getTypeArgTInfo(i);
TypeLoc TypeArgLoc = TypeArgInfo->getTypeLoc();
QualType TypeArg = TypeArgInfo->getType();
if (auto PackExpansionLoc = TypeArgLoc.getAs<PackExpansionTypeLoc>()) {
AnyChanged = true;
// We have a pack expansion. Instantiate it.
const auto *PackExpansion = PackExpansionLoc.getType()
->castAs<PackExpansionType>();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),
Unexpanded);
assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
// Determine whether the set of unexpanded parameter packs can
// and should be expanded.
TypeLoc PatternLoc = PackExpansionLoc.getPatternLoc();
bool Expand = false;
bool RetainExpansion = false;
Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
if (getDerived().TryExpandParameterPacks(
PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(),
Unexpanded, Expand, RetainExpansion, NumExpansions))
return QualType();
if (!Expand) {
// We can't expand this pack expansion into separate arguments yet;
// just substitute into the pattern and create a new pack expansion
// type.
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
TypeLocBuilder TypeArgBuilder;
TypeArgBuilder.reserve(PatternLoc.getFullDataSize());
QualType NewPatternType = getDerived().TransformType(TypeArgBuilder,
PatternLoc);
if (NewPatternType.isNull())
return QualType();
QualType NewExpansionType = SemaRef.Context.getPackExpansionType(
NewPatternType, NumExpansions);
auto NewExpansionLoc = TLB.push<PackExpansionTypeLoc>(NewExpansionType);
NewExpansionLoc.setEllipsisLoc(PackExpansionLoc.getEllipsisLoc());
NewTypeArgInfos.push_back(
TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewExpansionType));
continue;
}
// Substitute into the pack expansion pattern for each slice of the
// pack.
for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx);
TypeLocBuilder TypeArgBuilder;
TypeArgBuilder.reserve(PatternLoc.getFullDataSize());
QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder,
PatternLoc);
if (NewTypeArg.isNull())
return QualType();
NewTypeArgInfos.push_back(
TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg));
}
continue;
}
TypeLocBuilder TypeArgBuilder;
TypeArgBuilder.reserve(TypeArgLoc.getFullDataSize());
QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, TypeArgLoc);
if (NewTypeArg.isNull())
return QualType();
// If nothing changed, just keep the old TypeSourceInfo.
if (NewTypeArg == TypeArg) {
NewTypeArgInfos.push_back(TypeArgInfo);
continue;
}
NewTypeArgInfos.push_back(
TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg));
AnyChanged = true;
}
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() || AnyChanged) {
// Rebuild the type.
Result = getDerived().RebuildObjCObjectType(
BaseType,
TL.getLocStart(),
TL.getTypeArgsLAngleLoc(),
NewTypeArgInfos,
TL.getTypeArgsRAngleLoc(),
TL.getProtocolLAngleLoc(),
llvm::makeArrayRef(TL.getTypePtr()->qual_begin(),
TL.getNumProtocols()),
TL.getProtocolLocs(),
TL.getProtocolRAngleLoc());
if (Result.isNull())
return QualType();
}
ObjCObjectTypeLoc NewT = TLB.push<ObjCObjectTypeLoc>(Result);
assert(TL.hasBaseTypeAsWritten() && "Can't be dependent");
NewT.setHasBaseTypeAsWritten(true);
NewT.setTypeArgsLAngleLoc(TL.getTypeArgsLAngleLoc());
for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i)
NewT.setTypeArgTInfo(i, NewTypeArgInfos[i]);
NewT.setTypeArgsRAngleLoc(TL.getTypeArgsRAngleLoc());
NewT.setProtocolLAngleLoc(TL.getProtocolLAngleLoc());
for (unsigned i = 0, n = TL.getNumProtocols(); i != n; ++i)
NewT.setProtocolLoc(i, TL.getProtocolLoc(i));
NewT.setProtocolRAngleLoc(TL.getProtocolRAngleLoc());
return Result;
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB,
ObjCObjectPointerTypeLoc TL) {
// ObjCObjectPointerType is never dependent.
TLB.pushFullCopy(TL);
return TL.getType();
QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc());
if (PointeeType.isNull())
return QualType();
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
PointeeType != TL.getPointeeLoc().getType()) {
Result = getDerived().RebuildObjCObjectPointerType(PointeeType,
TL.getStarLoc());
if (Result.isNull())
return QualType();
}
ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result);
NewT.setStarLoc(TL.getStarLoc());
return Result;
}
//===----------------------------------------------------------------------===//
@ -10493,6 +10649,31 @@ TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType,
getDerived().getBaseEntity());
}
template<typename Derived>
QualType TreeTransform<Derived>::RebuildObjCObjectType(
QualType BaseType,
SourceLocation Loc,
SourceLocation TypeArgsLAngleLoc,
ArrayRef<TypeSourceInfo *> TypeArgs,
SourceLocation TypeArgsRAngleLoc,
SourceLocation ProtocolLAngleLoc,
ArrayRef<ObjCProtocolDecl *> Protocols,
ArrayRef<SourceLocation> ProtocolLocs,
SourceLocation ProtocolRAngleLoc) {
return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc,
TypeArgs, TypeArgsRAngleLoc,
ProtocolLAngleLoc, Protocols, ProtocolLocs,
ProtocolRAngleLoc,
/*FailOnError=*/true);
}
template<typename Derived>
QualType TreeTransform<Derived>::RebuildObjCObjectPointerType(
QualType PointeeType,
SourceLocation Star) {
return SemaRef.Context.getObjCObjectPointerType(PointeeType);
}
template<typename Derived>
QualType
TreeTransform<Derived>::RebuildArrayType(QualType ElementType,

View File

@ -17,19 +17,15 @@ typedef A<id<NSObject>, NSObject *> ASpecialization1;
// RUN: c-index-test -test-annotate-tokens=%s:7:1:9:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-INTERFACE-DECL %s
// CHECK-INTERFACE-DECL: Identifier: "T" [7:14 - 7:15] TemplateTypeParameter=T:7:14
// FIXME: Should be a type reference
// CHECK-INTERFACE-DECL: Identifier: "id" [7:18 - 7:20] TemplateTypeParameter=T:7:14
// CHECK-INTERFACE-DECL: Identifier: "id" [7:18 - 7:20] TypeRef=id:0:0
// CHECK-INTERFACE-DECL: Identifier: "U" [7:22 - 7:23] TemplateTypeParameter=U:7:22
// FIXME: Should be a class reference
// CHECK-INTERFACE-DECL: Identifier: "NSObject" [7:26 - 7:34] TemplateTypeParameter=U:7:22
// CHECK-INTERFACE-DECL: Identifier: "NSObject" [7:26 - 7:34] ObjCClassRef=NSObject:4:12
// RUN: c-index-test -test-annotate-tokens=%s:10:1:12:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-CATEGORY-DECL %s
// CHECK-CATEGORY-DECL: Identifier: "T" [10:14 - 10:15] TemplateTypeParameter=T:10:14
// FIXME: Should be a type reference
// CHECK-CATEGORY-DECL: Identifier: "id" [10:18 - 10:20] TemplateTypeParameter=T:10:14
// CHECK-CATEGORY-DECL: Identifier: "id" [10:18 - 10:20] TypeRef=id:0:0
// CHECK-CATEGORY-DECL: Identifier: "U" [10:22 - 10:23] TemplateTypeParameter=U:10:22
// FIXME: Should be a class reference
// CHECK-CATEGORY-DECL: Identifier: "NSObject" [10:26 - 10:34] TemplateTypeParameter=U:10:22
// CHECK-CATEGORY-DECL: Identifier: "NSObject" [10:26 - 10:34] ObjCClassRef=NSObject:4:12
// RUN: c-index-test -test-annotate-tokens=%s:13:1:14:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-SPECIALIZATION %s
// CHECK-SPECIALIZATION: Identifier: "id" [13:11 - 13:13] TypeRef=id:0:0

View File

@ -152,6 +152,7 @@ static Rdar8595462_A * Rdar8595462_staticVar;
@property int extensionProperty;
@end
typedef id<Proto> *proto_ptr;
// RUN: c-index-test -test-annotate-tokens=%s:1:1:118:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck %s
// CHECK: Punctuation: "@" [1:1 - 1:2] ObjCInterfaceDecl=Foo:1:12
@ -596,3 +597,9 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK-PROP: Keyword: "property" [152:4 - 152:12] ObjCPropertyDecl=extensionProperty:152:17
// CHECK-PROP: Keyword: "int" [152:13 - 152:16] ObjCPropertyDecl=extensionProperty:152:17
// CHECK-PROP: Identifier: "extensionProperty" [152:17 - 152:34] ObjCPropertyDecl=extensionProperty:152:17
// RUN: c-index-test -test-annotate-tokens=%s:155:1:156:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-ID-PROTO %s
// CHECK-ID-PROTO: Identifier: "id" [155:9 - 155:11] TypeRef=id:0:0
// CHECK-ID-PROTO: Punctuation: "<" [155:11 - 155:12] TypedefDecl=proto_ptr:155:20 (Definition)
// CHECK-ID-PROTO: Identifier: "Proto" [155:12 - 155:17] ObjCProtocolRef=Proto
// CHECK-ID-PROTO: Punctuation: ">" [155:17 - 155:18] TypedefDecl=proto_ptr:155:20 (Definition)

View File

@ -3,10 +3,9 @@
// FIXME: We could do much better with this, if we recognized
// placeholders somehow. However, we're content with not generating
// bogus 'archaic' warnings with bad location info.
@protocol <#protocol name#> <NSObject> // expected-error 2{{expected identifier}} \
// expected-error{{cannot find protocol declaration for 'NSObject'}} \
@protocol <#protocol name#> <NSObject> // expected-error {{expected identifier or '('}} \
// expected-error 2{{expected identifier}} \
// expected-warning{{protocol has no object type specified; defaults to qualified 'id'}}
<#methods#>
<#methods#> // expected-error{{expected identifier}}
@end // expected-error{{prefix attribute}}
@end

View File

@ -1,5 +1,9 @@
// RUN: %clang_cc1 -fblocks %s -verify
#if !__has_feature(objc_generics)
# error Compiler does not support Objective-C generics?
#endif
@protocol NSObject // expected-note{{'NSObject' declared here}}
@end
@ -255,14 +259,14 @@ typedef PC15<int (^)(int, int), // block pointers as 'id'
typedef PC15<NSObject *, NSObject *, id<NSCopying>> typeArgs8;
typedef PC15<NSObject *, NSObject *,
NSObject *> typeArgs8b; // expected-error{{type argument 'NSObject *' does not satisy the bound ('id<NSCopying>') of type parameter 'V'}}
NSObject *> typeArgs8b; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'V'}}
typedef PC15<id,
id, // expected-error{{type argument 'id' does not satisy the bound ('NSObject *') of type parameter 'U'}}
id, // expected-error{{type argument 'id' does not satisfy the bound ('NSObject *') of type parameter 'U'}}
id> typeArgs9;
typedef PC15<id, NSObject *,
id> typeArgs10; // expected-error{{type argument 'id' does not satisy the bound ('id<NSCopying>') of type parameter 'V'}}
id> typeArgs10; // expected-error{{type argument 'id' does not satisfy the bound ('id<NSCopying>') of type parameter 'V'}}
typedef PC15<id,
int (^)(int, int), // okay
@ -306,7 +310,7 @@ void testSpecializedTypePrinting() {
@interface PC23<T : NSObject *> : PC1<T, U> // expected-error{{unknown type name 'U'}}
@end
@interface PC24<T> : PC1<T, T> // expected-error{{type argument 'T' (aka 'id') does not satisy the bound ('NSObject *') of type parameter 'U'}}
@interface PC24<T> : PC1<T, T> // expected-error{{type argument 'T' (aka 'id') does not satisfy the bound ('NSObject *') of type parameter 'U'}}
@end
@interface NSFoo : PC1<NSObject *, NSObject *> // okay

View File

@ -40,3 +40,7 @@ Class <SomeProtocol> UnfortunateGCCExtension;
- (void)crashWith:(<Broken>)a { // expected-warning {{protocol has no object type specified; defaults to qualified 'id'}}
}
@end
typedef <SomeProtocol> id TwoTypeSpecs; // expected-warning{{no object type specified}}
// expected-error@-1{{typedef redefinition with different types ('id<SomeProtocol>' vs 'id')}}
// expected-error@-2{{expected ';' after top level declarator}}

View File

@ -0,0 +1,407 @@
// RUN: %clang_cc1 -fblocks -fsyntax-only -std=c++11 %s -verify
//
// Test the substitution of type arguments for type parameters when
// using parameterized classes in Objective-C.
__attribute__((objc_root_class))
@interface NSObject
+ (instancetype)alloc;
- (instancetype)init;
@end
@protocol NSCopying
@end
@interface NSString : NSObject <NSCopying>
@end
@interface NSNumber : NSObject <NSCopying>
@end
@interface NSArray<T> : NSObject <NSCopying> {
@public
T *data; // don't try this at home
}
- (T)objectAtIndexedSubscript:(int)index;
+ (NSArray<T> *)array;
@property (copy,nonatomic) T lastObject;
@end
@interface NSMutableArray<T> : NSArray<T>
-(instancetype)initWithArray:(NSArray<T> *)array; // expected-note{{passing argument}}
- (void)setObject:(T)object atIndexedSubscript:(int)index; // expected-note 2{{passing argument to parameter 'object' here}}
@end
@interface NSStringArray : NSArray<NSString *>
@end
@interface NSSet<T> : NSObject <NSCopying>
- (T)firstObject;
@property (nonatomic, copy) NSArray<T> *allObjects;
@end
// Parameterized inheritance (simple case)
@interface NSMutableSet<U : id<NSCopying>> : NSSet<U>
- (void)addObject:(U)object; // expected-note 7{{passing argument to parameter 'object' here}}
@end
@interface Widget : NSObject <NSCopying>
@end
// Non-parameterized class inheriting from a specialization of a
// parameterized class.
@interface WidgetSet : NSMutableSet<Widget *>
@end
// Parameterized inheritance with a more interesting transformation in
// the specialization.
@interface MutableSetOfArrays<T> : NSMutableSet<NSArray<T>*>
@end
// Inheriting from an unspecialized form of a parameterized type.
@interface UntypedMutableSet : NSMutableSet
@end
@interface Window : NSObject
@end
@interface NSDictionary<K, V> : NSObject <NSCopying>
- (V)objectForKeyedSubscript:(K)key; // expected-note 2{{parameter 'key'}}
@end
@interface NSMutableDictionary<K : id<NSCopying>, V> : NSDictionary<K, V> // expected-note 2{{type parameter 'K' declared here}} \
// expected-note 2{{'NSMutableDictionary' declared here}}
- (void)setObject:(V)object forKeyedSubscript:(K)key;
// expected-note@-1 {{parameter 'object' here}}
// expected-note@-2 {{parameter 'object' here}}
// expected-note@-3 {{parameter 'key' here}}
// expected-note@-4 {{parameter 'key' here}}
@property (strong) K someRandomKey;
@end
@interface WindowArray : NSArray<Window *>
@end
@interface NSSet<T> (Searching)
- (T)findObject:(T)object;
@end
// --------------------------------------------------------------------------
// Message sends.
// --------------------------------------------------------------------------
void test_message_send_result(
NSSet<NSString *> *stringSet,
NSMutableSet<NSString *> *mutStringSet,
WidgetSet *widgetSet,
UntypedMutableSet *untypedMutSet,
MutableSetOfArrays<NSString *> *mutStringArraySet,
NSSet *set,
NSMutableSet *mutSet,
MutableSetOfArrays *mutArraySet,
NSArray<NSString *> *stringArray,
void (^block)(void)) {
int *ip;
ip = [stringSet firstObject]; // expected-error{{from incompatible type 'NSString *'}}
ip = [mutStringSet firstObject]; // expected-error{{from incompatible type 'NSString *'}}
ip = [widgetSet firstObject]; // expected-error{{from incompatible type 'Widget *'}}
ip = [untypedMutSet firstObject]; // expected-error{{from incompatible type 'id'}}
ip = [mutStringArraySet firstObject]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
ip = [set firstObject]; // expected-error{{from incompatible type 'id'}}
ip = [mutSet firstObject]; // expected-error{{from incompatible type 'id'}}
ip = [mutArraySet firstObject]; // expected-error{{from incompatible type 'id'}}
ip = [block firstObject]; // expected-error{{from incompatible type 'id'}}
ip = [stringSet findObject:@"blah"]; // expected-error{{from incompatible type 'NSString *'}}
// Class messages.
ip = [NSSet<NSString *> alloc]; // expected-error{{from incompatible type 'NSSet<NSString *> *'}}
ip = [NSSet alloc]; // expected-error{{from incompatible type 'NSSet *'}}
ip = [MutableSetOfArrays<NSString *> alloc]; // expected-error{{from incompatible type 'MutableSetOfArrays<NSString *> *'}}
ip = [MutableSetOfArrays alloc]; // expected-error{{from incompatible type 'MutableSetOfArrays *'}}
ip = [NSArray<NSString *> array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
ip = [NSArray<NSString *><NSCopying> array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
ip = [[NSMutableArray<NSString *> alloc] init]; // expected-error{{from incompatible type 'NSMutableArray<NSString *> *'}}
[[NSMutableArray alloc] initWithArray: stringArray]; // okay
[[NSMutableArray<NSString *> alloc] initWithArray: stringArray]; // okay
[[NSMutableArray<NSNumber *> alloc] initWithArray: stringArray]; // expected-error{{parameter of type 'NSArray<NSNumber *> *' with an lvalue of type 'NSArray<NSString *> *'}}
}
void test_message_send_param(
NSMutableSet<NSString *> *mutStringSet,
WidgetSet *widgetSet,
UntypedMutableSet *untypedMutSet,
MutableSetOfArrays<NSString *> *mutStringArraySet,
NSMutableSet *mutSet,
MutableSetOfArrays *mutArraySet,
void (^block)(void)) {
Window *window;
[mutStringSet addObject: window]; // expected-error{{parameter of type 'NSString *'}}
[widgetSet addObject: window]; // expected-error{{parameter of type 'Widget *'}}
[untypedMutSet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
[mutStringArraySet addObject: window]; // expected-error{{parameter of type 'NSArray<NSString *> *'}}
[mutSet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
[mutArraySet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
[block addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
}
// --------------------------------------------------------------------------
// Property accesses.
// --------------------------------------------------------------------------
void test_property_read(
NSSet<NSString *> *stringSet,
NSMutableSet<NSString *> *mutStringSet,
WidgetSet *widgetSet,
UntypedMutableSet *untypedMutSet,
MutableSetOfArrays<NSString *> *mutStringArraySet,
NSSet *set,
NSMutableSet *mutSet,
MutableSetOfArrays *mutArraySet,
NSMutableDictionary *mutDict) {
int *ip;
ip = stringSet.allObjects; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
ip = mutStringSet.allObjects; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
ip = widgetSet.allObjects; // expected-error{{from incompatible type 'NSArray<Widget *> *'}}
ip = untypedMutSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
ip = mutStringArraySet.allObjects; // expected-error{{from incompatible type 'NSArray<NSArray<NSString *> *> *'}}
ip = set.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
ip = mutSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
ip = mutArraySet.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
ip = mutDict.someRandomKey; // expected-error{{from incompatible type 'id'}}
}
void test_property_write(
NSMutableSet<NSString *> *mutStringSet,
WidgetSet *widgetSet,
UntypedMutableSet *untypedMutSet,
MutableSetOfArrays<NSString *> *mutStringArraySet,
NSMutableSet *mutSet,
MutableSetOfArrays *mutArraySet,
NSMutableDictionary *mutDict) {
int *ip;
mutStringSet.allObjects = ip; // expected-error{{to 'NSArray<NSString *> *'}}
widgetSet.allObjects = ip; // expected-error{{to 'NSArray<Widget *> *'}}
untypedMutSet.allObjects = ip; // expected-error{{to 'NSArray *'}}
mutStringArraySet.allObjects = ip; // expected-error{{to 'NSArray<NSArray<NSString *> *> *'}}
mutSet.allObjects = ip; // expected-error{{to 'NSArray *'}}
mutArraySet.allObjects = ip; // expected-error{{to 'NSArray *'}}
mutDict.someRandomKey = ip; // expected-error{{to 'id<NSCopying>'}}
}
// --------------------------------------------------------------------------
// Subscripting
// --------------------------------------------------------------------------
void test_subscripting(
NSArray<NSString *> *stringArray,
NSMutableArray<NSString *> *mutStringArray,
NSArray *array,
NSMutableArray *mutArray,
NSDictionary<NSString *, Widget *> *stringWidgetDict,
NSMutableDictionary<NSString *, Widget *> *mutStringWidgetDict,
NSDictionary *dict,
NSMutableDictionary *mutDict) {
int *ip;
NSString *string;
Widget *widget;
Window *window;
ip = stringArray[0]; // expected-error{{from incompatible type 'NSString *'}}
ip = mutStringArray[0]; // expected-error{{from incompatible type 'NSString *'}}
mutStringArray[0] = ip; // expected-error{{parameter of type 'NSString *'}}
ip = array[0]; // expected-error{{from incompatible type 'id'}}
ip = mutArray[0]; // expected-error{{from incompatible type 'id'}}
mutArray[0] = ip; // expected-error{{parameter of type 'id'}}
ip = stringWidgetDict[string]; // expected-error{{from incompatible type 'Widget *'}}
widget = stringWidgetDict[widget]; // expected-error{{parameter of type 'NSString *'}}
ip = mutStringWidgetDict[string]; // expected-error{{from incompatible type 'Widget *'}}
widget = mutStringWidgetDict[widget]; // expected-error{{parameter of type 'NSString *'}}
mutStringWidgetDict[string] = ip; // expected-error{{parameter of type 'Widget *'}}
mutStringWidgetDict[widget] = widget; // expected-error{{parameter of type 'NSString *'}}
ip = dict[string]; // expected-error{{from incompatible type 'id'}}
ip = mutDict[string]; // expected-error{{incompatible type 'id'}}
mutDict[string] = ip; // expected-error{{parameter of type 'id'}}
widget = mutDict[window];
mutDict[window] = widget; // expected-error{{parameter of type 'id<NSCopying>'}}
}
// --------------------------------------------------------------------------
// Instance variable access.
// --------------------------------------------------------------------------
void test_instance_variable(NSArray<NSString *> *stringArray,
NSArray *array) {
int *ip;
ip = stringArray->data; // expected-error{{from incompatible type 'NSString **'}}
ip = array->data; // expected-error{{from incompatible type 'id *'}}
}
@implementation WindowArray
- (void)testInstanceVariable {
int *ip;
ip = data; // expected-error{{from incompatible type 'Window **'}}
}
@end
// --------------------------------------------------------------------------
// Implicit conversions.
// --------------------------------------------------------------------------
void test_implicit_conversions(NSArray<NSString *> *stringArray,
NSArray<NSNumber *> *numberArray,
NSMutableArray<NSString *> *mutStringArray,
NSArray *array,
NSMutableArray *mutArray) {
// Specialized -> unspecialized (same level)
array = stringArray;
// Unspecialized -> specialized (same level)
stringArray = array;
// Specialized -> specialized failure (same level).
stringArray = numberArray; // expected-error{{assigning to 'NSArray<NSString *> *' from incompatible type 'NSArray<NSNumber *> *'}}
// Specialized -> specialized (different levels).
stringArray = mutStringArray;
// Specialized -> specialized failure (different levels).
numberArray = mutStringArray; // expected-error{{assigning to 'NSArray<NSNumber *> *' from incompatible type 'NSMutableArray<NSString *> *'}}
// Unspecialized -> specialized (different levels).
stringArray = mutArray;
// Specialized -> unspecialized (different levels).
array = mutStringArray;
}
// --------------------------------------------------------------------------
// Ternary operator
// --------------------------------------------------------------------------
void test_ternary_operator(NSArray<NSString *> *stringArray,
NSArray<NSNumber *> *numberArray,
NSMutableArray<NSString *> *mutStringArray,
NSStringArray *stringArray2,
NSArray *array,
NSMutableArray *mutArray,
int cond) {
int *ip;
id object;
ip = cond ? stringArray : mutStringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
ip = cond ? mutStringArray : stringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
ip = cond ? stringArray2 : mutStringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
ip = cond ? mutStringArray : stringArray2; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
ip = cond ? stringArray : mutArray; // expected-error{{from incompatible type 'NSArray *'}}
ip = cond ? stringArray2 : mutArray; // expected-error{{from incompatible type 'NSArray *'}}
ip = cond ? mutArray : stringArray; // expected-error{{from incompatible type 'NSArray *'}}
ip = cond ? mutArray : stringArray2; // expected-error{{from incompatible type 'NSArray *'}}
object = cond ? stringArray : numberArray; // expected-warning{{incompatible operand types ('NSArray<NSString *> *' and 'NSArray<NSNumber *> *')}}
}
// --------------------------------------------------------------------------
// super
// --------------------------------------------------------------------------
@implementation NSStringArray
- (void)useSuperMethod {
int *ip;
ip = super.lastObject; // expected-error{{from incompatible type 'NSString *'}}
ip = [super objectAtIndexedSubscript:0]; // expected-error{{from incompatible type 'NSString *'}}
}
+ (void)useSuperMethod {
int *ip;
ip = super.array; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
ip = [super array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
}
@end
// --------------------------------------------------------------------------
// Template instantiation
// --------------------------------------------------------------------------
template<typename K, typename V>
struct NSMutableDictionaryOf {
typedef NSMutableDictionary<K, V> *type; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'K'}}
};
template<typename ...Args>
struct VariadicNSMutableDictionaryOf {
typedef NSMutableDictionary<Args...> *type; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'K'}}
// expected-error@-1{{too many type arguments for class 'NSMutableDictionary' (have 3, expected 2)}}
// expected-error@-2{{too few type arguments for class 'NSMutableDictionary' (have 1, expected 2)}}
};
void testInstantiation() {
int *ip;
typedef NSMutableDictionaryOf<NSString *, NSObject *>::type Dict1;
Dict1 d1 = ip; // expected-error{{cannot initialize a variable of type 'Dict1' (aka 'NSMutableDictionary<NSString *,NSObject *> *')}}
typedef NSMutableDictionaryOf<NSObject *, NSString *>::type Dict2; // expected-note{{in instantiation of template}}
}
void testVariadicInstantiation() {
int *ip;
typedef VariadicNSMutableDictionaryOf<NSString *, NSObject *>::type Dict1;
Dict1 d1 = ip; // expected-error{{cannot initialize a variable of type 'Dict1' (aka 'NSMutableDictionary<NSString *,NSObject *> *')}}
typedef VariadicNSMutableDictionaryOf<NSObject *, NSString *>::type Dict2; // expected-note{{in instantiation of template}}
typedef VariadicNSMutableDictionaryOf<NSString *, NSObject *, NSObject *>::type Dict3; // expected-note{{in instantiation of template}}
typedef VariadicNSMutableDictionaryOf<NSString *>::type Dict3; // expected-note{{in instantiation of template}}
}
// --------------------------------------------------------------------------
// Parameterized classes are not templates
// --------------------------------------------------------------------------
template<template<typename T, typename U> class TT>
struct AcceptsTemplateTemplate { };
typedef AcceptsTemplateTemplate<NSMutableDictionary> TemplateTemplateFail1; // expected-error{{template argument for template template parameter must be a class template or type alias template}}
template<typename T>
struct DependentTemplate {
typedef typename T::template apply<NSString *, NSObject *> type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}}
};
struct NSMutableDictionaryBuilder {
typedef NSMutableDictionary apply;
};
typedef DependentTemplate<NSMutableDictionaryBuilder>::type DependentTemplateFail1; // expected-note{{in instantiation of template class}}
template<typename K, typename V>
struct NonDependentTemplate {
typedef NSMutableDictionaryBuilder::template apply<NSString *, NSObject *> type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}}
// expected-error@-1{{expected member name or }}
};
// However, one can use an alias template to turn a parameterized
// class into a template.
template<typename K, typename V>
using NSMutableDictionaryAlias = NSMutableDictionary<K, V>;
typedef AcceptsTemplateTemplate<NSMutableDictionaryAlias> TemplateTemplateAlias1; // okay

View File

@ -916,6 +916,18 @@ bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
return false;
}
bool CursorVisitor::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
// Visit the bound, if it's explicit.
if (D->hasExplicitBound()) {
if (auto TInfo = D->getTypeSourceInfo()) {
if (Visit(TInfo->getTypeLoc()))
return true;
}
}
return false;
}
bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) {
if (TypeSourceInfo *TSInfo = ND->getReturnTypeSourceInfo())
if (Visit(TSInfo->getTypeLoc()))
@ -1091,14 +1103,6 @@ bool CursorVisitor::VisitObjCTypeParamList(ObjCTypeParamList *typeParamList) {
// Visit the type parameter.
if (Visit(MakeCXCursor(typeParam, TU, RegionOfInterest)))
return true;
// Visit the bound, if it's explicit.
if (typeParam->hasExplicitBound()) {
if (auto TInfo = typeParam->getTypeSourceInfo()) {
if (Visit(TInfo->getTypeLoc()))
return true;
}
}
}
return false;

View File

@ -217,6 +217,7 @@ public:
bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
bool VisitClassTemplateDecl(ClassTemplateDecl *D);
bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
bool VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
bool VisitObjCMethodDecl(ObjCMethodDecl *ND);
bool VisitObjCContainerDecl(ObjCContainerDecl *D);
bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND);