forked from OSchip/llvm-project
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:
parent
c5e07f5c11
commit
9bda6cff20
clang
include/clang
lib
AST
Lex
Parse
Sema
test
Index
Parser
SemaObjC
SemaObjCXX
tools/libclang
|
@ -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.
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue