summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp819
1 files changed, 750 insertions, 69 deletions
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp
index a597a16..ed60904 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp
@@ -13,6 +13,7 @@
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
@@ -95,14 +96,17 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
///
/// objc-class-declaration:
-/// '@' 'class' identifier-list ';'
+/// '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';'
+///
+/// objc-class-forward-decl:
+/// identifier objc-type-parameter-list[opt]
///
Parser::DeclGroupPtrTy
Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
ConsumeToken(); // the identifier "class"
SmallVector<IdentifierInfo *, 8> ClassNames;
SmallVector<SourceLocation, 8> ClassLocs;
-
+ SmallVector<ObjCTypeParamList *, 8> ClassTypeParams;
while (1) {
MaybeSkipAttributes(tok::objc_class);
@@ -115,6 +119,14 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
ClassLocs.push_back(Tok.getLocation());
ConsumeToken();
+ // Parse the optional objc-type-parameter-list.
+ ObjCTypeParamList *TypeParams = nullptr;
+ if (Tok.is(tok::less)) {
+ TypeParams = parseObjCTypeParamList();
+ if (TypeParams)
+ Actions.popObjCTypeParamList(getCurScope(), TypeParams);
+ }
+ ClassTypeParams.push_back(TypeParams);
if (!TryConsumeToken(tok::comma))
break;
}
@@ -125,6 +137,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
ClassLocs.data(),
+ ClassTypeParams,
ClassNames.size());
}
@@ -153,20 +166,20 @@ void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
/// objc-category-interface
///
/// objc-class-interface:
-/// '@' 'interface' identifier objc-superclass[opt]
-/// objc-protocol-refs[opt]
+/// '@' 'interface' identifier objc-type-parameter-list[opt]
+/// objc-superclass[opt] objc-protocol-refs[opt]
/// objc-class-instance-variables[opt]
/// objc-interface-decl-list
/// @end
///
/// objc-category-interface:
-/// '@' 'interface' identifier '(' identifier[opt] ')'
-/// objc-protocol-refs[opt]
+/// '@' 'interface' identifier objc-type-parameter-list[opt]
+/// '(' identifier[opt] ')' objc-protocol-refs[opt]
/// objc-interface-decl-list
/// @end
///
/// objc-superclass:
-/// ':' identifier
+/// ':' identifier objc-type-arguments[opt]
///
/// objc-class-interface-attributes:
/// __attribute__((visibility("default")))
@@ -201,7 +214,20 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
// We have a class or category name - consume it.
IdentifierInfo *nameId = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken();
- if (Tok.is(tok::l_paren) &&
+
+ // Parse the objc-type-parameter-list or objc-protocol-refs. For the latter
+ // case, LAngleLoc will be valid and ProtocolIdents will capture the
+ // protocol references (that have not yet been resolved).
+ SourceLocation LAngleLoc, EndProtoLoc;
+ SmallVector<IdentifierLocPair, 8> ProtocolIdents;
+ ObjCTypeParamList *typeParameterList = nullptr;
+ if (Tok.is(tok::less)) {
+ typeParameterList = parseObjCTypeParamListOrProtocolRefs(LAngleLoc,
+ ProtocolIdents,
+ EndProtoLoc);
+ }
+
+ if (Tok.is(tok::l_paren) &&
!isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
BalancedDelimiterTracker T(*this, tok::l_paren);
@@ -236,17 +262,19 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
}
// Next, we need to check for any protocol references.
- SourceLocation LAngleLoc, EndProtoLoc;
+ assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols");
SmallVector<Decl *, 8> ProtocolRefs;
SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
- ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
- LAngleLoc, EndProtoLoc))
+ ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
+ LAngleLoc, EndProtoLoc,
+ /*consumeLastToken=*/true))
return nullptr;
Decl *CategoryType =
Actions.ActOnStartCategoryInterface(AtLoc,
nameId, nameLoc,
+ typeParameterList,
categoryId, categoryLoc,
ProtocolRefs.data(),
ProtocolRefs.size(),
@@ -257,12 +285,20 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
+
+ if (typeParameterList)
+ Actions.popObjCTypeParamList(getCurScope(), typeParameterList);
+
return CategoryType;
}
// Parse a class interface.
IdentifierInfo *superClassId = nullptr;
SourceLocation superClassLoc;
-
+ SourceLocation typeArgsLAngleLoc;
+ SmallVector<ParsedType, 4> typeArgs;
+ SourceLocation typeArgsRAngleLoc;
+ SmallVector<Decl *, 4> protocols;
+ SmallVector<SourceLocation, 4> protocolLocs;
if (Tok.is(tok::colon)) { // a super class is specified.
ConsumeToken();
@@ -280,33 +316,295 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
}
superClassId = Tok.getIdentifierInfo();
superClassLoc = ConsumeToken();
+
+ // Type arguments for the superclass or protocol conformances.
+ if (Tok.is(tok::less)) {
+ parseObjCTypeArgsOrProtocolQualifiers(ParsedType(),
+ typeArgsLAngleLoc,
+ typeArgs,
+ typeArgsRAngleLoc,
+ LAngleLoc,
+ protocols,
+ protocolLocs,
+ EndProtoLoc,
+ /*consumeLastToken=*/true,
+ /*warnOnIncompleteProtocols=*/true);
+ }
}
+
// Next, we need to check for any protocol references.
- SmallVector<Decl *, 8> ProtocolRefs;
- SmallVector<SourceLocation, 8> ProtocolLocs;
- SourceLocation LAngleLoc, EndProtoLoc;
- if (Tok.is(tok::less) &&
- ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
- LAngleLoc, EndProtoLoc))
+ if (LAngleLoc.isValid()) {
+ if (!ProtocolIdents.empty()) {
+ // We already parsed the protocols named when we thought we had a
+ // type parameter list. Translate them into actual protocol references.
+ for (const auto &pair : ProtocolIdents) {
+ protocolLocs.push_back(pair.second);
+ }
+ Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true,
+ /*ForObjCContainer=*/true,
+ &ProtocolIdents[0], ProtocolIdents.size(),
+ protocols);
+ }
+ } else if (protocols.empty() && Tok.is(tok::less) &&
+ ParseObjCProtocolReferences(protocols, protocolLocs, true, true,
+ LAngleLoc, EndProtoLoc,
+ /*consumeLastToken=*/true)) {
return nullptr;
+ }
if (Tok.isNot(tok::less))
- Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
+ Actions.ActOnTypedefedProtocols(protocols, superClassId, superClassLoc);
Decl *ClsType =
- Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc,
- superClassId, superClassLoc,
- ProtocolRefs.data(), ProtocolRefs.size(),
- ProtocolLocs.data(),
+ Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc,
+ typeParameterList, superClassId,
+ superClassLoc,
+ typeArgs,
+ SourceRange(typeArgsLAngleLoc,
+ typeArgsRAngleLoc),
+ protocols.data(), protocols.size(),
+ protocolLocs.data(),
EndProtoLoc, attrs.getList());
if (Tok.is(tok::l_brace))
ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
+
+ if (typeParameterList)
+ Actions.popObjCTypeParamList(getCurScope(), typeParameterList);
+
return ClsType;
}
+/// Add an attribute for a context-sensitive type nullability to the given
+/// declarator.
+static void addContextSensitiveTypeNullability(Parser &P,
+ Declarator &D,
+ NullabilityKind nullability,
+ SourceLocation nullabilityLoc,
+ bool &addedToDeclSpec) {
+ // Create the attribute.
+ auto getNullabilityAttr = [&]() -> AttributeList * {
+ return D.getAttributePool().create(
+ P.getNullabilityKeyword(nullability),
+ SourceRange(nullabilityLoc),
+ nullptr, SourceLocation(),
+ nullptr, 0,
+ AttributeList::AS_ContextSensitiveKeyword);
+ };
+
+ if (D.getNumTypeObjects() > 0) {
+ // Add the attribute to the declarator chunk nearest the declarator.
+ auto nullabilityAttr = getNullabilityAttr();
+ DeclaratorChunk &chunk = D.getTypeObject(0);
+ nullabilityAttr->setNext(chunk.getAttrListRef());
+ chunk.getAttrListRef() = nullabilityAttr;
+ } else if (!addedToDeclSpec) {
+ // Otherwise, just put it on the declaration specifiers (if one
+ // isn't there already).
+ D.getMutableDeclSpec().addAttributes(getNullabilityAttr());
+ addedToDeclSpec = true;
+ }
+}
+
+/// Parse an Objective-C type parameter list, if present, or capture
+/// the locations of the protocol identifiers for a list of protocol
+/// references.
+///
+/// objc-type-parameter-list:
+/// '<' objc-type-parameter (',' objc-type-parameter)* '>'
+///
+/// objc-type-parameter:
+/// objc-type-parameter-variance? identifier objc-type-parameter-bound[opt]
+///
+/// objc-type-parameter-bound:
+/// ':' type-name
+///
+/// objc-type-parameter-variance:
+/// '__covariant'
+/// '__contravariant'
+///
+/// \param lAngleLoc The location of the starting '<'.
+///
+/// \param protocolIdents Will capture the list of identifiers, if the
+/// angle brackets contain a list of protocol references rather than a
+/// type parameter list.
+///
+/// \param rAngleLoc The location of the ending '>'.
+ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(
+ SourceLocation &lAngleLoc,
+ SmallVectorImpl<IdentifierLocPair> &protocolIdents,
+ SourceLocation &rAngleLoc,
+ bool mayBeProtocolList) {
+ assert(Tok.is(tok::less) && "Not at the beginning of a type parameter list");
+
+ // Within the type parameter list, don't treat '>' as an operator.
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
+
+ // Local function to "flush" the protocol identifiers, turning them into
+ // type parameters.
+ SmallVector<Decl *, 4> typeParams;
+ auto makeProtocolIdentsIntoTypeParameters = [&]() {
+ unsigned index = 0;
+ for (const auto &pair : protocolIdents) {
+ DeclResult typeParam = Actions.actOnObjCTypeParam(
+ getCurScope(),
+ ObjCTypeParamVariance::Invariant,
+ SourceLocation(),
+ index++,
+ pair.first,
+ pair.second,
+ SourceLocation(),
+ ParsedType());
+ if (typeParam.isUsable())
+ typeParams.push_back(typeParam.get());
+ }
+
+ protocolIdents.clear();
+ mayBeProtocolList = false;
+ };
+
+ bool invalid = false;
+ lAngleLoc = ConsumeToken();
+
+ do {
+ // Parse the variance, if any.
+ SourceLocation varianceLoc;
+ ObjCTypeParamVariance variance = ObjCTypeParamVariance::Invariant;
+ if (Tok.is(tok::kw___covariant) || Tok.is(tok::kw___contravariant)) {
+ variance = Tok.is(tok::kw___covariant)
+ ? ObjCTypeParamVariance::Covariant
+ : ObjCTypeParamVariance::Contravariant;
+ varianceLoc = ConsumeToken();
+
+ // Once we've seen a variance specific , we know this is not a
+ // list of protocol references.
+ if (mayBeProtocolList) {
+ // Up until now, we have been queuing up parameters because they
+ // might be protocol references. Turn them into parameters now.
+ makeProtocolIdentsIntoTypeParameters();
+ }
+ }
+
+ // Parse the identifier.
+ if (!Tok.is(tok::identifier)) {
+ // Code completion.
+ if (Tok.is(tok::code_completion)) {
+ // FIXME: If these aren't protocol references, we'll need different
+ // completions.
+ Actions.CodeCompleteObjCProtocolReferences(protocolIdents.data(),
+ protocolIdents.size());
+ cutOffParsing();
+
+ // FIXME: Better recovery here?.
+ return nullptr;
+ }
+
+ Diag(Tok, diag::err_objc_expected_type_parameter);
+ invalid = true;
+ break;
+ }
+
+ IdentifierInfo *paramName = Tok.getIdentifierInfo();
+ SourceLocation paramLoc = ConsumeToken();
+
+ // If there is a bound, parse it.
+ SourceLocation colonLoc;
+ TypeResult boundType;
+ if (TryConsumeToken(tok::colon, colonLoc)) {
+ // Once we've seen a bound, we know this is not a list of protocol
+ // references.
+ if (mayBeProtocolList) {
+ // Up until now, we have been queuing up parameters because they
+ // might be protocol references. Turn them into parameters now.
+ makeProtocolIdentsIntoTypeParameters();
+ }
+
+ // type-name
+ boundType = ParseTypeName();
+ if (boundType.isInvalid())
+ invalid = true;
+ } else if (mayBeProtocolList) {
+ // If this could still be a protocol list, just capture the identifier.
+ // We don't want to turn it into a parameter.
+ protocolIdents.push_back(std::make_pair(paramName, paramLoc));
+ continue;
+ }
+
+ // Create the type parameter.
+ DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(),
+ variance,
+ varianceLoc,
+ typeParams.size(),
+ paramName,
+ paramLoc,
+ colonLoc,
+ boundType.isUsable()
+ ? boundType.get()
+ : ParsedType());
+ if (typeParam.isUsable())
+ typeParams.push_back(typeParam.get());
+ } while (TryConsumeToken(tok::comma));
+
+ // Parse the '>'.
+ if (invalid) {
+ SkipUntil(tok::greater, tok::at, StopBeforeMatch);
+ if (Tok.is(tok::greater))
+ ConsumeToken();
+ } else if (ParseGreaterThanInTemplateList(rAngleLoc,
+ /*ConsumeLastToken=*/true,
+ /*ObjCGenericList=*/true)) {
+ Diag(lAngleLoc, diag::note_matching) << "'<'";
+ SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus,
+ tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace,
+ tok::comma, tok::semi },
+ StopBeforeMatch);
+ if (Tok.is(tok::greater))
+ ConsumeToken();
+ }
+
+ if (mayBeProtocolList) {
+ // A type parameter list must be followed by either a ':' (indicating the
+ // presence of a superclass) or a '(' (indicating that this is a category
+ // or extension). This disambiguates between an objc-type-parameter-list
+ // and a objc-protocol-refs.
+ if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_paren)) {
+ // Returning null indicates that we don't have a type parameter list.
+ // The results the caller needs to handle the protocol references are
+ // captured in the reference parameters already.
+ return nullptr;
+ }
+
+ // We have a type parameter list that looks like a list of protocol
+ // references. Turn that parameter list into type parameters.
+ makeProtocolIdentsIntoTypeParameters();
+ }
+
+ // Form the type parameter list.
+ ObjCTypeParamList *list = Actions.actOnObjCTypeParamList(
+ getCurScope(),
+ lAngleLoc,
+ typeParams,
+ rAngleLoc);
+
+ // Clear out the angle locations; they're used by the caller to indicate
+ // whether there are any protocol references.
+ lAngleLoc = SourceLocation();
+ rAngleLoc = SourceLocation();
+ return list;
+}
+
+/// Parse an objc-type-parameter-list.
+ObjCTypeParamList *Parser::parseObjCTypeParamList() {
+ SourceLocation lAngleLoc;
+ SmallVector<IdentifierLocPair, 1> protocolIdents;
+ SourceLocation rAngleLoc;
+ return parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents,
+ rAngleLoc,
+ /*mayBeProtocolList=*/false);
+}
+
/// objc-interface-decl-list:
/// empty
/// objc-interface-decl-list objc-property-decl [OBJC2]
@@ -330,7 +628,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
while (1) {
// If this is a method prototype, parse it.
- if (Tok.is(tok::minus) || Tok.is(tok::plus)) {
+ if (Tok.isOneOf(tok::minus, tok::plus)) {
if (Decl *methodPrototype =
ParseObjCMethodPrototype(MethodImplKind, false))
allMethods.push_back(methodPrototype);
@@ -445,6 +743,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
ParseObjCPropertyAttribute(OCDS);
}
+ bool addedToDeclSpec = false;
auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) {
if (FD.D.getIdentifier() == nullptr) {
Diag(AtLoc, diag::err_objc_property_requires_field_name)
@@ -457,6 +756,13 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
return;
}
+ // Map a nullability property attribute to a context-sensitive keyword
+ // attribute.
+ if (OCDS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+ addContextSensitiveTypeNullability(*this, FD.D, OCDS.getNullability(),
+ OCDS.getNullabilityLoc(),
+ addedToDeclSpec);
+
// Install the property declarator into interfaceDecl.
IdentifierInfo *SelName =
OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
@@ -510,6 +816,24 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
Actions.ActOnAtEnd(getCurScope(), AtEnd, allMethods, allTUVariables);
}
+/// Diagnose redundant or conflicting nullability information.
+static void diagnoseRedundantPropertyNullability(Parser &P,
+ ObjCDeclSpec &DS,
+ NullabilityKind nullability,
+ SourceLocation nullabilityLoc){
+ if (DS.getNullability() == nullability) {
+ P.Diag(nullabilityLoc, diag::warn_nullability_duplicate)
+ << DiagNullabilityKind(nullability, true)
+ << SourceRange(DS.getNullabilityLoc());
+ return;
+ }
+
+ P.Diag(nullabilityLoc, diag::err_nullability_conflicting)
+ << DiagNullabilityKind(nullability, true)
+ << DiagNullabilityKind(DS.getNullability(), true)
+ << SourceRange(DS.getNullabilityLoc());
+}
+
/// Parse property attribute declarations.
///
/// property-attr-decl: '(' property-attrlist ')'
@@ -529,6 +853,10 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
/// strong
/// weak
/// unsafe_unretained
+/// nonnull
+/// nullable
+/// null_unspecified
+/// null_resettable
///
void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
assert(Tok.getKind() == tok::l_paren);
@@ -614,6 +942,37 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter);
DS.setGetterName(SelIdent);
}
+ } else if (II->isStr("nonnull")) {
+ if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+ diagnoseRedundantPropertyNullability(*this, DS,
+ NullabilityKind::NonNull,
+ Tok.getLocation());
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
+ DS.setNullability(Tok.getLocation(), NullabilityKind::NonNull);
+ } else if (II->isStr("nullable")) {
+ if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+ diagnoseRedundantPropertyNullability(*this, DS,
+ NullabilityKind::Nullable,
+ Tok.getLocation());
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
+ DS.setNullability(Tok.getLocation(), NullabilityKind::Nullable);
+ } else if (II->isStr("null_unspecified")) {
+ if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+ diagnoseRedundantPropertyNullability(*this, DS,
+ NullabilityKind::Unspecified,
+ Tok.getLocation());
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
+ DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
+ } else if (II->isStr("null_resettable")) {
+ if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+ diagnoseRedundantPropertyNullability(*this, DS,
+ NullabilityKind::Unspecified,
+ Tok.getLocation());
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
+ DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
+
+ // Also set the null_resettable bit.
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_null_resettable);
} else {
Diag(AttrName, diag::err_objc_expected_property_attr) << II;
SkipUntil(tok::r_paren, StopAtSemi);
@@ -641,7 +1000,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
///
Decl *Parser::ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind,
bool MethodDefinition) {
- assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-");
+ assert(Tok.isOneOf(tok::minus, tok::plus) && "expected +/-");
tok::TokenKind methodType = Tok.getKind();
SourceLocation mLoc = ConsumeToken();
@@ -779,6 +1138,17 @@ bool Parser::isTokIdentifier_in() const {
/// objc-type-qualifier
/// objc-type-qualifiers objc-type-qualifier
///
+/// objc-type-qualifier:
+/// 'in'
+/// 'out'
+/// 'inout'
+/// 'oneway'
+/// 'bycopy'
+/// 'byref'
+/// 'nonnull'
+/// 'nullable'
+/// 'null_unspecified'
+///
void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
Declarator::TheContext Context) {
assert(Context == Declarator::ObjCParameterContext ||
@@ -796,10 +1166,13 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
const IdentifierInfo *II = Tok.getIdentifierInfo();
for (unsigned i = 0; i != objc_NumQuals; ++i) {
- if (II != ObjCTypeQuals[i])
+ if (II != ObjCTypeQuals[i] ||
+ NextToken().is(tok::less) ||
+ NextToken().is(tok::coloncolon))
continue;
ObjCDeclSpec::ObjCDeclQualifier Qual;
+ NullabilityKind Nullability;
switch (i) {
default: llvm_unreachable("Unknown decl qualifier");
case objc_in: Qual = ObjCDeclSpec::DQ_In; break;
@@ -808,8 +1181,28 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;
case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;
case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break;
+
+ case objc_nonnull:
+ Qual = ObjCDeclSpec::DQ_CSNullability;
+ Nullability = NullabilityKind::NonNull;
+ break;
+
+ case objc_nullable:
+ Qual = ObjCDeclSpec::DQ_CSNullability;
+ Nullability = NullabilityKind::Nullable;
+ break;
+
+ case objc_null_unspecified:
+ Qual = ObjCDeclSpec::DQ_CSNullability;
+ Nullability = NullabilityKind::Unspecified;
+ break;
}
+
+ // FIXME: Diagnose redundant specifiers.
DS.setObjCDeclQualifier(Qual);
+ if (Qual == ObjCDeclSpec::DQ_CSNullability)
+ DS.setNullability(Tok.getLocation(), Nullability);
+
ConsumeToken();
II = nullptr;
break;
@@ -878,17 +1271,28 @@ 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);
// If that's not invalid, extract a type.
if (!declarator.isInvalidType()) {
+ // Map a nullability specifier to a context-sensitive keyword attribute.
+ bool addedToDeclSpec = false;
+ 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();
@@ -898,15 +1302,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) {
- Ty = Actions.ActOnObjCInstanceType(Tok.getLocation());
- ConsumeToken();
- }
}
if (Tok.is(tok::r_paren))
@@ -1151,8 +1546,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
bool Parser::
ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
SmallVectorImpl<SourceLocation> &ProtocolLocs,
- bool WarnOnDeclarations,
- SourceLocation &LAngleLoc, SourceLocation &EndLoc) {
+ bool WarnOnDeclarations, bool ForObjCContainer,
+ SourceLocation &LAngleLoc, SourceLocation &EndLoc,
+ bool consumeLastToken) {
assert(Tok.is(tok::less) && "expected <");
LAngleLoc = ConsumeToken(); // the "<"
@@ -1182,31 +1578,274 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
}
// Consume the '>'.
- if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true))
+ if (ParseGreaterThanInTemplateList(EndLoc, consumeLastToken,
+ /*ObjCGenericList=*/false))
return true;
// Convert the list of protocols identifiers into a list of protocol decls.
- Actions.FindProtocolDeclaration(WarnOnDeclarations,
+ Actions.FindProtocolDeclaration(WarnOnDeclarations, ForObjCContainer,
&ProtocolIdents[0], ProtocolIdents.size(),
Protocols);
return false;
}
-/// \brief Parse the Objective-C protocol qualifiers that follow a typename
-/// in a decl-specifier-seq, starting at the '<'.
-bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
+TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) {
assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'");
assert(getLangOpts().ObjC1 && "Protocol qualifiers only exist in Objective-C");
- SourceLocation LAngleLoc, EndProtoLoc;
- SmallVector<Decl *, 8> ProtocolDecl;
- SmallVector<SourceLocation, 8> ProtocolLocs;
- bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
- LAngleLoc, EndProtoLoc);
- DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
- ProtocolLocs.data(), LAngleLoc);
- if (EndProtoLoc.isValid())
- DS.SetRangeEnd(EndProtoLoc);
- return Result;
+
+ SourceLocation lAngleLoc;
+ SmallVector<Decl *, 8> protocols;
+ SmallVector<SourceLocation, 8> protocolLocs;
+ (void)ParseObjCProtocolReferences(protocols, protocolLocs, false, false,
+ lAngleLoc, rAngleLoc,
+ /*consumeLastToken=*/true);
+ TypeResult result = Actions.actOnObjCProtocolQualifierType(lAngleLoc,
+ protocols,
+ protocolLocs,
+ rAngleLoc);
+ if (result.isUsable()) {
+ Diag(lAngleLoc, diag::warn_objc_protocol_qualifier_missing_id)
+ << FixItHint::CreateInsertion(lAngleLoc, "id")
+ << SourceRange(lAngleLoc, rAngleLoc);
+ }
+
+ return result;
+}
+
+/// Parse Objective-C type arguments or protocol qualifiers.
+///
+/// objc-type-arguments:
+/// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>'
+///
+void Parser::parseObjCTypeArgsOrProtocolQualifiers(
+ ParsedType baseType,
+ SourceLocation &typeArgsLAngleLoc,
+ SmallVectorImpl<ParsedType> &typeArgs,
+ SourceLocation &typeArgsRAngleLoc,
+ SourceLocation &protocolLAngleLoc,
+ SmallVectorImpl<Decl *> &protocols,
+ SmallVectorImpl<SourceLocation> &protocolLocs,
+ SourceLocation &protocolRAngleLoc,
+ bool consumeLastToken,
+ bool warnOnIncompleteProtocols) {
+ assert(Tok.is(tok::less) && "Not at the start of type args or protocols");
+ SourceLocation lAngleLoc = ConsumeToken();
+
+ // Whether all of the elements we've parsed thus far are single
+ // identifiers, which might be types or might be protocols.
+ bool allSingleIdentifiers = true;
+ SmallVector<IdentifierInfo *, 4> identifiers;
+ SmallVectorImpl<SourceLocation> &identifierLocs = protocolLocs;
+
+ // Parse a list of comma-separated identifiers, bailing out if we
+ // see something different.
+ do {
+ // Parse a single identifier.
+ if (Tok.is(tok::identifier) &&
+ (NextToken().is(tok::comma) ||
+ NextToken().is(tok::greater) ||
+ NextToken().is(tok::greatergreater))) {
+ identifiers.push_back(Tok.getIdentifierInfo());
+ identifierLocs.push_back(ConsumeToken());
+ continue;
+ }
+
+ if (Tok.is(tok::code_completion)) {
+ // FIXME: Also include types here.
+ SmallVector<IdentifierLocPair, 4> identifierLocPairs;
+ for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
+ identifierLocPairs.push_back(IdentifierLocPair(identifiers[i],
+ identifierLocs[i]));
+ }
+
+ QualType BaseT = Actions.GetTypeFromParser(baseType);
+ if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) {
+ Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type);
+ } else {
+ Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs.data(),
+ identifierLocPairs.size());
+ }
+ cutOffParsing();
+ return;
+ }
+
+ allSingleIdentifiers = false;
+ break;
+ } while (TryConsumeToken(tok::comma));
+
+ // If we parsed an identifier list, semantic analysis sorts out
+ // whether it refers to protocols or to type arguments.
+ if (allSingleIdentifiers) {
+ // Parse the closing '>'.
+ SourceLocation rAngleLoc;
+ (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken,
+ /*ObjCGenericList=*/true);
+
+ // Let Sema figure out what we parsed.
+ Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(),
+ baseType,
+ lAngleLoc,
+ identifiers,
+ identifierLocs,
+ rAngleLoc,
+ typeArgsLAngleLoc,
+ typeArgs,
+ typeArgsRAngleLoc,
+ protocolLAngleLoc,
+ protocols,
+ protocolRAngleLoc,
+ warnOnIncompleteProtocols);
+ return;
+ }
+
+ // We syntactically matched a type argument, so commit to parsing
+ // type arguments.
+
+ // Convert the identifiers into type arguments.
+ bool invalid = false;
+ for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
+ ParsedType typeArg
+ = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope());
+ if (typeArg) {
+ DeclSpec DS(AttrFactory);
+ const char *prevSpec = nullptr;
+ unsigned diagID;
+ DS.SetTypeSpecType(TST_typename, identifierLocs[i], prevSpec, diagID,
+ typeArg, Actions.getASTContext().getPrintingPolicy());
+
+ // Form a declarator to turn this into a type.
+ Declarator D(DS, Declarator::TypeNameContext);
+ TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D);
+ if (fullTypeArg.isUsable())
+ typeArgs.push_back(fullTypeArg.get());
+ else
+ invalid = true;
+ } else {
+ invalid = true;
+ }
+ }
+
+ // Continue parsing type-names.
+ do {
+ TypeResult typeArg = ParseTypeName();
+
+ // Consume the '...' for a pack expansion.
+ SourceLocation ellipsisLoc;
+ TryConsumeToken(tok::ellipsis, ellipsisLoc);
+ if (typeArg.isUsable() && ellipsisLoc.isValid()) {
+ typeArg = Actions.ActOnPackExpansion(typeArg.get(), ellipsisLoc);
+ }
+
+ if (typeArg.isUsable()) {
+ typeArgs.push_back(typeArg.get());
+ } else {
+ invalid = true;
+ }
+ } while (TryConsumeToken(tok::comma));
+
+ // Parse the closing '>'.
+ SourceLocation rAngleLoc;
+ (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken,
+ /*ObjCGenericList=*/true);
+
+ if (invalid) {
+ typeArgs.clear();
+ return;
+ }
+
+ // Record left/right angle locations.
+ typeArgsLAngleLoc = lAngleLoc;
+ typeArgsRAngleLoc = rAngleLoc;
+}
+
+void Parser::parseObjCTypeArgsAndProtocolQualifiers(
+ ParsedType baseType,
+ SourceLocation &typeArgsLAngleLoc,
+ SmallVectorImpl<ParsedType> &typeArgs,
+ SourceLocation &typeArgsRAngleLoc,
+ SourceLocation &protocolLAngleLoc,
+ SmallVectorImpl<Decl *> &protocols,
+ SmallVectorImpl<SourceLocation> &protocolLocs,
+ SourceLocation &protocolRAngleLoc,
+ bool consumeLastToken) {
+ assert(Tok.is(tok::less));
+
+ // Parse the first angle-bracket-delimited clause.
+ parseObjCTypeArgsOrProtocolQualifiers(baseType,
+ typeArgsLAngleLoc,
+ typeArgs,
+ typeArgsRAngleLoc,
+ protocolLAngleLoc,
+ protocols,
+ protocolLocs,
+ protocolRAngleLoc,
+ consumeLastToken,
+ /*warnOnIncompleteProtocols=*/false);
+
+ // An Objective-C object pointer followed by type arguments
+ // can then be followed again by a set of protocol references, e.g.,
+ // \c NSArray<NSView><NSTextDelegate>
+ if ((consumeLastToken && Tok.is(tok::less)) ||
+ (!consumeLastToken && NextToken().is(tok::less))) {
+ // If we aren't consuming the last token, the prior '>' is still hanging
+ // there. Consume it before we parse the protocol qualifiers.
+ if (!consumeLastToken)
+ ConsumeToken();
+
+ if (!protocols.empty()) {
+ SkipUntilFlags skipFlags = SkipUntilFlags();
+ if (!consumeLastToken)
+ skipFlags = skipFlags | StopBeforeMatch;
+ Diag(Tok, diag::err_objc_type_args_after_protocols)
+ << SourceRange(protocolLAngleLoc, protocolRAngleLoc);
+ SkipUntil(tok::greater, tok::greatergreater, skipFlags);
+ } else {
+ ParseObjCProtocolReferences(protocols, protocolLocs,
+ /*WarnOnDeclarations=*/false,
+ /*ForObjCContainer=*/false,
+ protocolLAngleLoc, protocolRAngleLoc,
+ consumeLastToken);
+ }
+ }
+}
+
+TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers(
+ SourceLocation loc,
+ ParsedType type,
+ bool consumeLastToken,
+ SourceLocation &endLoc) {
+ assert(Tok.is(tok::less));
+ SourceLocation typeArgsLAngleLoc;
+ SmallVector<ParsedType, 4> typeArgs;
+ SourceLocation typeArgsRAngleLoc;
+ SourceLocation protocolLAngleLoc;
+ SmallVector<Decl *, 4> protocols;
+ SmallVector<SourceLocation, 4> protocolLocs;
+ SourceLocation protocolRAngleLoc;
+
+ // Parse type arguments and protocol qualifiers.
+ parseObjCTypeArgsAndProtocolQualifiers(type, typeArgsLAngleLoc, typeArgs,
+ typeArgsRAngleLoc, protocolLAngleLoc,
+ protocols, protocolLocs,
+ protocolRAngleLoc, consumeLastToken);
+
+ // Compute the location of the last token.
+ if (consumeLastToken)
+ endLoc = PrevTokLocation;
+ else
+ endLoc = Tok.getLocation();
+
+ return Actions.actOnObjCTypeArgsAndProtocolQualifiers(
+ getCurScope(),
+ loc,
+ type,
+ typeArgsLAngleLoc,
+ typeArgs,
+ typeArgsRAngleLoc,
+ protocolLAngleLoc,
+ protocols,
+ protocolLocs,
+ protocolRAngleLoc);
}
void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
@@ -1308,6 +1947,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) {
Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
// Install the declarator into the interface decl.
+ FD.D.setObjCIvar(true);
Decl *Field = Actions.ActOnIvar(
getCurScope(), FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D,
FD.BitfieldSize, visibility);
@@ -1416,8 +2056,9 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
SmallVector<Decl *, 8> ProtocolRefs;
SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
- ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false,
- LAngleLoc, EndProtoLoc))
+ ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true,
+ LAngleLoc, EndProtoLoc,
+ /*consumeLastToken=*/true))
return DeclGroupPtrTy();
Decl *ProtoType =
@@ -1467,6 +2108,22 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
SourceLocation nameLoc = ConsumeToken(); // consume class or category name
Decl *ObjCImpDecl = nullptr;
+ // Neither a type parameter list nor a list of protocol references is
+ // permitted here. Parse and diagnose them.
+ if (Tok.is(tok::less)) {
+ SourceLocation lAngleLoc, rAngleLoc;
+ SmallVector<IdentifierLocPair, 8> protocolIdents;
+ SourceLocation diagLoc = Tok.getLocation();
+ if (parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents,
+ rAngleLoc)) {
+ Diag(diagLoc, diag::err_objc_parameterized_implementation)
+ << SourceRange(diagLoc, PrevTokLocation);
+ } else if (lAngleLoc.isValid()) {
+ Diag(lAngleLoc, diag::err_unexpected_protocol_qualifier)
+ << FixItHint::CreateRemoval(SourceRange(lAngleLoc, rAngleLoc));
+ }
+ }
+
if (Tok.is(tok::l_paren)) {
// we have a category implementation.
ConsumeParen();
@@ -1495,9 +2152,14 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
rparenLoc = ConsumeParen();
if (Tok.is(tok::less)) { // we have illegal '<' try to recover
Diag(Tok, diag::err_unexpected_protocol_qualifier);
- AttributeFactory attr;
- DeclSpec DS(attr);
- (void)ParseObjCProtocolQualifiers(DS);
+ SourceLocation protocolLAngleLoc, protocolRAngleLoc;
+ SmallVector<Decl *, 4> protocols;
+ SmallVector<SourceLocation, 4> protocolLocs;
+ (void)ParseObjCProtocolReferences(protocols, protocolLocs,
+ /*warnOnIncompleteProtocols=*/false,
+ /*ForObjCContainer=*/false,
+ protocolLAngleLoc, protocolRAngleLoc,
+ /*consumeLastToken=*/true);
}
ObjCImpDecl = Actions.ActOnStartCategoryImplementation(
AtLoc, nameId, nameLoc, categoryId,
@@ -1525,10 +2187,15 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc);
else if (Tok.is(tok::less)) { // we have illegal '<' try to recover
Diag(Tok, diag::err_unexpected_protocol_qualifier);
- // try to recover.
- AttributeFactory attr;
- DeclSpec DS(attr);
- (void)ParseObjCProtocolQualifiers(DS);
+
+ SourceLocation protocolLAngleLoc, protocolRAngleLoc;
+ SmallVector<Decl *, 4> protocols;
+ SmallVector<SourceLocation, 4> protocolLocs;
+ (void)ParseObjCProtocolReferences(protocols, protocolLocs,
+ /*warnOnIncompleteProtocols=*/false,
+ /*ForObjCContainer=*/false,
+ protocolLAngleLoc, protocolRAngleLoc,
+ /*consumeLastToken=*/true);
}
}
assert(ObjCImpDecl);
@@ -2169,8 +2836,8 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
InMessageExpressionRAIIObject InMessage(*this, true);
- if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
- Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope))
+ if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_typename,
+ tok::annot_cxxscope))
TryAnnotateTypeOrScopeToken();
if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) {
@@ -2264,7 +2931,7 @@ bool Parser::isStartOfObjCClassMessageMissingOpenBracket() {
if (!Type.get().isNull() && Type.get()->isObjCObjectOrInterfaceType()) {
const Token &AfterNext = GetLookAheadToken(2);
- if (AfterNext.is(tok::colon) || AfterNext.is(tok::r_square)) {
+ if (AfterNext.isOneOf(tok::colon, tok::r_square)) {
if (Tok.is(tok::identifier))
TryAnnotateTypeOrScopeToken();
@@ -2346,6 +3013,21 @@ ExprResult Parser::ParseObjCMessageExpression() {
ConsumeToken(); // the type name
+ // Parse type arguments and protocol qualifiers.
+ if (Tok.is(tok::less)) {
+ SourceLocation NewEndLoc;
+ TypeResult NewReceiverType
+ = parseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType,
+ /*consumeLastToken=*/true,
+ NewEndLoc);
+ if (!NewReceiverType.isUsable()) {
+ SkipUntil(tok::r_square, StopAtSemi);
+ return ExprError();
+ }
+
+ ReceiverType = NewReceiverType.get();
+ }
+
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
ReceiverType, nullptr);
@@ -2890,9 +3572,8 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
// Consume the previously pushed token.
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
- assert((Tok.is(tok::l_brace) || Tok.is(tok::kw_try) ||
- Tok.is(tok::colon)) &&
- "Inline objective-c method not starting with '{' or 'try' or ':'");
+ assert(Tok.isOneOf(tok::l_brace, tok::kw_try, tok::colon) &&
+ "Inline objective-c method not starting with '{' or 'try' or ':'");
// Enter a scope for the method or c-function body.
ParseScope BodyScope(this,
parseMethod
OpenPOWER on IntegriCloud