xref: /openbsd-src/gnu/llvm/clang/lib/Parse/ParseObjc.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===--- ParseObjC.cpp - Objective C Parsing ------------------------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick //  This file implements the Objective-C portions of the Parser interface.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick 
13e5dd7070Spatrick #include "clang/AST/ASTContext.h"
14*12c85518Srobert #include "clang/AST/ODRDiagsEmitter.h"
15e5dd7070Spatrick #include "clang/AST/PrettyDeclStackTrace.h"
16e5dd7070Spatrick #include "clang/Basic/CharInfo.h"
17ec727ea7Spatrick #include "clang/Basic/TargetInfo.h"
18e5dd7070Spatrick #include "clang/Parse/ParseDiagnostic.h"
19ec727ea7Spatrick #include "clang/Parse/Parser.h"
20e5dd7070Spatrick #include "clang/Parse/RAIIObjectsForParser.h"
21e5dd7070Spatrick #include "clang/Sema/DeclSpec.h"
22e5dd7070Spatrick #include "clang/Sema/Scope.h"
23e5dd7070Spatrick #include "llvm/ADT/SmallVector.h"
24e5dd7070Spatrick #include "llvm/ADT/StringExtras.h"
25e5dd7070Spatrick 
26e5dd7070Spatrick using namespace clang;
27e5dd7070Spatrick 
28e5dd7070Spatrick /// Skips attributes after an Objective-C @ directive. Emits a diagnostic.
MaybeSkipAttributes(tok::ObjCKeywordKind Kind)29e5dd7070Spatrick void Parser::MaybeSkipAttributes(tok::ObjCKeywordKind Kind) {
30e5dd7070Spatrick   ParsedAttributes attrs(AttrFactory);
31e5dd7070Spatrick   if (Tok.is(tok::kw___attribute)) {
32e5dd7070Spatrick     if (Kind == tok::objc_interface || Kind == tok::objc_protocol)
33e5dd7070Spatrick       Diag(Tok, diag::err_objc_postfix_attribute_hint)
34e5dd7070Spatrick           << (Kind == tok::objc_protocol);
35e5dd7070Spatrick     else
36e5dd7070Spatrick       Diag(Tok, diag::err_objc_postfix_attribute);
37e5dd7070Spatrick     ParseGNUAttributes(attrs);
38e5dd7070Spatrick   }
39e5dd7070Spatrick }
40e5dd7070Spatrick 
41e5dd7070Spatrick /// ParseObjCAtDirectives - Handle parts of the external-declaration production:
42e5dd7070Spatrick ///       external-declaration: [C99 6.9]
43e5dd7070Spatrick /// [OBJC]  objc-class-definition
44e5dd7070Spatrick /// [OBJC]  objc-class-declaration
45e5dd7070Spatrick /// [OBJC]  objc-alias-declaration
46e5dd7070Spatrick /// [OBJC]  objc-protocol-definition
47e5dd7070Spatrick /// [OBJC]  objc-method-definition
48e5dd7070Spatrick /// [OBJC]  '@' 'end'
49e5dd7070Spatrick Parser::DeclGroupPtrTy
ParseObjCAtDirectives(ParsedAttributes & DeclAttrs,ParsedAttributes & DeclSpecAttrs)50*12c85518Srobert Parser::ParseObjCAtDirectives(ParsedAttributes &DeclAttrs,
51*12c85518Srobert                               ParsedAttributes &DeclSpecAttrs) {
52*12c85518Srobert   DeclAttrs.takeAllFrom(DeclSpecAttrs);
53*12c85518Srobert 
54e5dd7070Spatrick   SourceLocation AtLoc = ConsumeToken(); // the "@"
55e5dd7070Spatrick 
56e5dd7070Spatrick   if (Tok.is(tok::code_completion)) {
57e5dd7070Spatrick     cutOffParsing();
58a9ac8606Spatrick     Actions.CodeCompleteObjCAtDirective(getCurScope());
59e5dd7070Spatrick     return nullptr;
60e5dd7070Spatrick   }
61e5dd7070Spatrick 
62*12c85518Srobert   switch (Tok.getObjCKeywordID()) {
63*12c85518Srobert   case tok::objc_interface:
64*12c85518Srobert   case tok::objc_protocol:
65*12c85518Srobert   case tok::objc_implementation:
66*12c85518Srobert     break;
67*12c85518Srobert   default:
68*12c85518Srobert     llvm::for_each(DeclAttrs, [this](const auto &Attr) {
69*12c85518Srobert       if (Attr.isGNUAttribute())
70*12c85518Srobert         Diag(Tok.getLocation(), diag::err_objc_unexpected_attr);
71*12c85518Srobert     });
72*12c85518Srobert   }
73*12c85518Srobert 
74e5dd7070Spatrick   Decl *SingleDecl = nullptr;
75e5dd7070Spatrick   switch (Tok.getObjCKeywordID()) {
76e5dd7070Spatrick   case tok::objc_class:
77e5dd7070Spatrick     return ParseObjCAtClassDeclaration(AtLoc);
78e5dd7070Spatrick   case tok::objc_interface:
79*12c85518Srobert     SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, DeclAttrs);
80e5dd7070Spatrick     break;
81e5dd7070Spatrick   case tok::objc_protocol:
82*12c85518Srobert     return ParseObjCAtProtocolDeclaration(AtLoc, DeclAttrs);
83e5dd7070Spatrick   case tok::objc_implementation:
84*12c85518Srobert     return ParseObjCAtImplementationDeclaration(AtLoc, DeclAttrs);
85e5dd7070Spatrick   case tok::objc_end:
86e5dd7070Spatrick     return ParseObjCAtEndDeclaration(AtLoc);
87e5dd7070Spatrick   case tok::objc_compatibility_alias:
88e5dd7070Spatrick     SingleDecl = ParseObjCAtAliasDeclaration(AtLoc);
89e5dd7070Spatrick     break;
90e5dd7070Spatrick   case tok::objc_synthesize:
91e5dd7070Spatrick     SingleDecl = ParseObjCPropertySynthesize(AtLoc);
92e5dd7070Spatrick     break;
93e5dd7070Spatrick   case tok::objc_dynamic:
94e5dd7070Spatrick     SingleDecl = ParseObjCPropertyDynamic(AtLoc);
95e5dd7070Spatrick     break;
96e5dd7070Spatrick   case tok::objc_import:
97e5dd7070Spatrick     if (getLangOpts().Modules || getLangOpts().DebuggerSupport) {
98*12c85518Srobert       Sema::ModuleImportState IS = Sema::ModuleImportState::NotACXX20Module;
99*12c85518Srobert       SingleDecl = ParseModuleImport(AtLoc, IS);
100e5dd7070Spatrick       break;
101e5dd7070Spatrick     }
102e5dd7070Spatrick     Diag(AtLoc, diag::err_atimport);
103e5dd7070Spatrick     SkipUntil(tok::semi);
104e5dd7070Spatrick     return Actions.ConvertDeclToDeclGroup(nullptr);
105e5dd7070Spatrick   default:
106e5dd7070Spatrick     Diag(AtLoc, diag::err_unexpected_at);
107e5dd7070Spatrick     SkipUntil(tok::semi);
108e5dd7070Spatrick     SingleDecl = nullptr;
109e5dd7070Spatrick     break;
110e5dd7070Spatrick   }
111e5dd7070Spatrick   return Actions.ConvertDeclToDeclGroup(SingleDecl);
112e5dd7070Spatrick }
113e5dd7070Spatrick 
114e5dd7070Spatrick /// Class to handle popping type parameters when leaving the scope.
115e5dd7070Spatrick class Parser::ObjCTypeParamListScope {
116e5dd7070Spatrick   Sema &Actions;
117e5dd7070Spatrick   Scope *S;
118e5dd7070Spatrick   ObjCTypeParamList *Params;
119e5dd7070Spatrick 
120e5dd7070Spatrick public:
ObjCTypeParamListScope(Sema & Actions,Scope * S)121e5dd7070Spatrick   ObjCTypeParamListScope(Sema &Actions, Scope *S)
122e5dd7070Spatrick       : Actions(Actions), S(S), Params(nullptr) {}
123e5dd7070Spatrick 
~ObjCTypeParamListScope()124e5dd7070Spatrick   ~ObjCTypeParamListScope() {
125e5dd7070Spatrick     leave();
126e5dd7070Spatrick   }
127e5dd7070Spatrick 
enter(ObjCTypeParamList * P)128e5dd7070Spatrick   void enter(ObjCTypeParamList *P) {
129e5dd7070Spatrick     assert(!Params);
130e5dd7070Spatrick     Params = P;
131e5dd7070Spatrick   }
132e5dd7070Spatrick 
leave()133e5dd7070Spatrick   void leave() {
134e5dd7070Spatrick     if (Params)
135e5dd7070Spatrick       Actions.popObjCTypeParamList(S, Params);
136e5dd7070Spatrick     Params = nullptr;
137e5dd7070Spatrick   }
138e5dd7070Spatrick };
139e5dd7070Spatrick 
140e5dd7070Spatrick ///
141e5dd7070Spatrick /// objc-class-declaration:
142e5dd7070Spatrick ///    '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';'
143e5dd7070Spatrick ///
144e5dd7070Spatrick /// objc-class-forward-decl:
145e5dd7070Spatrick ///   identifier objc-type-parameter-list[opt]
146e5dd7070Spatrick ///
147e5dd7070Spatrick Parser::DeclGroupPtrTy
ParseObjCAtClassDeclaration(SourceLocation atLoc)148e5dd7070Spatrick Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
149e5dd7070Spatrick   ConsumeToken(); // the identifier "class"
150e5dd7070Spatrick   SmallVector<IdentifierInfo *, 8> ClassNames;
151e5dd7070Spatrick   SmallVector<SourceLocation, 8> ClassLocs;
152e5dd7070Spatrick   SmallVector<ObjCTypeParamList *, 8> ClassTypeParams;
153e5dd7070Spatrick 
154*12c85518Srobert   while (true) {
155e5dd7070Spatrick     MaybeSkipAttributes(tok::objc_class);
156e5dd7070Spatrick     if (expectIdentifier()) {
157e5dd7070Spatrick       SkipUntil(tok::semi);
158e5dd7070Spatrick       return Actions.ConvertDeclToDeclGroup(nullptr);
159e5dd7070Spatrick     }
160e5dd7070Spatrick     ClassNames.push_back(Tok.getIdentifierInfo());
161e5dd7070Spatrick     ClassLocs.push_back(Tok.getLocation());
162e5dd7070Spatrick     ConsumeToken();
163e5dd7070Spatrick 
164e5dd7070Spatrick     // Parse the optional objc-type-parameter-list.
165e5dd7070Spatrick     ObjCTypeParamList *TypeParams = nullptr;
166e5dd7070Spatrick     if (Tok.is(tok::less))
167e5dd7070Spatrick       TypeParams = parseObjCTypeParamList();
168e5dd7070Spatrick     ClassTypeParams.push_back(TypeParams);
169e5dd7070Spatrick     if (!TryConsumeToken(tok::comma))
170e5dd7070Spatrick       break;
171e5dd7070Spatrick   }
172e5dd7070Spatrick 
173e5dd7070Spatrick   // Consume the ';'.
174e5dd7070Spatrick   if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@class"))
175e5dd7070Spatrick     return Actions.ConvertDeclToDeclGroup(nullptr);
176e5dd7070Spatrick 
177e5dd7070Spatrick   return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
178e5dd7070Spatrick                                               ClassLocs.data(),
179e5dd7070Spatrick                                               ClassTypeParams,
180e5dd7070Spatrick                                               ClassNames.size());
181e5dd7070Spatrick }
182e5dd7070Spatrick 
CheckNestedObjCContexts(SourceLocation AtLoc)183e5dd7070Spatrick void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
184e5dd7070Spatrick {
185e5dd7070Spatrick   Sema::ObjCContainerKind ock = Actions.getObjCContainerKind();
186e5dd7070Spatrick   if (ock == Sema::OCK_None)
187e5dd7070Spatrick     return;
188e5dd7070Spatrick 
189e5dd7070Spatrick   Decl *Decl = Actions.getObjCDeclContext();
190e5dd7070Spatrick   if (CurParsedObjCImpl) {
191e5dd7070Spatrick     CurParsedObjCImpl->finish(AtLoc);
192e5dd7070Spatrick   } else {
193e5dd7070Spatrick     Actions.ActOnAtEnd(getCurScope(), AtLoc);
194e5dd7070Spatrick   }
195e5dd7070Spatrick   Diag(AtLoc, diag::err_objc_missing_end)
196e5dd7070Spatrick       << FixItHint::CreateInsertion(AtLoc, "@end\n");
197e5dd7070Spatrick   if (Decl)
198e5dd7070Spatrick     Diag(Decl->getBeginLoc(), diag::note_objc_container_start) << (int)ock;
199e5dd7070Spatrick }
200e5dd7070Spatrick 
201e5dd7070Spatrick ///
202e5dd7070Spatrick ///   objc-interface:
203e5dd7070Spatrick ///     objc-class-interface-attributes[opt] objc-class-interface
204e5dd7070Spatrick ///     objc-category-interface
205e5dd7070Spatrick ///
206e5dd7070Spatrick ///   objc-class-interface:
207e5dd7070Spatrick ///     '@' 'interface' identifier objc-type-parameter-list[opt]
208e5dd7070Spatrick ///       objc-superclass[opt] objc-protocol-refs[opt]
209e5dd7070Spatrick ///       objc-class-instance-variables[opt]
210e5dd7070Spatrick ///       objc-interface-decl-list
211e5dd7070Spatrick ///     @end
212e5dd7070Spatrick ///
213e5dd7070Spatrick ///   objc-category-interface:
214e5dd7070Spatrick ///     '@' 'interface' identifier objc-type-parameter-list[opt]
215e5dd7070Spatrick ///       '(' identifier[opt] ')' objc-protocol-refs[opt]
216e5dd7070Spatrick ///       objc-interface-decl-list
217e5dd7070Spatrick ///     @end
218e5dd7070Spatrick ///
219e5dd7070Spatrick ///   objc-superclass:
220e5dd7070Spatrick ///     ':' identifier objc-type-arguments[opt]
221e5dd7070Spatrick ///
222e5dd7070Spatrick ///   objc-class-interface-attributes:
223e5dd7070Spatrick ///     __attribute__((visibility("default")))
224e5dd7070Spatrick ///     __attribute__((visibility("hidden")))
225e5dd7070Spatrick ///     __attribute__((deprecated))
226e5dd7070Spatrick ///     __attribute__((unavailable))
227e5dd7070Spatrick ///     __attribute__((objc_exception)) - used by NSException on 64-bit
228e5dd7070Spatrick ///     __attribute__((objc_root_class))
229e5dd7070Spatrick ///
ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,ParsedAttributes & attrs)230e5dd7070Spatrick Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
231e5dd7070Spatrick                                               ParsedAttributes &attrs) {
232e5dd7070Spatrick   assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
233e5dd7070Spatrick          "ParseObjCAtInterfaceDeclaration(): Expected @interface");
234e5dd7070Spatrick   CheckNestedObjCContexts(AtLoc);
235e5dd7070Spatrick   ConsumeToken(); // the "interface" identifier
236e5dd7070Spatrick 
237e5dd7070Spatrick   // Code completion after '@interface'.
238e5dd7070Spatrick   if (Tok.is(tok::code_completion)) {
239e5dd7070Spatrick     cutOffParsing();
240a9ac8606Spatrick     Actions.CodeCompleteObjCInterfaceDecl(getCurScope());
241e5dd7070Spatrick     return nullptr;
242e5dd7070Spatrick   }
243e5dd7070Spatrick 
244e5dd7070Spatrick   MaybeSkipAttributes(tok::objc_interface);
245e5dd7070Spatrick 
246e5dd7070Spatrick   if (expectIdentifier())
247e5dd7070Spatrick     return nullptr; // missing class or category name.
248e5dd7070Spatrick 
249e5dd7070Spatrick   // We have a class or category name - consume it.
250e5dd7070Spatrick   IdentifierInfo *nameId = Tok.getIdentifierInfo();
251e5dd7070Spatrick   SourceLocation nameLoc = ConsumeToken();
252e5dd7070Spatrick 
253e5dd7070Spatrick   // Parse the objc-type-parameter-list or objc-protocol-refs. For the latter
254e5dd7070Spatrick   // case, LAngleLoc will be valid and ProtocolIdents will capture the
255e5dd7070Spatrick   // protocol references (that have not yet been resolved).
256e5dd7070Spatrick   SourceLocation LAngleLoc, EndProtoLoc;
257e5dd7070Spatrick   SmallVector<IdentifierLocPair, 8> ProtocolIdents;
258e5dd7070Spatrick   ObjCTypeParamList *typeParameterList = nullptr;
259e5dd7070Spatrick   ObjCTypeParamListScope typeParamScope(Actions, getCurScope());
260e5dd7070Spatrick   if (Tok.is(tok::less))
261e5dd7070Spatrick     typeParameterList = parseObjCTypeParamListOrProtocolRefs(
262e5dd7070Spatrick         typeParamScope, LAngleLoc, ProtocolIdents, EndProtoLoc);
263e5dd7070Spatrick 
264e5dd7070Spatrick   if (Tok.is(tok::l_paren) &&
265e5dd7070Spatrick       !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
266e5dd7070Spatrick 
267e5dd7070Spatrick     BalancedDelimiterTracker T(*this, tok::l_paren);
268e5dd7070Spatrick     T.consumeOpen();
269e5dd7070Spatrick 
270e5dd7070Spatrick     SourceLocation categoryLoc;
271e5dd7070Spatrick     IdentifierInfo *categoryId = nullptr;
272e5dd7070Spatrick     if (Tok.is(tok::code_completion)) {
273e5dd7070Spatrick       cutOffParsing();
274a9ac8606Spatrick       Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc);
275e5dd7070Spatrick       return nullptr;
276e5dd7070Spatrick     }
277e5dd7070Spatrick 
278e5dd7070Spatrick     // For ObjC2, the category name is optional (not an error).
279e5dd7070Spatrick     if (Tok.is(tok::identifier)) {
280e5dd7070Spatrick       categoryId = Tok.getIdentifierInfo();
281e5dd7070Spatrick       categoryLoc = ConsumeToken();
282e5dd7070Spatrick     }
283e5dd7070Spatrick     else if (!getLangOpts().ObjC) {
284e5dd7070Spatrick       Diag(Tok, diag::err_expected)
285e5dd7070Spatrick           << tok::identifier; // missing category name.
286e5dd7070Spatrick       return nullptr;
287e5dd7070Spatrick     }
288e5dd7070Spatrick 
289e5dd7070Spatrick     T.consumeClose();
290e5dd7070Spatrick     if (T.getCloseLocation().isInvalid())
291e5dd7070Spatrick       return nullptr;
292e5dd7070Spatrick 
293e5dd7070Spatrick     // Next, we need to check for any protocol references.
294e5dd7070Spatrick     assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols");
295e5dd7070Spatrick     SmallVector<Decl *, 8> ProtocolRefs;
296e5dd7070Spatrick     SmallVector<SourceLocation, 8> ProtocolLocs;
297e5dd7070Spatrick     if (Tok.is(tok::less) &&
298e5dd7070Spatrick         ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
299e5dd7070Spatrick                                     LAngleLoc, EndProtoLoc,
300e5dd7070Spatrick                                     /*consumeLastToken=*/true))
301e5dd7070Spatrick       return nullptr;
302e5dd7070Spatrick 
303*12c85518Srobert     ObjCCategoryDecl *CategoryType = Actions.ActOnStartCategoryInterface(
304e5dd7070Spatrick         AtLoc, nameId, nameLoc, typeParameterList, categoryId, categoryLoc,
305e5dd7070Spatrick         ProtocolRefs.data(), ProtocolRefs.size(), ProtocolLocs.data(),
306e5dd7070Spatrick         EndProtoLoc, attrs);
307e5dd7070Spatrick 
308e5dd7070Spatrick     if (Tok.is(tok::l_brace))
309e5dd7070Spatrick       ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
310e5dd7070Spatrick 
311e5dd7070Spatrick     ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
312e5dd7070Spatrick 
313e5dd7070Spatrick     return CategoryType;
314e5dd7070Spatrick   }
315e5dd7070Spatrick   // Parse a class interface.
316e5dd7070Spatrick   IdentifierInfo *superClassId = nullptr;
317e5dd7070Spatrick   SourceLocation superClassLoc;
318e5dd7070Spatrick   SourceLocation typeArgsLAngleLoc;
319e5dd7070Spatrick   SmallVector<ParsedType, 4> typeArgs;
320e5dd7070Spatrick   SourceLocation typeArgsRAngleLoc;
321e5dd7070Spatrick   SmallVector<Decl *, 4> protocols;
322e5dd7070Spatrick   SmallVector<SourceLocation, 4> protocolLocs;
323e5dd7070Spatrick   if (Tok.is(tok::colon)) { // a super class is specified.
324e5dd7070Spatrick     ConsumeToken();
325e5dd7070Spatrick 
326e5dd7070Spatrick     // Code completion of superclass names.
327e5dd7070Spatrick     if (Tok.is(tok::code_completion)) {
328e5dd7070Spatrick       cutOffParsing();
329a9ac8606Spatrick       Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc);
330e5dd7070Spatrick       return nullptr;
331e5dd7070Spatrick     }
332e5dd7070Spatrick 
333e5dd7070Spatrick     if (expectIdentifier())
334e5dd7070Spatrick       return nullptr; // missing super class name.
335e5dd7070Spatrick     superClassId = Tok.getIdentifierInfo();
336e5dd7070Spatrick     superClassLoc = ConsumeToken();
337e5dd7070Spatrick 
338e5dd7070Spatrick     // Type arguments for the superclass or protocol conformances.
339e5dd7070Spatrick     if (Tok.is(tok::less)) {
340e5dd7070Spatrick       parseObjCTypeArgsOrProtocolQualifiers(
341e5dd7070Spatrick           nullptr, typeArgsLAngleLoc, typeArgs, typeArgsRAngleLoc, LAngleLoc,
342e5dd7070Spatrick           protocols, protocolLocs, EndProtoLoc,
343e5dd7070Spatrick           /*consumeLastToken=*/true,
344e5dd7070Spatrick           /*warnOnIncompleteProtocols=*/true);
345e5dd7070Spatrick       if (Tok.is(tok::eof))
346e5dd7070Spatrick         return nullptr;
347e5dd7070Spatrick     }
348e5dd7070Spatrick   }
349e5dd7070Spatrick 
350e5dd7070Spatrick   // Next, we need to check for any protocol references.
351e5dd7070Spatrick   if (LAngleLoc.isValid()) {
352e5dd7070Spatrick     if (!ProtocolIdents.empty()) {
353e5dd7070Spatrick       // We already parsed the protocols named when we thought we had a
354e5dd7070Spatrick       // type parameter list. Translate them into actual protocol references.
355e5dd7070Spatrick       for (const auto &pair : ProtocolIdents) {
356e5dd7070Spatrick         protocolLocs.push_back(pair.second);
357e5dd7070Spatrick       }
358e5dd7070Spatrick       Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true,
359e5dd7070Spatrick                                       /*ForObjCContainer=*/true,
360e5dd7070Spatrick                                       ProtocolIdents, protocols);
361e5dd7070Spatrick     }
362e5dd7070Spatrick   } else if (protocols.empty() && Tok.is(tok::less) &&
363e5dd7070Spatrick              ParseObjCProtocolReferences(protocols, protocolLocs, true, true,
364e5dd7070Spatrick                                          LAngleLoc, EndProtoLoc,
365e5dd7070Spatrick                                          /*consumeLastToken=*/true)) {
366e5dd7070Spatrick     return nullptr;
367e5dd7070Spatrick   }
368e5dd7070Spatrick 
369e5dd7070Spatrick   if (Tok.isNot(tok::less))
370e5dd7070Spatrick     Actions.ActOnTypedefedProtocols(protocols, protocolLocs,
371e5dd7070Spatrick                                     superClassId, superClassLoc);
372e5dd7070Spatrick 
373*12c85518Srobert   Sema::SkipBodyInfo SkipBody;
374*12c85518Srobert   ObjCInterfaceDecl *ClsType = Actions.ActOnStartClassInterface(
375e5dd7070Spatrick       getCurScope(), AtLoc, nameId, nameLoc, typeParameterList, superClassId,
376e5dd7070Spatrick       superClassLoc, typeArgs,
377e5dd7070Spatrick       SourceRange(typeArgsLAngleLoc, typeArgsRAngleLoc), protocols.data(),
378*12c85518Srobert       protocols.size(), protocolLocs.data(), EndProtoLoc, attrs, &SkipBody);
379e5dd7070Spatrick 
380e5dd7070Spatrick   if (Tok.is(tok::l_brace))
381e5dd7070Spatrick     ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
382e5dd7070Spatrick 
383e5dd7070Spatrick   ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
384e5dd7070Spatrick 
385*12c85518Srobert   if (SkipBody.CheckSameAsPrevious) {
386*12c85518Srobert     auto *PreviousDef = cast<ObjCInterfaceDecl>(SkipBody.Previous);
387*12c85518Srobert     if (Actions.ActOnDuplicateODRHashDefinition(ClsType, PreviousDef)) {
388*12c85518Srobert       ClsType->mergeDuplicateDefinitionWithCommon(PreviousDef->getDefinition());
389*12c85518Srobert     } else {
390*12c85518Srobert       ODRDiagsEmitter DiagsEmitter(Diags, Actions.getASTContext(),
391*12c85518Srobert                                    getPreprocessor().getLangOpts());
392*12c85518Srobert       DiagsEmitter.diagnoseMismatch(PreviousDef, ClsType);
393*12c85518Srobert       ClsType->setInvalidDecl();
394*12c85518Srobert     }
395*12c85518Srobert   }
396*12c85518Srobert 
397e5dd7070Spatrick   return ClsType;
398e5dd7070Spatrick }
399e5dd7070Spatrick 
400e5dd7070Spatrick /// Add an attribute for a context-sensitive type nullability to the given
401e5dd7070Spatrick /// declarator.
addContextSensitiveTypeNullability(Parser & P,Declarator & D,NullabilityKind nullability,SourceLocation nullabilityLoc,bool & addedToDeclSpec)402e5dd7070Spatrick static void addContextSensitiveTypeNullability(Parser &P,
403e5dd7070Spatrick                                                Declarator &D,
404e5dd7070Spatrick                                                NullabilityKind nullability,
405e5dd7070Spatrick                                                SourceLocation nullabilityLoc,
406e5dd7070Spatrick                                                bool &addedToDeclSpec) {
407e5dd7070Spatrick   // Create the attribute.
408e5dd7070Spatrick   auto getNullabilityAttr = [&](AttributePool &Pool) -> ParsedAttr * {
409e5dd7070Spatrick     return Pool.create(P.getNullabilityKeyword(nullability),
410e5dd7070Spatrick                        SourceRange(nullabilityLoc), nullptr, SourceLocation(),
411e5dd7070Spatrick                        nullptr, 0, ParsedAttr::AS_ContextSensitiveKeyword);
412e5dd7070Spatrick   };
413e5dd7070Spatrick 
414e5dd7070Spatrick   if (D.getNumTypeObjects() > 0) {
415e5dd7070Spatrick     // Add the attribute to the declarator chunk nearest the declarator.
416e5dd7070Spatrick     D.getTypeObject(0).getAttrs().addAtEnd(
417e5dd7070Spatrick         getNullabilityAttr(D.getAttributePool()));
418e5dd7070Spatrick   } else if (!addedToDeclSpec) {
419e5dd7070Spatrick     // Otherwise, just put it on the declaration specifiers (if one
420e5dd7070Spatrick     // isn't there already).
421e5dd7070Spatrick     D.getMutableDeclSpec().getAttributes().addAtEnd(
422e5dd7070Spatrick         getNullabilityAttr(D.getMutableDeclSpec().getAttributes().getPool()));
423e5dd7070Spatrick     addedToDeclSpec = true;
424e5dd7070Spatrick   }
425e5dd7070Spatrick }
426e5dd7070Spatrick 
427e5dd7070Spatrick /// Parse an Objective-C type parameter list, if present, or capture
428e5dd7070Spatrick /// the locations of the protocol identifiers for a list of protocol
429e5dd7070Spatrick /// references.
430e5dd7070Spatrick ///
431e5dd7070Spatrick ///   objc-type-parameter-list:
432e5dd7070Spatrick ///     '<' objc-type-parameter (',' objc-type-parameter)* '>'
433e5dd7070Spatrick ///
434e5dd7070Spatrick ///   objc-type-parameter:
435e5dd7070Spatrick ///     objc-type-parameter-variance? identifier objc-type-parameter-bound[opt]
436e5dd7070Spatrick ///
437e5dd7070Spatrick ///   objc-type-parameter-bound:
438e5dd7070Spatrick ///     ':' type-name
439e5dd7070Spatrick ///
440e5dd7070Spatrick ///   objc-type-parameter-variance:
441e5dd7070Spatrick ///     '__covariant'
442e5dd7070Spatrick ///     '__contravariant'
443e5dd7070Spatrick ///
444e5dd7070Spatrick /// \param lAngleLoc The location of the starting '<'.
445e5dd7070Spatrick ///
446e5dd7070Spatrick /// \param protocolIdents Will capture the list of identifiers, if the
447e5dd7070Spatrick /// angle brackets contain a list of protocol references rather than a
448e5dd7070Spatrick /// type parameter list.
449e5dd7070Spatrick ///
450e5dd7070Spatrick /// \param rAngleLoc The location of the ending '>'.
parseObjCTypeParamListOrProtocolRefs(ObjCTypeParamListScope & Scope,SourceLocation & lAngleLoc,SmallVectorImpl<IdentifierLocPair> & protocolIdents,SourceLocation & rAngleLoc,bool mayBeProtocolList)451e5dd7070Spatrick ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(
452e5dd7070Spatrick     ObjCTypeParamListScope &Scope, SourceLocation &lAngleLoc,
453e5dd7070Spatrick     SmallVectorImpl<IdentifierLocPair> &protocolIdents,
454e5dd7070Spatrick     SourceLocation &rAngleLoc, bool mayBeProtocolList) {
455e5dd7070Spatrick   assert(Tok.is(tok::less) && "Not at the beginning of a type parameter list");
456e5dd7070Spatrick 
457e5dd7070Spatrick   // Within the type parameter list, don't treat '>' as an operator.
458e5dd7070Spatrick   GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
459e5dd7070Spatrick 
460e5dd7070Spatrick   // Local function to "flush" the protocol identifiers, turning them into
461e5dd7070Spatrick   // type parameters.
462e5dd7070Spatrick   SmallVector<Decl *, 4> typeParams;
463e5dd7070Spatrick   auto makeProtocolIdentsIntoTypeParameters = [&]() {
464e5dd7070Spatrick     unsigned index = 0;
465e5dd7070Spatrick     for (const auto &pair : protocolIdents) {
466e5dd7070Spatrick       DeclResult typeParam = Actions.actOnObjCTypeParam(
467e5dd7070Spatrick           getCurScope(), ObjCTypeParamVariance::Invariant, SourceLocation(),
468e5dd7070Spatrick           index++, pair.first, pair.second, SourceLocation(), nullptr);
469e5dd7070Spatrick       if (typeParam.isUsable())
470e5dd7070Spatrick         typeParams.push_back(typeParam.get());
471e5dd7070Spatrick     }
472e5dd7070Spatrick 
473e5dd7070Spatrick     protocolIdents.clear();
474e5dd7070Spatrick     mayBeProtocolList = false;
475e5dd7070Spatrick   };
476e5dd7070Spatrick 
477e5dd7070Spatrick   bool invalid = false;
478e5dd7070Spatrick   lAngleLoc = ConsumeToken();
479e5dd7070Spatrick 
480e5dd7070Spatrick   do {
481e5dd7070Spatrick     // Parse the variance, if any.
482e5dd7070Spatrick     SourceLocation varianceLoc;
483e5dd7070Spatrick     ObjCTypeParamVariance variance = ObjCTypeParamVariance::Invariant;
484e5dd7070Spatrick     if (Tok.is(tok::kw___covariant) || Tok.is(tok::kw___contravariant)) {
485e5dd7070Spatrick       variance = Tok.is(tok::kw___covariant)
486e5dd7070Spatrick                    ? ObjCTypeParamVariance::Covariant
487e5dd7070Spatrick                    : ObjCTypeParamVariance::Contravariant;
488e5dd7070Spatrick       varianceLoc = ConsumeToken();
489e5dd7070Spatrick 
490e5dd7070Spatrick       // Once we've seen a variance specific , we know this is not a
491e5dd7070Spatrick       // list of protocol references.
492e5dd7070Spatrick       if (mayBeProtocolList) {
493e5dd7070Spatrick         // Up until now, we have been queuing up parameters because they
494e5dd7070Spatrick         // might be protocol references. Turn them into parameters now.
495e5dd7070Spatrick         makeProtocolIdentsIntoTypeParameters();
496e5dd7070Spatrick       }
497e5dd7070Spatrick     }
498e5dd7070Spatrick 
499e5dd7070Spatrick     // Parse the identifier.
500e5dd7070Spatrick     if (!Tok.is(tok::identifier)) {
501e5dd7070Spatrick       // Code completion.
502e5dd7070Spatrick       if (Tok.is(tok::code_completion)) {
503e5dd7070Spatrick         // FIXME: If these aren't protocol references, we'll need different
504e5dd7070Spatrick         // completions.
505e5dd7070Spatrick         cutOffParsing();
506a9ac8606Spatrick         Actions.CodeCompleteObjCProtocolReferences(protocolIdents);
507e5dd7070Spatrick 
508e5dd7070Spatrick         // FIXME: Better recovery here?.
509e5dd7070Spatrick         return nullptr;
510e5dd7070Spatrick       }
511e5dd7070Spatrick 
512e5dd7070Spatrick       Diag(Tok, diag::err_objc_expected_type_parameter);
513e5dd7070Spatrick       invalid = true;
514e5dd7070Spatrick       break;
515e5dd7070Spatrick     }
516e5dd7070Spatrick 
517e5dd7070Spatrick     IdentifierInfo *paramName = Tok.getIdentifierInfo();
518e5dd7070Spatrick     SourceLocation paramLoc = ConsumeToken();
519e5dd7070Spatrick 
520e5dd7070Spatrick     // If there is a bound, parse it.
521e5dd7070Spatrick     SourceLocation colonLoc;
522e5dd7070Spatrick     TypeResult boundType;
523e5dd7070Spatrick     if (TryConsumeToken(tok::colon, colonLoc)) {
524e5dd7070Spatrick       // Once we've seen a bound, we know this is not a list of protocol
525e5dd7070Spatrick       // references.
526e5dd7070Spatrick       if (mayBeProtocolList) {
527e5dd7070Spatrick         // Up until now, we have been queuing up parameters because they
528e5dd7070Spatrick         // might be protocol references. Turn them into parameters now.
529e5dd7070Spatrick         makeProtocolIdentsIntoTypeParameters();
530e5dd7070Spatrick       }
531e5dd7070Spatrick 
532e5dd7070Spatrick       // type-name
533e5dd7070Spatrick       boundType = ParseTypeName();
534e5dd7070Spatrick       if (boundType.isInvalid())
535e5dd7070Spatrick         invalid = true;
536e5dd7070Spatrick     } else if (mayBeProtocolList) {
537e5dd7070Spatrick       // If this could still be a protocol list, just capture the identifier.
538e5dd7070Spatrick       // We don't want to turn it into a parameter.
539e5dd7070Spatrick       protocolIdents.push_back(std::make_pair(paramName, paramLoc));
540e5dd7070Spatrick       continue;
541e5dd7070Spatrick     }
542e5dd7070Spatrick 
543e5dd7070Spatrick     // Create the type parameter.
544e5dd7070Spatrick     DeclResult typeParam = Actions.actOnObjCTypeParam(
545e5dd7070Spatrick         getCurScope(), variance, varianceLoc, typeParams.size(), paramName,
546e5dd7070Spatrick         paramLoc, colonLoc, boundType.isUsable() ? boundType.get() : nullptr);
547e5dd7070Spatrick     if (typeParam.isUsable())
548e5dd7070Spatrick       typeParams.push_back(typeParam.get());
549e5dd7070Spatrick   } while (TryConsumeToken(tok::comma));
550e5dd7070Spatrick 
551e5dd7070Spatrick   // Parse the '>'.
552e5dd7070Spatrick   if (invalid) {
553e5dd7070Spatrick     SkipUntil(tok::greater, tok::at, StopBeforeMatch);
554e5dd7070Spatrick     if (Tok.is(tok::greater))
555e5dd7070Spatrick       ConsumeToken();
556ec727ea7Spatrick   } else if (ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc,
557e5dd7070Spatrick                                             /*ConsumeLastToken=*/true,
558e5dd7070Spatrick                                             /*ObjCGenericList=*/true)) {
559e5dd7070Spatrick     SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus,
560e5dd7070Spatrick                tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace,
561e5dd7070Spatrick                tok::comma, tok::semi },
562e5dd7070Spatrick               StopBeforeMatch);
563e5dd7070Spatrick     if (Tok.is(tok::greater))
564e5dd7070Spatrick       ConsumeToken();
565e5dd7070Spatrick   }
566e5dd7070Spatrick 
567e5dd7070Spatrick   if (mayBeProtocolList) {
568e5dd7070Spatrick     // A type parameter list must be followed by either a ':' (indicating the
569e5dd7070Spatrick     // presence of a superclass) or a '(' (indicating that this is a category
570e5dd7070Spatrick     // or extension). This disambiguates between an objc-type-parameter-list
571e5dd7070Spatrick     // and a objc-protocol-refs.
572e5dd7070Spatrick     if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_paren)) {
573e5dd7070Spatrick       // Returning null indicates that we don't have a type parameter list.
574e5dd7070Spatrick       // The results the caller needs to handle the protocol references are
575e5dd7070Spatrick       // captured in the reference parameters already.
576e5dd7070Spatrick       return nullptr;
577e5dd7070Spatrick     }
578e5dd7070Spatrick 
579e5dd7070Spatrick     // We have a type parameter list that looks like a list of protocol
580e5dd7070Spatrick     // references. Turn that parameter list into type parameters.
581e5dd7070Spatrick     makeProtocolIdentsIntoTypeParameters();
582e5dd7070Spatrick   }
583e5dd7070Spatrick 
584e5dd7070Spatrick   // Form the type parameter list and enter its scope.
585e5dd7070Spatrick   ObjCTypeParamList *list = Actions.actOnObjCTypeParamList(
586e5dd7070Spatrick                               getCurScope(),
587e5dd7070Spatrick                               lAngleLoc,
588e5dd7070Spatrick                               typeParams,
589e5dd7070Spatrick                               rAngleLoc);
590e5dd7070Spatrick   Scope.enter(list);
591e5dd7070Spatrick 
592e5dd7070Spatrick   // Clear out the angle locations; they're used by the caller to indicate
593e5dd7070Spatrick   // whether there are any protocol references.
594e5dd7070Spatrick   lAngleLoc = SourceLocation();
595e5dd7070Spatrick   rAngleLoc = SourceLocation();
596e5dd7070Spatrick   return invalid ? nullptr : list;
597e5dd7070Spatrick }
598e5dd7070Spatrick 
599e5dd7070Spatrick /// Parse an objc-type-parameter-list.
parseObjCTypeParamList()600e5dd7070Spatrick ObjCTypeParamList *Parser::parseObjCTypeParamList() {
601e5dd7070Spatrick   SourceLocation lAngleLoc;
602e5dd7070Spatrick   SmallVector<IdentifierLocPair, 1> protocolIdents;
603e5dd7070Spatrick   SourceLocation rAngleLoc;
604e5dd7070Spatrick 
605e5dd7070Spatrick   ObjCTypeParamListScope Scope(Actions, getCurScope());
606e5dd7070Spatrick   return parseObjCTypeParamListOrProtocolRefs(Scope, lAngleLoc, protocolIdents,
607e5dd7070Spatrick                                               rAngleLoc,
608e5dd7070Spatrick                                               /*mayBeProtocolList=*/false);
609e5dd7070Spatrick }
610e5dd7070Spatrick 
611e5dd7070Spatrick ///   objc-interface-decl-list:
612e5dd7070Spatrick ///     empty
613e5dd7070Spatrick ///     objc-interface-decl-list objc-property-decl [OBJC2]
614e5dd7070Spatrick ///     objc-interface-decl-list objc-method-requirement [OBJC2]
615e5dd7070Spatrick ///     objc-interface-decl-list objc-method-proto ';'
616e5dd7070Spatrick ///     objc-interface-decl-list declaration
617e5dd7070Spatrick ///     objc-interface-decl-list ';'
618e5dd7070Spatrick ///
619e5dd7070Spatrick ///   objc-method-requirement: [OBJC2]
620e5dd7070Spatrick ///     @required
621e5dd7070Spatrick ///     @optional
622e5dd7070Spatrick ///
ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,Decl * CDecl)623e5dd7070Spatrick void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
624e5dd7070Spatrick                                         Decl *CDecl) {
625e5dd7070Spatrick   SmallVector<Decl *, 32> allMethods;
626e5dd7070Spatrick   SmallVector<DeclGroupPtrTy, 8> allTUVariables;
627e5dd7070Spatrick   tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
628e5dd7070Spatrick 
629e5dd7070Spatrick   SourceRange AtEnd;
630e5dd7070Spatrick 
631*12c85518Srobert   while (true) {
632e5dd7070Spatrick     // If this is a method prototype, parse it.
633e5dd7070Spatrick     if (Tok.isOneOf(tok::minus, tok::plus)) {
634e5dd7070Spatrick       if (Decl *methodPrototype =
635e5dd7070Spatrick           ParseObjCMethodPrototype(MethodImplKind, false))
636e5dd7070Spatrick         allMethods.push_back(methodPrototype);
637e5dd7070Spatrick       // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
638e5dd7070Spatrick       // method definitions.
639e5dd7070Spatrick       if (ExpectAndConsumeSemi(diag::err_expected_semi_after_method_proto)) {
640e5dd7070Spatrick         // We didn't find a semi and we error'ed out. Skip until a ';' or '@'.
641e5dd7070Spatrick         SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
642e5dd7070Spatrick         if (Tok.is(tok::semi))
643e5dd7070Spatrick           ConsumeToken();
644e5dd7070Spatrick       }
645e5dd7070Spatrick       continue;
646e5dd7070Spatrick     }
647e5dd7070Spatrick     if (Tok.is(tok::l_paren)) {
648e5dd7070Spatrick       Diag(Tok, diag::err_expected_minus_or_plus);
649e5dd7070Spatrick       ParseObjCMethodDecl(Tok.getLocation(),
650e5dd7070Spatrick                           tok::minus,
651e5dd7070Spatrick                           MethodImplKind, false);
652e5dd7070Spatrick       continue;
653e5dd7070Spatrick     }
654e5dd7070Spatrick     // Ignore excess semicolons.
655e5dd7070Spatrick     if (Tok.is(tok::semi)) {
656e5dd7070Spatrick       // FIXME: This should use ConsumeExtraSemi() for extraneous semicolons,
657e5dd7070Spatrick       // to make -Wextra-semi diagnose them.
658e5dd7070Spatrick       ConsumeToken();
659e5dd7070Spatrick       continue;
660e5dd7070Spatrick     }
661e5dd7070Spatrick 
662e5dd7070Spatrick     // If we got to the end of the file, exit the loop.
663e5dd7070Spatrick     if (isEofOrEom())
664e5dd7070Spatrick       break;
665e5dd7070Spatrick 
666e5dd7070Spatrick     // Code completion within an Objective-C interface.
667e5dd7070Spatrick     if (Tok.is(tok::code_completion)) {
668a9ac8606Spatrick       cutOffParsing();
669e5dd7070Spatrick       Actions.CodeCompleteOrdinaryName(getCurScope(),
670e5dd7070Spatrick                             CurParsedObjCImpl? Sema::PCC_ObjCImplementation
671e5dd7070Spatrick                                              : Sema::PCC_ObjCInterface);
672a9ac8606Spatrick       return;
673e5dd7070Spatrick     }
674e5dd7070Spatrick 
675e5dd7070Spatrick     // If we don't have an @ directive, parse it as a function definition.
676e5dd7070Spatrick     if (Tok.isNot(tok::at)) {
677e5dd7070Spatrick       // The code below does not consume '}'s because it is afraid of eating the
678e5dd7070Spatrick       // end of a namespace.  Because of the way this code is structured, an
679e5dd7070Spatrick       // erroneous r_brace would cause an infinite loop if not handled here.
680e5dd7070Spatrick       if (Tok.is(tok::r_brace))
681e5dd7070Spatrick         break;
682e5dd7070Spatrick 
683*12c85518Srobert       ParsedAttributes EmptyDeclAttrs(AttrFactory);
684*12c85518Srobert       ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
685e5dd7070Spatrick 
686e5dd7070Spatrick       // Since we call ParseDeclarationOrFunctionDefinition() instead of
687e5dd7070Spatrick       // ParseExternalDeclaration() below (so that this doesn't parse nested
688e5dd7070Spatrick       // @interfaces), this needs to duplicate some code from the latter.
689e5dd7070Spatrick       if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
690e5dd7070Spatrick         SourceLocation DeclEnd;
691*12c85518Srobert         ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
692*12c85518Srobert         allTUVariables.push_back(ParseDeclaration(DeclaratorContext::File,
693*12c85518Srobert                                                   DeclEnd, EmptyDeclAttrs,
694*12c85518Srobert                                                   EmptyDeclSpecAttrs));
695e5dd7070Spatrick         continue;
696e5dd7070Spatrick       }
697e5dd7070Spatrick 
698*12c85518Srobert       allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(
699*12c85518Srobert           EmptyDeclAttrs, EmptyDeclSpecAttrs));
700e5dd7070Spatrick       continue;
701e5dd7070Spatrick     }
702e5dd7070Spatrick 
703e5dd7070Spatrick     // Otherwise, we have an @ directive, eat the @.
704e5dd7070Spatrick     SourceLocation AtLoc = ConsumeToken(); // the "@"
705e5dd7070Spatrick     if (Tok.is(tok::code_completion)) {
706a9ac8606Spatrick       cutOffParsing();
707e5dd7070Spatrick       Actions.CodeCompleteObjCAtDirective(getCurScope());
708a9ac8606Spatrick       return;
709e5dd7070Spatrick     }
710e5dd7070Spatrick 
711e5dd7070Spatrick     tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
712e5dd7070Spatrick 
713e5dd7070Spatrick     if (DirectiveKind == tok::objc_end) { // @end -> terminate list
714e5dd7070Spatrick       AtEnd.setBegin(AtLoc);
715e5dd7070Spatrick       AtEnd.setEnd(Tok.getLocation());
716e5dd7070Spatrick       break;
717e5dd7070Spatrick     } else if (DirectiveKind == tok::objc_not_keyword) {
718e5dd7070Spatrick       Diag(Tok, diag::err_objc_unknown_at);
719e5dd7070Spatrick       SkipUntil(tok::semi);
720e5dd7070Spatrick       continue;
721e5dd7070Spatrick     }
722e5dd7070Spatrick 
723e5dd7070Spatrick     // Eat the identifier.
724e5dd7070Spatrick     ConsumeToken();
725e5dd7070Spatrick 
726e5dd7070Spatrick     switch (DirectiveKind) {
727e5dd7070Spatrick     default:
728e5dd7070Spatrick       // FIXME: If someone forgets an @end on a protocol, this loop will
729e5dd7070Spatrick       // continue to eat up tons of stuff and spew lots of nonsense errors.  It
730e5dd7070Spatrick       // would probably be better to bail out if we saw an @class or @interface
731e5dd7070Spatrick       // or something like that.
732e5dd7070Spatrick       Diag(AtLoc, diag::err_objc_illegal_interface_qual);
733e5dd7070Spatrick       // Skip until we see an '@' or '}' or ';'.
734e5dd7070Spatrick       SkipUntil(tok::r_brace, tok::at, StopAtSemi);
735e5dd7070Spatrick       break;
736e5dd7070Spatrick 
737e5dd7070Spatrick     case tok::objc_implementation:
738e5dd7070Spatrick     case tok::objc_interface:
739e5dd7070Spatrick       Diag(AtLoc, diag::err_objc_missing_end)
740e5dd7070Spatrick           << FixItHint::CreateInsertion(AtLoc, "@end\n");
741e5dd7070Spatrick       Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)
742e5dd7070Spatrick           << (int)Actions.getObjCContainerKind();
743e5dd7070Spatrick       ConsumeToken();
744e5dd7070Spatrick       break;
745e5dd7070Spatrick 
746e5dd7070Spatrick     case tok::objc_required:
747e5dd7070Spatrick     case tok::objc_optional:
748e5dd7070Spatrick       // This is only valid on protocols.
749e5dd7070Spatrick       if (contextKey != tok::objc_protocol)
750e5dd7070Spatrick         Diag(AtLoc, diag::err_objc_directive_only_in_protocol);
751e5dd7070Spatrick       else
752e5dd7070Spatrick         MethodImplKind = DirectiveKind;
753e5dd7070Spatrick       break;
754e5dd7070Spatrick 
755e5dd7070Spatrick     case tok::objc_property:
756e5dd7070Spatrick       ObjCDeclSpec OCDS;
757e5dd7070Spatrick       SourceLocation LParenLoc;
758e5dd7070Spatrick       // Parse property attribute list, if any.
759e5dd7070Spatrick       if (Tok.is(tok::l_paren)) {
760e5dd7070Spatrick         LParenLoc = Tok.getLocation();
761e5dd7070Spatrick         ParseObjCPropertyAttribute(OCDS);
762e5dd7070Spatrick       }
763e5dd7070Spatrick 
764e5dd7070Spatrick       bool addedToDeclSpec = false;
765e5dd7070Spatrick       auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) {
766e5dd7070Spatrick         if (FD.D.getIdentifier() == nullptr) {
767e5dd7070Spatrick           Diag(AtLoc, diag::err_objc_property_requires_field_name)
768e5dd7070Spatrick               << FD.D.getSourceRange();
769e5dd7070Spatrick           return;
770e5dd7070Spatrick         }
771e5dd7070Spatrick         if (FD.BitfieldSize) {
772e5dd7070Spatrick           Diag(AtLoc, diag::err_objc_property_bitfield)
773e5dd7070Spatrick               << FD.D.getSourceRange();
774e5dd7070Spatrick           return;
775e5dd7070Spatrick         }
776e5dd7070Spatrick 
777e5dd7070Spatrick         // Map a nullability property attribute to a context-sensitive keyword
778e5dd7070Spatrick         // attribute.
779ec727ea7Spatrick         if (OCDS.getPropertyAttributes() &
780ec727ea7Spatrick             ObjCPropertyAttribute::kind_nullability)
781e5dd7070Spatrick           addContextSensitiveTypeNullability(*this, FD.D, OCDS.getNullability(),
782e5dd7070Spatrick                                              OCDS.getNullabilityLoc(),
783e5dd7070Spatrick                                              addedToDeclSpec);
784e5dd7070Spatrick 
785e5dd7070Spatrick         // Install the property declarator into interfaceDecl.
786e5dd7070Spatrick         IdentifierInfo *SelName =
787e5dd7070Spatrick             OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
788e5dd7070Spatrick 
789e5dd7070Spatrick         Selector GetterSel = PP.getSelectorTable().getNullarySelector(SelName);
790e5dd7070Spatrick         IdentifierInfo *SetterName = OCDS.getSetterName();
791e5dd7070Spatrick         Selector SetterSel;
792e5dd7070Spatrick         if (SetterName)
793e5dd7070Spatrick           SetterSel = PP.getSelectorTable().getSelector(1, &SetterName);
794e5dd7070Spatrick         else
795e5dd7070Spatrick           SetterSel = SelectorTable::constructSetterSelector(
796e5dd7070Spatrick               PP.getIdentifierTable(), PP.getSelectorTable(),
797e5dd7070Spatrick               FD.D.getIdentifier());
798e5dd7070Spatrick         Decl *Property = Actions.ActOnProperty(
799e5dd7070Spatrick             getCurScope(), AtLoc, LParenLoc, FD, OCDS, GetterSel, SetterSel,
800e5dd7070Spatrick             MethodImplKind);
801e5dd7070Spatrick 
802e5dd7070Spatrick         FD.complete(Property);
803e5dd7070Spatrick       };
804e5dd7070Spatrick 
805e5dd7070Spatrick       // Parse all the comma separated declarators.
806e5dd7070Spatrick       ParsingDeclSpec DS(*this);
807e5dd7070Spatrick       ParseStructDeclaration(DS, ObjCPropertyCallback);
808e5dd7070Spatrick 
809e5dd7070Spatrick       ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
810e5dd7070Spatrick       break;
811e5dd7070Spatrick     }
812e5dd7070Spatrick   }
813e5dd7070Spatrick 
814e5dd7070Spatrick   // We break out of the big loop in two cases: when we see @end or when we see
815e5dd7070Spatrick   // EOF.  In the former case, eat the @end.  In the later case, emit an error.
816e5dd7070Spatrick   if (Tok.is(tok::code_completion)) {
817a9ac8606Spatrick     cutOffParsing();
818e5dd7070Spatrick     Actions.CodeCompleteObjCAtDirective(getCurScope());
819a9ac8606Spatrick     return;
820e5dd7070Spatrick   } else if (Tok.isObjCAtKeyword(tok::objc_end)) {
821e5dd7070Spatrick     ConsumeToken(); // the "end" identifier
822e5dd7070Spatrick   } else {
823e5dd7070Spatrick     Diag(Tok, diag::err_objc_missing_end)
824e5dd7070Spatrick         << FixItHint::CreateInsertion(Tok.getLocation(), "\n@end\n");
825e5dd7070Spatrick     Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)
826e5dd7070Spatrick         << (int)Actions.getObjCContainerKind();
827e5dd7070Spatrick     AtEnd.setBegin(Tok.getLocation());
828e5dd7070Spatrick     AtEnd.setEnd(Tok.getLocation());
829e5dd7070Spatrick   }
830e5dd7070Spatrick 
831e5dd7070Spatrick   // Insert collected methods declarations into the @interface object.
832e5dd7070Spatrick   // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
833e5dd7070Spatrick   Actions.ActOnAtEnd(getCurScope(), AtEnd, allMethods, allTUVariables);
834e5dd7070Spatrick }
835e5dd7070Spatrick 
836e5dd7070Spatrick /// Diagnose redundant or conflicting nullability information.
diagnoseRedundantPropertyNullability(Parser & P,ObjCDeclSpec & DS,NullabilityKind nullability,SourceLocation nullabilityLoc)837e5dd7070Spatrick static void diagnoseRedundantPropertyNullability(Parser &P,
838e5dd7070Spatrick                                                  ObjCDeclSpec &DS,
839e5dd7070Spatrick                                                  NullabilityKind nullability,
840e5dd7070Spatrick                                                  SourceLocation nullabilityLoc){
841e5dd7070Spatrick   if (DS.getNullability() == nullability) {
842e5dd7070Spatrick     P.Diag(nullabilityLoc, diag::warn_nullability_duplicate)
843e5dd7070Spatrick       << DiagNullabilityKind(nullability, true)
844e5dd7070Spatrick       << SourceRange(DS.getNullabilityLoc());
845e5dd7070Spatrick     return;
846e5dd7070Spatrick   }
847e5dd7070Spatrick 
848e5dd7070Spatrick   P.Diag(nullabilityLoc, diag::err_nullability_conflicting)
849e5dd7070Spatrick     << DiagNullabilityKind(nullability, true)
850e5dd7070Spatrick     << DiagNullabilityKind(DS.getNullability(), true)
851e5dd7070Spatrick     << SourceRange(DS.getNullabilityLoc());
852e5dd7070Spatrick }
853e5dd7070Spatrick 
854e5dd7070Spatrick ///   Parse property attribute declarations.
855e5dd7070Spatrick ///
856e5dd7070Spatrick ///   property-attr-decl: '(' property-attrlist ')'
857e5dd7070Spatrick ///   property-attrlist:
858e5dd7070Spatrick ///     property-attribute
859e5dd7070Spatrick ///     property-attrlist ',' property-attribute
860e5dd7070Spatrick ///   property-attribute:
861e5dd7070Spatrick ///     getter '=' identifier
862e5dd7070Spatrick ///     setter '=' identifier ':'
863e5dd7070Spatrick ///     direct
864e5dd7070Spatrick ///     readonly
865e5dd7070Spatrick ///     readwrite
866e5dd7070Spatrick ///     assign
867e5dd7070Spatrick ///     retain
868e5dd7070Spatrick ///     copy
869e5dd7070Spatrick ///     nonatomic
870e5dd7070Spatrick ///     atomic
871e5dd7070Spatrick ///     strong
872e5dd7070Spatrick ///     weak
873e5dd7070Spatrick ///     unsafe_unretained
874e5dd7070Spatrick ///     nonnull
875e5dd7070Spatrick ///     nullable
876e5dd7070Spatrick ///     null_unspecified
877e5dd7070Spatrick ///     null_resettable
878e5dd7070Spatrick ///     class
879e5dd7070Spatrick ///
ParseObjCPropertyAttribute(ObjCDeclSpec & DS)880e5dd7070Spatrick void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
881e5dd7070Spatrick   assert(Tok.getKind() == tok::l_paren);
882e5dd7070Spatrick   BalancedDelimiterTracker T(*this, tok::l_paren);
883e5dd7070Spatrick   T.consumeOpen();
884e5dd7070Spatrick 
885*12c85518Srobert   while (true) {
886e5dd7070Spatrick     if (Tok.is(tok::code_completion)) {
887a9ac8606Spatrick       cutOffParsing();
888e5dd7070Spatrick       Actions.CodeCompleteObjCPropertyFlags(getCurScope(), DS);
889a9ac8606Spatrick       return;
890e5dd7070Spatrick     }
891e5dd7070Spatrick     const IdentifierInfo *II = Tok.getIdentifierInfo();
892e5dd7070Spatrick 
893e5dd7070Spatrick     // If this is not an identifier at all, bail out early.
894e5dd7070Spatrick     if (!II) {
895e5dd7070Spatrick       T.consumeClose();
896e5dd7070Spatrick       return;
897e5dd7070Spatrick     }
898e5dd7070Spatrick 
899e5dd7070Spatrick     SourceLocation AttrName = ConsumeToken(); // consume last attribute name
900e5dd7070Spatrick 
901e5dd7070Spatrick     if (II->isStr("readonly"))
902ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_readonly);
903e5dd7070Spatrick     else if (II->isStr("assign"))
904ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_assign);
905e5dd7070Spatrick     else if (II->isStr("unsafe_unretained"))
906ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained);
907e5dd7070Spatrick     else if (II->isStr("readwrite"))
908ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_readwrite);
909e5dd7070Spatrick     else if (II->isStr("retain"))
910ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_retain);
911e5dd7070Spatrick     else if (II->isStr("strong"))
912ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
913e5dd7070Spatrick     else if (II->isStr("copy"))
914ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_copy);
915e5dd7070Spatrick     else if (II->isStr("nonatomic"))
916ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nonatomic);
917e5dd7070Spatrick     else if (II->isStr("atomic"))
918ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_atomic);
919e5dd7070Spatrick     else if (II->isStr("weak"))
920ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_weak);
921e5dd7070Spatrick     else if (II->isStr("getter") || II->isStr("setter")) {
922e5dd7070Spatrick       bool IsSetter = II->getNameStart()[0] == 's';
923e5dd7070Spatrick 
924e5dd7070Spatrick       // getter/setter require extra treatment.
925e5dd7070Spatrick       unsigned DiagID = IsSetter ? diag::err_objc_expected_equal_for_setter :
926e5dd7070Spatrick                                    diag::err_objc_expected_equal_for_getter;
927e5dd7070Spatrick 
928e5dd7070Spatrick       if (ExpectAndConsume(tok::equal, DiagID)) {
929e5dd7070Spatrick         SkipUntil(tok::r_paren, StopAtSemi);
930e5dd7070Spatrick         return;
931e5dd7070Spatrick       }
932e5dd7070Spatrick 
933e5dd7070Spatrick       if (Tok.is(tok::code_completion)) {
934a9ac8606Spatrick         cutOffParsing();
935e5dd7070Spatrick         if (IsSetter)
936e5dd7070Spatrick           Actions.CodeCompleteObjCPropertySetter(getCurScope());
937e5dd7070Spatrick         else
938e5dd7070Spatrick           Actions.CodeCompleteObjCPropertyGetter(getCurScope());
939a9ac8606Spatrick         return;
940e5dd7070Spatrick       }
941e5dd7070Spatrick 
942e5dd7070Spatrick       SourceLocation SelLoc;
943e5dd7070Spatrick       IdentifierInfo *SelIdent = ParseObjCSelectorPiece(SelLoc);
944e5dd7070Spatrick 
945e5dd7070Spatrick       if (!SelIdent) {
946e5dd7070Spatrick         Diag(Tok, diag::err_objc_expected_selector_for_getter_setter)
947e5dd7070Spatrick           << IsSetter;
948e5dd7070Spatrick         SkipUntil(tok::r_paren, StopAtSemi);
949e5dd7070Spatrick         return;
950e5dd7070Spatrick       }
951e5dd7070Spatrick 
952e5dd7070Spatrick       if (IsSetter) {
953ec727ea7Spatrick         DS.setPropertyAttributes(ObjCPropertyAttribute::kind_setter);
954e5dd7070Spatrick         DS.setSetterName(SelIdent, SelLoc);
955e5dd7070Spatrick 
956e5dd7070Spatrick         if (ExpectAndConsume(tok::colon,
957e5dd7070Spatrick                              diag::err_expected_colon_after_setter_name)) {
958e5dd7070Spatrick           SkipUntil(tok::r_paren, StopAtSemi);
959e5dd7070Spatrick           return;
960e5dd7070Spatrick         }
961e5dd7070Spatrick       } else {
962ec727ea7Spatrick         DS.setPropertyAttributes(ObjCPropertyAttribute::kind_getter);
963e5dd7070Spatrick         DS.setGetterName(SelIdent, SelLoc);
964e5dd7070Spatrick       }
965e5dd7070Spatrick     } else if (II->isStr("nonnull")) {
966ec727ea7Spatrick       if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)
967e5dd7070Spatrick         diagnoseRedundantPropertyNullability(*this, DS,
968e5dd7070Spatrick                                              NullabilityKind::NonNull,
969e5dd7070Spatrick                                              Tok.getLocation());
970ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
971e5dd7070Spatrick       DS.setNullability(Tok.getLocation(), NullabilityKind::NonNull);
972e5dd7070Spatrick     } else if (II->isStr("nullable")) {
973ec727ea7Spatrick       if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)
974e5dd7070Spatrick         diagnoseRedundantPropertyNullability(*this, DS,
975e5dd7070Spatrick                                              NullabilityKind::Nullable,
976e5dd7070Spatrick                                              Tok.getLocation());
977ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
978e5dd7070Spatrick       DS.setNullability(Tok.getLocation(), NullabilityKind::Nullable);
979e5dd7070Spatrick     } else if (II->isStr("null_unspecified")) {
980ec727ea7Spatrick       if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)
981e5dd7070Spatrick         diagnoseRedundantPropertyNullability(*this, DS,
982e5dd7070Spatrick                                              NullabilityKind::Unspecified,
983e5dd7070Spatrick                                              Tok.getLocation());
984ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
985e5dd7070Spatrick       DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
986e5dd7070Spatrick     } else if (II->isStr("null_resettable")) {
987ec727ea7Spatrick       if (DS.getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)
988e5dd7070Spatrick         diagnoseRedundantPropertyNullability(*this, DS,
989e5dd7070Spatrick                                              NullabilityKind::Unspecified,
990e5dd7070Spatrick                                              Tok.getLocation());
991ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
992e5dd7070Spatrick       DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
993e5dd7070Spatrick 
994e5dd7070Spatrick       // Also set the null_resettable bit.
995ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_null_resettable);
996e5dd7070Spatrick     } else if (II->isStr("class")) {
997ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_class);
998e5dd7070Spatrick     } else if (II->isStr("direct")) {
999ec727ea7Spatrick       DS.setPropertyAttributes(ObjCPropertyAttribute::kind_direct);
1000e5dd7070Spatrick     } else {
1001e5dd7070Spatrick       Diag(AttrName, diag::err_objc_expected_property_attr) << II;
1002e5dd7070Spatrick       SkipUntil(tok::r_paren, StopAtSemi);
1003e5dd7070Spatrick       return;
1004e5dd7070Spatrick     }
1005e5dd7070Spatrick 
1006e5dd7070Spatrick     if (Tok.isNot(tok::comma))
1007e5dd7070Spatrick       break;
1008e5dd7070Spatrick 
1009e5dd7070Spatrick     ConsumeToken();
1010e5dd7070Spatrick   }
1011e5dd7070Spatrick 
1012e5dd7070Spatrick   T.consumeClose();
1013e5dd7070Spatrick }
1014e5dd7070Spatrick 
1015e5dd7070Spatrick ///   objc-method-proto:
1016e5dd7070Spatrick ///     objc-instance-method objc-method-decl objc-method-attributes[opt]
1017e5dd7070Spatrick ///     objc-class-method objc-method-decl objc-method-attributes[opt]
1018e5dd7070Spatrick ///
1019e5dd7070Spatrick ///   objc-instance-method: '-'
1020e5dd7070Spatrick ///   objc-class-method: '+'
1021e5dd7070Spatrick ///
1022e5dd7070Spatrick ///   objc-method-attributes:         [OBJC2]
1023e5dd7070Spatrick ///     __attribute__((deprecated))
1024e5dd7070Spatrick ///
ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind,bool MethodDefinition)1025e5dd7070Spatrick Decl *Parser::ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind,
1026e5dd7070Spatrick                                        bool MethodDefinition) {
1027e5dd7070Spatrick   assert(Tok.isOneOf(tok::minus, tok::plus) && "expected +/-");
1028e5dd7070Spatrick 
1029e5dd7070Spatrick   tok::TokenKind methodType = Tok.getKind();
1030e5dd7070Spatrick   SourceLocation mLoc = ConsumeToken();
1031e5dd7070Spatrick   Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, MethodImplKind,
1032e5dd7070Spatrick                                     MethodDefinition);
1033e5dd7070Spatrick   // Since this rule is used for both method declarations and definitions,
1034e5dd7070Spatrick   // the caller is (optionally) responsible for consuming the ';'.
1035e5dd7070Spatrick   return MDecl;
1036e5dd7070Spatrick }
1037e5dd7070Spatrick 
1038e5dd7070Spatrick ///   objc-selector:
1039e5dd7070Spatrick ///     identifier
1040e5dd7070Spatrick ///     one of
1041e5dd7070Spatrick ///       enum struct union if else while do for switch case default
1042e5dd7070Spatrick ///       break continue return goto asm sizeof typeof __alignof
1043e5dd7070Spatrick ///       unsigned long const short volatile signed restrict _Complex
1044e5dd7070Spatrick ///       in out inout bycopy byref oneway int char float double void _Bool
1045e5dd7070Spatrick ///
ParseObjCSelectorPiece(SourceLocation & SelectorLoc)1046e5dd7070Spatrick IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
1047e5dd7070Spatrick 
1048e5dd7070Spatrick   switch (Tok.getKind()) {
1049e5dd7070Spatrick   default:
1050e5dd7070Spatrick     return nullptr;
1051e5dd7070Spatrick   case tok::colon:
1052e5dd7070Spatrick     // Empty selector piece uses the location of the ':'.
1053e5dd7070Spatrick     SelectorLoc = Tok.getLocation();
1054e5dd7070Spatrick     return nullptr;
1055e5dd7070Spatrick   case tok::ampamp:
1056e5dd7070Spatrick   case tok::ampequal:
1057e5dd7070Spatrick   case tok::amp:
1058e5dd7070Spatrick   case tok::pipe:
1059e5dd7070Spatrick   case tok::tilde:
1060e5dd7070Spatrick   case tok::exclaim:
1061e5dd7070Spatrick   case tok::exclaimequal:
1062e5dd7070Spatrick   case tok::pipepipe:
1063e5dd7070Spatrick   case tok::pipeequal:
1064e5dd7070Spatrick   case tok::caret:
1065e5dd7070Spatrick   case tok::caretequal: {
1066e5dd7070Spatrick     std::string ThisTok(PP.getSpelling(Tok));
1067e5dd7070Spatrick     if (isLetter(ThisTok[0])) {
1068e5dd7070Spatrick       IdentifierInfo *II = &PP.getIdentifierTable().get(ThisTok);
1069e5dd7070Spatrick       Tok.setKind(tok::identifier);
1070e5dd7070Spatrick       SelectorLoc = ConsumeToken();
1071e5dd7070Spatrick       return II;
1072e5dd7070Spatrick     }
1073e5dd7070Spatrick     return nullptr;
1074e5dd7070Spatrick   }
1075e5dd7070Spatrick 
1076e5dd7070Spatrick   case tok::identifier:
1077e5dd7070Spatrick   case tok::kw_asm:
1078e5dd7070Spatrick   case tok::kw_auto:
1079e5dd7070Spatrick   case tok::kw_bool:
1080e5dd7070Spatrick   case tok::kw_break:
1081e5dd7070Spatrick   case tok::kw_case:
1082e5dd7070Spatrick   case tok::kw_catch:
1083e5dd7070Spatrick   case tok::kw_char:
1084e5dd7070Spatrick   case tok::kw_class:
1085e5dd7070Spatrick   case tok::kw_const:
1086e5dd7070Spatrick   case tok::kw_const_cast:
1087e5dd7070Spatrick   case tok::kw_continue:
1088e5dd7070Spatrick   case tok::kw_default:
1089e5dd7070Spatrick   case tok::kw_delete:
1090e5dd7070Spatrick   case tok::kw_do:
1091e5dd7070Spatrick   case tok::kw_double:
1092e5dd7070Spatrick   case tok::kw_dynamic_cast:
1093e5dd7070Spatrick   case tok::kw_else:
1094e5dd7070Spatrick   case tok::kw_enum:
1095e5dd7070Spatrick   case tok::kw_explicit:
1096e5dd7070Spatrick   case tok::kw_export:
1097e5dd7070Spatrick   case tok::kw_extern:
1098e5dd7070Spatrick   case tok::kw_false:
1099e5dd7070Spatrick   case tok::kw_float:
1100e5dd7070Spatrick   case tok::kw_for:
1101e5dd7070Spatrick   case tok::kw_friend:
1102e5dd7070Spatrick   case tok::kw_goto:
1103e5dd7070Spatrick   case tok::kw_if:
1104e5dd7070Spatrick   case tok::kw_inline:
1105e5dd7070Spatrick   case tok::kw_int:
1106e5dd7070Spatrick   case tok::kw_long:
1107e5dd7070Spatrick   case tok::kw_mutable:
1108e5dd7070Spatrick   case tok::kw_namespace:
1109e5dd7070Spatrick   case tok::kw_new:
1110e5dd7070Spatrick   case tok::kw_operator:
1111e5dd7070Spatrick   case tok::kw_private:
1112e5dd7070Spatrick   case tok::kw_protected:
1113e5dd7070Spatrick   case tok::kw_public:
1114e5dd7070Spatrick   case tok::kw_register:
1115e5dd7070Spatrick   case tok::kw_reinterpret_cast:
1116e5dd7070Spatrick   case tok::kw_restrict:
1117e5dd7070Spatrick   case tok::kw_return:
1118e5dd7070Spatrick   case tok::kw_short:
1119e5dd7070Spatrick   case tok::kw_signed:
1120e5dd7070Spatrick   case tok::kw_sizeof:
1121e5dd7070Spatrick   case tok::kw_static:
1122e5dd7070Spatrick   case tok::kw_static_cast:
1123e5dd7070Spatrick   case tok::kw_struct:
1124e5dd7070Spatrick   case tok::kw_switch:
1125e5dd7070Spatrick   case tok::kw_template:
1126e5dd7070Spatrick   case tok::kw_this:
1127e5dd7070Spatrick   case tok::kw_throw:
1128e5dd7070Spatrick   case tok::kw_true:
1129e5dd7070Spatrick   case tok::kw_try:
1130e5dd7070Spatrick   case tok::kw_typedef:
1131e5dd7070Spatrick   case tok::kw_typeid:
1132e5dd7070Spatrick   case tok::kw_typename:
1133e5dd7070Spatrick   case tok::kw_typeof:
1134e5dd7070Spatrick   case tok::kw_union:
1135e5dd7070Spatrick   case tok::kw_unsigned:
1136e5dd7070Spatrick   case tok::kw_using:
1137e5dd7070Spatrick   case tok::kw_virtual:
1138e5dd7070Spatrick   case tok::kw_void:
1139e5dd7070Spatrick   case tok::kw_volatile:
1140e5dd7070Spatrick   case tok::kw_wchar_t:
1141e5dd7070Spatrick   case tok::kw_while:
1142e5dd7070Spatrick   case tok::kw__Bool:
1143e5dd7070Spatrick   case tok::kw__Complex:
1144e5dd7070Spatrick   case tok::kw___alignof:
1145e5dd7070Spatrick   case tok::kw___auto_type:
1146e5dd7070Spatrick     IdentifierInfo *II = Tok.getIdentifierInfo();
1147e5dd7070Spatrick     SelectorLoc = ConsumeToken();
1148e5dd7070Spatrick     return II;
1149e5dd7070Spatrick   }
1150e5dd7070Spatrick }
1151e5dd7070Spatrick 
1152e5dd7070Spatrick ///  objc-for-collection-in: 'in'
1153e5dd7070Spatrick ///
isTokIdentifier_in() const1154e5dd7070Spatrick bool Parser::isTokIdentifier_in() const {
1155e5dd7070Spatrick   // FIXME: May have to do additional look-ahead to only allow for
1156e5dd7070Spatrick   // valid tokens following an 'in'; such as an identifier, unary operators,
1157e5dd7070Spatrick   // '[' etc.
1158e5dd7070Spatrick   return (getLangOpts().ObjC && Tok.is(tok::identifier) &&
1159e5dd7070Spatrick           Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]);
1160e5dd7070Spatrick }
1161e5dd7070Spatrick 
1162e5dd7070Spatrick /// ParseObjCTypeQualifierList - This routine parses the objective-c's type
1163e5dd7070Spatrick /// qualifier list and builds their bitmask representation in the input
1164e5dd7070Spatrick /// argument.
1165e5dd7070Spatrick ///
1166e5dd7070Spatrick ///   objc-type-qualifiers:
1167e5dd7070Spatrick ///     objc-type-qualifier
1168e5dd7070Spatrick ///     objc-type-qualifiers objc-type-qualifier
1169e5dd7070Spatrick ///
1170e5dd7070Spatrick ///   objc-type-qualifier:
1171e5dd7070Spatrick ///     'in'
1172e5dd7070Spatrick ///     'out'
1173e5dd7070Spatrick ///     'inout'
1174e5dd7070Spatrick ///     'oneway'
1175e5dd7070Spatrick ///     'bycopy'
1176e5dd7070Spatrick ///     'byref'
1177e5dd7070Spatrick ///     'nonnull'
1178e5dd7070Spatrick ///     'nullable'
1179e5dd7070Spatrick ///     'null_unspecified'
1180e5dd7070Spatrick ///
ParseObjCTypeQualifierList(ObjCDeclSpec & DS,DeclaratorContext Context)1181e5dd7070Spatrick void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
1182e5dd7070Spatrick                                         DeclaratorContext Context) {
1183a9ac8606Spatrick   assert(Context == DeclaratorContext::ObjCParameter ||
1184a9ac8606Spatrick          Context == DeclaratorContext::ObjCResult);
1185e5dd7070Spatrick 
1186*12c85518Srobert   while (true) {
1187e5dd7070Spatrick     if (Tok.is(tok::code_completion)) {
1188a9ac8606Spatrick       cutOffParsing();
1189a9ac8606Spatrick       Actions.CodeCompleteObjCPassingType(
1190a9ac8606Spatrick           getCurScope(), DS, Context == DeclaratorContext::ObjCParameter);
1191a9ac8606Spatrick       return;
1192e5dd7070Spatrick     }
1193e5dd7070Spatrick 
1194e5dd7070Spatrick     if (Tok.isNot(tok::identifier))
1195e5dd7070Spatrick       return;
1196e5dd7070Spatrick 
1197e5dd7070Spatrick     const IdentifierInfo *II = Tok.getIdentifierInfo();
1198e5dd7070Spatrick     for (unsigned i = 0; i != objc_NumQuals; ++i) {
1199e5dd7070Spatrick       if (II != ObjCTypeQuals[i] ||
1200e5dd7070Spatrick           NextToken().is(tok::less) ||
1201e5dd7070Spatrick           NextToken().is(tok::coloncolon))
1202e5dd7070Spatrick         continue;
1203e5dd7070Spatrick 
1204e5dd7070Spatrick       ObjCDeclSpec::ObjCDeclQualifier Qual;
1205e5dd7070Spatrick       NullabilityKind Nullability;
1206e5dd7070Spatrick       switch (i) {
1207e5dd7070Spatrick       default: llvm_unreachable("Unknown decl qualifier");
1208e5dd7070Spatrick       case objc_in:     Qual = ObjCDeclSpec::DQ_In; break;
1209e5dd7070Spatrick       case objc_out:    Qual = ObjCDeclSpec::DQ_Out; break;
1210e5dd7070Spatrick       case objc_inout:  Qual = ObjCDeclSpec::DQ_Inout; break;
1211e5dd7070Spatrick       case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;
1212e5dd7070Spatrick       case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;
1213e5dd7070Spatrick       case objc_byref:  Qual = ObjCDeclSpec::DQ_Byref; break;
1214e5dd7070Spatrick 
1215e5dd7070Spatrick       case objc_nonnull:
1216e5dd7070Spatrick         Qual = ObjCDeclSpec::DQ_CSNullability;
1217e5dd7070Spatrick         Nullability = NullabilityKind::NonNull;
1218e5dd7070Spatrick         break;
1219e5dd7070Spatrick 
1220e5dd7070Spatrick       case objc_nullable:
1221e5dd7070Spatrick         Qual = ObjCDeclSpec::DQ_CSNullability;
1222e5dd7070Spatrick         Nullability = NullabilityKind::Nullable;
1223e5dd7070Spatrick         break;
1224e5dd7070Spatrick 
1225e5dd7070Spatrick       case objc_null_unspecified:
1226e5dd7070Spatrick         Qual = ObjCDeclSpec::DQ_CSNullability;
1227e5dd7070Spatrick         Nullability = NullabilityKind::Unspecified;
1228e5dd7070Spatrick         break;
1229e5dd7070Spatrick       }
1230e5dd7070Spatrick 
1231e5dd7070Spatrick       // FIXME: Diagnose redundant specifiers.
1232e5dd7070Spatrick       DS.setObjCDeclQualifier(Qual);
1233e5dd7070Spatrick       if (Qual == ObjCDeclSpec::DQ_CSNullability)
1234e5dd7070Spatrick         DS.setNullability(Tok.getLocation(), Nullability);
1235e5dd7070Spatrick 
1236e5dd7070Spatrick       ConsumeToken();
1237e5dd7070Spatrick       II = nullptr;
1238e5dd7070Spatrick       break;
1239e5dd7070Spatrick     }
1240e5dd7070Spatrick 
1241e5dd7070Spatrick     // If this wasn't a recognized qualifier, bail out.
1242e5dd7070Spatrick     if (II) return;
1243e5dd7070Spatrick   }
1244e5dd7070Spatrick }
1245e5dd7070Spatrick 
1246e5dd7070Spatrick /// Take all the decl attributes out of the given list and add
1247e5dd7070Spatrick /// them to the given attribute set.
takeDeclAttributes(ParsedAttributesView & attrs,ParsedAttributesView & from)1248e5dd7070Spatrick static void takeDeclAttributes(ParsedAttributesView &attrs,
1249e5dd7070Spatrick                                ParsedAttributesView &from) {
1250e5dd7070Spatrick   for (auto &AL : llvm::reverse(from)) {
1251e5dd7070Spatrick     if (!AL.isUsedAsTypeAttr()) {
1252e5dd7070Spatrick       from.remove(&AL);
1253e5dd7070Spatrick       attrs.addAtEnd(&AL);
1254e5dd7070Spatrick     }
1255e5dd7070Spatrick   }
1256e5dd7070Spatrick }
1257e5dd7070Spatrick 
1258e5dd7070Spatrick /// takeDeclAttributes - Take all the decl attributes from the given
1259e5dd7070Spatrick /// declarator and add them to the given list.
takeDeclAttributes(ParsedAttributes & attrs,Declarator & D)1260e5dd7070Spatrick static void takeDeclAttributes(ParsedAttributes &attrs,
1261e5dd7070Spatrick                                Declarator &D) {
1262*12c85518Srobert   // This gets called only from Parser::ParseObjCTypeName(), and that should
1263*12c85518Srobert   // never add declaration attributes to the Declarator.
1264*12c85518Srobert   assert(D.getDeclarationAttributes().empty());
1265*12c85518Srobert 
1266e5dd7070Spatrick   // First, take ownership of all attributes.
1267e5dd7070Spatrick   attrs.getPool().takeAllFrom(D.getAttributePool());
1268e5dd7070Spatrick   attrs.getPool().takeAllFrom(D.getDeclSpec().getAttributePool());
1269e5dd7070Spatrick 
1270e5dd7070Spatrick   // Now actually move the attributes over.
1271e5dd7070Spatrick   takeDeclAttributes(attrs, D.getMutableDeclSpec().getAttributes());
1272e5dd7070Spatrick   takeDeclAttributes(attrs, D.getAttributes());
1273e5dd7070Spatrick   for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
1274e5dd7070Spatrick     takeDeclAttributes(attrs, D.getTypeObject(i).getAttrs());
1275e5dd7070Spatrick }
1276e5dd7070Spatrick 
1277e5dd7070Spatrick ///   objc-type-name:
1278e5dd7070Spatrick ///     '(' objc-type-qualifiers[opt] type-name ')'
1279e5dd7070Spatrick ///     '(' objc-type-qualifiers[opt] ')'
1280e5dd7070Spatrick ///
ParseObjCTypeName(ObjCDeclSpec & DS,DeclaratorContext context,ParsedAttributes * paramAttrs)1281e5dd7070Spatrick ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
1282e5dd7070Spatrick                                      DeclaratorContext context,
1283e5dd7070Spatrick                                      ParsedAttributes *paramAttrs) {
1284a9ac8606Spatrick   assert(context == DeclaratorContext::ObjCParameter ||
1285a9ac8606Spatrick          context == DeclaratorContext::ObjCResult);
1286e5dd7070Spatrick   assert((paramAttrs != nullptr) ==
1287a9ac8606Spatrick          (context == DeclaratorContext::ObjCParameter));
1288e5dd7070Spatrick 
1289e5dd7070Spatrick   assert(Tok.is(tok::l_paren) && "expected (");
1290e5dd7070Spatrick 
1291e5dd7070Spatrick   BalancedDelimiterTracker T(*this, tok::l_paren);
1292e5dd7070Spatrick   T.consumeOpen();
1293e5dd7070Spatrick 
1294e5dd7070Spatrick   ObjCDeclContextSwitch ObjCDC(*this);
1295e5dd7070Spatrick 
1296e5dd7070Spatrick   // Parse type qualifiers, in, inout, etc.
1297e5dd7070Spatrick   ParseObjCTypeQualifierList(DS, context);
1298e5dd7070Spatrick   SourceLocation TypeStartLoc = Tok.getLocation();
1299e5dd7070Spatrick 
1300e5dd7070Spatrick   ParsedType Ty;
1301e5dd7070Spatrick   if (isTypeSpecifierQualifier() || isObjCInstancetype()) {
1302e5dd7070Spatrick     // Parse an abstract declarator.
1303e5dd7070Spatrick     DeclSpec declSpec(AttrFactory);
1304e5dd7070Spatrick     declSpec.setObjCQualifiers(&DS);
1305e5dd7070Spatrick     DeclSpecContext dsContext = DeclSpecContext::DSC_normal;
1306a9ac8606Spatrick     if (context == DeclaratorContext::ObjCResult)
1307e5dd7070Spatrick       dsContext = DeclSpecContext::DSC_objc_method_result;
1308e5dd7070Spatrick     ParseSpecifierQualifierList(declSpec, AS_none, dsContext);
1309*12c85518Srobert     Declarator declarator(declSpec, ParsedAttributesView::none(), context);
1310e5dd7070Spatrick     ParseDeclarator(declarator);
1311e5dd7070Spatrick 
1312e5dd7070Spatrick     // If that's not invalid, extract a type.
1313e5dd7070Spatrick     if (!declarator.isInvalidType()) {
1314e5dd7070Spatrick       // Map a nullability specifier to a context-sensitive keyword attribute.
1315e5dd7070Spatrick       bool addedToDeclSpec = false;
1316e5dd7070Spatrick       if (DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability)
1317e5dd7070Spatrick         addContextSensitiveTypeNullability(*this, declarator,
1318e5dd7070Spatrick                                            DS.getNullability(),
1319e5dd7070Spatrick                                            DS.getNullabilityLoc(),
1320e5dd7070Spatrick                                            addedToDeclSpec);
1321e5dd7070Spatrick 
1322e5dd7070Spatrick       TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator);
1323e5dd7070Spatrick       if (!type.isInvalid())
1324e5dd7070Spatrick         Ty = type.get();
1325e5dd7070Spatrick 
1326e5dd7070Spatrick       // If we're parsing a parameter, steal all the decl attributes
1327e5dd7070Spatrick       // and add them to the decl spec.
1328a9ac8606Spatrick       if (context == DeclaratorContext::ObjCParameter)
1329e5dd7070Spatrick         takeDeclAttributes(*paramAttrs, declarator);
1330e5dd7070Spatrick     }
1331e5dd7070Spatrick   }
1332e5dd7070Spatrick 
1333e5dd7070Spatrick   if (Tok.is(tok::r_paren))
1334e5dd7070Spatrick     T.consumeClose();
1335e5dd7070Spatrick   else if (Tok.getLocation() == TypeStartLoc) {
1336e5dd7070Spatrick     // If we didn't eat any tokens, then this isn't a type.
1337e5dd7070Spatrick     Diag(Tok, diag::err_expected_type);
1338e5dd7070Spatrick     SkipUntil(tok::r_paren, StopAtSemi);
1339e5dd7070Spatrick   } else {
1340e5dd7070Spatrick     // Otherwise, we found *something*, but didn't get a ')' in the right
1341e5dd7070Spatrick     // place.  Emit an error then return what we have as the type.
1342e5dd7070Spatrick     T.consumeClose();
1343e5dd7070Spatrick   }
1344e5dd7070Spatrick   return Ty;
1345e5dd7070Spatrick }
1346e5dd7070Spatrick 
1347e5dd7070Spatrick ///   objc-method-decl:
1348e5dd7070Spatrick ///     objc-selector
1349e5dd7070Spatrick ///     objc-keyword-selector objc-parmlist[opt]
1350e5dd7070Spatrick ///     objc-type-name objc-selector
1351e5dd7070Spatrick ///     objc-type-name objc-keyword-selector objc-parmlist[opt]
1352e5dd7070Spatrick ///
1353e5dd7070Spatrick ///   objc-keyword-selector:
1354e5dd7070Spatrick ///     objc-keyword-decl
1355e5dd7070Spatrick ///     objc-keyword-selector objc-keyword-decl
1356e5dd7070Spatrick ///
1357e5dd7070Spatrick ///   objc-keyword-decl:
1358e5dd7070Spatrick ///     objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
1359e5dd7070Spatrick ///     objc-selector ':' objc-keyword-attributes[opt] identifier
1360e5dd7070Spatrick ///     ':' objc-type-name objc-keyword-attributes[opt] identifier
1361e5dd7070Spatrick ///     ':' objc-keyword-attributes[opt] identifier
1362e5dd7070Spatrick ///
1363e5dd7070Spatrick ///   objc-parmlist:
1364e5dd7070Spatrick ///     objc-parms objc-ellipsis[opt]
1365e5dd7070Spatrick ///
1366e5dd7070Spatrick ///   objc-parms:
1367e5dd7070Spatrick ///     objc-parms , parameter-declaration
1368e5dd7070Spatrick ///
1369e5dd7070Spatrick ///   objc-ellipsis:
1370e5dd7070Spatrick ///     , ...
1371e5dd7070Spatrick ///
1372e5dd7070Spatrick ///   objc-keyword-attributes:         [OBJC2]
1373e5dd7070Spatrick ///     __attribute__((unused))
1374e5dd7070Spatrick ///
ParseObjCMethodDecl(SourceLocation mLoc,tok::TokenKind mType,tok::ObjCKeywordKind MethodImplKind,bool MethodDefinition)1375e5dd7070Spatrick Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
1376e5dd7070Spatrick                                   tok::TokenKind mType,
1377e5dd7070Spatrick                                   tok::ObjCKeywordKind MethodImplKind,
1378e5dd7070Spatrick                                   bool MethodDefinition) {
1379e5dd7070Spatrick   ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
1380e5dd7070Spatrick 
1381e5dd7070Spatrick   if (Tok.is(tok::code_completion)) {
1382a9ac8606Spatrick     cutOffParsing();
1383e5dd7070Spatrick     Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
1384e5dd7070Spatrick                                        /*ReturnType=*/nullptr);
1385e5dd7070Spatrick     return nullptr;
1386e5dd7070Spatrick   }
1387e5dd7070Spatrick 
1388e5dd7070Spatrick   // Parse the return type if present.
1389e5dd7070Spatrick   ParsedType ReturnType;
1390e5dd7070Spatrick   ObjCDeclSpec DSRet;
1391e5dd7070Spatrick   if (Tok.is(tok::l_paren))
1392a9ac8606Spatrick     ReturnType =
1393a9ac8606Spatrick         ParseObjCTypeName(DSRet, DeclaratorContext::ObjCResult, nullptr);
1394e5dd7070Spatrick 
1395e5dd7070Spatrick   // If attributes exist before the method, parse them.
1396e5dd7070Spatrick   ParsedAttributes methodAttrs(AttrFactory);
1397a9ac8606Spatrick   MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
1398a9ac8606Spatrick                        methodAttrs);
1399e5dd7070Spatrick 
1400e5dd7070Spatrick   if (Tok.is(tok::code_completion)) {
1401a9ac8606Spatrick     cutOffParsing();
1402e5dd7070Spatrick     Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
1403e5dd7070Spatrick                                        ReturnType);
1404e5dd7070Spatrick     return nullptr;
1405e5dd7070Spatrick   }
1406e5dd7070Spatrick 
1407e5dd7070Spatrick   // Now parse the selector.
1408e5dd7070Spatrick   SourceLocation selLoc;
1409e5dd7070Spatrick   IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
1410e5dd7070Spatrick 
1411e5dd7070Spatrick   // An unnamed colon is valid.
1412e5dd7070Spatrick   if (!SelIdent && Tok.isNot(tok::colon)) { // missing selector name.
1413e5dd7070Spatrick     Diag(Tok, diag::err_expected_selector_for_method)
1414e5dd7070Spatrick       << SourceRange(mLoc, Tok.getLocation());
1415e5dd7070Spatrick     // Skip until we get a ; or @.
1416e5dd7070Spatrick     SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
1417e5dd7070Spatrick     return nullptr;
1418e5dd7070Spatrick   }
1419e5dd7070Spatrick 
1420e5dd7070Spatrick   SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo;
1421e5dd7070Spatrick   if (Tok.isNot(tok::colon)) {
1422e5dd7070Spatrick     // If attributes exist after the method, parse them.
1423a9ac8606Spatrick     MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
1424a9ac8606Spatrick                          methodAttrs);
1425e5dd7070Spatrick 
1426e5dd7070Spatrick     Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
1427e5dd7070Spatrick     Decl *Result = Actions.ActOnMethodDeclaration(
1428e5dd7070Spatrick         getCurScope(), mLoc, Tok.getLocation(), mType, DSRet, ReturnType,
1429e5dd7070Spatrick         selLoc, Sel, nullptr, CParamInfo.data(), CParamInfo.size(), methodAttrs,
1430e5dd7070Spatrick         MethodImplKind, false, MethodDefinition);
1431e5dd7070Spatrick     PD.complete(Result);
1432e5dd7070Spatrick     return Result;
1433e5dd7070Spatrick   }
1434e5dd7070Spatrick 
1435e5dd7070Spatrick   SmallVector<IdentifierInfo *, 12> KeyIdents;
1436e5dd7070Spatrick   SmallVector<SourceLocation, 12> KeyLocs;
1437e5dd7070Spatrick   SmallVector<Sema::ObjCArgInfo, 12> ArgInfos;
1438e5dd7070Spatrick   ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
1439e5dd7070Spatrick                             Scope::FunctionDeclarationScope | Scope::DeclScope);
1440e5dd7070Spatrick 
1441e5dd7070Spatrick   AttributePool allParamAttrs(AttrFactory);
1442*12c85518Srobert   while (true) {
1443e5dd7070Spatrick     ParsedAttributes paramAttrs(AttrFactory);
1444e5dd7070Spatrick     Sema::ObjCArgInfo ArgInfo;
1445e5dd7070Spatrick 
1446e5dd7070Spatrick     // Each iteration parses a single keyword argument.
1447e5dd7070Spatrick     if (ExpectAndConsume(tok::colon))
1448e5dd7070Spatrick       break;
1449e5dd7070Spatrick 
1450e5dd7070Spatrick     ArgInfo.Type = nullptr;
1451e5dd7070Spatrick     if (Tok.is(tok::l_paren)) // Parse the argument type if present.
1452a9ac8606Spatrick       ArgInfo.Type = ParseObjCTypeName(
1453a9ac8606Spatrick           ArgInfo.DeclSpec, DeclaratorContext::ObjCParameter, &paramAttrs);
1454e5dd7070Spatrick 
1455e5dd7070Spatrick     // If attributes exist before the argument name, parse them.
1456e5dd7070Spatrick     // Regardless, collect all the attributes we've parsed so far.
1457a9ac8606Spatrick     MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
1458a9ac8606Spatrick                          paramAttrs);
1459e5dd7070Spatrick     ArgInfo.ArgAttrs = paramAttrs;
1460e5dd7070Spatrick 
1461e5dd7070Spatrick     // Code completion for the next piece of the selector.
1462e5dd7070Spatrick     if (Tok.is(tok::code_completion)) {
1463a9ac8606Spatrick       cutOffParsing();
1464e5dd7070Spatrick       KeyIdents.push_back(SelIdent);
1465e5dd7070Spatrick       Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
1466e5dd7070Spatrick                                                  mType == tok::minus,
1467e5dd7070Spatrick                                                  /*AtParameterName=*/true,
1468e5dd7070Spatrick                                                  ReturnType, KeyIdents);
1469e5dd7070Spatrick       return nullptr;
1470e5dd7070Spatrick     }
1471e5dd7070Spatrick 
1472e5dd7070Spatrick     if (expectIdentifier())
1473e5dd7070Spatrick       break; // missing argument name.
1474e5dd7070Spatrick 
1475e5dd7070Spatrick     ArgInfo.Name = Tok.getIdentifierInfo();
1476e5dd7070Spatrick     ArgInfo.NameLoc = Tok.getLocation();
1477e5dd7070Spatrick     ConsumeToken(); // Eat the identifier.
1478e5dd7070Spatrick 
1479e5dd7070Spatrick     ArgInfos.push_back(ArgInfo);
1480e5dd7070Spatrick     KeyIdents.push_back(SelIdent);
1481e5dd7070Spatrick     KeyLocs.push_back(selLoc);
1482e5dd7070Spatrick 
1483e5dd7070Spatrick     // Make sure the attributes persist.
1484e5dd7070Spatrick     allParamAttrs.takeAllFrom(paramAttrs.getPool());
1485e5dd7070Spatrick 
1486e5dd7070Spatrick     // Code completion for the next piece of the selector.
1487e5dd7070Spatrick     if (Tok.is(tok::code_completion)) {
1488a9ac8606Spatrick       cutOffParsing();
1489e5dd7070Spatrick       Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
1490e5dd7070Spatrick                                                  mType == tok::minus,
1491e5dd7070Spatrick                                                  /*AtParameterName=*/false,
1492e5dd7070Spatrick                                                  ReturnType, KeyIdents);
1493e5dd7070Spatrick       return nullptr;
1494e5dd7070Spatrick     }
1495e5dd7070Spatrick 
1496e5dd7070Spatrick     // Check for another keyword selector.
1497e5dd7070Spatrick     SelIdent = ParseObjCSelectorPiece(selLoc);
1498e5dd7070Spatrick     if (!SelIdent && Tok.isNot(tok::colon))
1499e5dd7070Spatrick       break;
1500e5dd7070Spatrick     if (!SelIdent) {
1501e5dd7070Spatrick       SourceLocation ColonLoc = Tok.getLocation();
1502e5dd7070Spatrick       if (PP.getLocForEndOfToken(ArgInfo.NameLoc) == ColonLoc) {
1503e5dd7070Spatrick         Diag(ArgInfo.NameLoc, diag::warn_missing_selector_name) << ArgInfo.Name;
1504e5dd7070Spatrick         Diag(ArgInfo.NameLoc, diag::note_missing_selector_name) << ArgInfo.Name;
1505e5dd7070Spatrick         Diag(ColonLoc, diag::note_force_empty_selector_name) << ArgInfo.Name;
1506e5dd7070Spatrick       }
1507e5dd7070Spatrick     }
1508e5dd7070Spatrick     // We have a selector or a colon, continue parsing.
1509e5dd7070Spatrick   }
1510e5dd7070Spatrick 
1511e5dd7070Spatrick   bool isVariadic = false;
1512e5dd7070Spatrick   bool cStyleParamWarned = false;
1513e5dd7070Spatrick   // Parse the (optional) parameter list.
1514e5dd7070Spatrick   while (Tok.is(tok::comma)) {
1515e5dd7070Spatrick     ConsumeToken();
1516e5dd7070Spatrick     if (Tok.is(tok::ellipsis)) {
1517e5dd7070Spatrick       isVariadic = true;
1518e5dd7070Spatrick       ConsumeToken();
1519e5dd7070Spatrick       break;
1520e5dd7070Spatrick     }
1521e5dd7070Spatrick     if (!cStyleParamWarned) {
1522e5dd7070Spatrick       Diag(Tok, diag::warn_cstyle_param);
1523e5dd7070Spatrick       cStyleParamWarned = true;
1524e5dd7070Spatrick     }
1525e5dd7070Spatrick     DeclSpec DS(AttrFactory);
1526e5dd7070Spatrick     ParseDeclarationSpecifiers(DS);
1527e5dd7070Spatrick     // Parse the declarator.
1528*12c85518Srobert     Declarator ParmDecl(DS, ParsedAttributesView::none(),
1529*12c85518Srobert                         DeclaratorContext::Prototype);
1530e5dd7070Spatrick     ParseDeclarator(ParmDecl);
1531e5dd7070Spatrick     IdentifierInfo *ParmII = ParmDecl.getIdentifier();
1532e5dd7070Spatrick     Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl);
1533e5dd7070Spatrick     CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
1534e5dd7070Spatrick                                                     ParmDecl.getIdentifierLoc(),
1535e5dd7070Spatrick                                                     Param,
1536e5dd7070Spatrick                                                     nullptr));
1537e5dd7070Spatrick   }
1538e5dd7070Spatrick 
1539e5dd7070Spatrick   // FIXME: Add support for optional parameter list...
1540e5dd7070Spatrick   // If attributes exist after the method, parse them.
1541a9ac8606Spatrick   MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
1542a9ac8606Spatrick                        methodAttrs);
1543e5dd7070Spatrick 
1544e5dd7070Spatrick   if (KeyIdents.size() == 0)
1545e5dd7070Spatrick     return nullptr;
1546e5dd7070Spatrick 
1547e5dd7070Spatrick   Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
1548e5dd7070Spatrick                                                    &KeyIdents[0]);
1549e5dd7070Spatrick   Decl *Result = Actions.ActOnMethodDeclaration(
1550e5dd7070Spatrick       getCurScope(), mLoc, Tok.getLocation(), mType, DSRet, ReturnType, KeyLocs,
1551e5dd7070Spatrick       Sel, &ArgInfos[0], CParamInfo.data(), CParamInfo.size(), methodAttrs,
1552e5dd7070Spatrick       MethodImplKind, isVariadic, MethodDefinition);
1553e5dd7070Spatrick 
1554e5dd7070Spatrick   PD.complete(Result);
1555e5dd7070Spatrick   return Result;
1556e5dd7070Spatrick }
1557e5dd7070Spatrick 
1558e5dd7070Spatrick ///   objc-protocol-refs:
1559e5dd7070Spatrick ///     '<' identifier-list '>'
1560e5dd7070Spatrick ///
1561e5dd7070Spatrick bool Parser::
ParseObjCProtocolReferences(SmallVectorImpl<Decl * > & Protocols,SmallVectorImpl<SourceLocation> & ProtocolLocs,bool WarnOnDeclarations,bool ForObjCContainer,SourceLocation & LAngleLoc,SourceLocation & EndLoc,bool consumeLastToken)1562e5dd7070Spatrick ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
1563e5dd7070Spatrick                             SmallVectorImpl<SourceLocation> &ProtocolLocs,
1564e5dd7070Spatrick                             bool WarnOnDeclarations, bool ForObjCContainer,
1565e5dd7070Spatrick                             SourceLocation &LAngleLoc, SourceLocation &EndLoc,
1566e5dd7070Spatrick                             bool consumeLastToken) {
1567e5dd7070Spatrick   assert(Tok.is(tok::less) && "expected <");
1568e5dd7070Spatrick 
1569e5dd7070Spatrick   LAngleLoc = ConsumeToken(); // the "<"
1570e5dd7070Spatrick 
1571e5dd7070Spatrick   SmallVector<IdentifierLocPair, 8> ProtocolIdents;
1572e5dd7070Spatrick 
1573*12c85518Srobert   while (true) {
1574e5dd7070Spatrick     if (Tok.is(tok::code_completion)) {
1575e5dd7070Spatrick       cutOffParsing();
1576a9ac8606Spatrick       Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents);
1577e5dd7070Spatrick       return true;
1578e5dd7070Spatrick     }
1579e5dd7070Spatrick 
1580e5dd7070Spatrick     if (expectIdentifier()) {
1581e5dd7070Spatrick       SkipUntil(tok::greater, StopAtSemi);
1582e5dd7070Spatrick       return true;
1583e5dd7070Spatrick     }
1584e5dd7070Spatrick     ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(),
1585e5dd7070Spatrick                                        Tok.getLocation()));
1586e5dd7070Spatrick     ProtocolLocs.push_back(Tok.getLocation());
1587e5dd7070Spatrick     ConsumeToken();
1588e5dd7070Spatrick 
1589e5dd7070Spatrick     if (!TryConsumeToken(tok::comma))
1590e5dd7070Spatrick       break;
1591e5dd7070Spatrick   }
1592e5dd7070Spatrick 
1593e5dd7070Spatrick   // Consume the '>'.
1594ec727ea7Spatrick   if (ParseGreaterThanInTemplateList(LAngleLoc, EndLoc, consumeLastToken,
1595e5dd7070Spatrick                                      /*ObjCGenericList=*/false))
1596e5dd7070Spatrick     return true;
1597e5dd7070Spatrick 
1598e5dd7070Spatrick   // Convert the list of protocols identifiers into a list of protocol decls.
1599e5dd7070Spatrick   Actions.FindProtocolDeclaration(WarnOnDeclarations, ForObjCContainer,
1600e5dd7070Spatrick                                   ProtocolIdents, Protocols);
1601e5dd7070Spatrick   return false;
1602e5dd7070Spatrick }
1603e5dd7070Spatrick 
parseObjCProtocolQualifierType(SourceLocation & rAngleLoc)1604e5dd7070Spatrick TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) {
1605e5dd7070Spatrick   assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'");
1606e5dd7070Spatrick   assert(getLangOpts().ObjC && "Protocol qualifiers only exist in Objective-C");
1607e5dd7070Spatrick 
1608e5dd7070Spatrick   SourceLocation lAngleLoc;
1609e5dd7070Spatrick   SmallVector<Decl *, 8> protocols;
1610e5dd7070Spatrick   SmallVector<SourceLocation, 8> protocolLocs;
1611e5dd7070Spatrick   (void)ParseObjCProtocolReferences(protocols, protocolLocs, false, false,
1612e5dd7070Spatrick                                     lAngleLoc, rAngleLoc,
1613e5dd7070Spatrick                                     /*consumeLastToken=*/true);
1614e5dd7070Spatrick   TypeResult result = Actions.actOnObjCProtocolQualifierType(lAngleLoc,
1615e5dd7070Spatrick                                                              protocols,
1616e5dd7070Spatrick                                                              protocolLocs,
1617e5dd7070Spatrick                                                              rAngleLoc);
1618e5dd7070Spatrick   if (result.isUsable()) {
1619e5dd7070Spatrick     Diag(lAngleLoc, diag::warn_objc_protocol_qualifier_missing_id)
1620e5dd7070Spatrick       << FixItHint::CreateInsertion(lAngleLoc, "id")
1621e5dd7070Spatrick       << SourceRange(lAngleLoc, rAngleLoc);
1622e5dd7070Spatrick   }
1623e5dd7070Spatrick 
1624e5dd7070Spatrick   return result;
1625e5dd7070Spatrick }
1626e5dd7070Spatrick 
1627e5dd7070Spatrick /// Parse Objective-C type arguments or protocol qualifiers.
1628e5dd7070Spatrick ///
1629e5dd7070Spatrick ///   objc-type-arguments:
1630e5dd7070Spatrick ///     '<' type-name '...'[opt] (',' type-name '...'[opt])* '>'
1631e5dd7070Spatrick ///
parseObjCTypeArgsOrProtocolQualifiers(ParsedType baseType,SourceLocation & typeArgsLAngleLoc,SmallVectorImpl<ParsedType> & typeArgs,SourceLocation & typeArgsRAngleLoc,SourceLocation & protocolLAngleLoc,SmallVectorImpl<Decl * > & protocols,SmallVectorImpl<SourceLocation> & protocolLocs,SourceLocation & protocolRAngleLoc,bool consumeLastToken,bool warnOnIncompleteProtocols)1632e5dd7070Spatrick void Parser::parseObjCTypeArgsOrProtocolQualifiers(
1633e5dd7070Spatrick        ParsedType baseType,
1634e5dd7070Spatrick        SourceLocation &typeArgsLAngleLoc,
1635e5dd7070Spatrick        SmallVectorImpl<ParsedType> &typeArgs,
1636e5dd7070Spatrick        SourceLocation &typeArgsRAngleLoc,
1637e5dd7070Spatrick        SourceLocation &protocolLAngleLoc,
1638e5dd7070Spatrick        SmallVectorImpl<Decl *> &protocols,
1639e5dd7070Spatrick        SmallVectorImpl<SourceLocation> &protocolLocs,
1640e5dd7070Spatrick        SourceLocation &protocolRAngleLoc,
1641e5dd7070Spatrick        bool consumeLastToken,
1642e5dd7070Spatrick        bool warnOnIncompleteProtocols) {
1643e5dd7070Spatrick   assert(Tok.is(tok::less) && "Not at the start of type args or protocols");
1644e5dd7070Spatrick   SourceLocation lAngleLoc = ConsumeToken();
1645e5dd7070Spatrick 
1646e5dd7070Spatrick   // Whether all of the elements we've parsed thus far are single
1647e5dd7070Spatrick   // identifiers, which might be types or might be protocols.
1648e5dd7070Spatrick   bool allSingleIdentifiers = true;
1649e5dd7070Spatrick   SmallVector<IdentifierInfo *, 4> identifiers;
1650e5dd7070Spatrick   SmallVectorImpl<SourceLocation> &identifierLocs = protocolLocs;
1651e5dd7070Spatrick 
1652e5dd7070Spatrick   // Parse a list of comma-separated identifiers, bailing out if we
1653e5dd7070Spatrick   // see something different.
1654e5dd7070Spatrick   do {
1655e5dd7070Spatrick     // Parse a single identifier.
1656e5dd7070Spatrick     if (Tok.is(tok::identifier) &&
1657e5dd7070Spatrick         (NextToken().is(tok::comma) ||
1658e5dd7070Spatrick          NextToken().is(tok::greater) ||
1659e5dd7070Spatrick          NextToken().is(tok::greatergreater))) {
1660e5dd7070Spatrick       identifiers.push_back(Tok.getIdentifierInfo());
1661e5dd7070Spatrick       identifierLocs.push_back(ConsumeToken());
1662e5dd7070Spatrick       continue;
1663e5dd7070Spatrick     }
1664e5dd7070Spatrick 
1665e5dd7070Spatrick     if (Tok.is(tok::code_completion)) {
1666e5dd7070Spatrick       // FIXME: Also include types here.
1667e5dd7070Spatrick       SmallVector<IdentifierLocPair, 4> identifierLocPairs;
1668e5dd7070Spatrick       for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
1669e5dd7070Spatrick         identifierLocPairs.push_back(IdentifierLocPair(identifiers[i],
1670e5dd7070Spatrick                                                        identifierLocs[i]));
1671e5dd7070Spatrick       }
1672e5dd7070Spatrick 
1673e5dd7070Spatrick       QualType BaseT = Actions.GetTypeFromParser(baseType);
1674a9ac8606Spatrick       cutOffParsing();
1675e5dd7070Spatrick       if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) {
1676e5dd7070Spatrick         Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type);
1677e5dd7070Spatrick       } else {
1678e5dd7070Spatrick         Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs);
1679e5dd7070Spatrick       }
1680e5dd7070Spatrick       return;
1681e5dd7070Spatrick     }
1682e5dd7070Spatrick 
1683e5dd7070Spatrick     allSingleIdentifiers = false;
1684e5dd7070Spatrick     break;
1685e5dd7070Spatrick   } while (TryConsumeToken(tok::comma));
1686e5dd7070Spatrick 
1687e5dd7070Spatrick   // If we parsed an identifier list, semantic analysis sorts out
1688e5dd7070Spatrick   // whether it refers to protocols or to type arguments.
1689e5dd7070Spatrick   if (allSingleIdentifiers) {
1690e5dd7070Spatrick     // Parse the closing '>'.
1691e5dd7070Spatrick     SourceLocation rAngleLoc;
1692ec727ea7Spatrick     (void)ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc, consumeLastToken,
1693e5dd7070Spatrick                                          /*ObjCGenericList=*/true);
1694e5dd7070Spatrick 
1695e5dd7070Spatrick     // Let Sema figure out what we parsed.
1696e5dd7070Spatrick     Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(),
1697e5dd7070Spatrick                                                   baseType,
1698e5dd7070Spatrick                                                   lAngleLoc,
1699e5dd7070Spatrick                                                   identifiers,
1700e5dd7070Spatrick                                                   identifierLocs,
1701e5dd7070Spatrick                                                   rAngleLoc,
1702e5dd7070Spatrick                                                   typeArgsLAngleLoc,
1703e5dd7070Spatrick                                                   typeArgs,
1704e5dd7070Spatrick                                                   typeArgsRAngleLoc,
1705e5dd7070Spatrick                                                   protocolLAngleLoc,
1706e5dd7070Spatrick                                                   protocols,
1707e5dd7070Spatrick                                                   protocolRAngleLoc,
1708e5dd7070Spatrick                                                   warnOnIncompleteProtocols);
1709e5dd7070Spatrick     return;
1710e5dd7070Spatrick   }
1711e5dd7070Spatrick 
1712e5dd7070Spatrick   // We parsed an identifier list but stumbled into non single identifiers, this
1713e5dd7070Spatrick   // means we might (a) check that what we already parsed is a legitimate type
1714e5dd7070Spatrick   // (not a protocol or unknown type) and (b) parse the remaining ones, which
1715e5dd7070Spatrick   // must all be type args.
1716e5dd7070Spatrick 
1717e5dd7070Spatrick   // Convert the identifiers into type arguments.
1718e5dd7070Spatrick   bool invalid = false;
1719e5dd7070Spatrick   IdentifierInfo *foundProtocolId = nullptr, *foundValidTypeId = nullptr;
1720e5dd7070Spatrick   SourceLocation foundProtocolSrcLoc, foundValidTypeSrcLoc;
1721e5dd7070Spatrick   SmallVector<IdentifierInfo *, 2> unknownTypeArgs;
1722e5dd7070Spatrick   SmallVector<SourceLocation, 2> unknownTypeArgsLoc;
1723e5dd7070Spatrick 
1724e5dd7070Spatrick   for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
1725e5dd7070Spatrick     ParsedType typeArg
1726e5dd7070Spatrick       = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope());
1727e5dd7070Spatrick     if (typeArg) {
1728e5dd7070Spatrick       DeclSpec DS(AttrFactory);
1729e5dd7070Spatrick       const char *prevSpec = nullptr;
1730e5dd7070Spatrick       unsigned diagID;
1731e5dd7070Spatrick       DS.SetTypeSpecType(TST_typename, identifierLocs[i], prevSpec, diagID,
1732e5dd7070Spatrick                          typeArg, Actions.getASTContext().getPrintingPolicy());
1733e5dd7070Spatrick 
1734e5dd7070Spatrick       // Form a declarator to turn this into a type.
1735*12c85518Srobert       Declarator D(DS, ParsedAttributesView::none(),
1736*12c85518Srobert                    DeclaratorContext::TypeName);
1737e5dd7070Spatrick       TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D);
1738e5dd7070Spatrick       if (fullTypeArg.isUsable()) {
1739e5dd7070Spatrick         typeArgs.push_back(fullTypeArg.get());
1740e5dd7070Spatrick         if (!foundValidTypeId) {
1741e5dd7070Spatrick           foundValidTypeId = identifiers[i];
1742e5dd7070Spatrick           foundValidTypeSrcLoc = identifierLocs[i];
1743e5dd7070Spatrick         }
1744e5dd7070Spatrick       } else {
1745e5dd7070Spatrick         invalid = true;
1746e5dd7070Spatrick         unknownTypeArgs.push_back(identifiers[i]);
1747e5dd7070Spatrick         unknownTypeArgsLoc.push_back(identifierLocs[i]);
1748e5dd7070Spatrick       }
1749e5dd7070Spatrick     } else {
1750e5dd7070Spatrick       invalid = true;
1751e5dd7070Spatrick       if (!Actions.LookupProtocol(identifiers[i], identifierLocs[i])) {
1752e5dd7070Spatrick         unknownTypeArgs.push_back(identifiers[i]);
1753e5dd7070Spatrick         unknownTypeArgsLoc.push_back(identifierLocs[i]);
1754e5dd7070Spatrick       } else if (!foundProtocolId) {
1755e5dd7070Spatrick         foundProtocolId = identifiers[i];
1756e5dd7070Spatrick         foundProtocolSrcLoc = identifierLocs[i];
1757e5dd7070Spatrick       }
1758e5dd7070Spatrick     }
1759e5dd7070Spatrick   }
1760e5dd7070Spatrick 
1761e5dd7070Spatrick   // Continue parsing type-names.
1762e5dd7070Spatrick   do {
1763e5dd7070Spatrick     Token CurTypeTok = Tok;
1764e5dd7070Spatrick     TypeResult typeArg = ParseTypeName();
1765e5dd7070Spatrick 
1766e5dd7070Spatrick     // Consume the '...' for a pack expansion.
1767e5dd7070Spatrick     SourceLocation ellipsisLoc;
1768e5dd7070Spatrick     TryConsumeToken(tok::ellipsis, ellipsisLoc);
1769e5dd7070Spatrick     if (typeArg.isUsable() && ellipsisLoc.isValid()) {
1770e5dd7070Spatrick       typeArg = Actions.ActOnPackExpansion(typeArg.get(), ellipsisLoc);
1771e5dd7070Spatrick     }
1772e5dd7070Spatrick 
1773e5dd7070Spatrick     if (typeArg.isUsable()) {
1774e5dd7070Spatrick       typeArgs.push_back(typeArg.get());
1775e5dd7070Spatrick       if (!foundValidTypeId) {
1776e5dd7070Spatrick         foundValidTypeId = CurTypeTok.getIdentifierInfo();
1777e5dd7070Spatrick         foundValidTypeSrcLoc = CurTypeTok.getLocation();
1778e5dd7070Spatrick       }
1779e5dd7070Spatrick     } else {
1780e5dd7070Spatrick       invalid = true;
1781e5dd7070Spatrick     }
1782e5dd7070Spatrick   } while (TryConsumeToken(tok::comma));
1783e5dd7070Spatrick 
1784e5dd7070Spatrick   // Diagnose the mix between type args and protocols.
1785e5dd7070Spatrick   if (foundProtocolId && foundValidTypeId)
1786e5dd7070Spatrick     Actions.DiagnoseTypeArgsAndProtocols(foundProtocolId, foundProtocolSrcLoc,
1787e5dd7070Spatrick                                          foundValidTypeId,
1788e5dd7070Spatrick                                          foundValidTypeSrcLoc);
1789e5dd7070Spatrick 
1790e5dd7070Spatrick   // Diagnose unknown arg types.
1791e5dd7070Spatrick   ParsedType T;
1792e5dd7070Spatrick   if (unknownTypeArgs.size())
1793e5dd7070Spatrick     for (unsigned i = 0, e = unknownTypeArgsLoc.size(); i < e; ++i)
1794e5dd7070Spatrick       Actions.DiagnoseUnknownTypeName(unknownTypeArgs[i], unknownTypeArgsLoc[i],
1795e5dd7070Spatrick                                       getCurScope(), nullptr, T);
1796e5dd7070Spatrick 
1797e5dd7070Spatrick   // Parse the closing '>'.
1798e5dd7070Spatrick   SourceLocation rAngleLoc;
1799ec727ea7Spatrick   (void)ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc, consumeLastToken,
1800e5dd7070Spatrick                                        /*ObjCGenericList=*/true);
1801e5dd7070Spatrick 
1802e5dd7070Spatrick   if (invalid) {
1803e5dd7070Spatrick     typeArgs.clear();
1804e5dd7070Spatrick     return;
1805e5dd7070Spatrick   }
1806e5dd7070Spatrick 
1807e5dd7070Spatrick   // Record left/right angle locations.
1808e5dd7070Spatrick   typeArgsLAngleLoc = lAngleLoc;
1809e5dd7070Spatrick   typeArgsRAngleLoc = rAngleLoc;
1810e5dd7070Spatrick }
1811e5dd7070Spatrick 
parseObjCTypeArgsAndProtocolQualifiers(ParsedType baseType,SourceLocation & typeArgsLAngleLoc,SmallVectorImpl<ParsedType> & typeArgs,SourceLocation & typeArgsRAngleLoc,SourceLocation & protocolLAngleLoc,SmallVectorImpl<Decl * > & protocols,SmallVectorImpl<SourceLocation> & protocolLocs,SourceLocation & protocolRAngleLoc,bool consumeLastToken)1812e5dd7070Spatrick void Parser::parseObjCTypeArgsAndProtocolQualifiers(
1813e5dd7070Spatrick        ParsedType baseType,
1814e5dd7070Spatrick        SourceLocation &typeArgsLAngleLoc,
1815e5dd7070Spatrick        SmallVectorImpl<ParsedType> &typeArgs,
1816e5dd7070Spatrick        SourceLocation &typeArgsRAngleLoc,
1817e5dd7070Spatrick        SourceLocation &protocolLAngleLoc,
1818e5dd7070Spatrick        SmallVectorImpl<Decl *> &protocols,
1819e5dd7070Spatrick        SmallVectorImpl<SourceLocation> &protocolLocs,
1820e5dd7070Spatrick        SourceLocation &protocolRAngleLoc,
1821e5dd7070Spatrick        bool consumeLastToken) {
1822e5dd7070Spatrick   assert(Tok.is(tok::less));
1823e5dd7070Spatrick 
1824e5dd7070Spatrick   // Parse the first angle-bracket-delimited clause.
1825e5dd7070Spatrick   parseObjCTypeArgsOrProtocolQualifiers(baseType,
1826e5dd7070Spatrick                                         typeArgsLAngleLoc,
1827e5dd7070Spatrick                                         typeArgs,
1828e5dd7070Spatrick                                         typeArgsRAngleLoc,
1829e5dd7070Spatrick                                         protocolLAngleLoc,
1830e5dd7070Spatrick                                         protocols,
1831e5dd7070Spatrick                                         protocolLocs,
1832e5dd7070Spatrick                                         protocolRAngleLoc,
1833e5dd7070Spatrick                                         consumeLastToken,
1834e5dd7070Spatrick                                         /*warnOnIncompleteProtocols=*/false);
1835e5dd7070Spatrick   if (Tok.is(tok::eof)) // Nothing else to do here...
1836e5dd7070Spatrick     return;
1837e5dd7070Spatrick 
1838e5dd7070Spatrick   // An Objective-C object pointer followed by type arguments
1839e5dd7070Spatrick   // can then be followed again by a set of protocol references, e.g.,
1840e5dd7070Spatrick   // \c NSArray<NSView><NSTextDelegate>
1841e5dd7070Spatrick   if ((consumeLastToken && Tok.is(tok::less)) ||
1842e5dd7070Spatrick       (!consumeLastToken && NextToken().is(tok::less))) {
1843e5dd7070Spatrick     // If we aren't consuming the last token, the prior '>' is still hanging
1844e5dd7070Spatrick     // there. Consume it before we parse the protocol qualifiers.
1845e5dd7070Spatrick     if (!consumeLastToken)
1846e5dd7070Spatrick       ConsumeToken();
1847e5dd7070Spatrick 
1848e5dd7070Spatrick     if (!protocols.empty()) {
1849e5dd7070Spatrick       SkipUntilFlags skipFlags = SkipUntilFlags();
1850e5dd7070Spatrick       if (!consumeLastToken)
1851e5dd7070Spatrick         skipFlags = skipFlags | StopBeforeMatch;
1852e5dd7070Spatrick       Diag(Tok, diag::err_objc_type_args_after_protocols)
1853e5dd7070Spatrick         << SourceRange(protocolLAngleLoc, protocolRAngleLoc);
1854e5dd7070Spatrick       SkipUntil(tok::greater, tok::greatergreater, skipFlags);
1855e5dd7070Spatrick     } else {
1856e5dd7070Spatrick       ParseObjCProtocolReferences(protocols, protocolLocs,
1857e5dd7070Spatrick                                   /*WarnOnDeclarations=*/false,
1858e5dd7070Spatrick                                   /*ForObjCContainer=*/false,
1859e5dd7070Spatrick                                   protocolLAngleLoc, protocolRAngleLoc,
1860e5dd7070Spatrick                                   consumeLastToken);
1861e5dd7070Spatrick     }
1862e5dd7070Spatrick   }
1863e5dd7070Spatrick }
1864e5dd7070Spatrick 
parseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,ParsedType type,bool consumeLastToken,SourceLocation & endLoc)1865e5dd7070Spatrick TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers(
1866e5dd7070Spatrick              SourceLocation loc,
1867e5dd7070Spatrick              ParsedType type,
1868e5dd7070Spatrick              bool consumeLastToken,
1869e5dd7070Spatrick              SourceLocation &endLoc) {
1870e5dd7070Spatrick   assert(Tok.is(tok::less));
1871e5dd7070Spatrick   SourceLocation typeArgsLAngleLoc;
1872e5dd7070Spatrick   SmallVector<ParsedType, 4> typeArgs;
1873e5dd7070Spatrick   SourceLocation typeArgsRAngleLoc;
1874e5dd7070Spatrick   SourceLocation protocolLAngleLoc;
1875e5dd7070Spatrick   SmallVector<Decl *, 4> protocols;
1876e5dd7070Spatrick   SmallVector<SourceLocation, 4> protocolLocs;
1877e5dd7070Spatrick   SourceLocation protocolRAngleLoc;
1878e5dd7070Spatrick 
1879e5dd7070Spatrick   // Parse type arguments and protocol qualifiers.
1880e5dd7070Spatrick   parseObjCTypeArgsAndProtocolQualifiers(type, typeArgsLAngleLoc, typeArgs,
1881e5dd7070Spatrick                                          typeArgsRAngleLoc, protocolLAngleLoc,
1882e5dd7070Spatrick                                          protocols, protocolLocs,
1883e5dd7070Spatrick                                          protocolRAngleLoc, consumeLastToken);
1884e5dd7070Spatrick 
1885e5dd7070Spatrick   if (Tok.is(tok::eof))
1886e5dd7070Spatrick     return true; // Invalid type result.
1887e5dd7070Spatrick 
1888e5dd7070Spatrick   // Compute the location of the last token.
1889e5dd7070Spatrick   if (consumeLastToken)
1890e5dd7070Spatrick     endLoc = PrevTokLocation;
1891e5dd7070Spatrick   else
1892e5dd7070Spatrick     endLoc = Tok.getLocation();
1893e5dd7070Spatrick 
1894e5dd7070Spatrick   return Actions.actOnObjCTypeArgsAndProtocolQualifiers(
1895e5dd7070Spatrick            getCurScope(),
1896e5dd7070Spatrick            loc,
1897e5dd7070Spatrick            type,
1898e5dd7070Spatrick            typeArgsLAngleLoc,
1899e5dd7070Spatrick            typeArgs,
1900e5dd7070Spatrick            typeArgsRAngleLoc,
1901e5dd7070Spatrick            protocolLAngleLoc,
1902e5dd7070Spatrick            protocols,
1903e5dd7070Spatrick            protocolLocs,
1904e5dd7070Spatrick            protocolRAngleLoc);
1905e5dd7070Spatrick }
1906e5dd7070Spatrick 
HelperActionsForIvarDeclarations(ObjCContainerDecl * interfaceDecl,SourceLocation atLoc,BalancedDelimiterTracker & T,SmallVectorImpl<Decl * > & AllIvarDecls,bool RBraceMissing)1907*12c85518Srobert void Parser::HelperActionsForIvarDeclarations(
1908*12c85518Srobert     ObjCContainerDecl *interfaceDecl, SourceLocation atLoc,
1909*12c85518Srobert     BalancedDelimiterTracker &T, SmallVectorImpl<Decl *> &AllIvarDecls,
1910e5dd7070Spatrick     bool RBraceMissing) {
1911e5dd7070Spatrick   if (!RBraceMissing)
1912e5dd7070Spatrick     T.consumeClose();
1913e5dd7070Spatrick 
1914*12c85518Srobert   assert(getObjCDeclContext() == interfaceDecl &&
1915*12c85518Srobert          "Ivars should have interfaceDecl as their decl context");
1916e5dd7070Spatrick   Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls);
1917e5dd7070Spatrick   // Call ActOnFields() even if we don't have any decls. This is useful
1918e5dd7070Spatrick   // for code rewriting tools that need to be aware of the empty list.
1919e5dd7070Spatrick   Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl, AllIvarDecls,
1920e5dd7070Spatrick                       T.getOpenLocation(), T.getCloseLocation(),
1921e5dd7070Spatrick                       ParsedAttributesView());
1922e5dd7070Spatrick }
1923e5dd7070Spatrick 
1924e5dd7070Spatrick ///   objc-class-instance-variables:
1925e5dd7070Spatrick ///     '{' objc-instance-variable-decl-list[opt] '}'
1926e5dd7070Spatrick ///
1927e5dd7070Spatrick ///   objc-instance-variable-decl-list:
1928e5dd7070Spatrick ///     objc-visibility-spec
1929e5dd7070Spatrick ///     objc-instance-variable-decl ';'
1930e5dd7070Spatrick ///     ';'
1931e5dd7070Spatrick ///     objc-instance-variable-decl-list objc-visibility-spec
1932e5dd7070Spatrick ///     objc-instance-variable-decl-list objc-instance-variable-decl ';'
1933e5dd7070Spatrick ///     objc-instance-variable-decl-list static_assert-declaration
1934e5dd7070Spatrick ///     objc-instance-variable-decl-list ';'
1935e5dd7070Spatrick ///
1936e5dd7070Spatrick ///   objc-visibility-spec:
1937e5dd7070Spatrick ///     @private
1938e5dd7070Spatrick ///     @protected
1939e5dd7070Spatrick ///     @public
1940e5dd7070Spatrick ///     @package [OBJC2]
1941e5dd7070Spatrick ///
1942e5dd7070Spatrick ///   objc-instance-variable-decl:
1943e5dd7070Spatrick ///     struct-declaration
1944e5dd7070Spatrick ///
ParseObjCClassInstanceVariables(ObjCContainerDecl * interfaceDecl,tok::ObjCKeywordKind visibility,SourceLocation atLoc)1945*12c85518Srobert void Parser::ParseObjCClassInstanceVariables(ObjCContainerDecl *interfaceDecl,
1946e5dd7070Spatrick                                              tok::ObjCKeywordKind visibility,
1947e5dd7070Spatrick                                              SourceLocation atLoc) {
1948e5dd7070Spatrick   assert(Tok.is(tok::l_brace) && "expected {");
1949e5dd7070Spatrick   SmallVector<Decl *, 32> AllIvarDecls;
1950e5dd7070Spatrick 
1951e5dd7070Spatrick   ParseScope ClassScope(this, Scope::DeclScope | Scope::ClassScope);
1952e5dd7070Spatrick 
1953e5dd7070Spatrick   BalancedDelimiterTracker T(*this, tok::l_brace);
1954e5dd7070Spatrick   T.consumeOpen();
1955e5dd7070Spatrick   // While we still have something to read, read the instance variables.
1956e5dd7070Spatrick   while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
1957e5dd7070Spatrick     // Each iteration of this loop reads one objc-instance-variable-decl.
1958e5dd7070Spatrick 
1959e5dd7070Spatrick     // Check for extraneous top-level semicolon.
1960e5dd7070Spatrick     if (Tok.is(tok::semi)) {
1961e5dd7070Spatrick       ConsumeExtraSemi(InstanceVariableList);
1962e5dd7070Spatrick       continue;
1963e5dd7070Spatrick     }
1964e5dd7070Spatrick 
1965e5dd7070Spatrick     // Set the default visibility to private.
1966e5dd7070Spatrick     if (TryConsumeToken(tok::at)) { // parse objc-visibility-spec
1967e5dd7070Spatrick       if (Tok.is(tok::code_completion)) {
1968a9ac8606Spatrick         cutOffParsing();
1969e5dd7070Spatrick         Actions.CodeCompleteObjCAtVisibility(getCurScope());
1970a9ac8606Spatrick         return;
1971e5dd7070Spatrick       }
1972e5dd7070Spatrick 
1973e5dd7070Spatrick       switch (Tok.getObjCKeywordID()) {
1974e5dd7070Spatrick       case tok::objc_private:
1975e5dd7070Spatrick       case tok::objc_public:
1976e5dd7070Spatrick       case tok::objc_protected:
1977e5dd7070Spatrick       case tok::objc_package:
1978e5dd7070Spatrick         visibility = Tok.getObjCKeywordID();
1979e5dd7070Spatrick         ConsumeToken();
1980e5dd7070Spatrick         continue;
1981e5dd7070Spatrick 
1982e5dd7070Spatrick       case tok::objc_end:
1983e5dd7070Spatrick         Diag(Tok, diag::err_objc_unexpected_atend);
1984e5dd7070Spatrick         Tok.setLocation(Tok.getLocation().getLocWithOffset(-1));
1985e5dd7070Spatrick         Tok.setKind(tok::at);
1986e5dd7070Spatrick         Tok.setLength(1);
1987e5dd7070Spatrick         PP.EnterToken(Tok, /*IsReinject*/true);
1988e5dd7070Spatrick         HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
1989e5dd7070Spatrick                                          T, AllIvarDecls, true);
1990e5dd7070Spatrick         return;
1991e5dd7070Spatrick 
1992e5dd7070Spatrick       default:
1993e5dd7070Spatrick         Diag(Tok, diag::err_objc_illegal_visibility_spec);
1994e5dd7070Spatrick         continue;
1995e5dd7070Spatrick       }
1996e5dd7070Spatrick     }
1997e5dd7070Spatrick 
1998e5dd7070Spatrick     if (Tok.is(tok::code_completion)) {
1999a9ac8606Spatrick       cutOffParsing();
2000e5dd7070Spatrick       Actions.CodeCompleteOrdinaryName(getCurScope(),
2001e5dd7070Spatrick                                        Sema::PCC_ObjCInstanceVariableList);
2002a9ac8606Spatrick       return;
2003e5dd7070Spatrick     }
2004e5dd7070Spatrick 
2005e5dd7070Spatrick     // This needs to duplicate a small amount of code from
2006e5dd7070Spatrick     // ParseStructUnionBody() for things that should work in both
2007e5dd7070Spatrick     // C struct and in Objective-C class instance variables.
2008e5dd7070Spatrick     if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
2009e5dd7070Spatrick       SourceLocation DeclEnd;
2010e5dd7070Spatrick       ParseStaticAssertDeclaration(DeclEnd);
2011e5dd7070Spatrick       continue;
2012e5dd7070Spatrick     }
2013e5dd7070Spatrick 
2014e5dd7070Spatrick     auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) {
2015*12c85518Srobert       assert(getObjCDeclContext() == interfaceDecl &&
2016*12c85518Srobert              "Ivar should have interfaceDecl as its decl context");
2017e5dd7070Spatrick       // Install the declarator into the interface decl.
2018e5dd7070Spatrick       FD.D.setObjCIvar(true);
2019e5dd7070Spatrick       Decl *Field = Actions.ActOnIvar(
2020e5dd7070Spatrick           getCurScope(), FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D,
2021e5dd7070Spatrick           FD.BitfieldSize, visibility);
2022e5dd7070Spatrick       if (Field)
2023e5dd7070Spatrick         AllIvarDecls.push_back(Field);
2024e5dd7070Spatrick       FD.complete(Field);
2025e5dd7070Spatrick     };
2026e5dd7070Spatrick 
2027e5dd7070Spatrick     // Parse all the comma separated declarators.
2028e5dd7070Spatrick     ParsingDeclSpec DS(*this);
2029e5dd7070Spatrick     ParseStructDeclaration(DS, ObjCIvarCallback);
2030e5dd7070Spatrick 
2031e5dd7070Spatrick     if (Tok.is(tok::semi)) {
2032e5dd7070Spatrick       ConsumeToken();
2033e5dd7070Spatrick     } else {
2034e5dd7070Spatrick       Diag(Tok, diag::err_expected_semi_decl_list);
2035e5dd7070Spatrick       // Skip to end of block or statement
2036e5dd7070Spatrick       SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
2037e5dd7070Spatrick     }
2038e5dd7070Spatrick   }
2039e5dd7070Spatrick   HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
2040e5dd7070Spatrick                                    T, AllIvarDecls, false);
2041e5dd7070Spatrick }
2042e5dd7070Spatrick 
2043e5dd7070Spatrick ///   objc-protocol-declaration:
2044e5dd7070Spatrick ///     objc-protocol-definition
2045e5dd7070Spatrick ///     objc-protocol-forward-reference
2046e5dd7070Spatrick ///
2047e5dd7070Spatrick ///   objc-protocol-definition:
2048e5dd7070Spatrick ///     \@protocol identifier
2049e5dd7070Spatrick ///       objc-protocol-refs[opt]
2050e5dd7070Spatrick ///       objc-interface-decl-list
2051e5dd7070Spatrick ///     \@end
2052e5dd7070Spatrick ///
2053e5dd7070Spatrick ///   objc-protocol-forward-reference:
2054e5dd7070Spatrick ///     \@protocol identifier-list ';'
2055e5dd7070Spatrick ///
2056e5dd7070Spatrick ///   "\@protocol identifier ;" should be resolved as "\@protocol
2057e5dd7070Spatrick ///   identifier-list ;": objc-interface-decl-list may not start with a
2058e5dd7070Spatrick ///   semicolon in the first alternative if objc-protocol-refs are omitted.
2059e5dd7070Spatrick Parser::DeclGroupPtrTy
ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,ParsedAttributes & attrs)2060e5dd7070Spatrick Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
2061e5dd7070Spatrick                                        ParsedAttributes &attrs) {
2062e5dd7070Spatrick   assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
2063e5dd7070Spatrick          "ParseObjCAtProtocolDeclaration(): Expected @protocol");
2064e5dd7070Spatrick   ConsumeToken(); // the "protocol" identifier
2065e5dd7070Spatrick 
2066e5dd7070Spatrick   if (Tok.is(tok::code_completion)) {
2067e5dd7070Spatrick     cutOffParsing();
2068a9ac8606Spatrick     Actions.CodeCompleteObjCProtocolDecl(getCurScope());
2069e5dd7070Spatrick     return nullptr;
2070e5dd7070Spatrick   }
2071e5dd7070Spatrick 
2072e5dd7070Spatrick   MaybeSkipAttributes(tok::objc_protocol);
2073e5dd7070Spatrick 
2074e5dd7070Spatrick   if (expectIdentifier())
2075e5dd7070Spatrick     return nullptr; // missing protocol name.
2076e5dd7070Spatrick   // Save the protocol name, then consume it.
2077e5dd7070Spatrick   IdentifierInfo *protocolName = Tok.getIdentifierInfo();
2078e5dd7070Spatrick   SourceLocation nameLoc = ConsumeToken();
2079e5dd7070Spatrick 
2080e5dd7070Spatrick   if (TryConsumeToken(tok::semi)) { // forward declaration of one protocol.
2081e5dd7070Spatrick     IdentifierLocPair ProtoInfo(protocolName, nameLoc);
2082e5dd7070Spatrick     return Actions.ActOnForwardProtocolDeclaration(AtLoc, ProtoInfo, attrs);
2083e5dd7070Spatrick   }
2084e5dd7070Spatrick 
2085e5dd7070Spatrick   CheckNestedObjCContexts(AtLoc);
2086e5dd7070Spatrick 
2087e5dd7070Spatrick   if (Tok.is(tok::comma)) { // list of forward declarations.
2088e5dd7070Spatrick     SmallVector<IdentifierLocPair, 8> ProtocolRefs;
2089e5dd7070Spatrick     ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));
2090e5dd7070Spatrick 
2091e5dd7070Spatrick     // Parse the list of forward declarations.
2092*12c85518Srobert     while (true) {
2093e5dd7070Spatrick       ConsumeToken(); // the ','
2094e5dd7070Spatrick       if (expectIdentifier()) {
2095e5dd7070Spatrick         SkipUntil(tok::semi);
2096e5dd7070Spatrick         return nullptr;
2097e5dd7070Spatrick       }
2098e5dd7070Spatrick       ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),
2099e5dd7070Spatrick                                                Tok.getLocation()));
2100e5dd7070Spatrick       ConsumeToken(); // the identifier
2101e5dd7070Spatrick 
2102e5dd7070Spatrick       if (Tok.isNot(tok::comma))
2103e5dd7070Spatrick         break;
2104e5dd7070Spatrick     }
2105e5dd7070Spatrick     // Consume the ';'.
2106e5dd7070Spatrick     if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@protocol"))
2107e5dd7070Spatrick       return nullptr;
2108e5dd7070Spatrick 
2109e5dd7070Spatrick     return Actions.ActOnForwardProtocolDeclaration(AtLoc, ProtocolRefs, attrs);
2110e5dd7070Spatrick   }
2111e5dd7070Spatrick 
2112e5dd7070Spatrick   // Last, and definitely not least, parse a protocol declaration.
2113e5dd7070Spatrick   SourceLocation LAngleLoc, EndProtoLoc;
2114e5dd7070Spatrick 
2115e5dd7070Spatrick   SmallVector<Decl *, 8> ProtocolRefs;
2116e5dd7070Spatrick   SmallVector<SourceLocation, 8> ProtocolLocs;
2117e5dd7070Spatrick   if (Tok.is(tok::less) &&
2118e5dd7070Spatrick       ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true,
2119e5dd7070Spatrick                                   LAngleLoc, EndProtoLoc,
2120e5dd7070Spatrick                                   /*consumeLastToken=*/true))
2121e5dd7070Spatrick     return nullptr;
2122e5dd7070Spatrick 
2123*12c85518Srobert   Sema::SkipBodyInfo SkipBody;
2124*12c85518Srobert   ObjCProtocolDecl *ProtoType = Actions.ActOnStartProtocolInterface(
2125e5dd7070Spatrick       AtLoc, protocolName, nameLoc, ProtocolRefs.data(), ProtocolRefs.size(),
2126*12c85518Srobert       ProtocolLocs.data(), EndProtoLoc, attrs, &SkipBody);
2127e5dd7070Spatrick 
2128e5dd7070Spatrick   ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType);
2129*12c85518Srobert   if (SkipBody.CheckSameAsPrevious) {
2130*12c85518Srobert     auto *PreviousDef = cast<ObjCProtocolDecl>(SkipBody.Previous);
2131*12c85518Srobert     if (Actions.ActOnDuplicateODRHashDefinition(ProtoType, PreviousDef)) {
2132*12c85518Srobert       ProtoType->mergeDuplicateDefinitionWithCommon(
2133*12c85518Srobert           PreviousDef->getDefinition());
2134*12c85518Srobert     } else {
2135*12c85518Srobert       ODRDiagsEmitter DiagsEmitter(Diags, Actions.getASTContext(),
2136*12c85518Srobert                                    getPreprocessor().getLangOpts());
2137*12c85518Srobert       DiagsEmitter.diagnoseMismatch(PreviousDef, ProtoType);
2138*12c85518Srobert     }
2139*12c85518Srobert   }
2140e5dd7070Spatrick   return Actions.ConvertDeclToDeclGroup(ProtoType);
2141e5dd7070Spatrick }
2142e5dd7070Spatrick 
2143e5dd7070Spatrick ///   objc-implementation:
2144e5dd7070Spatrick ///     objc-class-implementation-prologue
2145e5dd7070Spatrick ///     objc-category-implementation-prologue
2146e5dd7070Spatrick ///
2147e5dd7070Spatrick ///   objc-class-implementation-prologue:
2148e5dd7070Spatrick ///     @implementation identifier objc-superclass[opt]
2149e5dd7070Spatrick ///       objc-class-instance-variables[opt]
2150e5dd7070Spatrick ///
2151e5dd7070Spatrick ///   objc-category-implementation-prologue:
2152e5dd7070Spatrick ///     @implementation identifier ( identifier )
2153e5dd7070Spatrick Parser::DeclGroupPtrTy
ParseObjCAtImplementationDeclaration(SourceLocation AtLoc,ParsedAttributes & Attrs)2154e5dd7070Spatrick Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc,
2155e5dd7070Spatrick                                              ParsedAttributes &Attrs) {
2156e5dd7070Spatrick   assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
2157e5dd7070Spatrick          "ParseObjCAtImplementationDeclaration(): Expected @implementation");
2158e5dd7070Spatrick   CheckNestedObjCContexts(AtLoc);
2159e5dd7070Spatrick   ConsumeToken(); // the "implementation" identifier
2160e5dd7070Spatrick 
2161e5dd7070Spatrick   // Code completion after '@implementation'.
2162e5dd7070Spatrick   if (Tok.is(tok::code_completion)) {
2163e5dd7070Spatrick     cutOffParsing();
2164a9ac8606Spatrick     Actions.CodeCompleteObjCImplementationDecl(getCurScope());
2165e5dd7070Spatrick     return nullptr;
2166e5dd7070Spatrick   }
2167e5dd7070Spatrick 
2168e5dd7070Spatrick   MaybeSkipAttributes(tok::objc_implementation);
2169e5dd7070Spatrick 
2170e5dd7070Spatrick   if (expectIdentifier())
2171e5dd7070Spatrick     return nullptr; // missing class or category name.
2172e5dd7070Spatrick   // We have a class or category name - consume it.
2173e5dd7070Spatrick   IdentifierInfo *nameId = Tok.getIdentifierInfo();
2174e5dd7070Spatrick   SourceLocation nameLoc = ConsumeToken(); // consume class or category name
2175*12c85518Srobert   ObjCImplDecl *ObjCImpDecl = nullptr;
2176e5dd7070Spatrick 
2177e5dd7070Spatrick   // Neither a type parameter list nor a list of protocol references is
2178e5dd7070Spatrick   // permitted here. Parse and diagnose them.
2179e5dd7070Spatrick   if (Tok.is(tok::less)) {
2180e5dd7070Spatrick     SourceLocation lAngleLoc, rAngleLoc;
2181e5dd7070Spatrick     SmallVector<IdentifierLocPair, 8> protocolIdents;
2182e5dd7070Spatrick     SourceLocation diagLoc = Tok.getLocation();
2183e5dd7070Spatrick     ObjCTypeParamListScope typeParamScope(Actions, getCurScope());
2184e5dd7070Spatrick     if (parseObjCTypeParamListOrProtocolRefs(typeParamScope, lAngleLoc,
2185e5dd7070Spatrick                                              protocolIdents, rAngleLoc)) {
2186e5dd7070Spatrick       Diag(diagLoc, diag::err_objc_parameterized_implementation)
2187e5dd7070Spatrick         << SourceRange(diagLoc, PrevTokLocation);
2188e5dd7070Spatrick     } else if (lAngleLoc.isValid()) {
2189e5dd7070Spatrick       Diag(lAngleLoc, diag::err_unexpected_protocol_qualifier)
2190e5dd7070Spatrick         << FixItHint::CreateRemoval(SourceRange(lAngleLoc, rAngleLoc));
2191e5dd7070Spatrick     }
2192e5dd7070Spatrick   }
2193e5dd7070Spatrick 
2194e5dd7070Spatrick   if (Tok.is(tok::l_paren)) {
2195e5dd7070Spatrick     // we have a category implementation.
2196e5dd7070Spatrick     ConsumeParen();
2197e5dd7070Spatrick     SourceLocation categoryLoc, rparenLoc;
2198e5dd7070Spatrick     IdentifierInfo *categoryId = nullptr;
2199e5dd7070Spatrick 
2200e5dd7070Spatrick     if (Tok.is(tok::code_completion)) {
2201e5dd7070Spatrick       cutOffParsing();
2202a9ac8606Spatrick       Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc);
2203e5dd7070Spatrick       return nullptr;
2204e5dd7070Spatrick     }
2205e5dd7070Spatrick 
2206e5dd7070Spatrick     if (Tok.is(tok::identifier)) {
2207e5dd7070Spatrick       categoryId = Tok.getIdentifierInfo();
2208e5dd7070Spatrick       categoryLoc = ConsumeToken();
2209e5dd7070Spatrick     } else {
2210e5dd7070Spatrick       Diag(Tok, diag::err_expected)
2211e5dd7070Spatrick           << tok::identifier; // missing category name.
2212e5dd7070Spatrick       return nullptr;
2213e5dd7070Spatrick     }
2214e5dd7070Spatrick     if (Tok.isNot(tok::r_paren)) {
2215e5dd7070Spatrick       Diag(Tok, diag::err_expected) << tok::r_paren;
2216e5dd7070Spatrick       SkipUntil(tok::r_paren); // don't stop at ';'
2217e5dd7070Spatrick       return nullptr;
2218e5dd7070Spatrick     }
2219e5dd7070Spatrick     rparenLoc = ConsumeParen();
2220e5dd7070Spatrick     if (Tok.is(tok::less)) { // we have illegal '<' try to recover
2221e5dd7070Spatrick       Diag(Tok, diag::err_unexpected_protocol_qualifier);
2222e5dd7070Spatrick       SourceLocation protocolLAngleLoc, protocolRAngleLoc;
2223e5dd7070Spatrick       SmallVector<Decl *, 4> protocols;
2224e5dd7070Spatrick       SmallVector<SourceLocation, 4> protocolLocs;
2225e5dd7070Spatrick       (void)ParseObjCProtocolReferences(protocols, protocolLocs,
2226e5dd7070Spatrick                                         /*warnOnIncompleteProtocols=*/false,
2227e5dd7070Spatrick                                         /*ForObjCContainer=*/false,
2228e5dd7070Spatrick                                         protocolLAngleLoc, protocolRAngleLoc,
2229e5dd7070Spatrick                                         /*consumeLastToken=*/true);
2230e5dd7070Spatrick     }
2231e5dd7070Spatrick     ObjCImpDecl = Actions.ActOnStartCategoryImplementation(
2232e5dd7070Spatrick         AtLoc, nameId, nameLoc, categoryId, categoryLoc, Attrs);
2233e5dd7070Spatrick 
2234e5dd7070Spatrick   } else {
2235e5dd7070Spatrick     // We have a class implementation
2236e5dd7070Spatrick     SourceLocation superClassLoc;
2237e5dd7070Spatrick     IdentifierInfo *superClassId = nullptr;
2238e5dd7070Spatrick     if (TryConsumeToken(tok::colon)) {
2239e5dd7070Spatrick       // We have a super class
2240e5dd7070Spatrick       if (expectIdentifier())
2241e5dd7070Spatrick         return nullptr; // missing super class name.
2242e5dd7070Spatrick       superClassId = Tok.getIdentifierInfo();
2243e5dd7070Spatrick       superClassLoc = ConsumeToken(); // Consume super class name
2244e5dd7070Spatrick     }
2245e5dd7070Spatrick     ObjCImpDecl = Actions.ActOnStartClassImplementation(
2246e5dd7070Spatrick         AtLoc, nameId, nameLoc, superClassId, superClassLoc, Attrs);
2247e5dd7070Spatrick 
2248e5dd7070Spatrick     if (Tok.is(tok::l_brace)) // we have ivars
2249e5dd7070Spatrick       ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc);
2250e5dd7070Spatrick     else if (Tok.is(tok::less)) { // we have illegal '<' try to recover
2251e5dd7070Spatrick       Diag(Tok, diag::err_unexpected_protocol_qualifier);
2252e5dd7070Spatrick 
2253e5dd7070Spatrick       SourceLocation protocolLAngleLoc, protocolRAngleLoc;
2254e5dd7070Spatrick       SmallVector<Decl *, 4> protocols;
2255e5dd7070Spatrick       SmallVector<SourceLocation, 4> protocolLocs;
2256e5dd7070Spatrick       (void)ParseObjCProtocolReferences(protocols, protocolLocs,
2257e5dd7070Spatrick                                         /*warnOnIncompleteProtocols=*/false,
2258e5dd7070Spatrick                                         /*ForObjCContainer=*/false,
2259e5dd7070Spatrick                                         protocolLAngleLoc, protocolRAngleLoc,
2260e5dd7070Spatrick                                         /*consumeLastToken=*/true);
2261e5dd7070Spatrick     }
2262e5dd7070Spatrick   }
2263e5dd7070Spatrick   assert(ObjCImpDecl);
2264e5dd7070Spatrick 
2265e5dd7070Spatrick   SmallVector<Decl *, 8> DeclsInGroup;
2266e5dd7070Spatrick 
2267e5dd7070Spatrick   {
2268e5dd7070Spatrick     ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl);
2269e5dd7070Spatrick     while (!ObjCImplParsing.isFinished() && !isEofOrEom()) {
2270*12c85518Srobert       ParsedAttributes DeclAttrs(AttrFactory);
2271*12c85518Srobert       MaybeParseCXX11Attributes(DeclAttrs);
2272*12c85518Srobert       ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
2273*12c85518Srobert       if (DeclGroupPtrTy DGP =
2274*12c85518Srobert               ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs)) {
2275e5dd7070Spatrick         DeclGroupRef DG = DGP.get();
2276e5dd7070Spatrick         DeclsInGroup.append(DG.begin(), DG.end());
2277e5dd7070Spatrick       }
2278e5dd7070Spatrick     }
2279e5dd7070Spatrick   }
2280e5dd7070Spatrick 
2281e5dd7070Spatrick   return Actions.ActOnFinishObjCImplementation(ObjCImpDecl, DeclsInGroup);
2282e5dd7070Spatrick }
2283e5dd7070Spatrick 
2284e5dd7070Spatrick Parser::DeclGroupPtrTy
ParseObjCAtEndDeclaration(SourceRange atEnd)2285e5dd7070Spatrick Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
2286e5dd7070Spatrick   assert(Tok.isObjCAtKeyword(tok::objc_end) &&
2287e5dd7070Spatrick          "ParseObjCAtEndDeclaration(): Expected @end");
2288e5dd7070Spatrick   ConsumeToken(); // the "end" identifier
2289e5dd7070Spatrick   if (CurParsedObjCImpl)
2290e5dd7070Spatrick     CurParsedObjCImpl->finish(atEnd);
2291e5dd7070Spatrick   else
2292e5dd7070Spatrick     // missing @implementation
2293e5dd7070Spatrick     Diag(atEnd.getBegin(), diag::err_expected_objc_container);
2294e5dd7070Spatrick   return nullptr;
2295e5dd7070Spatrick }
2296e5dd7070Spatrick 
~ObjCImplParsingDataRAII()2297e5dd7070Spatrick Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() {
2298e5dd7070Spatrick   if (!Finished) {
2299e5dd7070Spatrick     finish(P.Tok.getLocation());
2300e5dd7070Spatrick     if (P.isEofOrEom()) {
2301e5dd7070Spatrick       P.Diag(P.Tok, diag::err_objc_missing_end)
2302e5dd7070Spatrick           << FixItHint::CreateInsertion(P.Tok.getLocation(), "\n@end\n");
2303e5dd7070Spatrick       P.Diag(Dcl->getBeginLoc(), diag::note_objc_container_start)
2304e5dd7070Spatrick           << Sema::OCK_Implementation;
2305e5dd7070Spatrick     }
2306e5dd7070Spatrick   }
2307e5dd7070Spatrick   P.CurParsedObjCImpl = nullptr;
2308e5dd7070Spatrick   assert(LateParsedObjCMethods.empty());
2309e5dd7070Spatrick }
2310e5dd7070Spatrick 
finish(SourceRange AtEnd)2311e5dd7070Spatrick void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) {
2312e5dd7070Spatrick   assert(!Finished);
2313e5dd7070Spatrick   P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl, AtEnd.getBegin());
2314e5dd7070Spatrick   for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
2315e5dd7070Spatrick     P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
2316e5dd7070Spatrick                                true/*Methods*/);
2317e5dd7070Spatrick 
2318e5dd7070Spatrick   P.Actions.ActOnAtEnd(P.getCurScope(), AtEnd);
2319e5dd7070Spatrick 
2320e5dd7070Spatrick   if (HasCFunction)
2321e5dd7070Spatrick     for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
2322e5dd7070Spatrick       P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
2323e5dd7070Spatrick                                  false/*c-functions*/);
2324e5dd7070Spatrick 
2325e5dd7070Spatrick   /// Clear and free the cached objc methods.
2326e5dd7070Spatrick   for (LateParsedObjCMethodContainer::iterator
2327e5dd7070Spatrick          I = LateParsedObjCMethods.begin(),
2328e5dd7070Spatrick          E = LateParsedObjCMethods.end(); I != E; ++I)
2329e5dd7070Spatrick     delete *I;
2330e5dd7070Spatrick   LateParsedObjCMethods.clear();
2331e5dd7070Spatrick 
2332e5dd7070Spatrick   Finished = true;
2333e5dd7070Spatrick }
2334e5dd7070Spatrick 
2335e5dd7070Spatrick ///   compatibility-alias-decl:
2336e5dd7070Spatrick ///     @compatibility_alias alias-name  class-name ';'
2337e5dd7070Spatrick ///
ParseObjCAtAliasDeclaration(SourceLocation atLoc)2338e5dd7070Spatrick Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
2339e5dd7070Spatrick   assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
2340e5dd7070Spatrick          "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
2341e5dd7070Spatrick   ConsumeToken(); // consume compatibility_alias
2342e5dd7070Spatrick   if (expectIdentifier())
2343e5dd7070Spatrick     return nullptr;
2344e5dd7070Spatrick   IdentifierInfo *aliasId = Tok.getIdentifierInfo();
2345e5dd7070Spatrick   SourceLocation aliasLoc = ConsumeToken(); // consume alias-name
2346e5dd7070Spatrick   if (expectIdentifier())
2347e5dd7070Spatrick     return nullptr;
2348e5dd7070Spatrick   IdentifierInfo *classId = Tok.getIdentifierInfo();
2349e5dd7070Spatrick   SourceLocation classLoc = ConsumeToken(); // consume class-name;
2350e5dd7070Spatrick   ExpectAndConsume(tok::semi, diag::err_expected_after, "@compatibility_alias");
2351e5dd7070Spatrick   return Actions.ActOnCompatibilityAlias(atLoc, aliasId, aliasLoc,
2352e5dd7070Spatrick                                          classId, classLoc);
2353e5dd7070Spatrick }
2354e5dd7070Spatrick 
2355e5dd7070Spatrick ///   property-synthesis:
2356e5dd7070Spatrick ///     @synthesize property-ivar-list ';'
2357e5dd7070Spatrick ///
2358e5dd7070Spatrick ///   property-ivar-list:
2359e5dd7070Spatrick ///     property-ivar
2360e5dd7070Spatrick ///     property-ivar-list ',' property-ivar
2361e5dd7070Spatrick ///
2362e5dd7070Spatrick ///   property-ivar:
2363e5dd7070Spatrick ///     identifier
2364e5dd7070Spatrick ///     identifier '=' identifier
2365e5dd7070Spatrick ///
ParseObjCPropertySynthesize(SourceLocation atLoc)2366e5dd7070Spatrick Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
2367e5dd7070Spatrick   assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&
2368e5dd7070Spatrick          "ParseObjCPropertySynthesize(): Expected '@synthesize'");
2369e5dd7070Spatrick   ConsumeToken(); // consume synthesize
2370e5dd7070Spatrick 
2371e5dd7070Spatrick   while (true) {
2372e5dd7070Spatrick     if (Tok.is(tok::code_completion)) {
2373e5dd7070Spatrick       cutOffParsing();
2374a9ac8606Spatrick       Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
2375e5dd7070Spatrick       return nullptr;
2376e5dd7070Spatrick     }
2377e5dd7070Spatrick 
2378e5dd7070Spatrick     if (Tok.isNot(tok::identifier)) {
2379e5dd7070Spatrick       Diag(Tok, diag::err_synthesized_property_name);
2380e5dd7070Spatrick       SkipUntil(tok::semi);
2381e5dd7070Spatrick       return nullptr;
2382e5dd7070Spatrick     }
2383e5dd7070Spatrick 
2384e5dd7070Spatrick     IdentifierInfo *propertyIvar = nullptr;
2385e5dd7070Spatrick     IdentifierInfo *propertyId = Tok.getIdentifierInfo();
2386e5dd7070Spatrick     SourceLocation propertyLoc = ConsumeToken(); // consume property name
2387e5dd7070Spatrick     SourceLocation propertyIvarLoc;
2388e5dd7070Spatrick     if (TryConsumeToken(tok::equal)) {
2389e5dd7070Spatrick       // property '=' ivar-name
2390e5dd7070Spatrick       if (Tok.is(tok::code_completion)) {
2391e5dd7070Spatrick         cutOffParsing();
2392a9ac8606Spatrick         Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId);
2393e5dd7070Spatrick         return nullptr;
2394e5dd7070Spatrick       }
2395e5dd7070Spatrick 
2396e5dd7070Spatrick       if (expectIdentifier())
2397e5dd7070Spatrick         break;
2398e5dd7070Spatrick       propertyIvar = Tok.getIdentifierInfo();
2399e5dd7070Spatrick       propertyIvarLoc = ConsumeToken(); // consume ivar-name
2400e5dd7070Spatrick     }
2401e5dd7070Spatrick     Actions.ActOnPropertyImplDecl(
2402e5dd7070Spatrick         getCurScope(), atLoc, propertyLoc, true,
2403e5dd7070Spatrick         propertyId, propertyIvar, propertyIvarLoc,
2404e5dd7070Spatrick         ObjCPropertyQueryKind::OBJC_PR_query_unknown);
2405e5dd7070Spatrick     if (Tok.isNot(tok::comma))
2406e5dd7070Spatrick       break;
2407e5dd7070Spatrick     ConsumeToken(); // consume ','
2408e5dd7070Spatrick   }
2409e5dd7070Spatrick   ExpectAndConsume(tok::semi, diag::err_expected_after, "@synthesize");
2410e5dd7070Spatrick   return nullptr;
2411e5dd7070Spatrick }
2412e5dd7070Spatrick 
2413e5dd7070Spatrick ///   property-dynamic:
2414e5dd7070Spatrick ///     @dynamic  property-list
2415e5dd7070Spatrick ///
2416e5dd7070Spatrick ///   property-list:
2417e5dd7070Spatrick ///     identifier
2418e5dd7070Spatrick ///     property-list ',' identifier
2419e5dd7070Spatrick ///
ParseObjCPropertyDynamic(SourceLocation atLoc)2420e5dd7070Spatrick Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
2421e5dd7070Spatrick   assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&
2422e5dd7070Spatrick          "ParseObjCPropertyDynamic(): Expected '@dynamic'");
2423e5dd7070Spatrick   ConsumeToken(); // consume dynamic
2424e5dd7070Spatrick 
2425e5dd7070Spatrick   bool isClassProperty = false;
2426e5dd7070Spatrick   if (Tok.is(tok::l_paren)) {
2427e5dd7070Spatrick     ConsumeParen();
2428e5dd7070Spatrick     const IdentifierInfo *II = Tok.getIdentifierInfo();
2429e5dd7070Spatrick 
2430e5dd7070Spatrick     if (!II) {
2431e5dd7070Spatrick       Diag(Tok, diag::err_objc_expected_property_attr) << II;
2432e5dd7070Spatrick       SkipUntil(tok::r_paren, StopAtSemi);
2433e5dd7070Spatrick     } else {
2434e5dd7070Spatrick       SourceLocation AttrName = ConsumeToken(); // consume attribute name
2435e5dd7070Spatrick       if (II->isStr("class")) {
2436e5dd7070Spatrick         isClassProperty = true;
2437e5dd7070Spatrick         if (Tok.isNot(tok::r_paren)) {
2438e5dd7070Spatrick           Diag(Tok, diag::err_expected) << tok::r_paren;
2439e5dd7070Spatrick           SkipUntil(tok::r_paren, StopAtSemi);
2440e5dd7070Spatrick         } else
2441e5dd7070Spatrick           ConsumeParen();
2442e5dd7070Spatrick       } else {
2443e5dd7070Spatrick         Diag(AttrName, diag::err_objc_expected_property_attr) << II;
2444e5dd7070Spatrick         SkipUntil(tok::r_paren, StopAtSemi);
2445e5dd7070Spatrick       }
2446e5dd7070Spatrick     }
2447e5dd7070Spatrick   }
2448e5dd7070Spatrick 
2449e5dd7070Spatrick   while (true) {
2450e5dd7070Spatrick     if (Tok.is(tok::code_completion)) {
2451e5dd7070Spatrick       cutOffParsing();
2452a9ac8606Spatrick       Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
2453e5dd7070Spatrick       return nullptr;
2454e5dd7070Spatrick     }
2455e5dd7070Spatrick 
2456e5dd7070Spatrick     if (expectIdentifier()) {
2457e5dd7070Spatrick       SkipUntil(tok::semi);
2458e5dd7070Spatrick       return nullptr;
2459e5dd7070Spatrick     }
2460e5dd7070Spatrick 
2461e5dd7070Spatrick     IdentifierInfo *propertyId = Tok.getIdentifierInfo();
2462e5dd7070Spatrick     SourceLocation propertyLoc = ConsumeToken(); // consume property name
2463e5dd7070Spatrick     Actions.ActOnPropertyImplDecl(
2464e5dd7070Spatrick         getCurScope(), atLoc, propertyLoc, false,
2465e5dd7070Spatrick         propertyId, nullptr, SourceLocation(),
2466e5dd7070Spatrick         isClassProperty ? ObjCPropertyQueryKind::OBJC_PR_query_class :
2467e5dd7070Spatrick         ObjCPropertyQueryKind::OBJC_PR_query_unknown);
2468e5dd7070Spatrick 
2469e5dd7070Spatrick     if (Tok.isNot(tok::comma))
2470e5dd7070Spatrick       break;
2471e5dd7070Spatrick     ConsumeToken(); // consume ','
2472e5dd7070Spatrick   }
2473e5dd7070Spatrick   ExpectAndConsume(tok::semi, diag::err_expected_after, "@dynamic");
2474e5dd7070Spatrick   return nullptr;
2475e5dd7070Spatrick }
2476e5dd7070Spatrick 
2477e5dd7070Spatrick ///  objc-throw-statement:
2478e5dd7070Spatrick ///    throw expression[opt];
2479e5dd7070Spatrick ///
ParseObjCThrowStmt(SourceLocation atLoc)2480e5dd7070Spatrick StmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
2481e5dd7070Spatrick   ExprResult Res;
2482e5dd7070Spatrick   ConsumeToken(); // consume throw
2483e5dd7070Spatrick   if (Tok.isNot(tok::semi)) {
2484e5dd7070Spatrick     Res = ParseExpression();
2485e5dd7070Spatrick     if (Res.isInvalid()) {
2486e5dd7070Spatrick       SkipUntil(tok::semi);
2487e5dd7070Spatrick       return StmtError();
2488e5dd7070Spatrick     }
2489e5dd7070Spatrick   }
2490e5dd7070Spatrick   // consume ';'
2491e5dd7070Spatrick   ExpectAndConsume(tok::semi, diag::err_expected_after, "@throw");
2492e5dd7070Spatrick   return Actions.ActOnObjCAtThrowStmt(atLoc, Res.get(), getCurScope());
2493e5dd7070Spatrick }
2494e5dd7070Spatrick 
2495e5dd7070Spatrick /// objc-synchronized-statement:
2496e5dd7070Spatrick ///   @synchronized '(' expression ')' compound-statement
2497e5dd7070Spatrick ///
2498e5dd7070Spatrick StmtResult
ParseObjCSynchronizedStmt(SourceLocation atLoc)2499e5dd7070Spatrick Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
2500e5dd7070Spatrick   ConsumeToken(); // consume synchronized
2501e5dd7070Spatrick   if (Tok.isNot(tok::l_paren)) {
2502e5dd7070Spatrick     Diag(Tok, diag::err_expected_lparen_after) << "@synchronized";
2503e5dd7070Spatrick     return StmtError();
2504e5dd7070Spatrick   }
2505e5dd7070Spatrick 
2506e5dd7070Spatrick   // The operand is surrounded with parentheses.
2507e5dd7070Spatrick   ConsumeParen();  // '('
2508e5dd7070Spatrick   ExprResult operand(ParseExpression());
2509e5dd7070Spatrick 
2510e5dd7070Spatrick   if (Tok.is(tok::r_paren)) {
2511e5dd7070Spatrick     ConsumeParen();  // ')'
2512e5dd7070Spatrick   } else {
2513e5dd7070Spatrick     if (!operand.isInvalid())
2514e5dd7070Spatrick       Diag(Tok, diag::err_expected) << tok::r_paren;
2515e5dd7070Spatrick 
2516e5dd7070Spatrick     // Skip forward until we see a left brace, but don't consume it.
2517e5dd7070Spatrick     SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
2518e5dd7070Spatrick   }
2519e5dd7070Spatrick 
2520e5dd7070Spatrick   // Require a compound statement.
2521e5dd7070Spatrick   if (Tok.isNot(tok::l_brace)) {
2522e5dd7070Spatrick     if (!operand.isInvalid())
2523e5dd7070Spatrick       Diag(Tok, diag::err_expected) << tok::l_brace;
2524e5dd7070Spatrick     return StmtError();
2525e5dd7070Spatrick   }
2526e5dd7070Spatrick 
2527e5dd7070Spatrick   // Check the @synchronized operand now.
2528e5dd7070Spatrick   if (!operand.isInvalid())
2529e5dd7070Spatrick     operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.get());
2530e5dd7070Spatrick 
2531e5dd7070Spatrick   // Parse the compound statement within a new scope.
2532e5dd7070Spatrick   ParseScope bodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
2533e5dd7070Spatrick   StmtResult body(ParseCompoundStatementBody());
2534e5dd7070Spatrick   bodyScope.Exit();
2535e5dd7070Spatrick 
2536e5dd7070Spatrick   // If there was a semantic or parse error earlier with the
2537e5dd7070Spatrick   // operand, fail now.
2538e5dd7070Spatrick   if (operand.isInvalid())
2539e5dd7070Spatrick     return StmtError();
2540e5dd7070Spatrick 
2541e5dd7070Spatrick   if (body.isInvalid())
2542e5dd7070Spatrick     body = Actions.ActOnNullStmt(Tok.getLocation());
2543e5dd7070Spatrick 
2544e5dd7070Spatrick   return Actions.ActOnObjCAtSynchronizedStmt(atLoc, operand.get(), body.get());
2545e5dd7070Spatrick }
2546e5dd7070Spatrick 
2547e5dd7070Spatrick ///  objc-try-catch-statement:
2548e5dd7070Spatrick ///    @try compound-statement objc-catch-list[opt]
2549e5dd7070Spatrick ///    @try compound-statement objc-catch-list[opt] @finally compound-statement
2550e5dd7070Spatrick ///
2551e5dd7070Spatrick ///  objc-catch-list:
2552e5dd7070Spatrick ///    @catch ( parameter-declaration ) compound-statement
2553e5dd7070Spatrick ///    objc-catch-list @catch ( catch-parameter-declaration ) compound-statement
2554e5dd7070Spatrick ///  catch-parameter-declaration:
2555e5dd7070Spatrick ///     parameter-declaration
2556e5dd7070Spatrick ///     '...' [OBJC2]
2557e5dd7070Spatrick ///
ParseObjCTryStmt(SourceLocation atLoc)2558e5dd7070Spatrick StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
2559e5dd7070Spatrick   bool catch_or_finally_seen = false;
2560e5dd7070Spatrick 
2561e5dd7070Spatrick   ConsumeToken(); // consume try
2562e5dd7070Spatrick   if (Tok.isNot(tok::l_brace)) {
2563e5dd7070Spatrick     Diag(Tok, diag::err_expected) << tok::l_brace;
2564e5dd7070Spatrick     return StmtError();
2565e5dd7070Spatrick   }
2566e5dd7070Spatrick   StmtVector CatchStmts;
2567e5dd7070Spatrick   StmtResult FinallyStmt;
2568e5dd7070Spatrick   ParseScope TryScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
2569e5dd7070Spatrick   StmtResult TryBody(ParseCompoundStatementBody());
2570e5dd7070Spatrick   TryScope.Exit();
2571e5dd7070Spatrick   if (TryBody.isInvalid())
2572e5dd7070Spatrick     TryBody = Actions.ActOnNullStmt(Tok.getLocation());
2573e5dd7070Spatrick 
2574e5dd7070Spatrick   while (Tok.is(tok::at)) {
2575e5dd7070Spatrick     // At this point, we need to lookahead to determine if this @ is the start
2576e5dd7070Spatrick     // of an @catch or @finally.  We don't want to consume the @ token if this
2577e5dd7070Spatrick     // is an @try or @encode or something else.
2578e5dd7070Spatrick     Token AfterAt = GetLookAheadToken(1);
2579e5dd7070Spatrick     if (!AfterAt.isObjCAtKeyword(tok::objc_catch) &&
2580e5dd7070Spatrick         !AfterAt.isObjCAtKeyword(tok::objc_finally))
2581e5dd7070Spatrick       break;
2582e5dd7070Spatrick 
2583e5dd7070Spatrick     SourceLocation AtCatchFinallyLoc = ConsumeToken();
2584e5dd7070Spatrick     if (Tok.isObjCAtKeyword(tok::objc_catch)) {
2585e5dd7070Spatrick       Decl *FirstPart = nullptr;
2586e5dd7070Spatrick       ConsumeToken(); // consume catch
2587e5dd7070Spatrick       if (Tok.is(tok::l_paren)) {
2588e5dd7070Spatrick         ConsumeParen();
2589e5dd7070Spatrick         ParseScope CatchScope(this, Scope::DeclScope |
2590e5dd7070Spatrick                                         Scope::CompoundStmtScope |
2591e5dd7070Spatrick                                         Scope::AtCatchScope);
2592e5dd7070Spatrick         if (Tok.isNot(tok::ellipsis)) {
2593e5dd7070Spatrick           DeclSpec DS(AttrFactory);
2594e5dd7070Spatrick           ParseDeclarationSpecifiers(DS);
2595*12c85518Srobert           Declarator ParmDecl(DS, ParsedAttributesView::none(),
2596*12c85518Srobert                               DeclaratorContext::ObjCCatch);
2597e5dd7070Spatrick           ParseDeclarator(ParmDecl);
2598e5dd7070Spatrick 
2599e5dd7070Spatrick           // Inform the actions module about the declarator, so it
2600e5dd7070Spatrick           // gets added to the current scope.
2601e5dd7070Spatrick           FirstPart = Actions.ActOnObjCExceptionDecl(getCurScope(), ParmDecl);
2602e5dd7070Spatrick         } else
2603e5dd7070Spatrick           ConsumeToken(); // consume '...'
2604e5dd7070Spatrick 
2605e5dd7070Spatrick         SourceLocation RParenLoc;
2606e5dd7070Spatrick 
2607e5dd7070Spatrick         if (Tok.is(tok::r_paren))
2608e5dd7070Spatrick           RParenLoc = ConsumeParen();
2609e5dd7070Spatrick         else // Skip over garbage, until we get to ')'.  Eat the ')'.
2610e5dd7070Spatrick           SkipUntil(tok::r_paren, StopAtSemi);
2611e5dd7070Spatrick 
2612e5dd7070Spatrick         StmtResult CatchBody(true);
2613e5dd7070Spatrick         if (Tok.is(tok::l_brace))
2614e5dd7070Spatrick           CatchBody = ParseCompoundStatementBody();
2615e5dd7070Spatrick         else
2616e5dd7070Spatrick           Diag(Tok, diag::err_expected) << tok::l_brace;
2617e5dd7070Spatrick         if (CatchBody.isInvalid())
2618e5dd7070Spatrick           CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
2619e5dd7070Spatrick 
2620e5dd7070Spatrick         StmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
2621e5dd7070Spatrick                                                               RParenLoc,
2622e5dd7070Spatrick                                                               FirstPart,
2623e5dd7070Spatrick                                                               CatchBody.get());
2624e5dd7070Spatrick         if (!Catch.isInvalid())
2625e5dd7070Spatrick           CatchStmts.push_back(Catch.get());
2626e5dd7070Spatrick 
2627e5dd7070Spatrick       } else {
2628e5dd7070Spatrick         Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
2629e5dd7070Spatrick           << "@catch clause";
2630e5dd7070Spatrick         return StmtError();
2631e5dd7070Spatrick       }
2632e5dd7070Spatrick       catch_or_finally_seen = true;
2633e5dd7070Spatrick     } else {
2634e5dd7070Spatrick       assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");
2635e5dd7070Spatrick       ConsumeToken(); // consume finally
2636e5dd7070Spatrick       ParseScope FinallyScope(this,
2637e5dd7070Spatrick                               Scope::DeclScope | Scope::CompoundStmtScope);
2638e5dd7070Spatrick 
2639e5dd7070Spatrick       bool ShouldCapture =
2640e5dd7070Spatrick           getTargetInfo().getTriple().isWindowsMSVCEnvironment();
2641e5dd7070Spatrick       if (ShouldCapture)
2642e5dd7070Spatrick         Actions.ActOnCapturedRegionStart(Tok.getLocation(), getCurScope(),
2643e5dd7070Spatrick                                          CR_ObjCAtFinally, 1);
2644e5dd7070Spatrick 
2645e5dd7070Spatrick       StmtResult FinallyBody(true);
2646e5dd7070Spatrick       if (Tok.is(tok::l_brace))
2647e5dd7070Spatrick         FinallyBody = ParseCompoundStatementBody();
2648e5dd7070Spatrick       else
2649e5dd7070Spatrick         Diag(Tok, diag::err_expected) << tok::l_brace;
2650e5dd7070Spatrick 
2651e5dd7070Spatrick       if (FinallyBody.isInvalid()) {
2652e5dd7070Spatrick         FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
2653e5dd7070Spatrick         if (ShouldCapture)
2654e5dd7070Spatrick           Actions.ActOnCapturedRegionError();
2655e5dd7070Spatrick       } else if (ShouldCapture) {
2656e5dd7070Spatrick         FinallyBody = Actions.ActOnCapturedRegionEnd(FinallyBody.get());
2657e5dd7070Spatrick       }
2658e5dd7070Spatrick 
2659e5dd7070Spatrick       FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc,
2660e5dd7070Spatrick                                                    FinallyBody.get());
2661e5dd7070Spatrick       catch_or_finally_seen = true;
2662e5dd7070Spatrick       break;
2663e5dd7070Spatrick     }
2664e5dd7070Spatrick   }
2665e5dd7070Spatrick   if (!catch_or_finally_seen) {
2666e5dd7070Spatrick     Diag(atLoc, diag::err_missing_catch_finally);
2667e5dd7070Spatrick     return StmtError();
2668e5dd7070Spatrick   }
2669e5dd7070Spatrick 
2670e5dd7070Spatrick   return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.get(),
2671e5dd7070Spatrick                                     CatchStmts,
2672e5dd7070Spatrick                                     FinallyStmt.get());
2673e5dd7070Spatrick }
2674e5dd7070Spatrick 
2675e5dd7070Spatrick /// objc-autoreleasepool-statement:
2676e5dd7070Spatrick ///   @autoreleasepool compound-statement
2677e5dd7070Spatrick ///
2678e5dd7070Spatrick StmtResult
ParseObjCAutoreleasePoolStmt(SourceLocation atLoc)2679e5dd7070Spatrick Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
2680e5dd7070Spatrick   ConsumeToken(); // consume autoreleasepool
2681e5dd7070Spatrick   if (Tok.isNot(tok::l_brace)) {
2682e5dd7070Spatrick     Diag(Tok, diag::err_expected) << tok::l_brace;
2683e5dd7070Spatrick     return StmtError();
2684e5dd7070Spatrick   }
2685e5dd7070Spatrick   // Enter a scope to hold everything within the compound stmt.  Compound
2686e5dd7070Spatrick   // statements can always hold declarations.
2687e5dd7070Spatrick   ParseScope BodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
2688e5dd7070Spatrick 
2689e5dd7070Spatrick   StmtResult AutoreleasePoolBody(ParseCompoundStatementBody());
2690e5dd7070Spatrick 
2691e5dd7070Spatrick   BodyScope.Exit();
2692e5dd7070Spatrick   if (AutoreleasePoolBody.isInvalid())
2693e5dd7070Spatrick     AutoreleasePoolBody = Actions.ActOnNullStmt(Tok.getLocation());
2694e5dd7070Spatrick   return Actions.ActOnObjCAutoreleasePoolStmt(atLoc,
2695e5dd7070Spatrick                                                 AutoreleasePoolBody.get());
2696e5dd7070Spatrick }
2697e5dd7070Spatrick 
2698e5dd7070Spatrick /// StashAwayMethodOrFunctionBodyTokens -  Consume the tokens and store them
2699e5dd7070Spatrick /// for later parsing.
StashAwayMethodOrFunctionBodyTokens(Decl * MDecl)2700e5dd7070Spatrick void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) {
2701e5dd7070Spatrick   if (SkipFunctionBodies && (!MDecl || Actions.canSkipFunctionBody(MDecl)) &&
2702e5dd7070Spatrick       trySkippingFunctionBody()) {
2703e5dd7070Spatrick     Actions.ActOnSkippedFunctionBody(MDecl);
2704e5dd7070Spatrick     return;
2705e5dd7070Spatrick   }
2706e5dd7070Spatrick 
2707e5dd7070Spatrick   LexedMethod* LM = new LexedMethod(this, MDecl);
2708e5dd7070Spatrick   CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM);
2709e5dd7070Spatrick   CachedTokens &Toks = LM->Toks;
2710e5dd7070Spatrick   // Begin by storing the '{' or 'try' or ':' token.
2711e5dd7070Spatrick   Toks.push_back(Tok);
2712e5dd7070Spatrick   if (Tok.is(tok::kw_try)) {
2713e5dd7070Spatrick     ConsumeToken();
2714e5dd7070Spatrick     if (Tok.is(tok::colon)) {
2715e5dd7070Spatrick       Toks.push_back(Tok);
2716e5dd7070Spatrick       ConsumeToken();
2717e5dd7070Spatrick       while (Tok.isNot(tok::l_brace)) {
2718e5dd7070Spatrick         ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);
2719e5dd7070Spatrick         ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
2720e5dd7070Spatrick       }
2721e5dd7070Spatrick     }
2722e5dd7070Spatrick     Toks.push_back(Tok); // also store '{'
2723e5dd7070Spatrick   }
2724e5dd7070Spatrick   else if (Tok.is(tok::colon)) {
2725e5dd7070Spatrick     ConsumeToken();
2726e5dd7070Spatrick     // FIXME: This is wrong, due to C++11 braced initialization.
2727e5dd7070Spatrick     while (Tok.isNot(tok::l_brace)) {
2728e5dd7070Spatrick       ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);
2729e5dd7070Spatrick       ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
2730e5dd7070Spatrick     }
2731e5dd7070Spatrick     Toks.push_back(Tok); // also store '{'
2732e5dd7070Spatrick   }
2733e5dd7070Spatrick   ConsumeBrace();
2734e5dd7070Spatrick   // Consume everything up to (and including) the matching right brace.
2735e5dd7070Spatrick   ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
2736e5dd7070Spatrick   while (Tok.is(tok::kw_catch)) {
2737e5dd7070Spatrick     ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false);
2738e5dd7070Spatrick     ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
2739e5dd7070Spatrick   }
2740e5dd7070Spatrick }
2741e5dd7070Spatrick 
2742e5dd7070Spatrick ///   objc-method-def: objc-method-proto ';'[opt] '{' body '}'
2743e5dd7070Spatrick ///
ParseObjCMethodDefinition()2744e5dd7070Spatrick Decl *Parser::ParseObjCMethodDefinition() {
2745e5dd7070Spatrick   Decl *MDecl = ParseObjCMethodPrototype();
2746e5dd7070Spatrick 
2747e5dd7070Spatrick   PrettyDeclStackTraceEntry CrashInfo(Actions.Context, MDecl, Tok.getLocation(),
2748e5dd7070Spatrick                                       "parsing Objective-C method");
2749e5dd7070Spatrick 
2750e5dd7070Spatrick   // parse optional ';'
2751e5dd7070Spatrick   if (Tok.is(tok::semi)) {
2752e5dd7070Spatrick     if (CurParsedObjCImpl) {
2753e5dd7070Spatrick       Diag(Tok, diag::warn_semicolon_before_method_body)
2754e5dd7070Spatrick         << FixItHint::CreateRemoval(Tok.getLocation());
2755e5dd7070Spatrick     }
2756e5dd7070Spatrick     ConsumeToken();
2757e5dd7070Spatrick   }
2758e5dd7070Spatrick 
2759e5dd7070Spatrick   // We should have an opening brace now.
2760e5dd7070Spatrick   if (Tok.isNot(tok::l_brace)) {
2761e5dd7070Spatrick     Diag(Tok, diag::err_expected_method_body);
2762e5dd7070Spatrick 
2763e5dd7070Spatrick     // Skip over garbage, until we get to '{'.  Don't eat the '{'.
2764e5dd7070Spatrick     SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
2765e5dd7070Spatrick 
2766e5dd7070Spatrick     // If we didn't find the '{', bail out.
2767e5dd7070Spatrick     if (Tok.isNot(tok::l_brace))
2768e5dd7070Spatrick       return nullptr;
2769e5dd7070Spatrick   }
2770e5dd7070Spatrick 
2771e5dd7070Spatrick   if (!MDecl) {
2772e5dd7070Spatrick     ConsumeBrace();
2773e5dd7070Spatrick     SkipUntil(tok::r_brace);
2774e5dd7070Spatrick     return nullptr;
2775e5dd7070Spatrick   }
2776e5dd7070Spatrick 
2777e5dd7070Spatrick   // Allow the rest of sema to find private method decl implementations.
2778e5dd7070Spatrick   Actions.AddAnyMethodToGlobalPool(MDecl);
2779e5dd7070Spatrick   assert (CurParsedObjCImpl
2780e5dd7070Spatrick           && "ParseObjCMethodDefinition - Method out of @implementation");
2781e5dd7070Spatrick   // Consume the tokens and store them for later parsing.
2782e5dd7070Spatrick   StashAwayMethodOrFunctionBodyTokens(MDecl);
2783e5dd7070Spatrick   return MDecl;
2784e5dd7070Spatrick }
2785e5dd7070Spatrick 
ParseObjCAtStatement(SourceLocation AtLoc,ParsedStmtContext StmtCtx)2786e5dd7070Spatrick StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc,
2787e5dd7070Spatrick                                         ParsedStmtContext StmtCtx) {
2788e5dd7070Spatrick   if (Tok.is(tok::code_completion)) {
2789e5dd7070Spatrick     cutOffParsing();
2790a9ac8606Spatrick     Actions.CodeCompleteObjCAtStatement(getCurScope());
2791e5dd7070Spatrick     return StmtError();
2792e5dd7070Spatrick   }
2793e5dd7070Spatrick 
2794e5dd7070Spatrick   if (Tok.isObjCAtKeyword(tok::objc_try))
2795e5dd7070Spatrick     return ParseObjCTryStmt(AtLoc);
2796e5dd7070Spatrick 
2797e5dd7070Spatrick   if (Tok.isObjCAtKeyword(tok::objc_throw))
2798e5dd7070Spatrick     return ParseObjCThrowStmt(AtLoc);
2799e5dd7070Spatrick 
2800e5dd7070Spatrick   if (Tok.isObjCAtKeyword(tok::objc_synchronized))
2801e5dd7070Spatrick     return ParseObjCSynchronizedStmt(AtLoc);
2802e5dd7070Spatrick 
2803e5dd7070Spatrick   if (Tok.isObjCAtKeyword(tok::objc_autoreleasepool))
2804e5dd7070Spatrick     return ParseObjCAutoreleasePoolStmt(AtLoc);
2805e5dd7070Spatrick 
2806e5dd7070Spatrick   if (Tok.isObjCAtKeyword(tok::objc_import) &&
2807e5dd7070Spatrick       getLangOpts().DebuggerSupport) {
2808e5dd7070Spatrick     SkipUntil(tok::semi);
2809e5dd7070Spatrick     return Actions.ActOnNullStmt(Tok.getLocation());
2810e5dd7070Spatrick   }
2811e5dd7070Spatrick 
2812e5dd7070Spatrick   ExprStatementTokLoc = AtLoc;
2813e5dd7070Spatrick   ExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
2814e5dd7070Spatrick   if (Res.isInvalid()) {
2815e5dd7070Spatrick     // If the expression is invalid, skip ahead to the next semicolon. Not
2816e5dd7070Spatrick     // doing this opens us up to the possibility of infinite loops if
2817e5dd7070Spatrick     // ParseExpression does not consume any tokens.
2818e5dd7070Spatrick     SkipUntil(tok::semi);
2819e5dd7070Spatrick     return StmtError();
2820e5dd7070Spatrick   }
2821e5dd7070Spatrick 
2822e5dd7070Spatrick   // Otherwise, eat the semicolon.
2823e5dd7070Spatrick   ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
2824e5dd7070Spatrick   return handleExprStmt(Res, StmtCtx);
2825e5dd7070Spatrick }
2826e5dd7070Spatrick 
ParseObjCAtExpression(SourceLocation AtLoc)2827e5dd7070Spatrick ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
2828e5dd7070Spatrick   switch (Tok.getKind()) {
2829e5dd7070Spatrick   case tok::code_completion:
2830e5dd7070Spatrick     cutOffParsing();
2831a9ac8606Spatrick     Actions.CodeCompleteObjCAtExpression(getCurScope());
2832e5dd7070Spatrick     return ExprError();
2833e5dd7070Spatrick 
2834e5dd7070Spatrick   case tok::minus:
2835e5dd7070Spatrick   case tok::plus: {
2836e5dd7070Spatrick     tok::TokenKind Kind = Tok.getKind();
2837e5dd7070Spatrick     SourceLocation OpLoc = ConsumeToken();
2838e5dd7070Spatrick 
2839e5dd7070Spatrick     if (!Tok.is(tok::numeric_constant)) {
2840e5dd7070Spatrick       const char *Symbol = nullptr;
2841e5dd7070Spatrick       switch (Kind) {
2842e5dd7070Spatrick       case tok::minus: Symbol = "-"; break;
2843e5dd7070Spatrick       case tok::plus: Symbol = "+"; break;
2844e5dd7070Spatrick       default: llvm_unreachable("missing unary operator case");
2845e5dd7070Spatrick       }
2846e5dd7070Spatrick       Diag(Tok, diag::err_nsnumber_nonliteral_unary)
2847e5dd7070Spatrick         << Symbol;
2848e5dd7070Spatrick       return ExprError();
2849e5dd7070Spatrick     }
2850e5dd7070Spatrick 
2851e5dd7070Spatrick     ExprResult Lit(Actions.ActOnNumericConstant(Tok));
2852e5dd7070Spatrick     if (Lit.isInvalid()) {
2853e5dd7070Spatrick       return Lit;
2854e5dd7070Spatrick     }
2855e5dd7070Spatrick     ConsumeToken(); // Consume the literal token.
2856e5dd7070Spatrick 
2857e5dd7070Spatrick     Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.get());
2858e5dd7070Spatrick     if (Lit.isInvalid())
2859e5dd7070Spatrick       return Lit;
2860e5dd7070Spatrick 
2861e5dd7070Spatrick     return ParsePostfixExpressionSuffix(
2862e5dd7070Spatrick              Actions.BuildObjCNumericLiteral(AtLoc, Lit.get()));
2863e5dd7070Spatrick   }
2864e5dd7070Spatrick 
2865e5dd7070Spatrick   case tok::string_literal:    // primary-expression: string-literal
2866e5dd7070Spatrick   case tok::wide_string_literal:
2867e5dd7070Spatrick     return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
2868e5dd7070Spatrick 
2869e5dd7070Spatrick   case tok::char_constant:
2870e5dd7070Spatrick     return ParsePostfixExpressionSuffix(ParseObjCCharacterLiteral(AtLoc));
2871e5dd7070Spatrick 
2872e5dd7070Spatrick   case tok::numeric_constant:
2873e5dd7070Spatrick     return ParsePostfixExpressionSuffix(ParseObjCNumericLiteral(AtLoc));
2874e5dd7070Spatrick 
2875e5dd7070Spatrick   case tok::kw_true:  // Objective-C++, etc.
2876e5dd7070Spatrick   case tok::kw___objc_yes: // c/c++/objc/objc++ __objc_yes
2877e5dd7070Spatrick     return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, true));
2878e5dd7070Spatrick   case tok::kw_false: // Objective-C++, etc.
2879e5dd7070Spatrick   case tok::kw___objc_no: // c/c++/objc/objc++ __objc_no
2880e5dd7070Spatrick     return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, false));
2881e5dd7070Spatrick 
2882e5dd7070Spatrick   case tok::l_square:
2883e5dd7070Spatrick     // Objective-C array literal
2884e5dd7070Spatrick     return ParsePostfixExpressionSuffix(ParseObjCArrayLiteral(AtLoc));
2885e5dd7070Spatrick 
2886e5dd7070Spatrick   case tok::l_brace:
2887e5dd7070Spatrick     // Objective-C dictionary literal
2888e5dd7070Spatrick     return ParsePostfixExpressionSuffix(ParseObjCDictionaryLiteral(AtLoc));
2889e5dd7070Spatrick 
2890e5dd7070Spatrick   case tok::l_paren:
2891e5dd7070Spatrick     // Objective-C boxed expression
2892e5dd7070Spatrick     return ParsePostfixExpressionSuffix(ParseObjCBoxedExpr(AtLoc));
2893e5dd7070Spatrick 
2894e5dd7070Spatrick   default:
2895e5dd7070Spatrick     if (Tok.getIdentifierInfo() == nullptr)
2896e5dd7070Spatrick       return ExprError(Diag(AtLoc, diag::err_unexpected_at));
2897e5dd7070Spatrick 
2898e5dd7070Spatrick     switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
2899e5dd7070Spatrick     case tok::objc_encode:
2900e5dd7070Spatrick       return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc));
2901e5dd7070Spatrick     case tok::objc_protocol:
2902e5dd7070Spatrick       return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc));
2903e5dd7070Spatrick     case tok::objc_selector:
2904e5dd7070Spatrick       return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));
2905e5dd7070Spatrick     case tok::objc_available:
2906e5dd7070Spatrick       return ParseAvailabilityCheckExpr(AtLoc);
2907e5dd7070Spatrick       default: {
2908e5dd7070Spatrick         const char *str = nullptr;
2909e5dd7070Spatrick         // Only provide the @try/@finally/@autoreleasepool fixit when we're sure
2910e5dd7070Spatrick         // that this is a proper statement where such directives could actually
2911e5dd7070Spatrick         // occur.
2912e5dd7070Spatrick         if (GetLookAheadToken(1).is(tok::l_brace) &&
2913e5dd7070Spatrick             ExprStatementTokLoc == AtLoc) {
2914e5dd7070Spatrick           char ch = Tok.getIdentifierInfo()->getNameStart()[0];
2915e5dd7070Spatrick           str =
2916e5dd7070Spatrick             ch == 't' ? "try"
2917e5dd7070Spatrick                       : (ch == 'f' ? "finally"
2918e5dd7070Spatrick                                    : (ch == 'a' ? "autoreleasepool" : nullptr));
2919e5dd7070Spatrick         }
2920e5dd7070Spatrick         if (str) {
2921e5dd7070Spatrick           SourceLocation kwLoc = Tok.getLocation();
2922e5dd7070Spatrick           return ExprError(Diag(AtLoc, diag::err_unexpected_at) <<
2923e5dd7070Spatrick                              FixItHint::CreateReplacement(kwLoc, str));
2924e5dd7070Spatrick         }
2925e5dd7070Spatrick         else
2926e5dd7070Spatrick           return ExprError(Diag(AtLoc, diag::err_unexpected_at));
2927e5dd7070Spatrick       }
2928e5dd7070Spatrick     }
2929e5dd7070Spatrick   }
2930e5dd7070Spatrick }
2931e5dd7070Spatrick 
2932e5dd7070Spatrick /// Parse the receiver of an Objective-C++ message send.
2933e5dd7070Spatrick ///
2934e5dd7070Spatrick /// This routine parses the receiver of a message send in
2935e5dd7070Spatrick /// Objective-C++ either as a type or as an expression. Note that this
2936e5dd7070Spatrick /// routine must not be called to parse a send to 'super', since it
2937e5dd7070Spatrick /// has no way to return such a result.
2938e5dd7070Spatrick ///
2939e5dd7070Spatrick /// \param IsExpr Whether the receiver was parsed as an expression.
2940e5dd7070Spatrick ///
2941e5dd7070Spatrick /// \param TypeOrExpr If the receiver was parsed as an expression (\c
2942e5dd7070Spatrick /// IsExpr is true), the parsed expression. If the receiver was parsed
2943e5dd7070Spatrick /// as a type (\c IsExpr is false), the parsed type.
2944e5dd7070Spatrick ///
2945e5dd7070Spatrick /// \returns True if an error occurred during parsing or semantic
2946e5dd7070Spatrick /// analysis, in which case the arguments do not have valid
2947e5dd7070Spatrick /// values. Otherwise, returns false for a successful parse.
2948e5dd7070Spatrick ///
2949e5dd7070Spatrick ///   objc-receiver: [C++]
2950e5dd7070Spatrick ///     'super' [not parsed here]
2951e5dd7070Spatrick ///     expression
2952e5dd7070Spatrick ///     simple-type-specifier
2953e5dd7070Spatrick ///     typename-specifier
ParseObjCXXMessageReceiver(bool & IsExpr,void * & TypeOrExpr)2954e5dd7070Spatrick bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
2955e5dd7070Spatrick   InMessageExpressionRAIIObject InMessage(*this, true);
2956e5dd7070Spatrick 
2957e5dd7070Spatrick   if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_typename,
2958e5dd7070Spatrick                   tok::annot_cxxscope))
2959e5dd7070Spatrick     TryAnnotateTypeOrScopeToken();
2960e5dd7070Spatrick 
2961e5dd7070Spatrick   if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) {
2962e5dd7070Spatrick     //   objc-receiver:
2963e5dd7070Spatrick     //     expression
2964e5dd7070Spatrick     // Make sure any typos in the receiver are corrected or diagnosed, so that
2965e5dd7070Spatrick     // proper recovery can happen. FIXME: Perhaps filter the corrected expr to
2966e5dd7070Spatrick     // only the things that are valid ObjC receivers?
2967e5dd7070Spatrick     ExprResult Receiver = Actions.CorrectDelayedTyposInExpr(ParseExpression());
2968e5dd7070Spatrick     if (Receiver.isInvalid())
2969e5dd7070Spatrick       return true;
2970e5dd7070Spatrick 
2971e5dd7070Spatrick     IsExpr = true;
2972e5dd7070Spatrick     TypeOrExpr = Receiver.get();
2973e5dd7070Spatrick     return false;
2974e5dd7070Spatrick   }
2975e5dd7070Spatrick 
2976e5dd7070Spatrick   // objc-receiver:
2977e5dd7070Spatrick   //   typename-specifier
2978e5dd7070Spatrick   //   simple-type-specifier
2979e5dd7070Spatrick   //   expression (that starts with one of the above)
2980e5dd7070Spatrick   DeclSpec DS(AttrFactory);
2981e5dd7070Spatrick   ParseCXXSimpleTypeSpecifier(DS);
2982e5dd7070Spatrick 
2983e5dd7070Spatrick   if (Tok.is(tok::l_paren)) {
2984e5dd7070Spatrick     // If we see an opening parentheses at this point, we are
2985e5dd7070Spatrick     // actually parsing an expression that starts with a
2986e5dd7070Spatrick     // function-style cast, e.g.,
2987e5dd7070Spatrick     //
2988e5dd7070Spatrick     //   postfix-expression:
2989e5dd7070Spatrick     //     simple-type-specifier ( expression-list [opt] )
2990e5dd7070Spatrick     //     typename-specifier ( expression-list [opt] )
2991e5dd7070Spatrick     //
2992e5dd7070Spatrick     // Parse the remainder of this case, then the (optional)
2993e5dd7070Spatrick     // postfix-expression suffix, followed by the (optional)
2994e5dd7070Spatrick     // right-hand side of the binary expression. We have an
2995e5dd7070Spatrick     // instance method.
2996e5dd7070Spatrick     ExprResult Receiver = ParseCXXTypeConstructExpression(DS);
2997e5dd7070Spatrick     if (!Receiver.isInvalid())
2998e5dd7070Spatrick       Receiver = ParsePostfixExpressionSuffix(Receiver.get());
2999e5dd7070Spatrick     if (!Receiver.isInvalid())
3000e5dd7070Spatrick       Receiver = ParseRHSOfBinaryExpression(Receiver.get(), prec::Comma);
3001e5dd7070Spatrick     if (Receiver.isInvalid())
3002e5dd7070Spatrick       return true;
3003e5dd7070Spatrick 
3004e5dd7070Spatrick     IsExpr = true;
3005e5dd7070Spatrick     TypeOrExpr = Receiver.get();
3006e5dd7070Spatrick     return false;
3007e5dd7070Spatrick   }
3008e5dd7070Spatrick 
3009e5dd7070Spatrick   // We have a class message. Turn the simple-type-specifier or
3010e5dd7070Spatrick   // typename-specifier we parsed into a type and parse the
3011e5dd7070Spatrick   // remainder of the class message.
3012*12c85518Srobert   Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
3013*12c85518Srobert                             DeclaratorContext::TypeName);
3014e5dd7070Spatrick   TypeResult Type = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
3015e5dd7070Spatrick   if (Type.isInvalid())
3016e5dd7070Spatrick     return true;
3017e5dd7070Spatrick 
3018e5dd7070Spatrick   IsExpr = false;
3019e5dd7070Spatrick   TypeOrExpr = Type.get().getAsOpaquePtr();
3020e5dd7070Spatrick   return false;
3021e5dd7070Spatrick }
3022e5dd7070Spatrick 
3023e5dd7070Spatrick /// Determine whether the parser is currently referring to a an
3024e5dd7070Spatrick /// Objective-C message send, using a simplified heuristic to avoid overhead.
3025e5dd7070Spatrick ///
3026e5dd7070Spatrick /// This routine will only return true for a subset of valid message-send
3027e5dd7070Spatrick /// expressions.
isSimpleObjCMessageExpression()3028e5dd7070Spatrick bool Parser::isSimpleObjCMessageExpression() {
3029e5dd7070Spatrick   assert(Tok.is(tok::l_square) && getLangOpts().ObjC &&
3030e5dd7070Spatrick          "Incorrect start for isSimpleObjCMessageExpression");
3031e5dd7070Spatrick   return GetLookAheadToken(1).is(tok::identifier) &&
3032e5dd7070Spatrick          GetLookAheadToken(2).is(tok::identifier);
3033e5dd7070Spatrick }
3034e5dd7070Spatrick 
isStartOfObjCClassMessageMissingOpenBracket()3035e5dd7070Spatrick bool Parser::isStartOfObjCClassMessageMissingOpenBracket() {
3036e5dd7070Spatrick   if (!getLangOpts().ObjC || !NextToken().is(tok::identifier) ||
3037e5dd7070Spatrick       InMessageExpression)
3038e5dd7070Spatrick     return false;
3039e5dd7070Spatrick 
3040ec727ea7Spatrick   TypeResult Type;
3041e5dd7070Spatrick 
3042e5dd7070Spatrick   if (Tok.is(tok::annot_typename))
3043e5dd7070Spatrick     Type = getTypeAnnotation(Tok);
3044e5dd7070Spatrick   else if (Tok.is(tok::identifier))
3045e5dd7070Spatrick     Type = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(),
3046e5dd7070Spatrick                                getCurScope());
3047e5dd7070Spatrick   else
3048e5dd7070Spatrick     return false;
3049e5dd7070Spatrick 
3050ec727ea7Spatrick   // FIXME: Should not be querying properties of types from the parser.
3051ec727ea7Spatrick   if (Type.isUsable() && Type.get().get()->isObjCObjectOrInterfaceType()) {
3052e5dd7070Spatrick     const Token &AfterNext = GetLookAheadToken(2);
3053e5dd7070Spatrick     if (AfterNext.isOneOf(tok::colon, tok::r_square)) {
3054e5dd7070Spatrick       if (Tok.is(tok::identifier))
3055e5dd7070Spatrick         TryAnnotateTypeOrScopeToken();
3056e5dd7070Spatrick 
3057e5dd7070Spatrick       return Tok.is(tok::annot_typename);
3058e5dd7070Spatrick     }
3059e5dd7070Spatrick   }
3060e5dd7070Spatrick 
3061e5dd7070Spatrick   return false;
3062e5dd7070Spatrick }
3063e5dd7070Spatrick 
3064e5dd7070Spatrick ///   objc-message-expr:
3065e5dd7070Spatrick ///     '[' objc-receiver objc-message-args ']'
3066e5dd7070Spatrick ///
3067e5dd7070Spatrick ///   objc-receiver: [C]
3068e5dd7070Spatrick ///     'super'
3069e5dd7070Spatrick ///     expression
3070e5dd7070Spatrick ///     class-name
3071e5dd7070Spatrick ///     type-name
3072e5dd7070Spatrick ///
ParseObjCMessageExpression()3073e5dd7070Spatrick ExprResult Parser::ParseObjCMessageExpression() {
3074e5dd7070Spatrick   assert(Tok.is(tok::l_square) && "'[' expected");
3075e5dd7070Spatrick   SourceLocation LBracLoc = ConsumeBracket(); // consume '['
3076e5dd7070Spatrick 
3077e5dd7070Spatrick   if (Tok.is(tok::code_completion)) {
3078e5dd7070Spatrick     cutOffParsing();
3079a9ac8606Spatrick     Actions.CodeCompleteObjCMessageReceiver(getCurScope());
3080e5dd7070Spatrick     return ExprError();
3081e5dd7070Spatrick   }
3082e5dd7070Spatrick 
3083e5dd7070Spatrick   InMessageExpressionRAIIObject InMessage(*this, true);
3084e5dd7070Spatrick 
3085e5dd7070Spatrick   if (getLangOpts().CPlusPlus) {
3086e5dd7070Spatrick     // We completely separate the C and C++ cases because C++ requires
3087e5dd7070Spatrick     // more complicated (read: slower) parsing.
3088e5dd7070Spatrick 
3089e5dd7070Spatrick     // Handle send to super.
3090e5dd7070Spatrick     // FIXME: This doesn't benefit from the same typo-correction we
3091e5dd7070Spatrick     // get in Objective-C.
3092e5dd7070Spatrick     if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
3093e5dd7070Spatrick         NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope())
3094e5dd7070Spatrick       return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr,
3095e5dd7070Spatrick                                             nullptr);
3096e5dd7070Spatrick 
3097e5dd7070Spatrick     // Parse the receiver, which is either a type or an expression.
3098e5dd7070Spatrick     bool IsExpr;
3099e5dd7070Spatrick     void *TypeOrExpr = nullptr;
3100e5dd7070Spatrick     if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
3101e5dd7070Spatrick       SkipUntil(tok::r_square, StopAtSemi);
3102e5dd7070Spatrick       return ExprError();
3103e5dd7070Spatrick     }
3104e5dd7070Spatrick 
3105e5dd7070Spatrick     if (IsExpr)
3106e5dd7070Spatrick       return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr,
3107e5dd7070Spatrick                                             static_cast<Expr *>(TypeOrExpr));
3108e5dd7070Spatrick 
3109e5dd7070Spatrick     return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
3110e5dd7070Spatrick                               ParsedType::getFromOpaquePtr(TypeOrExpr),
3111e5dd7070Spatrick                                           nullptr);
3112e5dd7070Spatrick   }
3113e5dd7070Spatrick 
3114e5dd7070Spatrick   if (Tok.is(tok::identifier)) {
3115e5dd7070Spatrick     IdentifierInfo *Name = Tok.getIdentifierInfo();
3116e5dd7070Spatrick     SourceLocation NameLoc = Tok.getLocation();
3117e5dd7070Spatrick     ParsedType ReceiverType;
3118e5dd7070Spatrick     switch (Actions.getObjCMessageKind(getCurScope(), Name, NameLoc,
3119e5dd7070Spatrick                                        Name == Ident_super,
3120e5dd7070Spatrick                                        NextToken().is(tok::period),
3121e5dd7070Spatrick                                        ReceiverType)) {
3122e5dd7070Spatrick     case Sema::ObjCSuperMessage:
3123e5dd7070Spatrick       return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr,
3124e5dd7070Spatrick                                             nullptr);
3125e5dd7070Spatrick 
3126e5dd7070Spatrick     case Sema::ObjCClassMessage:
3127e5dd7070Spatrick       if (!ReceiverType) {
3128e5dd7070Spatrick         SkipUntil(tok::r_square, StopAtSemi);
3129e5dd7070Spatrick         return ExprError();
3130e5dd7070Spatrick       }
3131e5dd7070Spatrick 
3132e5dd7070Spatrick       ConsumeToken(); // the type name
3133e5dd7070Spatrick 
3134e5dd7070Spatrick       // Parse type arguments and protocol qualifiers.
3135e5dd7070Spatrick       if (Tok.is(tok::less)) {
3136e5dd7070Spatrick         SourceLocation NewEndLoc;
3137e5dd7070Spatrick         TypeResult NewReceiverType
3138e5dd7070Spatrick           = parseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType,
3139e5dd7070Spatrick                                                    /*consumeLastToken=*/true,
3140e5dd7070Spatrick                                                    NewEndLoc);
3141e5dd7070Spatrick         if (!NewReceiverType.isUsable()) {
3142e5dd7070Spatrick           SkipUntil(tok::r_square, StopAtSemi);
3143e5dd7070Spatrick           return ExprError();
3144e5dd7070Spatrick         }
3145e5dd7070Spatrick 
3146e5dd7070Spatrick         ReceiverType = NewReceiverType.get();
3147e5dd7070Spatrick       }
3148e5dd7070Spatrick 
3149e5dd7070Spatrick       return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
3150e5dd7070Spatrick                                             ReceiverType, nullptr);
3151e5dd7070Spatrick 
3152e5dd7070Spatrick     case Sema::ObjCInstanceMessage:
3153e5dd7070Spatrick       // Fall through to parse an expression.
3154e5dd7070Spatrick       break;
3155e5dd7070Spatrick     }
3156e5dd7070Spatrick   }
3157e5dd7070Spatrick 
3158e5dd7070Spatrick   // Otherwise, an arbitrary expression can be the receiver of a send.
3159e5dd7070Spatrick   ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
3160e5dd7070Spatrick   if (Res.isInvalid()) {
3161e5dd7070Spatrick     SkipUntil(tok::r_square, StopAtSemi);
3162e5dd7070Spatrick     return Res;
3163e5dd7070Spatrick   }
3164e5dd7070Spatrick 
3165e5dd7070Spatrick   return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr,
3166e5dd7070Spatrick                                         Res.get());
3167e5dd7070Spatrick }
3168e5dd7070Spatrick 
3169e5dd7070Spatrick /// Parse the remainder of an Objective-C message following the
3170e5dd7070Spatrick /// '[' objc-receiver.
3171e5dd7070Spatrick ///
3172e5dd7070Spatrick /// This routine handles sends to super, class messages (sent to a
3173e5dd7070Spatrick /// class name), and instance messages (sent to an object), and the
3174e5dd7070Spatrick /// target is represented by \p SuperLoc, \p ReceiverType, or \p
3175e5dd7070Spatrick /// ReceiverExpr, respectively. Only one of these parameters may have
3176e5dd7070Spatrick /// a valid value.
3177e5dd7070Spatrick ///
3178e5dd7070Spatrick /// \param LBracLoc The location of the opening '['.
3179e5dd7070Spatrick ///
3180e5dd7070Spatrick /// \param SuperLoc If this is a send to 'super', the location of the
3181e5dd7070Spatrick /// 'super' keyword that indicates a send to the superclass.
3182e5dd7070Spatrick ///
3183e5dd7070Spatrick /// \param ReceiverType If this is a class message, the type of the
3184e5dd7070Spatrick /// class we are sending a message to.
3185e5dd7070Spatrick ///
3186e5dd7070Spatrick /// \param ReceiverExpr If this is an instance message, the expression
3187e5dd7070Spatrick /// used to compute the receiver object.
3188e5dd7070Spatrick ///
3189e5dd7070Spatrick ///   objc-message-args:
3190e5dd7070Spatrick ///     objc-selector
3191e5dd7070Spatrick ///     objc-keywordarg-list
3192e5dd7070Spatrick ///
3193e5dd7070Spatrick ///   objc-keywordarg-list:
3194e5dd7070Spatrick ///     objc-keywordarg
3195e5dd7070Spatrick ///     objc-keywordarg-list objc-keywordarg
3196e5dd7070Spatrick ///
3197e5dd7070Spatrick ///   objc-keywordarg:
3198e5dd7070Spatrick ///     selector-name[opt] ':' objc-keywordexpr
3199e5dd7070Spatrick ///
3200e5dd7070Spatrick ///   objc-keywordexpr:
3201e5dd7070Spatrick ///     nonempty-expr-list
3202e5dd7070Spatrick ///
3203e5dd7070Spatrick ///   nonempty-expr-list:
3204e5dd7070Spatrick ///     assignment-expression
3205e5dd7070Spatrick ///     nonempty-expr-list , assignment-expression
3206e5dd7070Spatrick ///
3207e5dd7070Spatrick ExprResult
ParseObjCMessageExpressionBody(SourceLocation LBracLoc,SourceLocation SuperLoc,ParsedType ReceiverType,Expr * ReceiverExpr)3208e5dd7070Spatrick Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
3209e5dd7070Spatrick                                        SourceLocation SuperLoc,
3210e5dd7070Spatrick                                        ParsedType ReceiverType,
3211e5dd7070Spatrick                                        Expr *ReceiverExpr) {
3212e5dd7070Spatrick   InMessageExpressionRAIIObject InMessage(*this, true);
3213e5dd7070Spatrick 
3214e5dd7070Spatrick   if (Tok.is(tok::code_completion)) {
3215a9ac8606Spatrick     cutOffParsing();
3216e5dd7070Spatrick     if (SuperLoc.isValid())
3217*12c85518Srobert       Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
3218*12c85518Srobert                                            std::nullopt, false);
3219e5dd7070Spatrick     else if (ReceiverType)
3220*12c85518Srobert       Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
3221*12c85518Srobert                                            std::nullopt, false);
3222e5dd7070Spatrick     else
3223e5dd7070Spatrick       Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
3224*12c85518Srobert                                               std::nullopt, false);
3225e5dd7070Spatrick     return ExprError();
3226e5dd7070Spatrick   }
3227e5dd7070Spatrick 
3228e5dd7070Spatrick   // Parse objc-selector
3229e5dd7070Spatrick   SourceLocation Loc;
3230e5dd7070Spatrick   IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
3231e5dd7070Spatrick 
3232e5dd7070Spatrick   SmallVector<IdentifierInfo *, 12> KeyIdents;
3233e5dd7070Spatrick   SmallVector<SourceLocation, 12> KeyLocs;
3234e5dd7070Spatrick   ExprVector KeyExprs;
3235e5dd7070Spatrick 
3236e5dd7070Spatrick   if (Tok.is(tok::colon)) {
3237*12c85518Srobert     while (true) {
3238e5dd7070Spatrick       // Each iteration parses a single keyword argument.
3239e5dd7070Spatrick       KeyIdents.push_back(selIdent);
3240e5dd7070Spatrick       KeyLocs.push_back(Loc);
3241e5dd7070Spatrick 
3242e5dd7070Spatrick       if (ExpectAndConsume(tok::colon)) {
3243e5dd7070Spatrick         // We must manually skip to a ']', otherwise the expression skipper will
3244e5dd7070Spatrick         // stop at the ']' when it skips to the ';'.  We want it to skip beyond
3245e5dd7070Spatrick         // the enclosing expression.
3246e5dd7070Spatrick         SkipUntil(tok::r_square, StopAtSemi);
3247e5dd7070Spatrick         return ExprError();
3248e5dd7070Spatrick       }
3249e5dd7070Spatrick 
3250e5dd7070Spatrick       ///  Parse the expression after ':'
3251e5dd7070Spatrick 
3252e5dd7070Spatrick       if (Tok.is(tok::code_completion)) {
3253a9ac8606Spatrick         cutOffParsing();
3254e5dd7070Spatrick         if (SuperLoc.isValid())
3255e5dd7070Spatrick           Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
3256e5dd7070Spatrick                                                KeyIdents,
3257e5dd7070Spatrick                                                /*AtArgumentExpression=*/true);
3258e5dd7070Spatrick         else if (ReceiverType)
3259e5dd7070Spatrick           Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
3260e5dd7070Spatrick                                                KeyIdents,
3261e5dd7070Spatrick                                                /*AtArgumentExpression=*/true);
3262e5dd7070Spatrick         else
3263e5dd7070Spatrick           Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
3264e5dd7070Spatrick                                                   KeyIdents,
3265e5dd7070Spatrick                                                   /*AtArgumentExpression=*/true);
3266e5dd7070Spatrick 
3267e5dd7070Spatrick         return ExprError();
3268e5dd7070Spatrick       }
3269e5dd7070Spatrick 
3270e5dd7070Spatrick       ExprResult Expr;
3271e5dd7070Spatrick       if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
3272e5dd7070Spatrick         Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
3273e5dd7070Spatrick         Expr = ParseBraceInitializer();
3274e5dd7070Spatrick       } else
3275e5dd7070Spatrick         Expr = ParseAssignmentExpression();
3276e5dd7070Spatrick 
3277e5dd7070Spatrick       ExprResult Res(Expr);
3278e5dd7070Spatrick       if (Res.isInvalid()) {
3279e5dd7070Spatrick         // We must manually skip to a ']', otherwise the expression skipper will
3280e5dd7070Spatrick         // stop at the ']' when it skips to the ';'.  We want it to skip beyond
3281e5dd7070Spatrick         // the enclosing expression.
3282e5dd7070Spatrick         SkipUntil(tok::r_square, StopAtSemi);
3283e5dd7070Spatrick         return Res;
3284e5dd7070Spatrick       }
3285e5dd7070Spatrick 
3286e5dd7070Spatrick       // We have a valid expression.
3287e5dd7070Spatrick       KeyExprs.push_back(Res.get());
3288e5dd7070Spatrick 
3289e5dd7070Spatrick       // Code completion after each argument.
3290e5dd7070Spatrick       if (Tok.is(tok::code_completion)) {
3291a9ac8606Spatrick         cutOffParsing();
3292e5dd7070Spatrick         if (SuperLoc.isValid())
3293e5dd7070Spatrick           Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
3294e5dd7070Spatrick                                                KeyIdents,
3295e5dd7070Spatrick                                                /*AtArgumentExpression=*/false);
3296e5dd7070Spatrick         else if (ReceiverType)
3297e5dd7070Spatrick           Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
3298e5dd7070Spatrick                                                KeyIdents,
3299e5dd7070Spatrick                                                /*AtArgumentExpression=*/false);
3300e5dd7070Spatrick         else
3301e5dd7070Spatrick           Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
3302e5dd7070Spatrick                                                   KeyIdents,
3303e5dd7070Spatrick                                                 /*AtArgumentExpression=*/false);
3304e5dd7070Spatrick         return ExprError();
3305e5dd7070Spatrick       }
3306e5dd7070Spatrick 
3307e5dd7070Spatrick       // Check for another keyword selector.
3308e5dd7070Spatrick       selIdent = ParseObjCSelectorPiece(Loc);
3309e5dd7070Spatrick       if (!selIdent && Tok.isNot(tok::colon))
3310e5dd7070Spatrick         break;
3311e5dd7070Spatrick       // We have a selector or a colon, continue parsing.
3312e5dd7070Spatrick     }
3313e5dd7070Spatrick     // Parse the, optional, argument list, comma separated.
3314e5dd7070Spatrick     while (Tok.is(tok::comma)) {
3315e5dd7070Spatrick       SourceLocation commaLoc = ConsumeToken(); // Eat the ','.
3316e5dd7070Spatrick       ///  Parse the expression after ','
3317e5dd7070Spatrick       ExprResult Res(ParseAssignmentExpression());
3318e5dd7070Spatrick       if (Tok.is(tok::colon))
3319e5dd7070Spatrick         Res = Actions.CorrectDelayedTyposInExpr(Res);
3320e5dd7070Spatrick       if (Res.isInvalid()) {
3321e5dd7070Spatrick         if (Tok.is(tok::colon)) {
3322e5dd7070Spatrick           Diag(commaLoc, diag::note_extra_comma_message_arg) <<
3323e5dd7070Spatrick             FixItHint::CreateRemoval(commaLoc);
3324e5dd7070Spatrick         }
3325e5dd7070Spatrick         // We must manually skip to a ']', otherwise the expression skipper will
3326e5dd7070Spatrick         // stop at the ']' when it skips to the ';'.  We want it to skip beyond
3327e5dd7070Spatrick         // the enclosing expression.
3328e5dd7070Spatrick         SkipUntil(tok::r_square, StopAtSemi);
3329e5dd7070Spatrick         return Res;
3330e5dd7070Spatrick       }
3331e5dd7070Spatrick 
3332e5dd7070Spatrick       // We have a valid expression.
3333e5dd7070Spatrick       KeyExprs.push_back(Res.get());
3334e5dd7070Spatrick     }
3335e5dd7070Spatrick   } else if (!selIdent) {
3336e5dd7070Spatrick     Diag(Tok, diag::err_expected) << tok::identifier; // missing selector name.
3337e5dd7070Spatrick 
3338e5dd7070Spatrick     // We must manually skip to a ']', otherwise the expression skipper will
3339e5dd7070Spatrick     // stop at the ']' when it skips to the ';'.  We want it to skip beyond
3340e5dd7070Spatrick     // the enclosing expression.
3341e5dd7070Spatrick     SkipUntil(tok::r_square, StopAtSemi);
3342e5dd7070Spatrick     return ExprError();
3343e5dd7070Spatrick   }
3344e5dd7070Spatrick 
3345e5dd7070Spatrick   if (Tok.isNot(tok::r_square)) {
3346e5dd7070Spatrick     Diag(Tok, diag::err_expected)
3347e5dd7070Spatrick         << (Tok.is(tok::identifier) ? tok::colon : tok::r_square);
3348e5dd7070Spatrick     // We must manually skip to a ']', otherwise the expression skipper will
3349e5dd7070Spatrick     // stop at the ']' when it skips to the ';'.  We want it to skip beyond
3350e5dd7070Spatrick     // the enclosing expression.
3351e5dd7070Spatrick     SkipUntil(tok::r_square, StopAtSemi);
3352e5dd7070Spatrick     return ExprError();
3353e5dd7070Spatrick   }
3354e5dd7070Spatrick 
3355e5dd7070Spatrick   SourceLocation RBracLoc = ConsumeBracket(); // consume ']'
3356e5dd7070Spatrick 
3357e5dd7070Spatrick   unsigned nKeys = KeyIdents.size();
3358e5dd7070Spatrick   if (nKeys == 0) {
3359e5dd7070Spatrick     KeyIdents.push_back(selIdent);
3360e5dd7070Spatrick     KeyLocs.push_back(Loc);
3361e5dd7070Spatrick   }
3362e5dd7070Spatrick   Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);
3363e5dd7070Spatrick 
3364e5dd7070Spatrick   if (SuperLoc.isValid())
3365e5dd7070Spatrick     return Actions.ActOnSuperMessage(getCurScope(), SuperLoc, Sel,
3366e5dd7070Spatrick                                      LBracLoc, KeyLocs, RBracLoc, KeyExprs);
3367e5dd7070Spatrick   else if (ReceiverType)
3368e5dd7070Spatrick     return Actions.ActOnClassMessage(getCurScope(), ReceiverType, Sel,
3369e5dd7070Spatrick                                      LBracLoc, KeyLocs, RBracLoc, KeyExprs);
3370e5dd7070Spatrick   return Actions.ActOnInstanceMessage(getCurScope(), ReceiverExpr, Sel,
3371e5dd7070Spatrick                                       LBracLoc, KeyLocs, RBracLoc, KeyExprs);
3372e5dd7070Spatrick }
3373e5dd7070Spatrick 
ParseObjCStringLiteral(SourceLocation AtLoc)3374e5dd7070Spatrick ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
3375e5dd7070Spatrick   ExprResult Res(ParseStringLiteralExpression());
3376e5dd7070Spatrick   if (Res.isInvalid()) return Res;
3377e5dd7070Spatrick 
3378e5dd7070Spatrick   // @"foo" @"bar" is a valid concatenated string.  Eat any subsequent string
3379e5dd7070Spatrick   // expressions.  At this point, we know that the only valid thing that starts
3380e5dd7070Spatrick   // with '@' is an @"".
3381e5dd7070Spatrick   SmallVector<SourceLocation, 4> AtLocs;
3382e5dd7070Spatrick   ExprVector AtStrings;
3383e5dd7070Spatrick   AtLocs.push_back(AtLoc);
3384e5dd7070Spatrick   AtStrings.push_back(Res.get());
3385e5dd7070Spatrick 
3386e5dd7070Spatrick   while (Tok.is(tok::at)) {
3387e5dd7070Spatrick     AtLocs.push_back(ConsumeToken()); // eat the @.
3388e5dd7070Spatrick 
3389e5dd7070Spatrick     // Invalid unless there is a string literal.
3390e5dd7070Spatrick     if (!isTokenStringLiteral())
3391e5dd7070Spatrick       return ExprError(Diag(Tok, diag::err_objc_concat_string));
3392e5dd7070Spatrick 
3393e5dd7070Spatrick     ExprResult Lit(ParseStringLiteralExpression());
3394e5dd7070Spatrick     if (Lit.isInvalid())
3395e5dd7070Spatrick       return Lit;
3396e5dd7070Spatrick 
3397e5dd7070Spatrick     AtStrings.push_back(Lit.get());
3398e5dd7070Spatrick   }
3399e5dd7070Spatrick 
3400e5dd7070Spatrick   return Actions.ParseObjCStringLiteral(AtLocs.data(), AtStrings);
3401e5dd7070Spatrick }
3402e5dd7070Spatrick 
3403e5dd7070Spatrick /// ParseObjCBooleanLiteral -
3404e5dd7070Spatrick /// objc-scalar-literal : '@' boolean-keyword
3405e5dd7070Spatrick ///                        ;
3406e5dd7070Spatrick /// boolean-keyword: 'true' | 'false' | '__objc_yes' | '__objc_no'
3407e5dd7070Spatrick ///                        ;
ParseObjCBooleanLiteral(SourceLocation AtLoc,bool ArgValue)3408e5dd7070Spatrick ExprResult Parser::ParseObjCBooleanLiteral(SourceLocation AtLoc,
3409e5dd7070Spatrick                                            bool ArgValue) {
3410e5dd7070Spatrick   SourceLocation EndLoc = ConsumeToken();             // consume the keyword.
3411e5dd7070Spatrick   return Actions.ActOnObjCBoolLiteral(AtLoc, EndLoc, ArgValue);
3412e5dd7070Spatrick }
3413e5dd7070Spatrick 
3414e5dd7070Spatrick /// ParseObjCCharacterLiteral -
3415e5dd7070Spatrick /// objc-scalar-literal : '@' character-literal
3416e5dd7070Spatrick ///                        ;
ParseObjCCharacterLiteral(SourceLocation AtLoc)3417e5dd7070Spatrick ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {
3418e5dd7070Spatrick   ExprResult Lit(Actions.ActOnCharacterConstant(Tok));
3419e5dd7070Spatrick   if (Lit.isInvalid()) {
3420e5dd7070Spatrick     return Lit;
3421e5dd7070Spatrick   }
3422e5dd7070Spatrick   ConsumeToken(); // Consume the literal token.
3423e5dd7070Spatrick   return Actions.BuildObjCNumericLiteral(AtLoc, Lit.get());
3424e5dd7070Spatrick }
3425e5dd7070Spatrick 
3426e5dd7070Spatrick /// ParseObjCNumericLiteral -
3427e5dd7070Spatrick /// objc-scalar-literal : '@' scalar-literal
3428e5dd7070Spatrick ///                        ;
3429e5dd7070Spatrick /// scalar-literal : | numeric-constant			/* any numeric constant. */
3430e5dd7070Spatrick ///                    ;
ParseObjCNumericLiteral(SourceLocation AtLoc)3431e5dd7070Spatrick ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) {
3432e5dd7070Spatrick   ExprResult Lit(Actions.ActOnNumericConstant(Tok));
3433e5dd7070Spatrick   if (Lit.isInvalid()) {
3434e5dd7070Spatrick     return Lit;
3435e5dd7070Spatrick   }
3436e5dd7070Spatrick   ConsumeToken(); // Consume the literal token.
3437e5dd7070Spatrick   return Actions.BuildObjCNumericLiteral(AtLoc, Lit.get());
3438e5dd7070Spatrick }
3439e5dd7070Spatrick 
3440e5dd7070Spatrick /// ParseObjCBoxedExpr -
3441e5dd7070Spatrick /// objc-box-expression:
3442e5dd7070Spatrick ///       @( assignment-expression )
3443e5dd7070Spatrick ExprResult
ParseObjCBoxedExpr(SourceLocation AtLoc)3444e5dd7070Spatrick Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) {
3445e5dd7070Spatrick   if (Tok.isNot(tok::l_paren))
3446e5dd7070Spatrick     return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@");
3447e5dd7070Spatrick 
3448e5dd7070Spatrick   BalancedDelimiterTracker T(*this, tok::l_paren);
3449e5dd7070Spatrick   T.consumeOpen();
3450e5dd7070Spatrick   ExprResult ValueExpr(ParseAssignmentExpression());
3451e5dd7070Spatrick   if (T.consumeClose())
3452e5dd7070Spatrick     return ExprError();
3453e5dd7070Spatrick 
3454e5dd7070Spatrick   if (ValueExpr.isInvalid())
3455e5dd7070Spatrick     return ExprError();
3456e5dd7070Spatrick 
3457e5dd7070Spatrick   // Wrap the sub-expression in a parenthesized expression, to distinguish
3458e5dd7070Spatrick   // a boxed expression from a literal.
3459e5dd7070Spatrick   SourceLocation LPLoc = T.getOpenLocation(), RPLoc = T.getCloseLocation();
3460e5dd7070Spatrick   ValueExpr = Actions.ActOnParenExpr(LPLoc, RPLoc, ValueExpr.get());
3461e5dd7070Spatrick   return Actions.BuildObjCBoxedExpr(SourceRange(AtLoc, RPLoc),
3462e5dd7070Spatrick                                     ValueExpr.get());
3463e5dd7070Spatrick }
3464e5dd7070Spatrick 
ParseObjCArrayLiteral(SourceLocation AtLoc)3465e5dd7070Spatrick ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
3466e5dd7070Spatrick   ExprVector ElementExprs;                   // array elements.
3467e5dd7070Spatrick   ConsumeBracket(); // consume the l_square.
3468e5dd7070Spatrick 
3469e5dd7070Spatrick   bool HasInvalidEltExpr = false;
3470e5dd7070Spatrick   while (Tok.isNot(tok::r_square)) {
3471e5dd7070Spatrick     // Parse list of array element expressions (all must be id types).
3472e5dd7070Spatrick     ExprResult Res(ParseAssignmentExpression());
3473e5dd7070Spatrick     if (Res.isInvalid()) {
3474e5dd7070Spatrick       // We must manually skip to a ']', otherwise the expression skipper will
3475e5dd7070Spatrick       // stop at the ']' when it skips to the ';'.  We want it to skip beyond
3476e5dd7070Spatrick       // the enclosing expression.
3477e5dd7070Spatrick       SkipUntil(tok::r_square, StopAtSemi);
3478e5dd7070Spatrick       return Res;
3479e5dd7070Spatrick     }
3480e5dd7070Spatrick 
3481e5dd7070Spatrick     Res = Actions.CorrectDelayedTyposInExpr(Res.get());
3482e5dd7070Spatrick     if (Res.isInvalid())
3483e5dd7070Spatrick       HasInvalidEltExpr = true;
3484e5dd7070Spatrick 
3485e5dd7070Spatrick     // Parse the ellipsis that indicates a pack expansion.
3486e5dd7070Spatrick     if (Tok.is(tok::ellipsis))
3487e5dd7070Spatrick       Res = Actions.ActOnPackExpansion(Res.get(), ConsumeToken());
3488e5dd7070Spatrick     if (Res.isInvalid())
3489e5dd7070Spatrick       HasInvalidEltExpr = true;
3490e5dd7070Spatrick 
3491e5dd7070Spatrick     ElementExprs.push_back(Res.get());
3492e5dd7070Spatrick 
3493e5dd7070Spatrick     if (Tok.is(tok::comma))
3494e5dd7070Spatrick       ConsumeToken(); // Eat the ','.
3495e5dd7070Spatrick     else if (Tok.isNot(tok::r_square))
3496e5dd7070Spatrick       return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_square
3497e5dd7070Spatrick                                                             << tok::comma);
3498e5dd7070Spatrick   }
3499e5dd7070Spatrick   SourceLocation EndLoc = ConsumeBracket(); // location of ']'
3500e5dd7070Spatrick 
3501e5dd7070Spatrick   if (HasInvalidEltExpr)
3502e5dd7070Spatrick     return ExprError();
3503e5dd7070Spatrick 
3504e5dd7070Spatrick   MultiExprArg Args(ElementExprs);
3505e5dd7070Spatrick   return Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args);
3506e5dd7070Spatrick }
3507e5dd7070Spatrick 
ParseObjCDictionaryLiteral(SourceLocation AtLoc)3508e5dd7070Spatrick ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
3509e5dd7070Spatrick   SmallVector<ObjCDictionaryElement, 4> Elements; // dictionary elements.
3510e5dd7070Spatrick   ConsumeBrace(); // consume the l_square.
3511e5dd7070Spatrick   bool HasInvalidEltExpr = false;
3512e5dd7070Spatrick   while (Tok.isNot(tok::r_brace)) {
3513e5dd7070Spatrick     // Parse the comma separated key : value expressions.
3514e5dd7070Spatrick     ExprResult KeyExpr;
3515e5dd7070Spatrick     {
3516e5dd7070Spatrick       ColonProtectionRAIIObject X(*this);
3517e5dd7070Spatrick       KeyExpr = ParseAssignmentExpression();
3518e5dd7070Spatrick       if (KeyExpr.isInvalid()) {
3519e5dd7070Spatrick         // We must manually skip to a '}', otherwise the expression skipper will
3520e5dd7070Spatrick         // stop at the '}' when it skips to the ';'.  We want it to skip beyond
3521e5dd7070Spatrick         // the enclosing expression.
3522e5dd7070Spatrick         SkipUntil(tok::r_brace, StopAtSemi);
3523e5dd7070Spatrick         return KeyExpr;
3524e5dd7070Spatrick       }
3525e5dd7070Spatrick     }
3526e5dd7070Spatrick 
3527e5dd7070Spatrick     if (ExpectAndConsume(tok::colon)) {
3528e5dd7070Spatrick       SkipUntil(tok::r_brace, StopAtSemi);
3529e5dd7070Spatrick       return ExprError();
3530e5dd7070Spatrick     }
3531e5dd7070Spatrick 
3532e5dd7070Spatrick     ExprResult ValueExpr(ParseAssignmentExpression());
3533e5dd7070Spatrick     if (ValueExpr.isInvalid()) {
3534e5dd7070Spatrick       // We must manually skip to a '}', otherwise the expression skipper will
3535e5dd7070Spatrick       // stop at the '}' when it skips to the ';'.  We want it to skip beyond
3536e5dd7070Spatrick       // the enclosing expression.
3537e5dd7070Spatrick       SkipUntil(tok::r_brace, StopAtSemi);
3538e5dd7070Spatrick       return ValueExpr;
3539e5dd7070Spatrick     }
3540e5dd7070Spatrick 
3541e5dd7070Spatrick     // Check the key and value for possible typos
3542e5dd7070Spatrick     KeyExpr = Actions.CorrectDelayedTyposInExpr(KeyExpr.get());
3543e5dd7070Spatrick     ValueExpr = Actions.CorrectDelayedTyposInExpr(ValueExpr.get());
3544e5dd7070Spatrick     if (KeyExpr.isInvalid() || ValueExpr.isInvalid())
3545e5dd7070Spatrick       HasInvalidEltExpr = true;
3546e5dd7070Spatrick 
3547e5dd7070Spatrick     // Parse the ellipsis that designates this as a pack expansion. Do not
3548e5dd7070Spatrick     // ActOnPackExpansion here, leave it to template instantiation time where
3549e5dd7070Spatrick     // we can get better diagnostics.
3550e5dd7070Spatrick     SourceLocation EllipsisLoc;
3551e5dd7070Spatrick     if (getLangOpts().CPlusPlus)
3552e5dd7070Spatrick       TryConsumeToken(tok::ellipsis, EllipsisLoc);
3553e5dd7070Spatrick 
3554e5dd7070Spatrick     // We have a valid expression. Collect it in a vector so we can
3555e5dd7070Spatrick     // build the argument list.
3556*12c85518Srobert     ObjCDictionaryElement Element = {KeyExpr.get(), ValueExpr.get(),
3557*12c85518Srobert                                      EllipsisLoc, std::nullopt};
3558e5dd7070Spatrick     Elements.push_back(Element);
3559e5dd7070Spatrick 
3560e5dd7070Spatrick     if (!TryConsumeToken(tok::comma) && Tok.isNot(tok::r_brace))
3561e5dd7070Spatrick       return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_brace
3562e5dd7070Spatrick                                                             << tok::comma);
3563e5dd7070Spatrick   }
3564e5dd7070Spatrick   SourceLocation EndLoc = ConsumeBrace();
3565e5dd7070Spatrick 
3566e5dd7070Spatrick   if (HasInvalidEltExpr)
3567e5dd7070Spatrick     return ExprError();
3568e5dd7070Spatrick 
3569e5dd7070Spatrick   // Create the ObjCDictionaryLiteral.
3570e5dd7070Spatrick   return Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),
3571e5dd7070Spatrick                                             Elements);
3572e5dd7070Spatrick }
3573e5dd7070Spatrick 
3574e5dd7070Spatrick ///    objc-encode-expression:
3575e5dd7070Spatrick ///      \@encode ( type-name )
3576e5dd7070Spatrick ExprResult
ParseObjCEncodeExpression(SourceLocation AtLoc)3577e5dd7070Spatrick Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
3578e5dd7070Spatrick   assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
3579e5dd7070Spatrick 
3580e5dd7070Spatrick   SourceLocation EncLoc = ConsumeToken();
3581e5dd7070Spatrick 
3582e5dd7070Spatrick   if (Tok.isNot(tok::l_paren))
3583e5dd7070Spatrick     return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode");
3584e5dd7070Spatrick 
3585e5dd7070Spatrick   BalancedDelimiterTracker T(*this, tok::l_paren);
3586e5dd7070Spatrick   T.consumeOpen();
3587e5dd7070Spatrick 
3588e5dd7070Spatrick   TypeResult Ty = ParseTypeName();
3589e5dd7070Spatrick 
3590e5dd7070Spatrick   T.consumeClose();
3591e5dd7070Spatrick 
3592e5dd7070Spatrick   if (Ty.isInvalid())
3593e5dd7070Spatrick     return ExprError();
3594e5dd7070Spatrick 
3595e5dd7070Spatrick   return Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, T.getOpenLocation(),
3596e5dd7070Spatrick                                            Ty.get(), T.getCloseLocation());
3597e5dd7070Spatrick }
3598e5dd7070Spatrick 
3599e5dd7070Spatrick ///     objc-protocol-expression
3600e5dd7070Spatrick ///       \@protocol ( protocol-name )
3601e5dd7070Spatrick ExprResult
ParseObjCProtocolExpression(SourceLocation AtLoc)3602e5dd7070Spatrick Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
3603e5dd7070Spatrick   SourceLocation ProtoLoc = ConsumeToken();
3604e5dd7070Spatrick 
3605e5dd7070Spatrick   if (Tok.isNot(tok::l_paren))
3606e5dd7070Spatrick     return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol");
3607e5dd7070Spatrick 
3608e5dd7070Spatrick   BalancedDelimiterTracker T(*this, tok::l_paren);
3609e5dd7070Spatrick   T.consumeOpen();
3610e5dd7070Spatrick 
3611e5dd7070Spatrick   if (expectIdentifier())
3612e5dd7070Spatrick     return ExprError();
3613e5dd7070Spatrick 
3614e5dd7070Spatrick   IdentifierInfo *protocolId = Tok.getIdentifierInfo();
3615e5dd7070Spatrick   SourceLocation ProtoIdLoc = ConsumeToken();
3616e5dd7070Spatrick 
3617e5dd7070Spatrick   T.consumeClose();
3618e5dd7070Spatrick 
3619e5dd7070Spatrick   return Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
3620e5dd7070Spatrick                                              T.getOpenLocation(), ProtoIdLoc,
3621e5dd7070Spatrick                                              T.getCloseLocation());
3622e5dd7070Spatrick }
3623e5dd7070Spatrick 
3624e5dd7070Spatrick ///     objc-selector-expression
3625e5dd7070Spatrick ///       @selector '(' '('[opt] objc-keyword-selector ')'[opt] ')'
ParseObjCSelectorExpression(SourceLocation AtLoc)3626e5dd7070Spatrick ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
3627e5dd7070Spatrick   SourceLocation SelectorLoc = ConsumeToken();
3628e5dd7070Spatrick 
3629e5dd7070Spatrick   if (Tok.isNot(tok::l_paren))
3630e5dd7070Spatrick     return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector");
3631e5dd7070Spatrick 
3632e5dd7070Spatrick   SmallVector<IdentifierInfo *, 12> KeyIdents;
3633e5dd7070Spatrick   SourceLocation sLoc;
3634e5dd7070Spatrick 
3635e5dd7070Spatrick   BalancedDelimiterTracker T(*this, tok::l_paren);
3636e5dd7070Spatrick   T.consumeOpen();
3637e5dd7070Spatrick   bool HasOptionalParen = Tok.is(tok::l_paren);
3638e5dd7070Spatrick   if (HasOptionalParen)
3639e5dd7070Spatrick     ConsumeParen();
3640e5dd7070Spatrick 
3641e5dd7070Spatrick   if (Tok.is(tok::code_completion)) {
3642e5dd7070Spatrick     cutOffParsing();
3643a9ac8606Spatrick     Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
3644e5dd7070Spatrick     return ExprError();
3645e5dd7070Spatrick   }
3646e5dd7070Spatrick 
3647e5dd7070Spatrick   IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc);
3648e5dd7070Spatrick   if (!SelIdent &&  // missing selector name.
3649e5dd7070Spatrick       Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
3650e5dd7070Spatrick     return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
3651e5dd7070Spatrick 
3652e5dd7070Spatrick   KeyIdents.push_back(SelIdent);
3653e5dd7070Spatrick 
3654e5dd7070Spatrick   unsigned nColons = 0;
3655e5dd7070Spatrick   if (Tok.isNot(tok::r_paren)) {
3656*12c85518Srobert     while (true) {
3657e5dd7070Spatrick       if (TryConsumeToken(tok::coloncolon)) { // Handle :: in C++.
3658e5dd7070Spatrick         ++nColons;
3659e5dd7070Spatrick         KeyIdents.push_back(nullptr);
3660e5dd7070Spatrick       } else if (ExpectAndConsume(tok::colon)) // Otherwise expect ':'.
3661e5dd7070Spatrick         return ExprError();
3662e5dd7070Spatrick       ++nColons;
3663e5dd7070Spatrick 
3664e5dd7070Spatrick       if (Tok.is(tok::r_paren))
3665e5dd7070Spatrick         break;
3666e5dd7070Spatrick 
3667e5dd7070Spatrick       if (Tok.is(tok::code_completion)) {
3668e5dd7070Spatrick         cutOffParsing();
3669a9ac8606Spatrick         Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
3670e5dd7070Spatrick         return ExprError();
3671e5dd7070Spatrick       }
3672e5dd7070Spatrick 
3673e5dd7070Spatrick       // Check for another keyword selector.
3674e5dd7070Spatrick       SourceLocation Loc;
3675e5dd7070Spatrick       SelIdent = ParseObjCSelectorPiece(Loc);
3676e5dd7070Spatrick       KeyIdents.push_back(SelIdent);
3677e5dd7070Spatrick       if (!SelIdent && Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
3678e5dd7070Spatrick         break;
3679e5dd7070Spatrick     }
3680e5dd7070Spatrick   }
3681e5dd7070Spatrick   if (HasOptionalParen && Tok.is(tok::r_paren))
3682e5dd7070Spatrick     ConsumeParen(); // ')'
3683e5dd7070Spatrick   T.consumeClose();
3684e5dd7070Spatrick   Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
3685e5dd7070Spatrick   return Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
3686e5dd7070Spatrick                                              T.getOpenLocation(),
3687e5dd7070Spatrick                                              T.getCloseLocation(),
3688e5dd7070Spatrick                                              !HasOptionalParen);
3689e5dd7070Spatrick }
3690e5dd7070Spatrick 
ParseLexedObjCMethodDefs(LexedMethod & LM,bool parseMethod)3691e5dd7070Spatrick void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
3692e5dd7070Spatrick   // MCDecl might be null due to error in method or c-function  prototype, etc.
3693e5dd7070Spatrick   Decl *MCDecl = LM.D;
3694e5dd7070Spatrick   bool skip = MCDecl &&
3695e5dd7070Spatrick               ((parseMethod && !Actions.isObjCMethodDecl(MCDecl)) ||
3696e5dd7070Spatrick               (!parseMethod && Actions.isObjCMethodDecl(MCDecl)));
3697e5dd7070Spatrick   if (skip)
3698e5dd7070Spatrick     return;
3699e5dd7070Spatrick 
3700e5dd7070Spatrick   // Save the current token position.
3701e5dd7070Spatrick   SourceLocation OrigLoc = Tok.getLocation();
3702e5dd7070Spatrick 
3703e5dd7070Spatrick   assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!");
3704e5dd7070Spatrick   // Store an artificial EOF token to ensure that we don't run off the end of
3705e5dd7070Spatrick   // the method's body when we come to parse it.
3706e5dd7070Spatrick   Token Eof;
3707e5dd7070Spatrick   Eof.startToken();
3708e5dd7070Spatrick   Eof.setKind(tok::eof);
3709e5dd7070Spatrick   Eof.setEofData(MCDecl);
3710e5dd7070Spatrick   Eof.setLocation(OrigLoc);
3711e5dd7070Spatrick   LM.Toks.push_back(Eof);
3712e5dd7070Spatrick   // Append the current token at the end of the new token stream so that it
3713e5dd7070Spatrick   // doesn't get lost.
3714e5dd7070Spatrick   LM.Toks.push_back(Tok);
3715e5dd7070Spatrick   PP.EnterTokenStream(LM.Toks, true, /*IsReinject*/true);
3716e5dd7070Spatrick 
3717e5dd7070Spatrick   // Consume the previously pushed token.
3718e5dd7070Spatrick   ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
3719e5dd7070Spatrick 
3720e5dd7070Spatrick   assert(Tok.isOneOf(tok::l_brace, tok::kw_try, tok::colon) &&
3721e5dd7070Spatrick          "Inline objective-c method not starting with '{' or 'try' or ':'");
3722e5dd7070Spatrick   // Enter a scope for the method or c-function body.
3723e5dd7070Spatrick   ParseScope BodyScope(this, (parseMethod ? Scope::ObjCMethodScope : 0) |
3724e5dd7070Spatrick                                  Scope::FnScope | Scope::DeclScope |
3725e5dd7070Spatrick                                  Scope::CompoundStmtScope);
3726e5dd7070Spatrick 
3727e5dd7070Spatrick   // Tell the actions module that we have entered a method or c-function definition
3728e5dd7070Spatrick   // with the specified Declarator for the method/function.
3729e5dd7070Spatrick   if (parseMethod)
3730e5dd7070Spatrick     Actions.ActOnStartOfObjCMethodDef(getCurScope(), MCDecl);
3731e5dd7070Spatrick   else
3732e5dd7070Spatrick     Actions.ActOnStartOfFunctionDef(getCurScope(), MCDecl);
3733e5dd7070Spatrick   if (Tok.is(tok::kw_try))
3734e5dd7070Spatrick     ParseFunctionTryBlock(MCDecl, BodyScope);
3735e5dd7070Spatrick   else {
3736e5dd7070Spatrick     if (Tok.is(tok::colon))
3737e5dd7070Spatrick       ParseConstructorInitializer(MCDecl);
3738e5dd7070Spatrick     else
3739e5dd7070Spatrick       Actions.ActOnDefaultCtorInitializers(MCDecl);
3740e5dd7070Spatrick     ParseFunctionStatementBody(MCDecl, BodyScope);
3741e5dd7070Spatrick   }
3742e5dd7070Spatrick 
3743e5dd7070Spatrick   if (Tok.getLocation() != OrigLoc) {
3744e5dd7070Spatrick     // Due to parsing error, we either went over the cached tokens or
3745e5dd7070Spatrick     // there are still cached tokens left. If it's the latter case skip the
3746e5dd7070Spatrick     // leftover tokens.
3747e5dd7070Spatrick     // Since this is an uncommon situation that should be avoided, use the
3748e5dd7070Spatrick     // expensive isBeforeInTranslationUnit call.
3749e5dd7070Spatrick     if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
3750e5dd7070Spatrick                                                      OrigLoc))
3751e5dd7070Spatrick       while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
3752e5dd7070Spatrick         ConsumeAnyToken();
3753e5dd7070Spatrick   }
3754e5dd7070Spatrick   // Clean up the remaining EOF token.
3755e5dd7070Spatrick   ConsumeAnyToken();
3756e5dd7070Spatrick }
3757