From f09aad86528a168b8253ab8e0f456b0d8010ee6e Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 7 Jul 2015 03:58:14 +0000 Subject: [PATCH] C++ support for Objective-C lightweight generics. Teach C++'s tentative parsing to handle specializations of Objective-C class types (e.g., NSArray) as well as Objective-C protocol qualifiers (id) 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 " id" which should have been written as "id ". Implements template instantiation support for, e.g., NSArray* 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@241545 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Type.h | 6 +- include/clang/AST/TypeLoc.h | 26 ++ include/clang/Basic/DiagnosticSemaKinds.td | 2 +- include/clang/Parse/Parser.h | 40 +- include/clang/Sema/DeclSpec.h | 59 +-- include/clang/Sema/Sema.h | 43 +- lib/AST/Type.cpp | 15 +- lib/AST/TypeLoc.cpp | 42 ++ lib/Lex/PPMacroExpansion.cpp | 1 + lib/Parse/ParseDecl.cpp | 40 +- lib/Parse/ParseExprCXX.cpp | 7 - lib/Parse/ParseInit.cpp | 5 +- lib/Parse/ParseObjc.cpp | 289 +++++++++---- lib/Parse/Parser.cpp | 55 ++- lib/Sema/DeclSpec.cpp | 25 -- lib/Sema/SemaDeclObjC.cpp | 72 ++-- lib/Sema/SemaType.cpp | 350 +++++++++++---- lib/Sema/TreeTransform.h | 193 ++++++++- test/Index/annotate-parameterized-classes.m | 12 +- test/Index/annotate-tokens.m | 7 + test/Parser/placeholder-recovery.m | 9 +- test/SemaObjC/parameterized_classes.m | 12 +- test/SemaObjC/protocol-archane.m | 4 + .../SemaObjCXX/parameterized_classes_subst.mm | 407 ++++++++++++++++++ tools/libclang/CIndex.cpp | 20 +- tools/libclang/CursorVisitor.h | 1 + 26 files changed, 1377 insertions(+), 365 deletions(-) create mode 100644 test/SemaObjCXX/parameterized_classes_subst.mm diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 3a360f772b..c3188e4a24 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -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. diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 16b0c2c9bd..e55036489c 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -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 getProtocolLocs() const { + return llvm::makeArrayRef(getProtocolLocArray(), getNumProtocols()); + } + bool hasBaseTypeAsWritten() const { return getLocalData()->HasBaseTypeAsWritten; } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 4e3bd5c663..1cf9e676cf 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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. diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 717bec5809..8340739b64 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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 &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl &protocols, + SmallVectorImpl &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 &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl &protocols, + SmallVectorImpl &protocolLocs, + SourceLocation &protocolRAngleLoc, + bool consumeLastToken); + + /// Parse a protocol qualifier type such as '', which is + /// an anachronistic way of writing 'id'. + 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); diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index f4eb69cc8e..41d4900632 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -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. - ArrayRef 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" and protocol-qualified id - // "id". - 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 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 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. diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 5f170098d5..a2f1197f15 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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 identifiers, ArrayRef identifierLocs, SourceLocation rAngleLoc, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl &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 protocols, + ArrayRef protocolLocs, + SourceLocation rAngleLoc); + + /// Build a specialized and/or protocol-qualified Objective-C type. + TypeResult actOnObjCTypeArgsAndProtocolQualifiers( + Scope *S, + SourceLocation Loc, + ParsedType BaseType, + SourceLocation TypeArgsLAngleLoc, + ArrayRef TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef Protocols, + ArrayRef ProtocolLocs, + SourceLocation ProtocolRAngleLoc); + + /// Build an Objective-C object pointer type. + QualType BuildObjCObjectType(QualType BaseType, + SourceLocation Loc, + SourceLocation TypeArgsLAngleLoc, + ArrayRef TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef Protocols, + ArrayRef 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. diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 106d42071c..c3d5feb78a 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -469,7 +469,10 @@ const RecordType *Type::getAsUnionType() const { ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, ArrayRef typeArgs, ArrayRef 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 { diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 02d0cec708..85bda6a06d 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -19,6 +19,8 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; +static const unsigned TypeLocMaxDataAlign = llvm::alignOf(); + //===----------------------------------------------------------------------===// // TypeLoc Implementation //===----------------------------------------------------------------------===// @@ -125,6 +127,46 @@ void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL, } } +namespace { + class TypeLocCopier : public TypeLocVisitor { + 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()); \ + } +#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(Data) + == llvm::RoundUpToAlignment(reinterpret_cast(Data), + TypeLocMaxDataAlign) && + reinterpret_cast(other.Data) + == llvm::RoundUpToAlignment(reinterpret_cast(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; diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index d52519e331..0fb4456790 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -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) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 231f6d4d97..9c12abab39 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -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

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

const"). // If a type specifier follows, it will be diagnosed elsewhere. diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 02176c4105..c1dafe9b49 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1805,13 +1805,6 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); - // Objective-C supports syntax of the form 'id' where 'id' - // is a specific typedef and 'itf' 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; } diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index f62c8be076..fe7e8f8ea3 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -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(); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 669c0653df..3dbecd0900 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -267,7 +267,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, SmallVector 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 typeArgs; + SourceLocation typeArgsRAngleLoc; + SmallVector protocols; + SmallVector 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 ProtocolRefs; - SmallVector 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); - } - 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)) { + 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); + } + } 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 &Protocols, SmallVectorImpl &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 &Protocols, } // Consume the '>'. - if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true, + if (ParseGreaterThanInTemplateList(EndLoc, consumeLastToken, /*ObjCGenericList=*/false)) return true; @@ -1556,30 +1560,43 @@ ParseObjCProtocolReferences(SmallVectorImpl &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 ProtocolDecl; - SmallVector 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 protocols; + SmallVector 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)* '>' -/// -void Parser::ParseObjCTypeArgsOrProtocolQualifiers( - DeclSpec &DS, +/// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>' +/// +void Parser::parseObjCTypeArgsOrProtocolQualifiers( + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl &protocols, + SmallVectorImpl &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 identifiers; - SmallVector identifierLocs; + SmallVectorImpl &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 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 &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl &protocols, + SmallVectorImpl &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 - 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 typeArgs; + SourceLocation typeArgsRAngleLoc; + SourceLocation protocolLAngleLoc; + SmallVector protocols; + SmallVector protocolLocs; + SourceLocation protocolRAngleLoc; // Parse type arguments and protocol qualifiers. - ParseObjCTypeArgsAndProtocolQualifiers(DS); - - // Form a declarator to turn this into a type. - Declarator D(DS, Declarator::TypeNameContext); - return Actions.ActOnTypeName(getCurScope(), D); + parseObjCTypeArgsAndProtocolQualifiers(typeArgsLAngleLoc, typeArgs, + typeArgsRAngleLoc, protocolLAngleLoc, + protocols, protocolLocs, + protocolRAngleLoc, consumeLastToken); + + // 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 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 protocols; + SmallVector 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 protocols; + SmallVector 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(); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index e32df95548..e76f767786 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -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. diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 5c75536e94..ea3872f427 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -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 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(); diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index f28abf4c07..48aa2467d2 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -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 identifiers, ArrayRef identifierLocs, SourceLocation rAngleLoc, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl &protocols, + SourceLocation &protocolRAngleLoc, bool warnOnIncompleteProtocols) { // Local function that updates the declaration specifiers with // protocol information. - SmallVector 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(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(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 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; } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 1257ae361f..06d832c9de 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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 typeArgs, - SourceRange typeArgsRange) { + ArrayRef typeArgs, + SourceRange typeArgsRange, + bool failOnError = false) { // We can only apply type arguments to an Objective-C class type. const auto *objcObjectType = type->getAs(); 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 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()) + 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()) { + // 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(); @@ -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 protocols, - const SourceLocation *protocolLocs) { + const SourceLocation *protocolLocs, + bool failOnError = false) { ASTContext &ctx = S.Context; if (const ObjCObjectType *objT = dyn_cast(type.getTypePtr())){ // FIXME: Check for protocols to which the class type is already @@ -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 TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef Protocols, + ArrayRef 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 protocols, + ArrayRef protocolLocs, + SourceLocation rAngleLoc) { + // Form id. + 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(); + ObjCObjectPointerTL.setStarLoc(SourceLocation()); // implicit + + auto ObjCObjectTL = ObjCObjectPointerTL.getPointeeLoc() + .castAs(); + 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 TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef Protocols, + ArrayRef 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 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 or Class, we'll have an + // object pointer type. Fill in source information for it. + if (auto ObjCObjectPointerTL = ResultTL.getAs()) { + // The '*' is implicit. + ObjCObjectPointerTL.setStarLoc(SourceLocation()); + ResultTL = ObjCObjectPointerTL.getPointeeLoc(); + } + + auto ObjCObjectTL = ResultTL.castAs(); + + // 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: - // "" 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; diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 80896be981..8b150c3a65 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -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 TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef Protocols, + ArrayRef 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 QualType TreeTransform::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 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()) { + AnyChanged = true; + + // We have a pack expansion. Instantiate it. + const auto *PackExpansion = PackExpansionLoc.getType() + ->castAs(); + SmallVector 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 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(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(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 QualType TreeTransform::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(Result); + NewT.setStarLoc(TL.getStarLoc()); + return Result; } //===----------------------------------------------------------------------===// @@ -10493,6 +10649,31 @@ TreeTransform::RebuildMemberPointerType(QualType PointeeType, getDerived().getBaseEntity()); } +template +QualType TreeTransform::RebuildObjCObjectType( + QualType BaseType, + SourceLocation Loc, + SourceLocation TypeArgsLAngleLoc, + ArrayRef TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef Protocols, + ArrayRef ProtocolLocs, + SourceLocation ProtocolRAngleLoc) { + return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc, + TypeArgs, TypeArgsRAngleLoc, + ProtocolLAngleLoc, Protocols, ProtocolLocs, + ProtocolRAngleLoc, + /*FailOnError=*/true); +} + +template +QualType TreeTransform::RebuildObjCObjectPointerType( + QualType PointeeType, + SourceLocation Star) { + return SemaRef.Context.getObjCObjectPointerType(PointeeType); +} + template QualType TreeTransform::RebuildArrayType(QualType ElementType, diff --git a/test/Index/annotate-parameterized-classes.m b/test/Index/annotate-parameterized-classes.m index 6a53fed4bd..762ae2aece 100644 --- a/test/Index/annotate-parameterized-classes.m +++ b/test/Index/annotate-parameterized-classes.m @@ -17,19 +17,15 @@ typedef A, 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 diff --git a/test/Index/annotate-tokens.m b/test/Index/annotate-tokens.m index 9a7e28a666..0a76105a94 100644 --- a/test/Index/annotate-tokens.m +++ b/test/Index/annotate-tokens.m @@ -152,6 +152,7 @@ static Rdar8595462_A * Rdar8595462_staticVar; @property int extensionProperty; @end +typedef id *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) diff --git a/test/Parser/placeholder-recovery.m b/test/Parser/placeholder-recovery.m index 3fe1d62c30..b43b0e4a57 100644 --- a/test/Parser/placeholder-recovery.m +++ b/test/Parser/placeholder-recovery.m @@ -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#> // expected-error 2{{expected identifier}} \ -// expected-error{{cannot find protocol declaration for 'NSObject'}} \ +@protocol <#protocol name#> // 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 diff --git a/test/SemaObjC/parameterized_classes.m b/test/SemaObjC/parameterized_classes.m index 9834f7cd11..eb3e122e82 100644 --- a/test/SemaObjC/parameterized_classes.m +++ b/test/SemaObjC/parameterized_classes.m @@ -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> typeArgs8; typedef PC15 typeArgs8b; // expected-error{{type argument 'NSObject *' does not satisy the bound ('id') of type parameter 'V'}} + NSObject *> typeArgs8b; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id') of type parameter 'V'}} typedef PC15 typeArgs9; typedef PC15 typeArgs10; // expected-error{{type argument 'id' does not satisy the bound ('id') of type parameter 'V'}} + id> typeArgs10; // expected-error{{type argument 'id' does not satisfy the bound ('id') of type parameter 'V'}} typedef PC15 : PC1 // expected-error{{unknown type name 'U'}} @end -@interface PC24 : PC1 // expected-error{{type argument 'T' (aka 'id') does not satisy the bound ('NSObject *') of type parameter 'U'}} +@interface PC24 : PC1 // expected-error{{type argument 'T' (aka 'id') does not satisfy the bound ('NSObject *') of type parameter 'U'}} @end @interface NSFoo : PC1 // okay diff --git a/test/SemaObjC/protocol-archane.m b/test/SemaObjC/protocol-archane.m index 788edf276d..f2f6025a5a 100644 --- a/test/SemaObjC/protocol-archane.m +++ b/test/SemaObjC/protocol-archane.m @@ -40,3 +40,7 @@ Class UnfortunateGCCExtension; - (void)crashWith:()a { // expected-warning {{protocol has no object type specified; defaults to qualified 'id'}} } @end + +typedef id TwoTypeSpecs; // expected-warning{{no object type specified}} +// expected-error@-1{{typedef redefinition with different types ('id' vs 'id')}} +// expected-error@-2{{expected ';' after top level declarator}} diff --git a/test/SemaObjCXX/parameterized_classes_subst.mm b/test/SemaObjCXX/parameterized_classes_subst.mm new file mode 100644 index 0000000000..cd0096c3fe --- /dev/null +++ b/test/SemaObjCXX/parameterized_classes_subst.mm @@ -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 +@end + +@interface NSNumber : NSObject +@end + +@interface NSArray : NSObject { +@public + T *data; // don't try this at home +} +- (T)objectAtIndexedSubscript:(int)index; ++ (NSArray *)array; +@property (copy,nonatomic) T lastObject; +@end + +@interface NSMutableArray : NSArray +-(instancetype)initWithArray:(NSArray *)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 +@end + +@interface NSSet : NSObject +- (T)firstObject; +@property (nonatomic, copy) NSArray *allObjects; +@end + +// Parameterized inheritance (simple case) +@interface NSMutableSet> : NSSet +- (void)addObject:(U)object; // expected-note 7{{passing argument to parameter 'object' here}} +@end + +@interface Widget : NSObject +@end + +// Non-parameterized class inheriting from a specialization of a +// parameterized class. +@interface WidgetSet : NSMutableSet +@end + +// Parameterized inheritance with a more interesting transformation in +// the specialization. +@interface MutableSetOfArrays : NSMutableSet*> +@end + +// Inheriting from an unspecialized form of a parameterized type. +@interface UntypedMutableSet : NSMutableSet +@end + +@interface Window : NSObject +@end + +@interface NSDictionary : NSObject +- (V)objectForKeyedSubscript:(K)key; // expected-note 2{{parameter 'key'}} +@end + +@interface NSMutableDictionary, V> : NSDictionary // 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 +@end + +@interface NSSet (Searching) +- (T)findObject:(T)object; +@end + + +// -------------------------------------------------------------------------- +// Message sends. +// -------------------------------------------------------------------------- +void test_message_send_result( + NSSet *stringSet, + NSMutableSet *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays *mutStringArraySet, + NSSet *set, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + NSArray *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 *'}} + 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 alloc]; // expected-error{{from incompatible type 'NSSet *'}} + ip = [NSSet alloc]; // expected-error{{from incompatible type 'NSSet *'}} + ip = [MutableSetOfArrays alloc]; // expected-error{{from incompatible type 'MutableSetOfArrays *'}} + ip = [MutableSetOfArrays alloc]; // expected-error{{from incompatible type 'MutableSetOfArrays *'}} + ip = [NSArray array]; // expected-error{{from incompatible type 'NSArray *'}} + ip = [NSArray array]; // expected-error{{from incompatible type 'NSArray *'}} + + ip = [[NSMutableArray alloc] init]; // expected-error{{from incompatible type 'NSMutableArray *'}} + + [[NSMutableArray alloc] initWithArray: stringArray]; // okay + [[NSMutableArray alloc] initWithArray: stringArray]; // okay + [[NSMutableArray alloc] initWithArray: stringArray]; // expected-error{{parameter of type 'NSArray *' with an lvalue of type 'NSArray *'}} +} + +void test_message_send_param( + NSMutableSet *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays *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'}} + [mutStringArraySet addObject: window]; // expected-error{{parameter of type 'NSArray *'}} + [mutSet addObject: window]; // expected-error{{parameter of type 'id'}} + [mutArraySet addObject: window]; // expected-error{{parameter of type 'id'}} + [block addObject: window]; // expected-error{{parameter of type 'id'}} +} + +// -------------------------------------------------------------------------- +// Property accesses. +// -------------------------------------------------------------------------- +void test_property_read( + NSSet *stringSet, + NSMutableSet *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays *mutStringArraySet, + NSSet *set, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + NSMutableDictionary *mutDict) { + int *ip; + ip = stringSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}} + ip = mutStringSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}} + ip = widgetSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}} + ip = untypedMutSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}} + ip = mutStringArraySet.allObjects; // expected-error{{from incompatible type 'NSArray *> *'}} + 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 *mutStringSet, + WidgetSet *widgetSet, + UntypedMutableSet *untypedMutSet, + MutableSetOfArrays *mutStringArraySet, + NSMutableSet *mutSet, + MutableSetOfArrays *mutArraySet, + NSMutableDictionary *mutDict) { + int *ip; + + mutStringSet.allObjects = ip; // expected-error{{to 'NSArray *'}} + widgetSet.allObjects = ip; // expected-error{{to 'NSArray *'}} + untypedMutSet.allObjects = ip; // expected-error{{to 'NSArray *'}} + mutStringArraySet.allObjects = ip; // expected-error{{to 'NSArray *> *'}} + mutSet.allObjects = ip; // expected-error{{to 'NSArray *'}} + mutArraySet.allObjects = ip; // expected-error{{to 'NSArray *'}} + + mutDict.someRandomKey = ip; // expected-error{{to 'id'}} +} + +// -------------------------------------------------------------------------- +// Subscripting +// -------------------------------------------------------------------------- +void test_subscripting( + NSArray *stringArray, + NSMutableArray *mutStringArray, + NSArray *array, + NSMutableArray *mutArray, + NSDictionary *stringWidgetDict, + NSMutableDictionary *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'}} +} + +// -------------------------------------------------------------------------- +// Instance variable access. +// -------------------------------------------------------------------------- +void test_instance_variable(NSArray *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 *stringArray, + NSArray *numberArray, + NSMutableArray *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 *' from incompatible type 'NSArray *'}} + + // Specialized -> specialized (different levels). + stringArray = mutStringArray; + + // Specialized -> specialized failure (different levels). + numberArray = mutStringArray; // expected-error{{assigning to 'NSArray *' from incompatible type 'NSMutableArray *'}} + + // Unspecialized -> specialized (different levels). + stringArray = mutArray; + + // Specialized -> unspecialized (different levels). + array = mutStringArray; +} + +// -------------------------------------------------------------------------- +// Ternary operator +// -------------------------------------------------------------------------- +void test_ternary_operator(NSArray *stringArray, + NSArray *numberArray, + NSMutableArray *mutStringArray, + NSStringArray *stringArray2, + NSArray *array, + NSMutableArray *mutArray, + int cond) { + int *ip; + id object; + + ip = cond ? stringArray : mutStringArray; // expected-error{{from incompatible type 'NSArray *'}} + ip = cond ? mutStringArray : stringArray; // expected-error{{from incompatible type 'NSArray *'}} + + ip = cond ? stringArray2 : mutStringArray; // expected-error{{from incompatible type 'NSArray *'}} + ip = cond ? mutStringArray : stringArray2; // expected-error{{from incompatible type 'NSArray *'}} + + 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 *' and 'NSArray *')}} +} + +// -------------------------------------------------------------------------- +// 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 *'}} + ip = [super array]; // expected-error{{from incompatible type 'NSArray *'}} +} +@end + +// -------------------------------------------------------------------------- +// Template instantiation +// -------------------------------------------------------------------------- +template +struct NSMutableDictionaryOf { + typedef NSMutableDictionary *type; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id') of type parameter 'K'}} +}; + +template +struct VariadicNSMutableDictionaryOf { + typedef NSMutableDictionary *type; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id') 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::type Dict1; + Dict1 d1 = ip; // expected-error{{cannot initialize a variable of type 'Dict1' (aka 'NSMutableDictionary *')}} + + typedef NSMutableDictionaryOf::type Dict2; // expected-note{{in instantiation of template}} +} + +void testVariadicInstantiation() { + int *ip; + + typedef VariadicNSMutableDictionaryOf::type Dict1; + Dict1 d1 = ip; // expected-error{{cannot initialize a variable of type 'Dict1' (aka 'NSMutableDictionary *')}} + + typedef VariadicNSMutableDictionaryOf::type Dict2; // expected-note{{in instantiation of template}} + + typedef VariadicNSMutableDictionaryOf::type Dict3; // expected-note{{in instantiation of template}} + + typedef VariadicNSMutableDictionaryOf::type Dict3; // expected-note{{in instantiation of template}} +} + +// -------------------------------------------------------------------------- +// Parameterized classes are not templates +// -------------------------------------------------------------------------- +template class TT> +struct AcceptsTemplateTemplate { }; + +typedef AcceptsTemplateTemplate TemplateTemplateFail1; // expected-error{{template argument for template template parameter must be a class template or type alias template}} + +template +struct DependentTemplate { + typedef typename T::template apply type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}} +}; + +struct NSMutableDictionaryBuilder { + typedef NSMutableDictionary apply; +}; + +typedef DependentTemplate::type DependentTemplateFail1; // expected-note{{in instantiation of template class}} + +template +struct NonDependentTemplate { + typedef NSMutableDictionaryBuilder::template apply 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 +using NSMutableDictionaryAlias = NSMutableDictionary; + +typedef AcceptsTemplateTemplate TemplateTemplateAlias1; // okay + + diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index a2467ebad4..df0ed2ad65 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -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; diff --git a/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h index 2a0f520598..91f63b40f6 100644 --- a/tools/libclang/CursorVisitor.h +++ b/tools/libclang/CursorVisitor.h @@ -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); -- 2.50.1