Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -7318,6 +7318,12 @@ ArrayRef ProtocolId, SmallVectorImpl &Protocols); + void DiagnoseTypeArgsAndProtocols(IdentifierInfo *ProtocolId, + SourceLocation ProtocolLoc, + IdentifierInfo *TypeArgId, + SourceLocation TypeArgLoc, + bool SelectProtocolFirst = false); + /// Given a list of identifiers (and their locations), resolve the /// names to either Objective-C protocol qualifiers or type /// arguments, as appropriate. Index: lib/Parse/ParseObjc.cpp =================================================================== --- lib/Parse/ParseObjc.cpp +++ lib/Parse/ParseObjc.cpp @@ -1694,10 +1694,15 @@ } // We syntactically matched a type argument, so commit to parsing - // type arguments. + // type arguments. Finding protocol arguments after here is an error. // Convert the identifiers into type arguments. bool invalid = false; + IdentifierInfo *foundProtocolId = nullptr; + SourceLocation foundProtocolSrcLoc; + SmallVector unknownTypeArgs; + SmallVector unknownTypeArgsLoc; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { ParsedType typeArg = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope()); @@ -1717,11 +1722,24 @@ invalid = true; } else { invalid = true; + auto *P = Actions.LookupProtocol(identifiers[i], identifierLocs[i]); + if (!P) { + unknownTypeArgs.push_back(identifiers[i]); + unknownTypeArgsLoc.push_back(identifierLocs[i]); + continue; + } + if (!foundProtocolId) { + foundProtocolId = identifiers[i]; + foundProtocolSrcLoc = identifierLocs[i]; + } } } // Continue parsing type-names. + IdentifierInfo *foundValidTypeId = nullptr; + SourceLocation foundValidTypeSrcLoc; do { + Token CurTypeTok = Tok; TypeResult typeArg = ParseTypeName(); // Consume the '...' for a pack expansion. @@ -1733,11 +1751,28 @@ if (typeArg.isUsable()) { typeArgs.push_back(typeArg.get()); + if (!foundValidTypeId) { + foundValidTypeId = CurTypeTok.getIdentifierInfo(); + foundValidTypeSrcLoc = CurTypeTok.getLocation(); + } } else { invalid = true; } } while (TryConsumeToken(tok::comma)); + // Diagnose the mix between type args and protocols. + if (foundProtocolId && foundValidTypeId) + Actions.DiagnoseTypeArgsAndProtocols(foundProtocolId, foundProtocolSrcLoc, + foundValidTypeId, + foundValidTypeSrcLoc); + + // Diagnose unknown arg types. + ParsedType T; + if (unknownTypeArgs.size()) + for (unsigned i = 0, e = unknownTypeArgsLoc.size(); i < e; ++i) + Actions.DiagnoseUnknownTypeName(unknownTypeArgs[i], unknownTypeArgsLoc[i], + getCurScope(), nullptr, T); + // Parse the closing '>'. SourceLocation rAngleLoc; (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken, Index: lib/Sema/SemaDeclObjC.cpp =================================================================== --- lib/Sema/SemaDeclObjC.cpp +++ lib/Sema/SemaDeclObjC.cpp @@ -1303,6 +1303,16 @@ }; } // end anonymous namespace +void Sema::DiagnoseTypeArgsAndProtocols(IdentifierInfo *ProtocolId, + SourceLocation ProtocolLoc, + IdentifierInfo *TypeArgId, + SourceLocation TypeArgLoc, + bool SelectProtocolFirst) { + Diag(TypeArgLoc, diag::err_objc_type_args_and_protocols) + << SelectProtocolFirst << TypeArgId << ProtocolId + << SourceRange(ProtocolLoc); +} + void Sema::actOnObjCTypeArgsOrProtocolQualifiers( Scope *S, ParsedType baseType, @@ -1570,11 +1580,9 @@ // We have a conflict: some names refer to protocols and others // refer to types. - Diag(identifierLocs[i], diag::err_objc_type_args_and_protocols) - << (protocols[i] != nullptr) - << identifiers[i] - << identifiers[0] - << SourceRange(identifierLocs[0]); + DiagnoseTypeArgsAndProtocols(identifiers[0], identifierLocs[0], + identifiers[i], identifierLocs[i], + protocols[i] != nullptr); protocols.clear(); typeArgs.clear(); Index: test/SemaObjC/parameterized_classes.m =================================================================== --- test/SemaObjC/parameterized_classes.m +++ test/SemaObjC/parameterized_classes.m @@ -240,6 +240,9 @@ // Type/protocol conflict. typedef PC4 typeArgsProtocolQualsConflict1; // expected-error{{angle brackets contain both a type ('ObjCStringRef') and a protocol ('NSCopying')}} +typedef PC4 typeArgsProtocolQualsConflict2; // expected-error{{angle brackets contain both a type ('NSString') and a protocol ('NSCopying')}} +typedef PC4 typeArgsProtocolQualsConflict3; // expected-error{{angle brackets contain both a type ('NSString') and a protocol ('NSCopying')}} expected-error{{unknown type name 'UnknownType'}} +typedef PC4 typeArgsProtocolQualsConflict4; // expected-error{{unknown type name 'UnknownType'}} // Handling the '>>' in type argument lists. typedef PC4, NSObject *, id> typeArgs6;