]> granicus.if.org Git - clang/commitdiff
Teach the C++ simple-type-specifier parser and tentative parses about
authorDouglas Gregor <dgregor@apple.com>
Thu, 21 Oct 2010 23:17:00 +0000 (23:17 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 21 Oct 2010 23:17:00 +0000 (23:17 +0000)
protocol-qualified types such as id<Protocol>.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117081 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Parse/Parser.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseExprCXX.cpp
lib/Parse/ParseObjc.cpp
lib/Parse/ParseTentative.cpp
test/SemaObjCXX/protocol-lookup.mm

index c4cf05c31d14b3568fcd0d33779abb03e9515821..89e49c33ba98d4e89cfb660306e3b664ad38cd87 100644 (file)
@@ -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();
index e4c7569b61db338d109cbc9006df4a772e366118..35a35f33b5c9ed1dd7a293149fba0e717fd4f231 100644 (file)
@@ -1093,20 +1093,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
 
       // 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) || !getLang().ObjC1)
-        continue;
-
-      SourceLocation LAngleLoc, EndProtoLoc;
-      llvm::SmallVector<Decl *, 8> ProtocolDecl;
-      llvm::SmallVector<SourceLocation, 8> 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<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) || !getLang().ObjC1)
-        continue;
-
-      SourceLocation LAngleLoc, EndProtoLoc;
-      llvm::SmallVector<Decl *, 8> ProtocolDecl;
-      llvm::SmallVector<SourceLocation, 8> 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<p> 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<Decl *, 8> ProtocolDecl;
-        llvm::SmallVector<SourceLocation, 8> 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<p> 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<p> 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<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) || !getLang().ObjC1)
-      return true;
-
-    SourceLocation LAngleLoc, EndProtoLoc;
-    llvm::SmallVector<Decl *, 8> ProtocolDecl;
-    llvm::SmallVector<SourceLocation, 8> 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;
   }
 
index 77cb4492f6750278649981a9ca97bc1826b7b4ce..7b03757cdca579672048acc246c30905919c5046 100644 (file)
@@ -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<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) && getLang().ObjC1)
+      ParseObjCProtocolQualifiers(DS);
+    
+    DS.Finish(Diags, PP);
+    return;
   }
 
   // builtin types
index 2bd44703d9f6d9c651b8d387e8093c4ee8c0b6dd..f54c3eef07982aa0a9f785c4fdd926228265d90b 100644 (file)
@@ -1039,6 +1039,23 @@ ParseObjCProtocolReferences(llvm::SmallVectorImpl<Decl *> &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<Decl *, 8> ProtocolDecl;
+  llvm::SmallVector<SourceLocation, 8> 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] '}'
 ///
index 731822ecddd1265edfc7b1a2b9e64c1427516133..9bd000c323ec977562dfa9109565538edc93f929 100644 (file)
@@ -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();
index ed3fbe0f72bfc301b51fab7337c269ac99aa6e78..bd8444c0ad6826305c27f3dffcc6bbb1dc038343 100644 (file)
@@ -49,3 +49,8 @@
 
 @end
 
+void rdar8575095(id a) {
+  [id<NSObject>(a) retain];
+  id<NSObject> x(id<NSObject>(0));
+  id<NSObject> x2(id<NSObject>(y)); // expected-warning{{parentheses were disambiguated as a function declarator}}
+}