r240188 - Handle 'instancetype' in ParseDeclarationSpecifiers.

Douglas Gregor dgregor at apple.com
Fri Jun 19 16:18:00 PDT 2015


Author: dgregor
Date: Fri Jun 19 18:18:00 2015
New Revision: 240188

URL: http://llvm.org/viewvc/llvm-project?rev=240188&view=rev
Log:
Handle 'instancetype' in ParseDeclarationSpecifiers.

...instead of as a special case in ParseObjCTypeName with lots of
duplicated logic. Besides being a nice refactoring, this also allows
"- (instancetype __nonnull)self" in addition to "- (nonnull instancetype)self".

rdar://problem/19924646

Modified:
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/test/SemaObjC/nullability.m

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=240188&r1=240187&r2=240188&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Fri Jun 19 18:18:00 2015
@@ -626,6 +626,16 @@ private:
                                 const char *&PrevSpec, unsigned &DiagID,
                                 bool &isInvalid);
 
+  /// Returns true if the current token is the identifier 'instancetype'.
+  ///
+  /// Should only be used in Objective-C language modes.
+  bool isObjCInstancetype() {
+    assert(getLangOpts().ObjC1);
+    if (!Ident_instancetype)
+      Ident_instancetype = PP.getIdentifierInfo("instancetype");
+    return Tok.getIdentifierInfo() == Ident_instancetype;
+  }
+
   /// TryKeywordIdentFallback - For compatibility with system headers using
   /// keywords as identifiers, attempt to convert the current token to an
   /// identifier and optionally disable the keyword for the remainder of the
@@ -1692,7 +1702,8 @@ private:
     DSC_trailing, // C++11 trailing-type-specifier in a trailing return type
     DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration
     DSC_top_level, // top-level/namespace declaration context
-    DSC_template_type_arg // template type argument context
+    DSC_template_type_arg, // template type argument context
+    DSC_objc_method_result, // ObjC method result context, enables 'instancetype'
   };
 
   /// Is this a context in which we are parsing just a type-specifier (or
@@ -1702,6 +1713,7 @@ private:
     case DSC_normal:
     case DSC_class:
     case DSC_top_level:
+    case DSC_objc_method_result:
       return false;
 
     case DSC_template_type_arg:

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=240188&r1=240187&r2=240188&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Jun 19 18:18:00 2015
@@ -2941,6 +2941,19 @@ void Parser::ParseDeclarationSpecifiers(
       if (DS.isTypeAltiVecVector())
         goto DoneWithDeclSpec;
 
+      if (DSContext == DSC_objc_method_result && isObjCInstancetype()) {
+        ParsedType TypeRep = Actions.ActOnObjCInstanceType(Loc);
+        assert(TypeRep);
+        isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
+                                       DiagID, TypeRep, Policy);
+        if (isInvalid)
+          break;
+
+        DS.SetRangeEnd(Loc);
+        ConsumeToken();
+        continue;
+      }
+
       ParsedType TypeRep =
         Actions.getTypeName(*Tok.getIdentifierInfo(),
                             Tok.getLocation(), getCurScope());

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=240188&r1=240187&r2=240188&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Fri Jun 19 18:18:00 2015
@@ -1005,11 +1005,14 @@ ParsedType Parser::ParseObjCTypeName(Obj
   ParseObjCTypeQualifierList(DS, context);
 
   ParsedType Ty;
-  if (isTypeSpecifierQualifier()) {
+  if (isTypeSpecifierQualifier() || isObjCInstancetype()) {
     // Parse an abstract declarator.
     DeclSpec declSpec(AttrFactory);
     declSpec.setObjCQualifiers(&DS);
-    ParseSpecifierQualifierList(declSpec);
+    DeclSpecContext dsContext = DSC_normal;
+    if (context == Declarator::ObjCResultContext)
+      dsContext = DSC_objc_method_result;
+    ParseSpecifierQualifierList(declSpec, AS_none, dsContext);
     declSpec.SetRangeEnd(Tok.getLocation());
     Declarator declarator(declSpec, context);
     ParseDeclarator(declarator);
@@ -1033,38 +1036,6 @@ ParsedType Parser::ParseObjCTypeName(Obj
       if (context == Declarator::ObjCParameterContext)
         takeDeclAttributes(*paramAttrs, declarator);
     }
-  } else if (context == Declarator::ObjCResultContext &&
-             Tok.is(tok::identifier)) {
-    if (!Ident_instancetype)
-      Ident_instancetype = PP.getIdentifierInfo("instancetype");
-    
-    if (Tok.getIdentifierInfo() == Ident_instancetype) {
-      SourceLocation loc = ConsumeToken();
-      Ty = Actions.ActOnObjCInstanceType(loc);
-
-      // Synthesize an abstract declarator so we can use Sema::ActOnTypeName.
-      bool addedToDeclSpec = false;
-      const char *prevSpec;
-      unsigned diagID;
-      DeclSpec declSpec(AttrFactory);
-      declSpec.setObjCQualifiers(&DS);
-      declSpec.SetTypeSpecType(DeclSpec::TST_typename, loc, prevSpec, diagID,
-                               Ty,
-                               Actions.getASTContext().getPrintingPolicy());
-      declSpec.SetRangeEnd(loc);
-      Declarator declarator(declSpec, context);
-
-      // Map a nullability specifier to a context-sensitive keyword attribute.
-      if (DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability)
-        addContextSensitiveTypeNullability(*this, declarator,
-                                           DS.getNullability(),
-                                           DS.getNullabilityLoc(),
-                                           addedToDeclSpec);
-
-      TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator);
-      if (!type.isInvalid())
-        Ty = type.get();
-    }
   }
 
   if (Tok.is(tok::r_paren))

Modified: cfe/trunk/test/SemaObjC/nullability.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/nullability.m?rev=240188&r1=240187&r2=240188&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/nullability.m (original)
+++ cfe/trunk/test/SemaObjC/nullability.m Fri Jun 19 18:18:00 2015
@@ -156,6 +156,10 @@ __attribute__((objc_root_class))
 - (nonnull instancetype)initWithBlah:(nonnull id)blah;
 - (nullable instancetype)returnMe;
 + (nullable instancetype)returnInstanceOfMe;
+
+- (nonnull instancetype __nullable)initWithBlah2:(nonnull id)blah; // expected-error {{nullability specifier '__nullable' conflicts with existing specifier '__nonnull'}}
+- (instancetype __nullable)returnMe2;
++ (__nonnull instancetype)returnInstanceOfMe2;
 @end
 
 void test_instancetype(InitializableClass * __nonnull ic, id __nonnull object) {
@@ -163,6 +167,9 @@ void test_instancetype(InitializableClas
   ip = [InitializableClass returnMe]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'id __nullable'}}
   ip = [InitializableClass returnInstanceOfMe]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'InitializableClass * __nullable'}}
   ip = [object returnMe]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'id __nullable'}}
+
+  ip = [ic returnMe2]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'InitializableClass * __nullable'}}
+  ip = [InitializableClass returnInstanceOfMe2]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'InitializableClass * __nonnull'}}
 }
 
 // Check null_resettable getters/setters.





More information about the cfe-commits mailing list