From 9bd1d8d174a9d15ae343246c8322299248b9e92a Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 21 Oct 2010 23:17:00 +0000 Subject: [PATCH] Teach the C++ simple-type-specifier parser and tentative parses about protocol-qualified types such as id. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117081 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 2 + lib/Parse/ParseDecl.cpp | 78 ++++++++---------------------- lib/Parse/ParseExprCXX.cpp | 14 +++++- lib/Parse/ParseObjc.cpp | 17 +++++++ lib/Parse/ParseTentative.cpp | 75 +++++++++++++++++++++++++--- test/SemaObjCXX/protocol-lookup.mm | 5 ++ 6 files changed, 125 insertions(+), 66 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index c4cf05c31d..89e49c33ba 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -948,6 +948,7 @@ private: bool WarnOnDeclarations, SourceLocation &LAngleLoc, SourceLocation &EndProtoLoc); + void ParseObjCProtocolQualifiers(DeclSpec &DS); void ParseObjCInterfaceDeclList(Decl *interfaceDecl, tok::ObjCKeywordKind contextKey); Decl *ParseObjCAtProtocolDeclaration(SourceLocation atLoc, @@ -1423,6 +1424,7 @@ private: TPResult TryParseDeclarationSpecifier(); TPResult TryParseSimpleDeclaration(); TPResult TryParseTypeofSpecifier(); + TPResult TryParseProtocolQualifiers(); TPResult TryParseInitDeclaratorList(); TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true); TPResult TryParseParameterDeclarationClause(); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index e4c7569b61..35a35f33b5 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1093,20 +1093,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // 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) || !getLang().ObjC1) - continue; - - SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector ProtocolDecl; - llvm::SmallVector ProtocolLocs; - ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, - LAngleLoc, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), - ProtocolLocs.data(), LAngleLoc); - - DS.SetRangeEnd(EndProtoLoc); + // Objective-C interface. + if (Tok.is(tok::less) && getLang().ObjC1) + ParseObjCProtocolQualifiers(DS); + continue; } @@ -1163,21 +1153,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // 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) || !getLang().ObjC1) - continue; - - SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector ProtocolDecl; - llvm::SmallVector ProtocolLocs; - ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, - LAngleLoc, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), - ProtocolLocs.data(), LAngleLoc); - - DS.SetRangeEnd(EndProtoLoc); - + // Objective-C interface. + if (Tok.is(tok::less) && getLang().ObjC1) + ParseObjCProtocolQualifiers(DS); + // Need to support trailing type qualifiers (e.g. "id

const"). // If a type specifier follows, it will be diagnosed elsewhere. continue; @@ -1445,23 +1424,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (DS.hasTypeSpecifier() || !getLang().ObjC1) goto DoneWithDeclSpec; - { - SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector ProtocolDecl; - llvm::SmallVector ProtocolLocs; - ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, - LAngleLoc, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), - ProtocolLocs.data(), LAngleLoc); - DS.SetRangeEnd(EndProtoLoc); - - Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id) - << FixItHint::CreateInsertion(Loc, "id") - << SourceRange(Loc, EndProtoLoc); - // Need to support trailing type qualifiers (e.g. "id

const"). - // If a type specifier follows, it will be diagnosed elsewhere. - continue; - } + ParseObjCProtocolQualifiers(DS); + + Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id) + << FixItHint::CreateInsertion(Loc, "id") + << SourceRange(Loc, DS.getSourceRange().getEnd()); + + // Need to support trailing type qualifiers (e.g. "id

const"). + // If a type specifier follows, it will be diagnosed elsewhere. + continue; } // If the specifier wasn't legal, issue a diagnostic. if (isInvalid) { @@ -1576,18 +1547,9 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, // 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) || !getLang().ObjC1) - return true; - - SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector ProtocolDecl; - llvm::SmallVector ProtocolLocs; - ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, - LAngleLoc, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), - ProtocolLocs.data(), LAngleLoc); - - DS.SetRangeEnd(EndProtoLoc); + if (Tok.is(tok::less) && getLang().ObjC1) + ParseObjCProtocolQualifiers(DS); + return true; } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 77cb4492f6..7b03757cdc 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -914,7 +914,19 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { case tok::annot_typename: { DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, getTypeAnnotation(Tok)); - break; + + 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) && getLang().ObjC1) + ParseObjCProtocolQualifiers(DS); + + DS.Finish(Diags, PP); + return; } // builtin types diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 2bd44703d9..f54c3eef07 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -1039,6 +1039,23 @@ ParseObjCProtocolReferences(llvm::SmallVectorImpl &Protocols, return false; } +/// \brief Parse the Objective-C protocol qualifiers that follow a typename +/// in a decl-specifier-seq, starting at the '<'. +void Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) { + assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'"); + assert(getLang().ObjC1 && "Protocol qualifiers only exist in Objective-C"); + SourceLocation LAngleLoc, EndProtoLoc; + llvm::SmallVector ProtocolDecl; + llvm::SmallVector ProtocolLocs; + ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, + LAngleLoc, EndProtoLoc); + DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), + ProtocolLocs.data(), LAngleLoc); + if (EndProtoLoc.isValid()) + DS.SetRangeEnd(EndProtoLoc); +} + + /// objc-class-instance-variables: /// '{' objc-instance-variable-decl-list[opt] '}' /// diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 731822ecdd..9bd000c323 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -139,9 +139,13 @@ Parser::TPResult Parser::TryParseSimpleDeclaration() { if (Tok.is(tok::kw_typeof)) TryParseTypeofSpecifier(); - else + else { ConsumeToken(); - + + if (getLang().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } + assert(Tok.is(tok::l_paren) && "Expected '('"); TPResult TPR = TryParseInitDeclaratorList(); @@ -242,8 +246,12 @@ bool Parser::isCXXConditionDeclaration() { // type-specifier-seq if (Tok.is(tok::kw_typeof)) TryParseTypeofSpecifier(); - else + else { ConsumeToken(); + + if (getLang().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } assert(Tok.is(tok::l_paren) && "Expected '('"); // declarator @@ -313,8 +321,13 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { // type-specifier-seq if (Tok.is(tok::kw_typeof)) TryParseTypeofSpecifier(); - else + else { ConsumeToken(); + + if (getLang().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } + assert(Tok.is(tok::l_paren) && "Expected '('"); // declarator @@ -808,6 +821,28 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { // simple-type-specifier: + case tok::annot_typename: + case_typename: + // In Objective-C, we might have a protocol-qualified type. + if (getLang().ObjC1 && NextToken().is(tok::less)) { + // Tentatively parse the + TentativeParsingAction PA(*this); + ConsumeToken(); // The type token + + TPResult TPR = TryParseProtocolQualifiers(); + bool isFollowedByParen = Tok.is(tok::l_paren); + + PA.Revert(); + + if (TPR == TPResult::Error()) + return TPResult::Error(); + + if (isFollowedByParen) + return TPResult::Ambiguous(); + + return TPResult::True(); + } + case tok::kw_char: case tok::kw_wchar_t: case tok::kw_char16_t: @@ -821,8 +856,6 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw_float: case tok::kw_double: case tok::kw_void: - case tok::annot_typename: - case_typename: if (NextToken().is(tok::l_paren)) return TPResult::Ambiguous(); @@ -878,6 +911,30 @@ Parser::TPResult Parser::TryParseTypeofSpecifier() { return TPResult::Ambiguous(); } +/// [ObjC] protocol-qualifiers: +//// '<' identifier-list '>' +Parser::TPResult Parser::TryParseProtocolQualifiers() { + assert(Tok.is(tok::less) && "Expected '<' for qualifier list"); + ConsumeToken(); + do { + if (Tok.isNot(tok::identifier)) + return TPResult::Error(); + ConsumeToken(); + + if (Tok.is(tok::comma)) { + ConsumeToken(); + continue; + } + + if (Tok.is(tok::greater)) { + ConsumeToken(); + return TPResult::Ambiguous(); + } + } while (false); + + return TPResult::Error(); +} + Parser::TPResult Parser::TryParseDeclarationSpecifier() { TPResult TPR = isCXXDeclarationSpecifier(); if (TPR != TPResult::Ambiguous()) @@ -885,8 +942,12 @@ Parser::TPResult Parser::TryParseDeclarationSpecifier() { if (Tok.is(tok::kw_typeof)) TryParseTypeofSpecifier(); - else + else { ConsumeToken(); + + if (getLang().ObjC1 && Tok.is(tok::less)) + TryParseProtocolQualifiers(); + } assert(Tok.is(tok::l_paren) && "Expected '('!"); return TPResult::Ambiguous(); diff --git a/test/SemaObjCXX/protocol-lookup.mm b/test/SemaObjCXX/protocol-lookup.mm index ed3fbe0f72..bd8444c0ad 100644 --- a/test/SemaObjCXX/protocol-lookup.mm +++ b/test/SemaObjCXX/protocol-lookup.mm @@ -49,3 +49,8 @@ @end +void rdar8575095(id a) { + [id(a) retain]; + id x(id(0)); + id x2(id(y)); // expected-warning{{parentheses were disambiguated as a function declarator}} +} -- 2.40.0