diff options
-rw-r--r-- | include/clang/Parse/Parser.h | 14 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 13 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 39 | ||||
-rw-r--r-- | test/SemaObjC/nullability.m | 7 |
4 files changed, 38 insertions, 35 deletions
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 1025dd72cf..7042a1ef6e 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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: diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 96555fcf87..1c52552ea1 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2941,6 +2941,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, 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()); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index de347181bf..e4f7911138 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -1005,11 +1005,14 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, 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(ObjCDeclSpec &DS, 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)) diff --git a/test/SemaObjC/nullability.m b/test/SemaObjC/nullability.m index ca875b56a2..2cbdba1bd3 100644 --- a/test/SemaObjC/nullability.m +++ b/test/SemaObjC/nullability.m @@ -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(InitializableClass * __nonnull ic, id __nonnull object) { 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. |