diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/Type.cpp | 15 | ||||
| -rw-r--r-- | clang/lib/AST/TypeLoc.cpp | 42 | ||||
| -rw-r--r-- | clang/lib/Lex/PPMacroExpansion.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 40 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 7 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseInit.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseObjc.cpp | 289 | ||||
| -rw-r--r-- | clang/lib/Parse/Parser.cpp | 55 | ||||
| -rw-r--r-- | clang/lib/Sema/DeclSpec.cpp | 25 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 72 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 350 | ||||
| -rw-r--r-- | clang/lib/Sema/TreeTransform.h | 193 |
12 files changed, 822 insertions, 272 deletions
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 106d42071cc..c3d5feb78a9 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -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 { diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index 02d0cec708c..85bda6a06d9 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -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; diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index d52519e3313..0fb4456790e 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/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/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 231f6d4d97a..9c12abab39d 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/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<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. diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 02176c41059..c1dafe9b49b 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/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<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; } diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp index f62c8be0769..fe7e8f8ea35 100644 --- a/clang/lib/Parse/ParseInit.cpp +++ b/clang/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/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 669c0653df8..3dbecd09008 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -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); - } - 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<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)* '>' -/// -void Parser::ParseObjCTypeArgsOrProtocolQualifiers( - DeclSpec &DS, +/// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>' +/// +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); - - // 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<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(); diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index e32df95548d..e76f767786f 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/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/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 5c75536e94a..ea3872f4270 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/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<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(); diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index f28abf4c070..48aa2467d24 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/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<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; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 1257ae361f0..06d832c9de8 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/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<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; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 80896be981d..8b150c3a658 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/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<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; } //===----------------------------------------------------------------------===// @@ -10494,6 +10650,31 @@ TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType, } 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, ArrayType::ArraySizeModifier SizeMod, |

