//===--- ParseDecl.cpp - Swift Language Parser for Declarations -----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Declaration Parsing and AST Building
//
//===----------------------------------------------------------------------===//

#include "swift/Parse/Parser.h"
#include "swift/Parse/CodeCompletionCallbacks.h"
#include "swift/Parse/DelayedParsingCallbacks.h"
#include "swift/Subsystems.h"
#include "swift/AST/Attr.h"
#include "swift/AST/DebuggerClient.h"
#include "swift/AST/DiagnosticsParse.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/Module.h"
#include "swift/AST/ParameterList.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/StringExtras.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include <algorithm>

using namespace swift;

namespace {
  /// A RAII object for deciding whether this DeclKind needs special
  /// treatment when parsing in the "debugger context", and implementing
  /// that treatment.  The problem arises because, when lldb
  /// uses swift to parse expressions, it needs to emulate the current
  /// frame's scope. We do that, for instance, by making a class extension
  /// and running the code in a function in that extension.
  ///
  /// This causes two kinds of issues:
  /// 1) Some DeclKinds require to be parsed in TopLevel contexts only.
  /// 2) Sometimes the debugger wants a Decl to live beyond the current
  /// function invocation, in which case it should be parsed at the
  /// file scope level so it will be set up correctly for this purpose.
  ///
  /// Creating an instance of this object will cause it to figure out
  /// whether we are in the debugger function, whether it needs to swap 
  /// the Decl that is currently being parsed.
  /// If you have created the object, instead of returning the result
  /// with makeParserResult, use the object's fixupParserResult.  If
  /// no swap has occurred, these methods will work the same.  
  /// If the decl has been moved, then Parser::markWasHandled will be
  /// called on the Decl, and you should call declWasHandledAlready
  /// before you consume the Decl to see if you actually need to
  /// consume it.
  /// If you are making one of these objects to address issue 1, call
  /// the constructor that only takes a DeclKind, and it will be moved
  /// unconditionally.  Otherwise pass in the Name and DeclKind and the
  /// DebuggerClient will be asked whether to move it or not.
  class DebuggerContextChange {
  protected:
    Parser &P;
    Identifier Name;
    SourceFile *SF;
    Optional<Parser::ContextChange> CC;
  public:
    DebuggerContextChange (Parser &P)
      : P(P), SF(nullptr) {
      if (!inDebuggerContext())
        return;
      else
        switchContext();
    }
    
    DebuggerContextChange (Parser &P, Identifier &Name, DeclKind Kind)
      : P(P), Name(Name), SF(nullptr) {
      if (!inDebuggerContext())
        return;
      bool globalize = false;
        
      DebuggerClient *debug_client = getDebuggerClient();
      if (!debug_client)
        return;
      
      globalize = debug_client->shouldGlobalize(Name, Kind);
        
      if (globalize)
        switchContext();
    }
    
    bool movedToTopLevel() {
      return CC.hasValue();
    }
    
    template <typename T>
    ParserResult<T>
    fixupParserResult(ParserResult<T> &Result) {
      ParserStatus Status = Result;
      return fixupParserResult(Status, Result.getPtrOrNull());
    }
    
    template <typename T>
    ParserResult<T>
    fixupParserResult(T *D) {
      if (CC.hasValue()) {
        swapDecl(D);
      }
      return ParserResult<T>(D);
    }
    
    template <typename T>
    ParserResult<T>
    fixupParserResult(ParserStatus Status, T *D) {
      if (CC.hasValue() && !Status.isError()) {
        // If there is an error, don't do our splicing trick,
        // just return the Decl and the status for reporting.
        swapDecl(D);
      }
      return makeParserResult(Status, D);
    }

    // The destructor doesn't need to do anything, the CC's destructor will
    // pop the context if we set it.
    ~DebuggerContextChange () {}
  protected:
  
    DebuggerClient *getDebuggerClient()
    {
      ModuleDecl *PM = P.CurDeclContext->getParentModule();
      if (!PM)
          return nullptr;
      else
           return PM->getDebugClient();
    }
    
    bool inDebuggerContext() {
      if (!P.Context.LangOpts.DebuggerSupport)
        return false;
      if (!P.CurDeclContext)
        return false;
      auto *func_decl = dyn_cast<FuncDecl>(P.CurDeclContext);
      if (!func_decl)
        return false;
        
      if (!func_decl->getAttrs().hasAttribute<LLDBDebuggerFunctionAttr>())
        return false;
      
      return true;
    }
    
    void switchContext () {
      SF = P.CurDeclContext->getParentSourceFile();
      CC.emplace (P, SF);
    }
    
    void swapDecl (Decl *D)
    {
      assert (SF);
      DebuggerClient *debug_client = getDebuggerClient();
      assert (debug_client);
      debug_client->didGlobalize(D);
      SF->Decls.push_back(D);
      P.markWasHandled(D);
    }
  };
} // end anonymous namespace

/// \brief Main entrypoint for the parser.
///
/// \verbatim
///   top-level:
///     stmt-brace-item*
///     decl-sil       [[only in SIL mode]
///     decl-sil-stage [[only in SIL mode]
/// \endverbatim
bool Parser::parseTopLevel() {
  SF.ASTStage = SourceFile::Parsing;

  // Prime the lexer.
  if (Tok.is(tok::NUM_TOKENS))
    consumeToken();

  // Parse the body of the file.
  SmallVector<ASTNode, 128> Items;

  skipExtraTopLevelRBraces();

  // If we are in SIL mode, and if the first token is the start of a sil
  // declaration, parse that one SIL function and return to the top level.  This
  // allows type declarations and other things to be parsed, name bound, and
  // type checked in batches, similar to immediate mode.  This also enforces
  // that SIL bodies can only be at the top level.
  if (Tok.is(tok::kw_sil)) {
    assert(isInSILMode() && "'sil' should only be a keyword in SIL mode");
    parseDeclSIL();
  } else if (Tok.is(tok::kw_sil_stage)) {
    assert(isInSILMode() && "'sil' should only be a keyword in SIL mode");
    parseDeclSILStage();
  } else if (Tok.is(tok::kw_sil_vtable)) {
    assert(isInSILMode() && "'sil' should only be a keyword in SIL mode");
    parseSILVTable();
  } else if (Tok.is(tok::kw_sil_global)) {
    assert(isInSILMode() && "'sil' should only be a keyword in SIL mode");
    parseSILGlobal();
  } else if (Tok.is(tok::kw_sil_witness_table)) {
    assert(isInSILMode() && "'sil' should only be a keyword in SIL mode");
    parseSILWitnessTable();
  } else if (Tok.is(tok::kw_sil_default_witness_table)) {
    assert(isInSILMode() && "'sil' should only be a keyword in SIL mode");
    parseSILDefaultWitnessTable();
  } else if (Tok.is(tok::kw_sil_coverage_map)) {
    assert(isInSILMode() && "'sil' should only be a keyword in SIL mode");
    parseSILCoverageMap();
  } else if (Tok.is(tok::kw_sil_scope)) {
    assert(isInSILMode() && "'sil' should only be a keyword in SIL mode");
    parseSILScope();
  } else {
    parseBraceItems(Items,
                    allowTopLevelCode() ? BraceItemListKind::TopLevelCode
                                        : BraceItemListKind::TopLevelLibrary);
  }
  
  // In the case of a catastrophic parse error, consume any trailing
  // #else, #elseif, or #endif and move on to the next statement or declaration
  // block.
  if (Tok.is(tok::pound_else) || Tok.is(tok::pound_elseif) ||
      Tok.is(tok::pound_endif)) {
    diagnose(Tok.getLoc(),
             diag::unexpected_conditional_compilation_block_terminator);
    consumeToken();
  }

  // If this is a Main source file, determine if we found code that needs to be
  // executed (this is used by the repl to know whether to compile and run the
  // newly parsed stuff).
  bool FoundTopLevelCodeToExecute = false;
  if (allowTopLevelCode()) {
    for (auto V : Items) {
      if (isa<TopLevelCodeDecl>(V.get<Decl*>()))
        FoundTopLevelCodeToExecute = true;
    }
  }

  // Add newly parsed decls to the module.
  for (auto Item : Items)
    if (auto *D = Item.dyn_cast<Decl*>())
      SF.Decls.push_back(D);

  // Note that the source file is fully parsed and verify it.
  SF.ASTStage = SourceFile::Parsed;
  verify(SF);

  // Next time start relexing from the beginning of the comment so that we can
  // attach it to the token.
  State->markParserPosition(Tok.getCommentRange().getStart(), PreviousLoc,
                            InPoundLineEnvironment);

  return FoundTopLevelCodeToExecute;
}

bool Parser::skipExtraTopLevelRBraces() {
  if (!Tok.is(tok::r_brace))
    return false;
  while (Tok.is(tok::r_brace)) {
    diagnose(Tok, diag::extra_rbrace)
        .fixItRemove(Tok.getLoc());
    consumeToken();
  }
  return true;
}



static Optional<StringRef>
getStringLiteralIfNotInterpolated(Parser &P, SourceLoc Loc, const Token &Tok,
                                  StringRef DiagText) {
  SmallVector<Lexer::StringSegment, 1> Segments;
  P.L->getStringLiteralSegments(Tok, Segments);
  if (Segments.size() != 1 ||
      Segments.front().Kind == Lexer::StringSegment::Expr) {
   P.diagnose(Loc, diag::attr_interpolated_string, DiagText);
   return None;
  }

  return P.SourceMgr.extractText(CharSourceRange(Segments.front().Loc,
                                                 Segments.front().Length));
}

bool Parser::parseSpecializeAttribute(swift::tok ClosingBrace, SourceLoc AtLoc,
                                      SourceLoc Loc, SpecializeAttr *&Attr) {
  assert(ClosingBrace == tok::r_paren || ClosingBrace == tok::r_square);
  SourceLoc lParenLoc = consumeToken();
  bool DiscardAttribute = false;
  StringRef AttrName = "_specialize";

  Optional<bool> exported;
  Optional<SpecializeAttr::SpecializationKind> kind;

  // Parse optional "exported" and "kind" labeled parameters.
  while (!Tok.is(tok::kw_where)) {
    if (Tok.is(tok::identifier)) {
      auto ParamLabel = Tok.getText();
      if (ParamLabel != "exported" && ParamLabel != "kind") {
        diagnose(Tok.getLoc(), diag::attr_specialize_unknown_parameter_name,
                 ParamLabel);
      }
      consumeToken();
      if (!consumeIf(tok::colon)) {
        diagnose(Tok.getLoc(), diag::attr_specialize_missing_colon, ParamLabel);
        skipUntil(tok::comma, tok::kw_where);
        if (Tok.is(ClosingBrace))
          break;
        if (Tok.is(tok::kw_where)) {
          continue;
        }
        if (Tok.is(tok::comma)) {
          consumeToken();
          continue;
        }
        DiscardAttribute = true;
        return false;
      }
      if ((ParamLabel == "exported" && exported.hasValue()) ||
          (ParamLabel == "kind" && kind.hasValue())) {
        diagnose(Tok.getLoc(), diag::attr_specialize_parameter_already_defined,
                 ParamLabel);
      }
      if (ParamLabel == "exported") {
        bool isTrue = consumeIf(tok::kw_true);
        bool isFalse = consumeIf(tok::kw_false);
        if (!isTrue && !isFalse) {
          diagnose(Tok.getLoc(), diag::attr_specialize_expected_bool_value);
          skipUntil(tok::comma, tok::kw_where);
          if (Tok.is(ClosingBrace))
            break;
          if (Tok.is(tok::kw_where)) {
            continue;
          }
          if (Tok.is(tok::comma)) {
            consumeToken();
            continue;
          }
          DiscardAttribute = true;
          return false;
        }
        if (ParamLabel == "exported") {
          exported = isTrue ? true : false;
        }
      }
      if (ParamLabel == "kind") {
        SourceLoc paramValueLoc;
        if (Tok.is(tok::identifier)) {
          if (Tok.getText() == "partial") {
            kind = SpecializeAttr::SpecializationKind::Partial;
          } else if (Tok.getText() == "full") {
            kind = SpecializeAttr::SpecializationKind::Full;
          } else {
            diagnose(Tok.getLoc(),
                     diag::attr_specialize_expected_partial_or_full);
          }
          consumeToken();
        } else if (consumeIf(tok::kw_true, paramValueLoc) ||
                   consumeIf(tok::kw_false, paramValueLoc)) {
          diagnose(paramValueLoc,
                   diag::attr_specialize_expected_partial_or_full);
        }
      }
      if (!consumeIf(tok::comma)) {
        diagnose(Tok.getLoc(), diag::attr_specialize_missing_comma);
        skipUntil(tok::comma, tok::kw_where);
        if (Tok.is(ClosingBrace))
          break;
        if (Tok.is(tok::kw_where)) {
          continue;
        }
        if (Tok.is(tok::comma)) {
          consumeToken();
          continue;
        }
        DiscardAttribute = true;
        return false;
      }
      continue;
    }
    diagnose(Tok.getLoc(),
             diag::attr_specialize_missing_parameter_label_or_where_clause);
    DiscardAttribute = true;
    return false;
  };

  // Parse the where clause.
  TrailingWhereClause *trailingWhereClause = nullptr;
  if (Tok.is(tok::kw_where)) {
    SourceLoc whereLoc;
    SmallVector<RequirementRepr, 4> requirements;
    bool firstTypeInComplete;
    parseGenericWhereClause(whereLoc, requirements, firstTypeInComplete,
                            /* AllowLayoutConstraints */ true);
    trailingWhereClause =
      TrailingWhereClause::create(Context, whereLoc, requirements);
  }

  // Parse the closing ')' or ']'.
  SourceLoc rParenLoc;
  if (!consumeIf(ClosingBrace, rParenLoc)) {
    if (ClosingBrace == tok::r_paren)
      diagnose(lParenLoc, diag::attr_expected_rparen, AttrName,
             /*DeclModifier=*/false);
    else if (ClosingBrace == tok::r_square)
      diagnose(lParenLoc, diag::attr_expected_rparen, AttrName,
             /*DeclModifier=*/false);
    return false;
  }
  // Not exported by default.
  if (!exported.hasValue())
    exported = false;
  // Full specialization by default.
  if (!kind.hasValue())
    kind = SpecializeAttr::SpecializationKind::Full;

  if (DiscardAttribute) {
    Attr = nullptr;
    return false;
  }
  // Store the attribute.
  Attr = SpecializeAttr::create(Context, AtLoc, SourceRange(Loc, rParenLoc),
                                trailingWhereClause, exported.getValue(),
                                kind.getValue());
  return true;
}

ParserResult<ImplementsAttr>
Parser::parseImplementsAttribute(SourceLoc AtLoc, SourceLoc Loc) {
  StringRef AttrName = "_implements";
  ParserStatus Status;

  if (Tok.isNot(tok::l_paren)) {
    diagnose(Loc, diag::attr_expected_lparen, AttrName,
             /*DeclModifier=*/false);
    Status.setIsParseError();
    return Status;
  }

  SourceLoc lParenLoc = consumeToken();

  ParserResult<TypeRepr> ProtocolType = parseType();
  Status |= ProtocolType;

  if (!(Status.shouldStopParsing() || consumeIf(tok::comma))) {
    diagnose(Tok.getLoc(), diag::attr_expected_comma, AttrName,
             /*DeclModifier=*/false);
    Status.setIsParseError();
  }

  DeclNameLoc MemberNameLoc;
  DeclName MemberName;
  if (!Status.shouldStopParsing()) {
    MemberName =
      parseUnqualifiedDeclName(/*afterDot=*/false, MemberNameLoc,
                               diag::attr_implements_expected_member_name,
                               /*allowOperators=*/true,
                               /*allowZeroArgCompoundNames=*/true);
    if (!MemberName) {
      Status.setIsParseError();
    }
  }

  if (Status.isError()) {
    skipUntil(tok::r_paren);
  }

  SourceLoc rParenLoc;
  if (!consumeIf(tok::r_paren, rParenLoc)) {
    diagnose(lParenLoc, diag::attr_expected_rparen, AttrName,
             /*DeclModifier=*/false);
    Status.setIsParseError();
  }

  if (Status.isError()) {
    return Status;
  }

  return ParserResult<ImplementsAttr>(
    ImplementsAttr::create(Context, AtLoc, SourceRange(Loc, rParenLoc),
                           ProtocolType.get(), MemberName, MemberNameLoc));
}

bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
                                   DeclAttrKind DK) {
  // Ok, it is a valid attribute, eat it, and then process it.
  StringRef AttrName = Tok.getText();
  SourceLoc Loc = consumeToken();
  bool DiscardAttribute = false;

  // Diagnose duplicated attributes.
  const DeclAttribute *DuplicateAttribute = nullptr;
  if (!DeclAttribute::allowMultipleAttributes(DK))
    if ((DuplicateAttribute = Attributes.getAttribute(DK))) {
      // Delay issuing the diagnostic until we parse the attribute.
      DiscardAttribute = true;
    }
 
  // If this is a SIL-only attribute, reject it.
  if ((DeclAttribute::getOptions(DK) & DeclAttribute::SILOnly) != 0 &&
      !isInSILMode()) {
    diagnose(Loc, diag::only_allowed_in_sil, AttrName);
    DiscardAttribute = true;
  }  

  // Filled in during parsing.  If there is a duplicate
  // diagnostic this can be used for better error presentation.
  SourceRange AttrRange;


  // Check 'Tok', return false if ':' or '=' cannot be found.
  // Complain if '=' is found and suggest replacing it with ": ".
  auto findAttrValueDelimiter = [&]() -> bool {
    if (!Tok.is(tok::colon)) {
      if (!Tok.is(tok::equal))
        return false;

      diagnose(Tok.getLoc(), diag::replace_equal_with_colon_for_value)
        .fixItReplace(Tok.getLoc(), ": ");
    }
    return true;
  };

  switch (DK) {
  case DAK_Count:
    llvm_unreachable("DAK_Count should not appear in parsing switch");

  case DAK_AutoClosure: {
    // If we don't have "(escaping", it's just a bare @autoclosure.
    if (Tok.isNot(tok::l_paren) || peekToken().getText() != "escaping") {
      if (!DiscardAttribute)
        Attributes.add(new (Context) AutoClosureAttr(AtLoc, Loc,
                                                     /*escaping=*/false));
      break;
    }

    // Consume the '('.
    SourceLoc lParenLoc = consumeToken(tok::l_paren);

    // Consume the 'escaping'.
    (void)consumeToken();

    // Parse the closing ')'.
    SourceLoc rParenLoc;
    parseMatchingToken(tok::r_paren, rParenLoc,
                       diag::attr_autoclosure_expected_r_paren,
                       lParenLoc);

    // Add the attribute.
    if (!DiscardAttribute)
      Attributes.add(new (Context) AutoClosureAttr(AtLoc,
                                                   SourceRange(Loc, rParenLoc),
                                                   /*escaping=*/true));

    break;
  }

  case DAK_RawDocComment:
  case DAK_ObjCBridged:
  case DAK_ObjCRuntimeName:
  case DAK_RestatedObjCConformance:
  case DAK_SynthesizedProtocol:
    llvm_unreachable("virtual attributes should not be parsed "
                     "by attribute parsing code");
  case DAK_SetterAccessibility:
    llvm_unreachable("handled by DAK_Accessibility");

#define SIMPLE_DECL_ATTR(_, CLASS, ...) \
  case DAK_##CLASS: \
    if (!DiscardAttribute) \
      Attributes.add(new (Context) CLASS##Attr(AtLoc, Loc)); \
    break;
#include "swift/AST/Attr.def"

  case DAK_Effects: {
    if (!consumeIf(tok::l_paren)) {
      diagnose(Loc, diag::attr_expected_lparen, AttrName,
               DeclAttribute::isDeclModifier(DK));      return false;
    }

    if (Tok.isNot(tok::identifier)) {
      diagnose(Loc, diag::effects_attribute_expect_option, AttrName);
      return false;
    }

    EffectsKind kind;
    if (Tok.getText() == "readonly")
      kind = EffectsKind::ReadOnly;
    else if (Tok.getText() == "readnone")
      kind = EffectsKind::ReadNone;
    else if (Tok.getText() == "readwrite")
      kind = EffectsKind::ReadWrite;
    else {
      diagnose(Loc, diag::effects_attribute_unknown_option,
               Tok.getText(), AttrName);
      return false;
    }
    AttrRange = SourceRange(Loc, Tok.getRange().getStart());
    consumeToken(tok::identifier);

    if (!consumeIf(tok::r_paren)) {
      diagnose(Loc, diag::attr_expected_rparen, AttrName,
               DeclAttribute::isDeclModifier(DK));
      return false;
    }

    if (!DiscardAttribute)
      Attributes.add(new (Context) EffectsAttr(AtLoc, AttrRange, kind));
    break;
  }

  case DAK_Inline: {
    if (!consumeIf(tok::l_paren)) {
      diagnose(Loc, diag::attr_expected_lparen, AttrName,
               DeclAttribute::isDeclModifier(DK));
      return false;
    }

    if (Tok.isNot(tok::identifier)) {
      diagnose(Loc, diag::inline_attribute_expect_option, AttrName);
      return false;
    }

    InlineKind kind;
    if (Tok.getText() == "never")
      kind = InlineKind::Never;
    else if (Tok.getText() == "__always")
      kind = InlineKind::Always;
    else {
      diagnose(Loc, diag::inline_attribute_unknown_option,
               Tok.getText(), AttrName);
      return false;
    }
    consumeToken(tok::identifier);
    AttrRange = SourceRange(Loc, Tok.getRange().getStart());
    
    if (!consumeIf(tok::r_paren)) {
      diagnose(Loc, diag::attr_expected_rparen, AttrName,
               DeclAttribute::isDeclModifier(DK));
      return false;
    }

    if (!DiscardAttribute)
      Attributes.add(new (Context) InlineAttr(AtLoc, AttrRange, kind));

    break;
  }

  case DAK_Ownership: {
    // Handle weak/unowned/unowned(unsafe).
    Ownership Kind = AttrName == "weak" ? Ownership::Weak : Ownership::Unowned;
    SourceLoc EndLoc = Loc;

    if (Kind == Ownership::Unowned && Tok.is(tok::l_paren)) {
      // Parse an optional specifier after unowned.
      SourceLoc lp = consumeToken(tok::l_paren);
      if (Tok.is(tok::identifier) && Tok.getText() == "safe") {
        consumeToken();
      } else if (Tok.is(tok::identifier) && Tok.getText() == "unsafe") {
        consumeToken();
        Kind = Ownership::Unmanaged;
      } else {
        diagnose(Tok, diag::attr_unowned_invalid_specifier);
        consumeIf(tok::identifier);
      }

      SourceLoc rp;
      parseMatchingToken(tok::r_paren, rp, diag::attr_unowned_expected_rparen,
                         lp);
      EndLoc = rp;
    }

    if (!DiscardAttribute)
      Attributes.add(new (Context) OwnershipAttr(SourceRange(Loc, EndLoc),
                                                 Kind));
    break;
  }

  case DAK_Accessibility: {

    // Diagnose using accessibility in a local scope, which isn't meaningful.
    if (CurDeclContext->isLocalContext()) {
      diagnose(Loc, diag::attr_only_at_non_local_scope, AttrName);
    }

    Accessibility access = llvm::StringSwitch<Accessibility>(AttrName)
      .Case("private", Accessibility::Private)
      .Case("fileprivate", Accessibility::FilePrivate)
      .Case("internal", Accessibility::Internal)
      .Case("public", Accessibility::Public)
      .Case("open", Accessibility::Open);

    if (!consumeIf(tok::l_paren)) {
      // Normal accessibility attribute.
      AttrRange = Loc;
      DuplicateAttribute = Attributes.getAttribute<AccessibilityAttr>();
      if (!DuplicateAttribute)
        Attributes.add(new (Context) AccessibilityAttr(AtLoc, Loc, access));
      break;
    }

    // Parse the subject.
    if (Tok.isContextualKeyword("set")) {
      consumeToken();
    } else {
      diagnose(Loc, diag::attr_accessibility_expected_set, AttrName);
      // Minimal recovery: if there's a single token and then an r_paren,
      // consume them both. If there's just an r_paren, consume that.
      if (!consumeIf(tok::r_paren)) {
        if (Tok.isNot(tok::l_paren) && peekToken().is(tok::r_paren)) {
          consumeToken();
          consumeToken(tok::r_paren);
        }
      }
      return false;
    }

    AttrRange = SourceRange(Loc, Tok.getLoc());

    if (!consumeIf(tok::r_paren)) {
      diagnose(Loc, diag::attr_expected_rparen, AttrName,
               DeclAttribute::isDeclModifier(DK));
      return false;
    }

    DuplicateAttribute = Attributes.getAttribute<SetterAccessibilityAttr>();
    if (!DuplicateAttribute) {
      Attributes.add(new (Context) SetterAccessibilityAttr(AtLoc, AttrRange,
                                                           access));
    }

    break;
  }

  case DAK_CDecl:
  case DAK_SILGenName: {
    if (!consumeIf(tok::l_paren)) {
      diagnose(Loc, diag::attr_expected_lparen, AttrName,
               DeclAttribute::isDeclModifier(DK));
      return false;
    }

    if (Tok.isNot(tok::string_literal)) {
      diagnose(Loc, diag::attr_expected_string_literal, AttrName);
      return false;
    }

    Optional<StringRef> AsmName =
      getStringLiteralIfNotInterpolated(*this, Loc, Tok, AttrName);

    consumeToken(tok::string_literal);

    if (AsmName.hasValue())
      AttrRange = SourceRange(Loc, Tok.getRange().getStart());
    else
      DiscardAttribute = true;

    if (!consumeIf(tok::r_paren)) {
      diagnose(Loc, diag::attr_expected_rparen, AttrName,
               DeclAttribute::isDeclModifier(DK));
      return false;
    }

    // Diagnose using @_silgen_name in a local scope.  These don't
    // actually work.
    if (CurDeclContext->isLocalContext()) {
      // Emit an error, but do not discard the attribute.  This enables
      // better recovery in the parser.
      diagnose(Loc, diag::attr_only_at_non_local_scope, AttrName);
    }

    if (!DiscardAttribute) {
      if (DK == DAK_SILGenName)
        Attributes.add(new (Context) SILGenNameAttr(AsmName.getValue(), AtLoc,
                                                AttrRange, /*Implicit=*/false));
      else if (DK == DAK_CDecl)
        Attributes.add(new (Context) CDeclAttr(AsmName.getValue(), AtLoc,
                                               AttrRange, /*Implicit=*/false));
      else
        llvm_unreachable("out of sync with switch");
    }

    break;
  }
  
  case DAK_Alignment: {
    if (!consumeIf(tok::l_paren)) {
      diagnose(Loc, diag::attr_expected_lparen, AttrName,
               DeclAttribute::isDeclModifier(DK));
      return false;
    }
    
    if (Tok.isNot(tok::integer_literal)) {
      diagnose(Loc, diag::alignment_must_be_positive_integer);
      return false;
    }
    
    StringRef alignmentText = Tok.getText();
    unsigned alignmentValue;
    if (alignmentText.getAsInteger(0, alignmentValue)) {
      diagnose(Loc, diag::alignment_must_be_positive_integer);
      return false;
    }
    
    consumeToken(tok::integer_literal);
    
    auto range = SourceRange(Loc, Tok.getRange().getStart());
    
    if (!consumeIf(tok::r_paren)) {
      diagnose(Loc, diag::attr_expected_rparen, AttrName,
               DeclAttribute::isDeclModifier(DK));
      return false;
    }

    Attributes.add(new (Context) AlignmentAttr(alignmentValue, AtLoc, range,
                                               /*implicit*/ false));
    
    break;
  }
  
  case DAK_SwiftNativeObjCRuntimeBase: {
    if (!consumeIf(tok::l_paren)) {
      diagnose(Loc, diag::attr_expected_lparen, AttrName,
               DeclAttribute::isDeclModifier(DK));
      return false;
    }

    if (Tok.isNot(tok::identifier)) {
      diagnose(Loc, diag::swift_native_objc_runtime_base_must_be_identifier);
      return false;
    }
    
    Identifier name = Context.getIdentifier(Tok.getText());
    
    consumeToken(tok::identifier);
    
    auto range = SourceRange(Loc, Tok.getRange().getStart());

    if (!consumeIf(tok::r_paren)) {
      diagnose(Loc, diag::attr_expected_rparen, AttrName,
               DeclAttribute::isDeclModifier(DK));
      return false;
    }
    
    Attributes.add(new (Context) SwiftNativeObjCRuntimeBaseAttr(name,
                                            AtLoc, range, /*implicit*/ false));
    break;
  }
  
  case DAK_Semantics: {
    if (!consumeIf(tok::l_paren)) {
      diagnose(Loc, diag::attr_expected_lparen, AttrName,
               DeclAttribute::isDeclModifier(DK));
      return false;
    }

    if (Tok.isNot(tok::string_literal)) {
      diagnose(Loc, diag::attr_expected_string_literal, AttrName);
      return false;
    }

    auto Value = getStringLiteralIfNotInterpolated(*this, Loc, Tok, AttrName);

    consumeToken(tok::string_literal);

    if (Value.hasValue())
      AttrRange = SourceRange(Loc, Tok.getRange().getStart());
    else
      DiscardAttribute = true;

    if (!consumeIf(tok::r_paren)) {
      diagnose(Loc, diag::attr_expected_rparen, AttrName,
               DeclAttribute::isDeclModifier(DK));
      return false;
    }

    // Diagnose using @_semantics in a local scope.  These don't
    // actually work.
    if (CurDeclContext->isLocalContext()) {
      // Emit an error, but do not discard the attribute.  This enables
      // better recovery in the parser.
      diagnose(Loc, diag::attr_only_at_non_local_scope, AttrName);
    }

    if (!DiscardAttribute)
      Attributes.add(new (Context) SemanticsAttr(Value.getValue(), AtLoc,
                                                 AttrRange,
                                                 /*Implicit=*/false));
    break;
  }

  case DAK_Available: {
    if (!consumeIf(tok::l_paren)) {
      diagnose(Loc, diag::attr_expected_lparen, AttrName,
               DeclAttribute::isDeclModifier(DK));
      return false;
    }

    // platform:
    //   *
    //   identifier
    if (!Tok.is(tok::identifier) &&
        !(Tok.isAnyOperator() && Tok.getText() == "*")) {
      if (Tok.is(tok::code_complete) && CodeCompletion) {
        CodeCompletion->completeDeclAttrParam(DAK_Available, 0);
        consumeToken(tok::code_complete);
      }
      diagnose(Tok.getLoc(), diag::attr_availability_platform, AttrName)
        .highlight(SourceRange(Tok.getLoc()));
      consumeIf(tok::r_paren);
      return false;
    }

    // Delay processing of platform until later, after we have
    // parsed more of the attribute.
    StringRef Platform = Tok.getText();

    if (Platform != "*" &&
        peekToken().isAny(tok::integer_literal, tok::floating_literal)) {
      // We have the short form of available: @available(iOS 8.0.1, *)
      SmallVector<AvailabilitySpec *, 5> Specs;
      ParserStatus Status = parseAvailabilitySpecList(Specs);

      if (Status.isError())
        return false;

      AttrRange = SourceRange(Loc, Tok.getLoc());
      // For each platform version spec in the spec list, create an
      // implicit AvailableAttr for the platform with the introduced
      // version from the spec. For example, if we have
      //   @available(iOS 8.0, OSX 10.10, *):
      // we will synthesize:
      //  @available(iOS, introduced: 8.0)
      //  @available(OSX, introduced: 10.10)
      //
      // Similarly if we have a language version spec in the spec
      // list, create an implicit AvailableAttr with the specified
      // version as the introduced argument. For example, if we have
      //   @available(swift 3.1)
      // we will synthesize
      //   @available(swift, introduced: 3.1)

      for (auto *Spec : Specs) {
        PlatformKind Platform;
        clang::VersionTuple Version;
        SourceRange VersionRange;
        PlatformAgnosticAvailabilityKind PlatformAgnostic;

        if (auto *PlatformVersionSpec =
            dyn_cast<PlatformVersionConstraintAvailabilitySpec>(Spec)) {
          Platform = PlatformVersionSpec->getPlatform();
          Version = PlatformVersionSpec->getVersion();
          VersionRange = PlatformVersionSpec->getVersionSrcRange();
          PlatformAgnostic = PlatformAgnosticAvailabilityKind::None;

        } else if (auto *LanguageVersionSpec =
                   dyn_cast<LanguageVersionConstraintAvailabilitySpec>(Spec)) {
          Platform = PlatformKind::none;
          Version = LanguageVersionSpec->getVersion();
          VersionRange = LanguageVersionSpec->getVersionSrcRange();
          PlatformAgnostic =
            PlatformAgnosticAvailabilityKind::SwiftVersionSpecific;

        } else {
          continue;
        }

        Attributes.add(new (Context)
                       AvailableAttr(AtLoc, AttrRange,
                                     Platform,
                                     /*Message=*/StringRef(),
                                     /*Rename=*/StringRef(),
                                     /*Introduced=*/Version,
                                     /*IntroducedRange=*/VersionRange,
                                     /*Deprecated=*/clang::VersionTuple(),
                                     /*DeprecatedRange=*/SourceRange(),
                                     /*Obsoleted=*/clang::VersionTuple(),
                                     /*ObsoletedRange=*/SourceRange(),
                                     PlatformAgnostic,
                                     /*Implicit=*/true));
      }

      if (!consumeIf(tok::r_paren)) {
        diagnose(Tok.getLoc(), diag::attr_expected_rparen, AttrName,
                 DeclAttribute::isDeclModifier(DK));
        return false;
      }

      break;
    }

    consumeToken();

    StringRef Message, Renamed;
    clang::VersionTuple Introduced, Deprecated, Obsoleted;
    SourceRange IntroducedRange, DeprecatedRange, ObsoletedRange;
    auto PlatformAgnostic = PlatformAgnosticAvailabilityKind::None;
    bool AnyAnnotations = false;
    int ParamIndex = 0;

    while (consumeIf(tok::comma)) {
      AnyAnnotations = true;
      StringRef ArgumentKindStr = Tok.getText();
      ParamIndex ++;

      enum {
        IsMessage, IsRenamed,
        IsIntroduced, IsDeprecated, IsObsoleted,
        IsUnavailable,
        IsInvalid
      } ArgumentKind = IsInvalid;

      if (Tok.is(tok::identifier)) {
        ArgumentKind =
          llvm::StringSwitch<decltype(ArgumentKind)>(ArgumentKindStr)
            .Case("message", IsMessage)
            .Case("renamed", IsRenamed)
            .Case("introduced", IsIntroduced)
            .Case("deprecated", IsDeprecated)
            .Case("obsoleted", IsObsoleted)
            .Case("unavailable", IsUnavailable)
            .Default(IsInvalid);
      }

      if (ArgumentKind == IsInvalid) {
        DiscardAttribute = true;
        diagnose(Tok.getLoc(), diag::attr_availability_expected_option,
                 AttrName)
          .highlight(SourceRange(Tok.getLoc()));
        if (Tok.is(tok::code_complete) && CodeCompletion) {
          CodeCompletion->completeDeclAttrParam(DAK_Available, ParamIndex);
          consumeToken(tok::code_complete);
        } else {
          consumeIf(tok::identifier);
        }
        break;
      }

      consumeToken();

      switch (ArgumentKind) {
      case IsMessage:
      case IsRenamed: {
        // Items with string arguments.
        if (findAttrValueDelimiter()) {
          consumeToken();
        } else {
          diagnose(Tok, diag::attr_availability_expected_equal,
                   AttrName, ArgumentKindStr);
          DiscardAttribute = true;
          if (peekToken().isAny(tok::r_paren, tok::comma))
            consumeToken();
          continue;
        }

        if (!Tok.is(tok::string_literal)) {
          diagnose(Loc, diag::attr_expected_string_literal, AttrName);
          DiscardAttribute = true;
          if (peekToken().isAny(tok::r_paren, tok::comma))
            consumeToken();
          continue;
        }

        auto Value =
          getStringLiteralIfNotInterpolated(*this, Loc, Tok, ArgumentKindStr);
        consumeToken();
        if (!Value) {
          DiscardAttribute = true;
          continue;
        }

        if (ArgumentKind == IsMessage) {
          Message = Value.getValue();
        } else {
          ParsedDeclName parsedName = parseDeclName(Value.getValue());
          if (!parsedName) {
            diagnose(Loc, diag::attr_availability_invalid_renamed, AttrName);
            DiscardAttribute = true;
            continue;
          }
          Renamed = Value.getValue();
        }
        break;
      }

      case IsDeprecated:
        if (!findAttrValueDelimiter()) {
          if (PlatformAgnostic != PlatformAgnosticAvailabilityKind::None) {
            diagnose(Tok, diag::attr_availability_unavailable_deprecated,
                     AttrName);
          }

          PlatformAgnostic = PlatformAgnosticAvailabilityKind::Deprecated;
          break;
        }
        LLVM_FALLTHROUGH;

      case IsIntroduced:
      case IsObsoleted: {
        // Items with version arguments.
        if (findAttrValueDelimiter()) {
          consumeToken();
        } else {
          diagnose(Tok, diag::attr_availability_expected_equal,
                   AttrName, ArgumentKindStr);
          DiscardAttribute = true;
          if (peekToken().isAny(tok::r_paren, tok::comma))
            consumeToken();
          continue;
        }

        auto &VersionArg = (ArgumentKind == IsIntroduced) ? Introduced :
                           (ArgumentKind == IsDeprecated) ? Deprecated :
                                                            Obsoleted;

        auto &VersionRange = (ArgumentKind == IsIntroduced) ? IntroducedRange :
                             (ArgumentKind == IsDeprecated) ? DeprecatedRange :
                                                              ObsoletedRange;

        if (parseVersionTuple(
                VersionArg, VersionRange,
                Diagnostic(diag::attr_availability_expected_version,
                           AttrName))) {
          DiscardAttribute = true;
          if (peekToken().isAny(tok::r_paren, tok::comma))
            consumeToken();
        }

        break;
      }

      case IsUnavailable:
        if (PlatformAgnostic != PlatformAgnosticAvailabilityKind::None) {
          diagnose(Tok, diag::attr_availability_unavailable_deprecated,
                   AttrName);
        }

        PlatformAgnostic = PlatformAgnosticAvailabilityKind::Unavailable;
        break;

      case IsInvalid:
        llvm_unreachable("handled above");
      }
    }

    if (!AnyAnnotations) {
      diagnose(Tok.getLoc(), diag::attr_expected_comma, AttrName,
               DeclAttribute::isDeclModifier(DK));
      DiscardAttribute = true;
    }

    AttrRange = SourceRange(Loc, Tok.getLoc());

    if (!consumeIf(tok::r_paren)) {
      if (!DiscardAttribute) {
        diagnose(Tok.getLoc(), diag::attr_expected_rparen, AttrName,
                 DeclAttribute::isDeclModifier(DK));
      }
      return false;
    }

    if (!DiscardAttribute) {
      auto PlatformKind = platformFromString(Platform);

      // Treat 'swift' as a valid version-qualifying token, when
      // at least some versions were mentioned and no other
      // platform-agnostic availability spec has been provided.
      bool SomeVersion = (!Introduced.empty() ||
                          !Deprecated.empty() ||
                          !Obsoleted.empty());
      if (!PlatformKind.hasValue() &&
          Platform == "swift" &&
          SomeVersion &&
          PlatformAgnostic == PlatformAgnosticAvailabilityKind::None) {
        PlatformKind = PlatformKind::none;
        PlatformAgnostic =
          PlatformAgnosticAvailabilityKind::SwiftVersionSpecific;
      }

      if (PlatformKind.hasValue()) {
        Attributes.add(new (Context)
                       AvailableAttr(AtLoc, AttrRange,
                                        PlatformKind.getValue(),
                                        Message, Renamed,
                                        Introduced, IntroducedRange,
                                        Deprecated, DeprecatedRange,
                                        Obsoleted, ObsoletedRange,
                                        PlatformAgnostic,
                                        /*Implicit=*/false));
      } else {
        // Not a known platform. Just drop the attribute.
        diagnose(Loc, diag::attr_availability_unknown_platform,
                 Platform, AttrName);
        return false;
      }
    }
    break;
  }

  case DAK_ObjC: {
    // Unnamed @objc attribute.
    if (Tok.isNot(tok::l_paren)) {
      auto attr = ObjCAttr::createUnnamed(Context, AtLoc, Loc);
      Attributes.add(attr);
      break;
    }

    // Parse the leading '('.
    SourceLoc LParenLoc = consumeToken(tok::l_paren);

    // Parse the names, with trailing colons (if there are present).
    SmallVector<Identifier, 4> Names;
    SmallVector<SourceLoc, 4> NameLocs;
    bool sawColon = false;
    while (true) {
      // Empty selector piece.
      if (Tok.is(tok::colon)) {
        Names.push_back(Identifier());
        NameLocs.push_back(Tok.getLoc());
        sawColon = true;
        consumeToken();
        continue;
      }

      // Name.
      if (Tok.is(tok::identifier) || Tok.isKeyword()) {
        Names.push_back(Context.getIdentifier(Tok.getText()));
        NameLocs.push_back(Tok.getLoc());
        consumeToken();

        // If we have a colon, consume it.
        if (Tok.is(tok::colon)) {
          consumeToken();
          sawColon = true;
          continue;
        } 
        
        // If we see a closing parentheses, we're done.
        if (Tok.is(tok::r_paren)) {
          // If we saw more than one identifier, there's a ':'
          // missing here. Complain and pretend we saw it.
          if (Names.size() > 1) {
            diagnose(Tok, diag::attr_objc_missing_colon)
              .fixItInsertAfter(NameLocs.back(), ":");
            sawColon = true;
          }

          break;
        }

        // If we see another identifier or keyword, complain about
        // the missing colon and keep going.
        if (Tok.is(tok::identifier) || Tok.isKeyword()) {
          diagnose(Tok, diag::attr_objc_missing_colon)
            .fixItInsertAfter(NameLocs.back(), ":");
          sawColon = true;
          continue;
        }

        // We don't know what happened. Break out.
        break;
      }

      break;
    }
    
    // Parse the matching ')'.
    SourceLoc RParenLoc;
    bool Invalid = parseMatchingToken(tok::r_paren, RParenLoc,
                                      diag::attr_objc_expected_rparen,
                                      LParenLoc);

    ObjCAttr *attr;
    if (Names.empty()) {
      // When there are no names, recover as if there were no parentheses.
      if (!Invalid)
        diagnose(LParenLoc, diag::attr_objc_empty_name);
      attr = ObjCAttr::createUnnamed(Context, AtLoc, Loc);
    } else if (!sawColon) {
      // When we didn't see a colon, this is a nullary name.
      assert(Names.size() == 1 && "Forgot to set sawColon?");
      attr = ObjCAttr::createNullary(Context, AtLoc, Loc, LParenLoc,
                                     NameLocs.front(), Names.front(),
                                     RParenLoc);
    } else {
      // When we did see a colon, this is a selector.
      attr = ObjCAttr::createSelector(Context, AtLoc, Loc, LParenLoc,
                                      NameLocs, Names, RParenLoc);
    }
    Attributes.add(attr);
    break;
  }

  case DAK_Specialize: {
    if (Tok.isNot(tok::l_paren)) {
      diagnose(Loc, diag::attr_expected_lparen, AttrName,
               DeclAttribute::isDeclModifier(DK));
      return false;
    }
    SpecializeAttr *Attr;
    if (!parseSpecializeAttribute(tok::r_paren, AtLoc, Loc, Attr))
      return false;

    Attributes.add(Attr);
    break;
    }

  case DAK_Implements: {
    ParserResult<ImplementsAttr> Attr = parseImplementsAttribute(AtLoc, Loc);
    if (Attr.isNonNull()) {
      Attributes.add(Attr.get());
    }
    break;
  }
  }

  if (DuplicateAttribute) {
    diagnose(Loc, diag::duplicate_attribute, DeclAttribute::isDeclModifier(DK))
      .highlight(AttrRange);
    diagnose(DuplicateAttribute->getLocation(), diag::previous_attribute, DeclAttribute::isDeclModifier(DK))
      .highlight(DuplicateAttribute->getRange());
  }

    // If this is a decl modifier spelled with an @, emit an error and remove it
  // with a fixit.
  if (AtLoc.isValid() && DeclAttribute::isDeclModifier(DK))
    diagnose(AtLoc, diag::cskeyword_not_attribute, AttrName).fixItRemove(AtLoc);
  
  return false;
}

bool Parser::parseVersionTuple(clang::VersionTuple &Version,
                               SourceRange &Range,
                               const Diagnostic &D) {
  // A version number is either an integer (8), a float (8.1), or a
  // float followed by a dot and an integer (8.1.0).
  if (!Tok.isAny(tok::integer_literal, tok::floating_literal)) {
    diagnose(Tok, D);
    return true;
  }

  SourceLoc StartLoc = Tok.getLoc();
  
  if (Tok.is(tok::integer_literal)) {
    unsigned major = 0;
    if (Tok.getText().getAsInteger(10, major)) {
      // Maybe the literal was in hex. Reject that.
      diagnose(Tok, D);
      consumeToken();
      return true;
    }
    Version = clang::VersionTuple(major);
    Range = SourceRange(StartLoc, Tok.getLoc());
    consumeToken();
    return false;
  }

  unsigned major = 0, minor = 0;
  StringRef majorPart, minorPart;
  std::tie(majorPart, minorPart) = Tok.getText().split('.');
  if (majorPart.getAsInteger(10, major) || minorPart.getAsInteger(10, minor)) {
    // Reject things like 0.1e5 and hex literals.
    diagnose(Tok, D);
    consumeToken();
    return true;
  }

  Range = SourceRange(StartLoc, Tok.getLoc());
  consumeToken();
  
  if (consumeIf(tok::period)) {
    unsigned micro = 0;
    if (!Tok.is(tok::integer_literal) ||
        Tok.getText().getAsInteger(10, micro)) {
      // Reject things like 0.1e5 and hex literals.
      diagnose(Tok, D);
      if (Tok.is(tok::integer_literal) ||
          peekToken().isAny(tok::r_paren, tok::comma))
        consumeToken();
      return true;
    }
    
    Range = SourceRange(StartLoc, Tok.getLoc());
    consumeToken();
    
    Version = clang::VersionTuple(major, minor, micro);
  } else {
    Version = clang::VersionTuple(major, minor);
  }

  return false;
}

/// \verbatim
///   attribute:
///     '_silgen_name' '(' identifier ')'
///     'semantics' '(' identifier ')'
///     'infix' '=' numeric_constant
///     'unary'
///     'stdlib'
///     'weak'
///     'inout'
///     'unowned'
///     'unowned' '(' 'safe' ')'
///     'unowned' '(' 'unsafe' ')'
///     'noreturn'
///     'optional'
///     'mutating'
///     ( 'private' | 'internal' | 'public' )
///     ( 'private' | 'internal' | 'public' ) '(' 'set' ')'
///     'requires_stored_property_inits'
/// \endverbatim
///
/// Note that various attributes (like mutating, weak, and unowned) are parsed
/// but rejected since they have context-sensitive keywords.
///
bool Parser::parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc) {
  // If this not an identifier, the attribute is malformed.
  if (Tok.isNot(tok::identifier) &&
      Tok.isNot(tok::kw_in) &&
      Tok.isNot(tok::kw_inout)) {
    diagnose(Tok, diag::expected_attribute_name);
    return true;
  }

  // If the attribute follows the new representation, switch
  // over to the alternate parsing path.
  DeclAttrKind DK = DeclAttribute::getAttrKindFromString(Tok.getText());

  if (DK == DAK_Count && Tok.getText() == "availability") {
    // We renamed @availability to @available, so if we see the former,
    // treat it as the latter and emit a Fix-It.
    DK = DAK_Available;
    diagnose(Tok, diag::attr_availability_renamed)
        .fixItReplace(Tok.getLoc(), "available");
  }


  if (DK == DAK_Count && Tok.getText() == "warn_unused_result") {
    // The behavior created by @warn_unused_result is now the default. Emit a
    // Fix-It to remove.
    SourceLoc attrLoc = consumeToken();

    // @warn_unused_result with no arguments.
    if (Tok.isNot(tok::l_paren)) {
      diagnose(AtLoc, diag::attr_warn_unused_result_removed)
        .fixItRemove(SourceRange(AtLoc, attrLoc));

      return false;
    }

    // @warn_unused_result with arguments.
    SourceLoc lParenLoc = consumeToken();
    skipUntil(tok::r_paren);

    // Parse the closing ')'.
    SourceLoc rParenLoc;
    if (Tok.isNot(tok::r_paren)) {
      parseMatchingToken(tok::r_paren, rParenLoc,
                         diag::attr_warn_unused_result_expected_rparen,
                         lParenLoc);
    }
    if (Tok.is(tok::r_paren)) {
      rParenLoc = consumeToken();
    }

    diagnose(AtLoc, diag::attr_warn_unused_result_removed)
      .fixItRemove(SourceRange(AtLoc, rParenLoc));

    return false;
  }

  // FIXME: Remove this after Swift 4.
  if (DK == DAK_Count && Tok.getText() == "NSKeyedArchiverClassName") {
    auto activeDiag = diagnose(Tok,diag::attr_nskeyedarchiverclassname_removed);
    activeDiag.fixItReplace(Tok.getLoc(), "objc");
    consumeToken();
    SourceLoc lParenLoc;
    if (consumeIf(tok::l_paren, lParenLoc)) {
      if (Tok.is(tok::string_literal)) {
        activeDiag.fixItRemoveChars(Tok.getLoc(),
                                    Tok.getLoc().getAdvancedLoc(1));
        SourceLoc endLoc = Tok.getLoc().getAdvancedLoc(Tok.getLength());
        activeDiag.fixItRemoveChars(endLoc.getAdvancedLoc(-1), endLoc);
      }
      skipUntil(tok::r_paren);
      SourceLoc rParenLoc;
      parseMatchingToken(tok::r_paren, rParenLoc,
                         diag::attr_warn_unused_result_expected_rparen,
                         lParenLoc);
    }
    return false;
  }

  // FIXME: Remove this after Swift 4.
  if (DK == DAK_Count &&
      Tok.getText() == "NSKeyedArchiverEncodeNonGenericSubclassesOnly") {
    diagnose(Tok,
             diag::attr_nskeyedarchiverencodenongenericsubclassesonly_removed)
      .fixItRemove(SourceRange(AtLoc, Tok.getLoc()));
    consumeToken();
    return false;
  }

  if (DK != DAK_Count && !DeclAttribute::shouldBeRejectedByParser(DK))
    return parseNewDeclAttribute(Attributes, AtLoc, DK);

  if (TypeAttributes::getAttrKindFromString(Tok.getText()) != TAK_Count)
    diagnose(Tok, diag::type_attribute_applied_to_decl);
  else
    diagnose(Tok, diag::unknown_attribute, Tok.getText());

  // Recover by eating @foo(...) when foo is not known.
  consumeToken();
  if (Tok.is(tok::l_paren))
    skipSingle();

  return true;
}

bool Parser::canParseTypeAttribute() {
  TypeAttributes attrs; // ignored
  return !parseTypeAttribute(attrs, /*justChecking*/ true);
}

/// \verbatim
///   attribute-type:
///     'noreturn'
/// \endverbatim
///
/// \param justChecking - if true, we're just checking whether we
///   canParseTypeAttribute; don't emit any diagnostics, and there's
///   no need to actually record the attribute
bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) {
  // If this not an identifier, the attribute is malformed.
  if (Tok.isNot(tok::identifier) &&
      // These are keywords that we accept as attribute names.
      Tok.isNot(tok::kw_in) && Tok.isNot(tok::kw_inout)) {
    if (!justChecking)
      diagnose(Tok, diag::expected_attribute_name);
    return true;
  }
  
  // Determine which attribute it is, and diagnose it if unknown.
  TypeAttrKind attr = TypeAttributes::getAttrKindFromString(Tok.getText());

  if (attr == TAK_Count) {
    if (justChecking) return true;

    auto declAttrID = DeclAttribute::getAttrKindFromString(Tok.getText());
    if (declAttrID == DAK_Count) {
      // Not a decl or type attribute.
      diagnose(Tok, diag::unknown_attribute, Tok.getText());
    } else {
      // Otherwise this is a valid decl attribute so they should have put it on
      // the decl instead of the type.

      // If this is the first attribute, and if we are on a simple decl, emit a
      // fixit to move the attribute.  Otherwise, we don't have the location of
      // the @ sign, or we don't have confidence that the fixit will be right.
      if (!Attributes.empty() || StructureMarkers.empty() ||
          StructureMarkers.back().Kind != StructureMarkerKind::Declaration ||
          StructureMarkers.back().Loc.isInvalid() ||
          peekToken().is(tok::equal)) {
        diagnose(Tok, diag::decl_attribute_applied_to_type);
      } else {
        // Otherwise, this is the first type attribute and we know where the
        // declaration is.  Emit the same diagnostic, but include a fixit to
        // move the attribute.  Unfortunately, we don't have enough info to add
        // the attribute to DeclAttributes.
        diagnose(Tok, diag::decl_attribute_applied_to_type)
          .fixItRemove(SourceRange(Attributes.AtLoc, Tok.getLoc()))
          .fixItInsert(StructureMarkers.back().Loc,
                       "@" + Tok.getText().str()+" ");
      }
    }
    
    // Recover by eating @foo(...) when foo is not known.
    consumeToken();
    if (Tok.is(tok::l_paren) && getEndOfPreviousLoc() == Tok.getLoc()) {
      ParserPosition LParenPosition = getParserPosition();
      skipSingle();
      // If we found '->', or 'throws' after paren, it's likely a parameter
      // of function type.
      if (Tok.isAny(tok::arrow, tok::kw_throws, tok::kw_rethrows,
                    tok::kw_throw))
        backtrackToPosition(LParenPosition);
    }
    return true;
  }
  
  // Ok, it is a valid attribute, eat it, and then process it.
  StringRef Text = Tok.getText();
  SourceLoc Loc = consumeToken();

  bool isAutoclosureEscaping = false;
  SourceRange autoclosureEscapingParenRange;
  StringRef conventionName;

  // Handle @autoclosure(escaping)
  if (attr == TAK_autoclosure) {
    // We need to do a bit of lookahead here to make sure we parse a (weird)
    // type like: "@autoclosure (escaping) -> Int" correctly (escaping is the
    // name of a type here).  We also want to support the case where the
    // function type coming up is a typealias, e.g. "@autoclosure (escaping) T".
    if (Tok.is(tok::l_paren) && peekToken().getText() == "escaping") {
      Parser::BacktrackingScope Backtrack(*this);
      consumeToken(tok::l_paren);
      consumeToken(tok::identifier);
      isAutoclosureEscaping =
        Tok.is(tok::r_paren) && peekToken().isNot(tok::arrow);
    }

    if (isAutoclosureEscaping) {
      autoclosureEscapingParenRange.Start = consumeToken(tok::l_paren);
      consumeToken(tok::identifier);
      autoclosureEscapingParenRange.End = consumeToken(tok::r_paren);
    }
  } else if (attr == TAK_convention) {
    SourceLoc LPLoc;
    if (!consumeIfNotAtStartOfLine(tok::l_paren)) {
      if (!justChecking)
        diagnose(Tok, diag::convention_attribute_expected_lparen);
      return true;
    }

    if (Tok.isNot(tok::identifier)) {
      if (!justChecking)
        diagnose(Tok, diag::convention_attribute_expected_name);
      return true;
    }

    conventionName = Tok.getText();
    consumeToken(tok::identifier);

    // Parse the ')'.  We can't use parseMatchingToken if we're in
    // just-checking mode.
    if (justChecking && Tok.isNot(tok::r_paren))
      return true;

    SourceLoc RPLoc;
    parseMatchingToken(tok::r_paren, RPLoc,
                       diag::convention_attribute_expected_rparen,
                       LPLoc);
  }


  // In just-checking mode, we only need to consume the tokens, and we don't
  // want to do any other analysis.
  if (justChecking)
    return false;

  // Diagnose duplicated attributes.
  if (Attributes.has(attr)) {
    diagnose(Loc, diag::duplicate_attribute, /*isModifier=*/false);
    return false;
  }

  // Handle any attribute-specific processing logic.
  switch (attr) {
  default: break;
  case TAK_autoclosure:
    // Handle @autoclosure(escaping)
    if (isAutoclosureEscaping) {
      // @noescape @autoclosure(escaping) makes no sense.
      if (Attributes.has(TAK_noescape)) {
        diagnose(Loc, diag::attr_noescape_conflicts_escaping_autoclosure);
      } else {
        diagnose(Loc, Context.isSwiftVersion3()
                          ? diag::swift3_attr_autoclosure_escaping_deprecated
                          : diag::attr_autoclosure_escaping_deprecated)
            .fixItReplace(autoclosureEscapingParenRange, " @escaping ");
      }
      Attributes.setAttr(TAK_escaping, Loc);
    } else if (Attributes.has(TAK_noescape)) {
      diagnose(Loc, diag::attr_noescape_implied_by_autoclosure);
    }
    break;

  case TAK_noescape:
    // You can't specify @noescape and @escaping together.
    if (Attributes.has(TAK_escaping)) {
      diagnose(Loc, diag::attr_escaping_conflicts_noescape);
      return false;
    }

    // @noescape after @autoclosure is redundant.
    if (Attributes.has(TAK_autoclosure)) {
      diagnose(Loc, diag::attr_noescape_implied_by_autoclosure);
    }

    // @noescape is deprecated and no longer used
    diagnose(Loc, Context.isSwiftVersion3()
                      ? diag::swift3_attr_noescape_deprecated
                      : diag::attr_noescape_deprecated)
        .fixItRemove({Attributes.AtLoc, Loc});

    break;
  case TAK_escaping:
    // You can't specify @noescape and @escaping together.
    if (Attributes.has(TAK_noescape)) {
      diagnose(Loc, diag::attr_escaping_conflicts_noescape);
      return false;
    }
    break;
  case TAK_out:
  case TAK_in:
  case TAK_owned:
  case TAK_unowned_inner_pointer:
  case TAK_guaranteed:
  case TAK_autoreleased:
  case TAK_callee_owned:
  case TAK_callee_guaranteed:
  case TAK_objc_metatype:
    if (!isInSILMode()) {
      diagnose(Loc, diag::only_allowed_in_sil, Text);
      return false;
    }
    break;
    
  // Ownership attributes.
  case TAK_sil_weak:
  case TAK_sil_unowned:
    if (!isInSILMode()) {
      diagnose(Loc, diag::only_allowed_in_sil, Text);
      return false;
    }
      
    if (Attributes.hasOwnership()) {
      diagnose(Loc, diag::duplicate_attribute, /*isModifier*/false);
      return false;
    }
    break;

  // 'inout' attribute.
  case TAK_inout:
    if (!isInSILMode()) {
      diagnose(Loc, diag::inout_not_attribute);
      return false;
    }
    break;
      
  case TAK_opened: {
    if (!isInSILMode()) {
      diagnose(Loc, diag::only_allowed_in_sil, "opened");
      return false;
    }

    // Parse the opened existential ID string in parens
    SourceLoc beginLoc = Tok.getLoc(), idLoc, endLoc;
    if (consumeIfNotAtStartOfLine(tok::l_paren)) {
      if (Tok.is(tok::string_literal)) {
        UUID openedID;
        idLoc = Tok.getLoc();
        auto literalText = Tok.getText().slice(1, Tok.getText().size() - 1);
        llvm::SmallString<UUID::StringBufferSize> text(literalText);
        if (auto openedID = UUID::fromString(text.c_str())) {
          Attributes.OpenedID = openedID;
        } else {
          diagnose(Tok, diag::opened_attribute_id_value);
        }
        consumeToken();
      } else {
        diagnose(Tok, diag::opened_attribute_id_value);
      }
      parseMatchingToken(tok::r_paren, endLoc,
                         diag::opened_attribute_expected_rparen,
                         beginLoc);
    } else {
      diagnose(Tok, diag::opened_attribute_expected_lparen);
    }

    break;
  }

  // Convention attribute.
  case TAK_convention:
    Attributes.convention = conventionName;
    break;
  }

  Attributes.setAttr(attr, Loc);
  return false;
}

/// \verbatim
///   attribute-list:
///     /*empty*/
///     attribute-list-clause attribute-list
///   attribute-list-clause:
///     '@' attribute
/// \endverbatim
bool Parser::parseDeclAttributeList(DeclAttributes &Attributes,
                                    bool &FoundCCToken) {
  FoundCCToken = false;
  while (Tok.is(tok::at_sign)) {
    if (peekToken().is(tok::code_complete)) {
      consumeToken(tok::at_sign);
      consumeToken(tok::code_complete);
      FoundCCToken = true;
      continue;
    }
    SourceLoc AtLoc = consumeToken();
    if (parseDeclAttribute(Attributes, AtLoc))
      return true;
  }
  return false;
}

/// \brief This is the internal implementation of \c parseTypeAttributeList,
/// which we expect to be inlined to handle the common case of an absent
/// attribute list.
///
/// \verbatim
///   attribute-list:
///     /*empty*/
///     attribute-list-clause attribute-list
///     'inout' attribute-list-clause attribute-list
///   attribute-list-clause:
///     '@' attribute
///     '@' attribute attribute-list-clause
/// \endverbatim
bool Parser::parseTypeAttributeListPresent(SourceLoc &InOutLoc,
                                           TypeAttributes &Attributes) {
  while (Tok.is(tok::kw_inout)) {
    if (InOutLoc.isValid())
      diagnose(Tok, diag::parameter_inout_var_let_repeated)
        .fixItRemove(InOutLoc);
    InOutLoc = consumeToken();
  }

  while (Tok.is(tok::at_sign)) {
    if (Attributes.AtLoc.isInvalid())
      Attributes.AtLoc = Tok.getLoc();
    consumeToken();
    if (parseTypeAttribute(Attributes))
      return true;
  }
  
  return false;
}

static bool isStartOfOperatorDecl(const Token &Tok, const Token &Tok2) {
  return Tok.isContextualKeyword("operator") &&
         (Tok2.isContextualKeyword("prefix") ||
          Tok2.isContextualKeyword("postfix") ||
          Tok2.isContextualKeyword("infix"));
}

/// \brief Diagnose issues with fixity attributes, if any.
static void diagnoseOperatorFixityAttributes(Parser &P,
                                             DeclAttributes &Attrs,
                                             const Decl *D) {
  auto isFixityAttr = [](DeclAttribute *attr){
    DeclAttrKind kind = attr->getKind();
    return attr->isValid() && (kind == DAK_Prefix ||
                               kind == DAK_Infix ||
                               kind == DAK_Postfix);
  };
  
  SmallVector<DeclAttribute *, 3> fixityAttrs;
  std::copy_if(Attrs.begin(), Attrs.end(),
               std::back_inserter(fixityAttrs), isFixityAttr);
  std::reverse(fixityAttrs.begin(), fixityAttrs.end());
  
  for (auto it = fixityAttrs.begin(); it != fixityAttrs.end(); ++it) {
    if (it != fixityAttrs.begin()) {
      auto *attr = *it;
      P.diagnose(attr->getLocation(), diag::mutually_exclusive_attrs,
                 attr->getAttrName(), fixityAttrs.front()->getAttrName(),
                 attr->isDeclModifier())
      .fixItRemove(attr->getRange());
      attr->setInvalid();
    }
  }
  
  // Operator declarations must specify a fixity.
  if (auto *OD = dyn_cast<OperatorDecl>(D)) {
    if (fixityAttrs.empty()) {
      P.diagnose(OD->getOperatorLoc(), diag::operator_decl_no_fixity);
    }
  }
  // Infix operator is only allowed on operator declarations, not on func.
  else if (isa<FuncDecl>(D)) {
    if (auto *attr = Attrs.getAttribute<InfixAttr>()) {
      P.diagnose(attr->getLocation(), diag::invalid_infix_on_func)
        .fixItRemove(attr->getLocation());
      attr->setInvalid();
    }
  } else {
    llvm_unreachable("unexpected decl kind?");
  }
}

bool swift::isKeywordPossibleDeclStart(const Token &Tok) {
  switch (Tok.getKind()) {
  case tok::at_sign:
  case tok::kw_associatedtype:
  case tok::kw_case:
  case tok::kw_class:
  case tok::kw_deinit:
  case tok::kw_enum:
  case tok::kw_extension:
  case tok::kw_fileprivate:
  case tok::kw_func:
  case tok::kw_import:
  case tok::kw_init:
  case tok::kw_internal:
  case tok::kw_let:
  case tok::kw_operator:
  case tok::kw_precedencegroup:
  case tok::kw_private:
  case tok::kw_protocol:
  case tok::kw_public:
  case tok::kw_static:
  case tok::kw_struct:
  case tok::kw_subscript:
  case tok::kw_typealias:
  case tok::kw_var:
  case tok::pound_if:
  case tok::identifier:
  case tok::pound_sourceLocation:
    return true;
  case tok::pound_line:
    // #line at the start of the line is a directive, but it's deprecated.
    // #line within a line is an expression.
    return Tok.isAtStartOfLine();

  case tok::kw_try:
    // 'try' is not a valid way to start a decl, but we special-case 'try let'
    // and 'try var' for better recovery.
    return true;
  default:
    return false;
  }
}

/// Given a current token of 'unowned', check to see if it is followed by a
/// "(safe)" or "(unsafe)" specifier.
static bool isParenthesizedUnowned(Parser &P) {
  assert(P.Tok.getText() == "unowned" && P.peekToken().is(tok::l_paren) &&
         "Invariant violated");
  
  // Look ahead to parse the parenthesized expression.
  Parser::BacktrackingScope Backtrack(P);
  P.consumeToken(tok::identifier);
  P.consumeToken(tok::l_paren);
  return P.Tok.is(tok::identifier) && P.peekToken().is(tok::r_paren) &&
          (P.Tok.getText() == "safe" || P.Tok.getText() == "unsafe");
}

  
bool Parser::isStartOfDecl() {
  // If this is obviously not the start of a decl, then we're done.
  if (!isKeywordPossibleDeclStart(Tok)) return false;

  // When 'init' appears inside another 'init', it's likely the user wants to
  // invoke an initializer but forgets to prefix it with 'self.' or 'super.'
  // Otherwise, expect 'init' to be the start of a declaration (and complain
  // when the expectation is not fulfilled).
  if (Tok.is(tok::kw_init)) {
    return !isa<ConstructorDecl>(CurDeclContext);
  }
  
  // The protocol keyword needs more checking to reject "protocol<Int>".
  if (Tok.is(tok::kw_protocol)) {
    const Token &Tok2 = peekToken();
    return !Tok2.isAnyOperator() || !Tok2.getText().equals("<");
  }

  // The 'try' case is only for simple local recovery, so we only bother to
  // check 'let' and 'var' right now.
  if (Tok.is(tok::kw_try))
    return peekToken().isAny(tok::kw_let, tok::kw_var);
  
  // Look through attribute list, because it may be an *type* attribute list.
  if (Tok.is(tok::at_sign)) {
    BacktrackingScope backtrack(*this);
    while (consumeIf(tok::at_sign)) {
      // If not identifier or code complete token, consider '@' as an incomplete
      // attribute.
      if (Tok.isNot(tok::identifier, tok::code_complete))
        continue;
      consumeToken();
      // Eat paren after attribute name; e.g. @foo(x)
      if (consumeIf(tok::l_paren)) {
        while (Tok.isNot(tok::r_brace, tok::eof, tok::pound_endif)) {
          if (consumeIf(tok::r_paren)) break;
          skipSingle();
        }
      }
    }
    // If this attribute is the last element in the block,
    // consider it is a start of incomplete decl.
    if (Tok.isAny(tok::r_brace, tok::eof, tok::pound_endif))
      return true;

    return isStartOfDecl();
  }

  // Otherwise, the only hard case left is the identifier case.
  if (Tok.isNot(tok::identifier)) return true;

  // If this is an operator declaration, handle it.
  const Token &Tok2 = peekToken();
  if (isStartOfOperatorDecl(Tok, Tok2))
    return true;
    
  // If this can't possibly be a contextual keyword, then this identifier is
  // not interesting.  Bail out.
  if (!Tok.isContextualDeclKeyword())
    return false;
      
  // If it might be, we do some more digging.

  // If this is 'unowned', check to see if it is valid.
  if (Tok.getText() == "unowned" && Tok2.is(tok::l_paren) &&
      isParenthesizedUnowned(*this)) {
    Parser::BacktrackingScope Backtrack(*this);
    consumeToken(tok::identifier);
    consumeToken(tok::l_paren);
    consumeToken(tok::identifier);
    consumeToken(tok::r_paren);
    return isStartOfDecl();
  }

  // If the next token is obviously not the start of a decl, bail early.
  if (!isKeywordPossibleDeclStart(Tok2))
    return false;
  
  // Otherwise, do a recursive parse.
  Parser::BacktrackingScope Backtrack(*this);
  consumeToken(tok::identifier);
  return isStartOfDecl();
}

void Parser::consumeDecl(ParserPosition BeginParserPosition,
                         ParseDeclOptions Flags,
                         bool IsTopLevel) {
  SourceLoc CurrentLoc = Tok.getLoc();
  backtrackToPosition(BeginParserPosition);
  SourceLoc BeginLoc = Tok.getLoc();
  // Consume tokens up to code completion token.
  while (Tok.isNot(tok::code_complete, tok::eof))
    consumeToken();

  // Consume the code completion token, if there is one.
  consumeIf(tok::code_complete);
  SourceLoc EndLoc = DelayedDeclEnd.isValid() &&
                     SourceMgr.isBeforeInBuffer(Tok.getLoc(), DelayedDeclEnd) ?
                       DelayedDeclEnd : Tok.getLoc();
  State->delayDecl(PersistentParserState::DelayedDeclKind::Decl, Flags.toRaw(),
                   CurDeclContext, { BeginLoc, EndLoc },
                   BeginParserPosition.PreviousLoc);

  while (SourceMgr.isBeforeInBuffer(Tok.getLoc(), CurrentLoc))
    consumeToken();

  if (IsTopLevel) {
    // Skip the rest of the file to prevent the parser from constructing the
    // AST for it.  Forward references are not allowed at the top level.
    while (Tok.isNot(tok::eof))
      consumeToken();
  }
}

void Parser::setLocalDiscriminator(ValueDecl *D) {
  // If we're not in a local context, this is unnecessary.
  if (!CurLocalContext || !D->getDeclContext()->isLocalContext())
    return;

  if (auto TD = dyn_cast<TypeDecl>(D))
    if (!getScopeInfo().isInactiveConfigBlock())
      SF.LocalTypeDecls.insert(TD);

  Identifier name = D->getBaseName().getIdentifier();
  unsigned discriminator = CurLocalContext->claimNextNamedDiscriminator(name);
  D->setLocalDiscriminator(discriminator);
}

void Parser::delayParseFromBeginningToHere(ParserPosition BeginParserPosition,
                                           ParseDeclOptions Flags) {
  auto CurLoc = Tok.getLoc();
  backtrackToPosition(BeginParserPosition);
  SourceLoc BeginLoc = Tok.getLoc();
  SourceLoc EndLoc = CurLoc;
  State->delayDecl(PersistentParserState::DelayedDeclKind::Decl,
                   Flags.toRaw(),
                   CurDeclContext, {BeginLoc, EndLoc},
                   BeginParserPosition.PreviousLoc);

  while (Tok.isNot(tok::eof))
    consumeToken();
}

/// \brief Parse a single syntactic declaration and return a list of decl
/// ASTs.  This can return multiple results for var decls that bind to multiple
/// values, structs that define a struct decl and a constructor, etc.
///
/// \verbatim
///   decl:
///     decl-typealias
///     decl-extension
///     decl-let
///     decl-var
///     decl-class
///     decl-func
///     decl-enum
///     decl-struct
///     decl-import
///     decl-operator
/// \endverbatim
ParserResult<Decl>
Parser::parseDecl(ParseDeclOptions Flags,
                  llvm::function_ref<void(Decl*)> Handler) {

  if (Tok.is(tok::pound_if)) {
    auto IfConfigResult = parseDeclIfConfig(Flags);
    if (auto ICD = IfConfigResult.getPtrOrNull()) {
      // The IfConfigDecl is ahead of its members in source order.
      Handler(ICD);
      // Copy the active members into the entries list.
      for (auto activeMember : ICD->getActiveMembers()) {
        Handler(activeMember);
      }
    }
    return IfConfigResult;
  }

  ParserPosition BeginParserPosition;
  if (isCodeCompletionFirstPass())
    BeginParserPosition = getParserPosition();

  SourceLoc tryLoc;
  (void)consumeIf(tok::kw_try, tryLoc);

  // Note that we're parsing a declaration.
  StructureMarkerRAII ParsingDecl(*this, Tok.getLoc(),
                                  StructureMarkerKind::Declaration);

  DeclAttributes Attributes;
  if (Tok.hasComment())
    Attributes.add(new (Context) RawDocCommentAttr(Tok.getCommentRange()));
  bool FoundCCTokenInAttr;
  parseDeclAttributeList(Attributes, FoundCCTokenInAttr);

  // Keep track of where and whether we see a contextual keyword on the decl.
  SourceLoc StaticLoc;
  StaticSpellingKind StaticSpelling = StaticSpellingKind::None;
  ParserResult<Decl> DeclResult;

  while (1) {
    // Save the original token, in case code-completion needs it.
    auto OrigTok = Tok;
    bool MayNeedOverrideCompletion = false;

    switch (Tok.getKind()) {
    // Modifiers
    case tok::kw_static:
      if (StaticLoc.isValid()) {
        diagnose(Tok, diag::decl_already_static,
                 StaticSpellingKind::KeywordStatic)
        .highlight(StaticLoc)
        .fixItRemove(Tok.getLoc());
      } else {
        StaticLoc = Tok.getLoc();
        StaticSpelling = StaticSpellingKind::KeywordStatic;
      }
      consumeToken(tok::kw_static);
      continue;

    // 'class' is a modifier on func, but is also a top-level decl.
    case tok::kw_class: {
      SourceLoc ClassLoc = consumeToken(tok::kw_class);

      // If 'class' is a modifier on another decl kind, like var or func,
      // then treat it as a modifier.
      if (isStartOfDecl()) {
        if (StaticLoc.isValid()) {
          diagnose(Tok, diag::decl_already_static,
                   StaticSpellingKind::KeywordClass)
            .highlight(StaticLoc).fixItRemove(ClassLoc);
        } else {
          StaticLoc = ClassLoc;
          StaticSpelling = StaticSpellingKind::KeywordClass;
        }
        continue;
      }

      // Otherwise this is the start of a class declaration.
      DeclResult = parseDeclClass(ClassLoc, Flags, Attributes);
      break;
    }

    case tok::kw_private:
    case tok::kw_fileprivate:
    case tok::kw_internal:
    case tok::kw_public:
      // We still model these specifiers as attributes.
      parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, DAK_Accessibility);
      continue;

    // Context sensitive keywords.
    case tok::identifier:
      // FIXME: This is ridiculous, this all needs to be sucked into the
      // declparsing goop.
      if (Tok.isContextualKeyword("open")) {
        parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, DAK_Accessibility);
        continue;
      }
      if (Tok.isContextualKeyword("weak") ||
          Tok.isContextualKeyword("unowned")) {
        parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, DAK_Ownership);
        continue;
      }
      if (Tok.isContextualKeyword("optional")) {
        parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, DAK_Optional);
        continue;
      }
      if (Tok.isContextualKeyword("required")) {
        parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, DAK_Required);
        continue;
      }
      if (Tok.isContextualKeyword("lazy")) {
        parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, DAK_Lazy);
        continue;
      }
      if (Tok.isContextualKeyword("final")) {
        parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, DAK_Final);
        continue;
      }
      if (Tok.isContextualKeyword("dynamic")) {
        parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Dynamic);
        continue;
      }
      if (Tok.isContextualKeyword("prefix")) {
        parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Prefix);
        continue;
      }
      if (Tok.isContextualKeyword("postfix")) {
        parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Postfix);
        continue;
      }
      if (Tok.isContextualKeyword("indirect")) {
        parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Indirect);
        continue;
      }
      if (Tok.isContextualKeyword("infix")) {
        parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Infix);
        continue;
      }
      if (Tok.isContextualKeyword("override")) {
        parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Override);
        continue;
      }
      if (Tok.isContextualKeyword("mutating")) {
        parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Mutating);
        continue;
      }
      if (Tok.isContextualKeyword("nonmutating")) {
        parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_NonMutating);
        continue;
      }
      if (Tok.isContextualKeyword("convenience")) {
        parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Convenience);
        continue;
      }

      // Otherwise this is not a context-sensitive keyword.
      LLVM_FALLTHROUGH;

    case tok::pound_if:
    case tok::pound_sourceLocation:
    case tok::pound_line:
      // We see some attributes right before these pounds.
      // TODO: Emit dedicated errors for them.
      LLVM_FALLTHROUGH;

    // Obvious nonsense.
    default:
      if (FoundCCTokenInAttr) {
        if (!CodeCompletion) {
          delayParseFromBeginningToHere(BeginParserPosition, Flags);
        } else {
          CodeCompletion->completeDeclAttrKeyword(nullptr, isInSILMode(),
                                                  false);
        }
      }

      diagnose(Tok, diag::expected_decl);

      if (CurDeclContext) {
        if (auto nominal = dyn_cast<NominalTypeDecl>(CurDeclContext)) {
          diagnose(nominal->getLoc(), diag::note_in_decl_extension, false,
                   nominal->getName());
        } else if (auto extension = dyn_cast<ExtensionDecl>(CurDeclContext)) {
          if (auto repr = extension->getExtendedTypeLoc().getTypeRepr()) {
            if (auto idRepr = dyn_cast<IdentTypeRepr>(repr)) {
              diagnose(extension->getLoc(), diag::note_in_decl_extension, true,
                idRepr->getComponentRange().front()->getIdentifier());
            }
          }
        }
      }
      return makeParserErrorResult<Decl>();

    case tok::unknown:
      consumeToken(tok::unknown);
      continue;

    // Unambiguous top level decls.
    case tok::kw_import:
      DeclResult = parseDeclImport(Flags, Attributes);
      break;
    case tok::kw_extension:
      DeclResult = parseDeclExtension(Flags, Attributes);
      break;
    case tok::kw_let:
    case tok::kw_var: {
      llvm::SmallVector<Decl *, 4> Entries;
      DeclResult = parseDeclVar(Flags, Attributes, Entries, StaticLoc,
                                StaticSpelling, tryLoc);
      StaticLoc = SourceLoc();   // we handled static if present.
      MayNeedOverrideCompletion = true;
      std::for_each(Entries.begin(), Entries.end(), Handler);
      if (auto *D = DeclResult.getPtrOrNull())
        markWasHandled(D);
      break;
    }
    case tok::kw_typealias:
      DeclResult = parseDeclTypeAlias(Flags, Attributes);
      MayNeedOverrideCompletion = true;
      break;
    case tok::kw_associatedtype:
      DeclResult = parseDeclAssociatedType(Flags, Attributes);
      break;
    case tok::kw_enum:
      DeclResult = parseDeclEnum(Flags, Attributes);
      break;
    case tok::kw_case: {
      llvm::SmallVector<Decl *, 4> Entries;
      DeclResult = parseDeclEnumCase(Flags, Attributes, Entries);
      std::for_each(Entries.begin(), Entries.end(), Handler);
      if (auto *D = DeclResult.getPtrOrNull())
        markWasHandled(D);
      break;
    }
    case tok::kw_struct:
      DeclResult = parseDeclStruct(Flags, Attributes);
      break;
    case tok::kw_init:
      DeclResult = parseDeclInit(Flags, Attributes);
      break;
    case tok::kw_deinit:
      DeclResult = parseDeclDeinit(Flags, Attributes);
      break;
    case tok::kw_operator:
      DeclResult = parseDeclOperator(Flags, Attributes);
      break;
    case tok::kw_precedencegroup:
      DeclResult = parseDeclPrecedenceGroup(Flags, Attributes);
      break;
    case tok::kw_protocol:
      DeclResult = parseDeclProtocol(Flags, Attributes);
      break;

    case tok::kw_func:
      DeclResult = parseDeclFunc(StaticLoc, StaticSpelling, Flags, Attributes);
      StaticLoc = SourceLoc();   // we handled static if present.
      MayNeedOverrideCompletion = true;
      break;

    case tok::kw_subscript: {
      if (StaticLoc.isValid()) {
        diagnose(Tok, diag::subscript_static, StaticSpelling)
          .fixItRemove(SourceRange(StaticLoc));
        StaticLoc = SourceLoc();
      }
      llvm::SmallVector<Decl *, 4> Entries;
      DeclResult = parseDeclSubscript(Flags, Attributes, Entries);
      std::for_each(Entries.begin(), Entries.end(), Handler);
      MayNeedOverrideCompletion = true;
      if (auto *D = DeclResult.getPtrOrNull())
        markWasHandled(D);
      break;
    }

    case tok::code_complete:
      MayNeedOverrideCompletion = true;
      DeclResult = makeParserError();
      // Handled below.
      break;
    }

    if (DeclResult.isParseError() && MayNeedOverrideCompletion &&
        Tok.is(tok::code_complete)) {
      DeclResult = makeParserCodeCompletionStatus();
      if (CodeCompletion) {
        // If we need to complete an override, collect the keywords already
        // specified so that we do not duplicate them in code completion
        // strings.
        SmallVector<StringRef, 3> Keywords;
        switch (OrigTok.getKind()) {
        case tok::kw_func:
        case tok::kw_subscript:
        case tok::kw_var:
        case tok::kw_let:
        case tok::kw_typealias:
          Keywords.push_back(OrigTok.getText());
          break;
        default:
          // Other tokens are already accounted for.
          break;
        }
        for (auto attr : Attributes) {
          Keywords.push_back(attr->getAttrName());
        }
        CodeCompletion->completeNominalMemberBeginning(Keywords);
      }
    }

    // If we 'break' out of the switch, break out of the loop too.
    break;
  }

  if (auto SF = CurDeclContext->getParentSourceFile()) {
    if (!getScopeInfo().isInactiveConfigBlock()) {
      for (auto Attr : Attributes) {
        if (isa<ObjCAttr>(Attr) || isa<DynamicAttr>(Attr))
          SF->AttrsRequiringFoundation.insert(Attr);
      }
    }
  }

  if (FoundCCTokenInAttr) {
    if (CodeCompletion) {
      CodeCompletion->completeDeclAttrKeyword(DeclResult.getPtrOrNull(),
                                              isInSILMode(),
                                              false);
    } else {
      delayParseFromBeginningToHere(BeginParserPosition, Flags);
      return makeParserError();
    }
  }

  if (DeclResult.hasCodeCompletion() && isCodeCompletionFirstPass() &&
      !CurDeclContext->isModuleScopeContext()) {
    // Only consume non-toplevel decls.
    consumeDecl(BeginParserPosition, Flags, /*IsTopLevel=*/false);

    return makeParserError();
  }

  if (DeclResult.isNonNull()) {
    Decl *D = DeclResult.get();
    if (!declWasHandledAlready(D))
      Handler(DeclResult.get());
  }

  if (!DeclResult.isParseError()) {
    // If we parsed 'class' or 'static', but didn't handle it above, complain
    // about it.
    if (StaticLoc.isValid())
      diagnose(DeclResult.get()->getLoc(), diag::decl_not_static,
               StaticSpelling)
          .fixItRemove(SourceRange(StaticLoc));
  }

  return DeclResult;
}

void Parser::parseDeclDelayed() {
  auto DelayedState = State->takeDelayedDeclState();
  assert(DelayedState.get() && "should have delayed state");

  auto BeginParserPosition = getParserPosition(DelayedState->BodyPos);
  auto EndLexerState = L->getStateForEndOfTokenLoc(DelayedState->BodyEnd);

  // ParserPositionRAII needs a primed parser to restore to.
  if (Tok.is(tok::NUM_TOKENS))
    consumeToken();

  // Ensure that we restore the parser state at exit.
  ParserPositionRAII PPR(*this);

  // Create a lexer that cannot go past the end state.
  Lexer LocalLex(*L, BeginParserPosition.LS, EndLexerState);

  // Temporarily swap out the parser's current lexer with our new one.
  llvm::SaveAndRestore<Lexer *> T(L, &LocalLex);

  // Rewind to the beginning of the decl.
  restoreParserPosition(BeginParserPosition);

  // Re-enter the lexical scope.
  Scope S(this, DelayedState->takeScope());
  ContextChange CC(*this, DelayedState->ParentContext);

  parseDecl(ParseDeclOptions(DelayedState->Flags), [](Decl *D) { });
}

/// \brief Parse an 'import' declaration, doing no token skipping on error.
///
/// \verbatim
///   decl-import:
///     'import' attribute-list import-kind? import-path
///   import-kind:
///     'typealias'
///     'struct'
///     'class'
///     'enum'
///     'protocol'
///     'var'
///     'func'
///   import-path:
///     any-identifier ('.' any-identifier)*
/// \endverbatim
ParserResult<ImportDecl> Parser::parseDeclImport(ParseDeclOptions Flags,
                                                 DeclAttributes &Attributes) {
  SourceLoc ImportLoc = consumeToken(tok::kw_import);
  DebuggerContextChange DCC (*this);

  if (!CodeCompletion && !DCC.movedToTopLevel() && !(Flags & PD_AllowTopLevel)) {
    diagnose(ImportLoc, diag::decl_inner_scope);
    return nullptr;
  }

  ImportKind Kind = ImportKind::Module;
  SourceLoc KindLoc;
  if (Tok.isKeyword()) {
    switch (Tok.getKind()) {
    case tok::kw_typealias:
      Kind = ImportKind::Type;
      break;
    case tok::kw_struct:
      Kind = ImportKind::Struct;
      break;
    case tok::kw_class:
      Kind = ImportKind::Class;
      break;
    case tok::kw_enum:
      Kind = ImportKind::Enum;
      break;
    case tok::kw_protocol:
      Kind = ImportKind::Protocol;
      break;
    case tok::kw_var:
    case tok::kw_let:
      Kind = ImportKind::Var;
      break;
    case tok::kw_func:
      Kind = ImportKind::Func;
      break;
    default:
      diagnose(Tok, diag::expected_identifier_in_decl, "import");
      diagnose(Tok, diag::keyword_cant_be_identifier, Tok.getText());
      diagnose(Tok, diag::backticks_to_escape);
      return nullptr;
    }
    KindLoc = consumeToken();
  }

  std::vector<std::pair<Identifier, SourceLoc>> ImportPath;
  do {
    if (Tok.is(tok::code_complete)) {
      consumeToken();
      if (CodeCompletion) {
        CodeCompletion->completeImportDecl(ImportPath);
      }
      return makeParserCodeCompletionStatus();
    }
    ImportPath.push_back(std::make_pair(Identifier(), Tok.getLoc()));
    if (parseAnyIdentifier(ImportPath.back().first,
                           diag::expected_identifier_in_decl, "import"))
      return nullptr;
  } while (consumeIf(tok::period));

  if (Tok.is(tok::code_complete)) {
    // We omit the code completion token if it immediately follows the module
    // identifiers.
    auto BufferId = SourceMgr.getCodeCompletionBufferID();
    auto IdEndOffset = SourceMgr.getLocOffsetInBuffer(ImportPath.back().second,
      BufferId) + ImportPath.back().first.str().size();
    auto CCTokenOffset = SourceMgr.getLocOffsetInBuffer(SourceMgr.
      getCodeCompletionLoc(), BufferId);
    if (IdEndOffset == CCTokenOffset) {
      consumeToken();
    }
  }

  if (Kind != ImportKind::Module && ImportPath.size() == 1) {
    diagnose(ImportPath.front().second, diag::decl_expected_module_name);
    return nullptr;
  }

  auto *ID = ImportDecl::create(Context, CurDeclContext, ImportLoc, Kind,
                                KindLoc, ImportPath);
  ID->getAttrs() = Attributes;
  return DCC.fixupParserResult(ID);
}

/// \brief Parse an inheritance clause.
///
/// \verbatim
///   inheritance:
///      ':' inherited (',' inherited)*
///
///   inherited:
///     'class'
///     type-identifier
/// \endverbatim
ParserStatus Parser::parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
                                      SourceLoc *classRequirementLoc) {
  Scope S(this, ScopeKind::InheritanceClause);
  consumeToken(tok::colon);

  // Clear out the class requirement location.
  if (classRequirementLoc)
    *classRequirementLoc = SourceLoc();

  ParserStatus Status;
  SourceLoc prevComma;
  do {
    // Parse the 'class' keyword for a class requirement.
    if (Tok.is(tok::kw_class)) {
      // If we aren't allowed to have a class requirement here, complain.
      auto classLoc = consumeToken();
      if (!classRequirementLoc) {
        SourceLoc endLoc = Tok.is(tok::comma) ? Tok.getLoc() : classLoc;
        diagnose(classLoc, diag::invalid_class_requirement)
          .fixItRemove(SourceRange(classLoc, endLoc));
        continue;
      }

      // If we already saw a class requirement, complain.
      if (classRequirementLoc->isValid()) {
        diagnose(classLoc, diag::redundant_class_requirement)
          .highlight(*classRequirementLoc)
          .fixItRemove(SourceRange(prevComma, classLoc));
        continue;
      }

      // If the class requirement was not the first requirement, complain.
      if (!Inherited.empty()) {
        SourceLoc properLoc = Inherited[0].getSourceRange().Start;
        diagnose(classLoc, diag::late_class_requirement)
          .fixItInsert(properLoc, "class, ")
          .fixItRemove(SourceRange(prevComma, classLoc));
      }

      // Record the location of the 'class' keyword.
      *classRequirementLoc = classLoc;
      continue;
    }

    bool usesDeprecatedCompositionSyntax =
      Tok.is(tok::kw_protocol) && startsWithLess(peekToken());
    bool isAny = Tok.is(tok::kw_Any); // We allow (redundant) inheritance from Any

    auto ParsedTypeResult = parseTypeForInheritance(
        diag::expected_identifier_for_type,
        diag::expected_ident_type_in_inheritance);
    Status |= ParsedTypeResult;

    // Recover and emit nice diagnostic for composition.
    if (auto Composition = dyn_cast_or_null<CompositionTypeRepr>(
          ParsedTypeResult.getPtrOrNull())) {
      // Record the protocols inside the composition.
      Inherited.append(Composition->getTypes().begin(),
                       Composition->getTypes().end());
      // We can inherit from Any
      if (!isAny) {
        if (usesDeprecatedCompositionSyntax) {
          // Provide fixits to remove the composition, leaving the types intact.
          auto compositionRange = Composition->getCompositionRange();
          auto token = Lexer::getTokenAtLocation(SourceMgr, compositionRange.End);
          diagnose(Composition->getSourceLoc(),
                   diag::disallowed_protocol_composition)
            .highlight({Composition->getStartLoc(), compositionRange.End})
            .fixItRemove({Composition->getSourceLoc(), compositionRange.Start})
            .fixItRemove(startsWithGreater(token)
                         ? compositionRange.End
                         : SourceLoc());
        } else {
          diagnose(Composition->getStartLoc(),
                   diag::disallowed_protocol_composition)
            .highlight(Composition->getSourceRange());
          // TODO: Decompose 'A & B & C' list to 'A, B, C'
        }
      }
      continue;
    }

    // Record the type if its a single type.
    if (ParsedTypeResult.isNonNull())
      Inherited.push_back(ParsedTypeResult.get());

    // Check for a ',', which indicates that there are more protocols coming.
  } while (consumeIf(tok::comma, prevComma));

  return Status;
}

enum class TokenProperty {
  None,
  StartsWithLess,
};

static ParserStatus
parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc,
                        StringRef DeclKindName, tok ResyncT1, tok ResyncT2,
                        tok ResyncT3, tok ResyncT4,
                        TokenProperty ResyncP1) {
  if (P.Tok.is(tok::identifier)) {
    Loc = P.consumeIdentifier(&Result);

    // We parsed an identifier for the declaration. If we see another
    // identifier, it might've been a single identifier that got broken by a
    // space or newline accidentally.
    if (P.Tok.isIdentifierOrUnderscore() && !P.Tok.isContextualDeclKeyword())
      P.diagnoseConsecutiveIDs(Result.str(), Loc, DeclKindName);

    // Return success anyway
    return makeParserSuccess();
  }

  P.checkForInputIncomplete();

  if (P.Tok.is(tok::integer_literal) || P.Tok.is(tok::floating_literal) ||
      (P.Tok.is(tok::unknown) && isdigit(P.Tok.getText()[0]))) {
    // Per rdar://problem/32316666, using numbers for identifiers is a common
    // error for beginners, so it's worth handling this in a special way.
    P.diagnose(P.Tok, diag::number_cant_start_decl_name, DeclKindName);

    // Pretend this works as an identifier, which shouldn't be observable since
    // actual uses of it will hit random other errors, e.g. `1()` won't be
    // callable.
    Result = P.Context.getIdentifier(P.Tok.getText());
    Loc = P.Tok.getLoc();
    P.consumeToken();

    // We recovered, so this is a success.
    return makeParserSuccess();
  }

  if (P.Tok.isKeyword()) {
    P.diagnose(P.Tok, diag::keyword_cant_be_identifier, P.Tok.getText());
    P.diagnose(P.Tok, diag::backticks_to_escape)
      .fixItReplace(P.Tok.getLoc(), "`" + P.Tok.getText().str() + "`");

    // Recover if the next token is one of the expected tokens.
    auto Next = P.peekToken();
    if (Next.isAny(ResyncT1, ResyncT2, ResyncT3, ResyncT4) ||
        (ResyncP1 != TokenProperty::None && P.startsWithLess(Next))) {
      llvm::SmallString<32> Name(P.Tok.getText());
      // Append an invalid character so that nothing can resolve to this name.
      Name += "#";
      Result = P.Context.getIdentifier(Name.str());
      Loc = P.Tok.getLoc();
      P.consumeToken();
      // Return success because we recovered.
      return makeParserSuccess();
    }
    return makeParserError();
  }

  P.diagnose(P.Tok, diag::expected_identifier_in_decl, DeclKindName);
  return makeParserError();
}

static ParserStatus
parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &L,
                        StringRef DeclKindName, tok ResyncT1, tok ResyncT2) {
  return parseIdentifierDeclName(P, Result, L, DeclKindName, ResyncT1, ResyncT2,
                                 tok::NUM_TOKENS, tok::NUM_TOKENS,
                                 TokenProperty::None);
}

static ParserStatus
parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &L,
                        StringRef DeclKindName, tok ResyncT1, tok ResyncT2,
                        tok ResyncT3, tok ResyncT4) {
  return parseIdentifierDeclName(P, Result, L, DeclKindName, ResyncT1, ResyncT2,
                                 ResyncT3, ResyncT4, TokenProperty::None);
}

static ParserStatus
parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &L,
                        StringRef DeclKindName, tok ResyncT1, tok ResyncT2,
                        TokenProperty ResyncP1) {
  return parseIdentifierDeclName(P, Result, L, DeclKindName, ResyncT1, ResyncT2,
                                 tok::NUM_TOKENS, tok::NUM_TOKENS, ResyncP1);
}

static ParserStatus
parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &L,
                        StringRef DeclKindName, tok ResyncT1, tok ResyncT2,
                        tok ResyncT3, TokenProperty ResyncP1) {
  return parseIdentifierDeclName(P, Result, L, DeclKindName, ResyncT1, ResyncT2,
                                 ResyncT3, tok::NUM_TOKENS, ResyncP1);
}

/// Add a fix-it to remove the space in consecutive identifiers.
/// Add a camel-cased option if it is different than the first option.
void Parser::diagnoseConsecutiveIDs(StringRef First, SourceLoc FirstLoc,
                                    StringRef DeclKindName) {
  assert(Tok.isAny(tok::identifier, tok::kw__));

  diagnose(Tok, diag::repeated_identifier, DeclKindName);
  auto Second = Tok.getText();
  auto SecondLoc = consumeToken();

  SourceRange FixRange(FirstLoc, SecondLoc);
  // Provide two fix-its: a direct concatenation of the two identifiers
  // and a camel-cased version.
  //
  auto DirectConcatenation = First.str() + Second.str();
  diagnose(SecondLoc, diag::join_identifiers)
    .fixItReplace(FixRange, DirectConcatenation);

  SmallString<8> CapitalizedScratch;
  auto Capitalized = camel_case::toSentencecase(Second,
                                                CapitalizedScratch);
  if (Capitalized != Second) {
    auto CamelCaseConcatenation = First.str() + Capitalized.str();
    diagnose(SecondLoc, diag::join_identifiers_camel_case)
      .fixItReplace(FixRange, CamelCaseConcatenation);
  }
}

/// Parse a Decl item in decl list.
ParserStatus Parser::parseDeclItem(bool &PreviousHadSemi,
                                   Parser::ParseDeclOptions Options,
                                   llvm::function_ref<void(Decl*)> handler) {
  if (Tok.is(tok::semi)) {
    // Consume ';' without preceding decl.
    diagnose(Tok, diag::unexpected_separator, ";")
      .fixItRemove(Tok.getLoc());
    consumeToken();
    // Return success because we already recovered.
    return makeParserSuccess();
  }

  // If the previous declaration didn't have a semicolon and this new
  // declaration doesn't start a line, complain.
  if (!PreviousHadSemi && !Tok.isAtStartOfLine() && !Tok.is(tok::unknown)) {
    auto endOfPrevious = getEndOfPreviousLoc();
    diagnose(endOfPrevious, diag::declaration_same_line_without_semi)
      .fixItInsert(endOfPrevious, ";");
  }

  if (Tok.isAny(tok::pound_sourceLocation, tok::pound_line)) {
    auto LineDirectiveStatus = parseLineDirective(Tok.is(tok::pound_line));
    if (LineDirectiveStatus.isError())
      skipUntilDeclRBrace(tok::semi, tok::pound_endif);
    return LineDirectiveStatus;
  }

  auto Result = parseDecl(Options, handler);
  if (Result.isParseError())
    skipUntilDeclRBrace(tok::semi, tok::pound_endif);
  SourceLoc SemiLoc;
  PreviousHadSemi = consumeIf(tok::semi, SemiLoc);
  if (PreviousHadSemi && Result.isNonNull())
    Result.get()->TrailingSemiLoc = SemiLoc;
  return Result;
}

/// \brief Parse the members in a struct/class/enum/protocol/extension.
///
/// \verbatim
///    decl* '}'
/// \endverbatim
bool Parser::parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc,
                           Diag<> ErrorDiag, ParseDeclOptions Options,
                           llvm::function_ref<void(Decl*)> handler) {
  ParserStatus Status;
  bool PreviousHadSemi = true;
  while (Tok.isNot(tok::r_brace)) {
    Status |= parseDeclItem(PreviousHadSemi, Options, handler);
    if (Tok.isAny(tok::eof, tok::pound_endif, tok::pound_else,
                  tok::pound_elseif)) {
      IsInputIncomplete = true;
      break;
    }
  }

  parseMatchingToken(tok::r_brace, RBLoc, ErrorDiag, LBLoc);

  // If we found the closing brace, then the caller should not care if there
  // were errors while parsing inner decls, because we recovered.
  return !RBLoc.isValid();
}

/// \brief Parse an 'extension' declaration.
///
/// \verbatim
///   extension:
///    'extension' attribute-list type inheritance? where-clause?
///        '{' decl* '}'
/// \endverbatim
ParserResult<ExtensionDecl>
Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) {
  SourceLoc ExtensionLoc = consumeToken(tok::kw_extension);
  
  DebuggerContextChange DCC (*this);

  // Parse the type being extended.
  ParserStatus status;
  ParserResult<TypeRepr> extendedType = parseType(diag::extension_type_expected);
  status |= extendedType;

  // Parse optional inheritance clause.
  SmallVector<TypeLoc, 2> Inherited;
  if (Tok.is(tok::colon))
    status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);

  // Parse the optional where-clause.
  TrailingWhereClause *trailingWhereClause = nullptr;
  if (Tok.is(tok::kw_where)) {
    SourceLoc whereLoc;
    SmallVector<RequirementRepr, 4> requirements;
    bool firstTypeInComplete;
    auto whereStatus = parseGenericWhereClause(whereLoc, requirements,
                                               firstTypeInComplete);
    if (whereStatus.isSuccess()) {
      trailingWhereClause = TrailingWhereClause::create(Context, whereLoc,
                                                        requirements);
    } else if (whereStatus.hasCodeCompletion()) {
      if (CodeCompletion && firstTypeInComplete) {
        CodeCompletion->completeGenericParams(extendedType.getPtrOrNull());
      } else
        return makeParserCodeCompletionResult<ExtensionDecl>();
    }
  }

  ExtensionDecl *ext = ExtensionDecl::create(Context, ExtensionLoc,
                                             extendedType.getPtrOrNull(),
                                             Context.AllocateCopy(Inherited),
                                             CurDeclContext,
                                             trailingWhereClause);
  ext->getAttrs() = Attributes;

  SourceLoc LBLoc, RBLoc;
  if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_extension)) {
    LBLoc = PreviousLoc;
    RBLoc = LBLoc;
    status.setIsParseError();
  } else {
    // Parse the body.
    ContextChange CC(*this, ext);
    Scope S(this, ScopeKind::Extension);

    ParseDeclOptions Options(PD_HasContainerType | PD_InExtension);

    if (parseDeclList(LBLoc, RBLoc, diag::expected_rbrace_extension,
                      Options, [&] (Decl *D) {ext->addMember(D);}))
      status.setIsParseError();

    // Don't propagate the code completion bit from members: we cannot help
    // code completion inside a member decl, and our callers cannot do
    // anything about it either.  But propagate the error bit.
  }

  ext->setBraces({LBLoc, RBLoc});

  if (!DCC.movedToTopLevel() && !(Flags & PD_AllowTopLevel)) {
    diagnose(ExtensionLoc, diag::decl_inner_scope);
    status.setIsParseError();

    // Tell the type checker not to touch this extension.
    ext->setInvalid();
  }

  return DCC.fixupParserResult(status, ext);
}

ParserStatus Parser::parseLineDirective(bool isLine) {
  SourceLoc Loc = consumeToken();
  if (isLine) {
    diagnose(Loc, diag::line_directive_style_deprecated)
        .fixItReplace(Loc, "#sourceLocation");
  }
  bool WasInPoundLineEnvironment = InPoundLineEnvironment;
  if (WasInPoundLineEnvironment) {
    SourceMgr.closeVirtualFile(Loc);
    InPoundLineEnvironment = false;
  }

  
  unsigned StartLine = 0;
  Optional<StringRef> Filename;
  const char *LastTokTextEnd;
  if (!isLine) {
    // #sourceLocation()
    // #sourceLocation(file: "foo", line: 42)
    if (parseToken(tok::l_paren, diag::sourceLocation_expected, "("))
      return makeParserError();

    // Handle the "reset" form.
    if (consumeIf(tok::r_paren)) {
      if (!WasInPoundLineEnvironment) {
        diagnose(Tok, diag::unexpected_line_directive);
        return makeParserError();
      }
      return makeParserSuccess();
    }
    
    if (parseSpecificIdentifier("file", diag::sourceLocation_expected,"file:")||
        parseToken(tok::colon, diag::sourceLocation_expected, ":"))
      return makeParserError();

    if (Tok.isNot(tok::string_literal)) {
      diagnose(Tok, diag::expected_line_directive_name);
      return makeParserError();
    }
    
    Filename = getStringLiteralIfNotInterpolated(*this, Loc, Tok,
                                                 "#sourceLocation");
    if (!Filename.hasValue())
      return makeParserError();
    consumeToken(tok::string_literal);
    
    if (parseToken(tok::comma, diag::sourceLocation_expected, ",") ||
        parseSpecificIdentifier("line", diag::sourceLocation_expected,"line:")||
        parseToken(tok::colon, diag::sourceLocation_expected, ":"))
      return makeParserError();
  
    if (Tok.isNot(tok::integer_literal)) {
      diagnose(Tok, diag::expected_line_directive_number);
      return makeParserError();
    }
    if (Tok.getText().getAsInteger(0, StartLine)) {
      diagnose(Tok, diag::expected_line_directive_number);
      return makeParserError();
    }
    if (StartLine == 0) {
      diagnose(Tok, diag::line_directive_line_zero);
      return makeParserError();
    }
    consumeToken(tok::integer_literal);

    LastTokTextEnd = Tok.getText().end();
    if (parseToken(tok::r_paren, diag::sourceLocation_expected, ")"))
      return makeParserError();
    
  } else {  // Legacy #line syntax.
  
    // #line\n returns to the main buffer.
    if (Tok.isAtStartOfLine()) {
      if (!WasInPoundLineEnvironment) {
        diagnose(Tok, diag::unexpected_line_directive);
        return makeParserError();
      }
      return makeParserSuccess();
    }

    // #line 42 "file.swift"\n
    if (Tok.isNot(tok::integer_literal)) {
      diagnose(Tok, diag::expected_line_directive_number);
      return makeParserError();
    }
    if (Tok.getText().getAsInteger(0, StartLine)) {
      diagnose(Tok, diag::expected_line_directive_number);
      return makeParserError();
    }
    if (StartLine == 0) {
      diagnose(Tok, diag::line_directive_line_zero);
      return makeParserError();
    }
    consumeToken(tok::integer_literal);

    if (Tok.isNot(tok::string_literal)) {
      diagnose(Tok, diag::expected_line_directive_name);
      return makeParserError();
    }
    
    Filename = getStringLiteralIfNotInterpolated(*this, Loc, Tok,
                                                 "#line");
    if (!Filename.hasValue())
      return makeParserError();
    LastTokTextEnd = Tok.getText().end();
    consumeToken(tok::string_literal);
  }
  
  // Skip over trailing whitespace and a single \n to the start of the next
  // line.
  while (*LastTokTextEnd == ' ' || *LastTokTextEnd == '\t')
    ++LastTokTextEnd;
  SourceLoc nextLineStartLoc = Lexer::getSourceLoc(LastTokTextEnd);
  
  if (*LastTokTextEnd == '\n')
    nextLineStartLoc = nextLineStartLoc.getAdvancedLoc(1);
  else {
    diagnose(Tok.getLoc(), diag::extra_tokens_line_directive);
    return makeParserError();
  }
  
  int LineOffset = StartLine - SourceMgr.getLineNumber(nextLineStartLoc);
 
  // Create a new virtual file for the region started by the #line marker.
  bool isNewFile = SourceMgr.openVirtualFile(nextLineStartLoc,
                                             Filename.getValue(), LineOffset);
  assert(isNewFile);(void)isNewFile;

  InPoundLineEnvironment = true;
  return makeParserSuccess();
}

/// \brief Parse a typealias decl.
///
/// \verbatim
///   decl-typealias:
///     'typealias' identifier generic-params? '=' type requirement-clause?
/// \endverbatim
ParserResult<TypeDecl> Parser::
parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) {
  ParserPosition startPosition = getParserPosition();
  SourceLoc TypeAliasLoc = consumeToken(tok::kw_typealias);
  SourceLoc EqualLoc;
  Identifier Id;
  SourceLoc IdLoc;
  ParserStatus Status;

  Status |= parseIdentifierDeclName(*this, Id, IdLoc, "typealias",
                                    tok::colon, tok::equal);
  if (Status.isError())
    return nullptr;
    
  DebuggerContextChange DCC(*this, Id, DeclKind::TypeAlias);

  Optional<Scope> GenericsScope;
  GenericsScope.emplace(this, ScopeKind::Generics);

  // Parse a generic parameter list if it is present.
  GenericParamList *genericParams = nullptr;
  if (startsWithLess(Tok)) {
    auto Result = parseGenericParameters();
    if (Result.hasCodeCompletion() && !CodeCompletion)
      return makeParserCodeCompletionStatus();
    genericParams = Result.getPtrOrNull();

    if (!genericParams) {
      // If the parser returned null, it is an already diagnosed parse error.
    } else if (!genericParams->getRequirements().empty()) {
      // Reject a where clause.
      diagnose(genericParams->getWhereLoc(),
               diag::associated_type_generic_parameter_list)
          .highlight(genericParams->getWhereClauseSourceRange());
    }
  }

  if (Flags.contains(PD_InProtocol) && !genericParams && !Tok.is(tok::equal)) {
    // If we're in a protocol and don't see an '=' this looks like leftover Swift 2
    // code intending to be an associatedtype.
    backtrackToPosition(startPosition);
    return parseDeclAssociatedType(Flags, Attributes);
  }
  
  ParserResult<TypeRepr> UnderlyingTy;

  if (Tok.is(tok::colon) || Tok.is(tok::equal)) {
    if (Tok.is(tok::colon)) {
      // It is a common mistake to write "typealias A : Int" instead of = Int.
      // Recognize this and produce a fixit.
      diagnose(Tok, diag::expected_equal_in_typealias)
          .fixItReplace(Tok.getLoc(), " = ");
      consumeToken(tok::colon);
    } else {
      EqualLoc = consumeToken(tok::equal);
    }

    UnderlyingTy = parseType(diag::expected_type_in_typealias);
    Status |= UnderlyingTy;
    if (UnderlyingTy.isNull())
      return Status;
  }

  // Parse a 'where' clause if present, adding it to our GenericParamList.
  if (Tok.is(tok::kw_where)) {
    auto whereStatus = parseFreestandingGenericWhereClause(genericParams);
    if (whereStatus.shouldStopParsing())
      return whereStatus;
  }

  if (UnderlyingTy.isNull()) {
    diagnose(Tok, diag::expected_equal_in_typealias);
    Status.setIsParseError();
    return Status;
  }

  auto *TAD = new (Context) TypeAliasDecl(TypeAliasLoc, EqualLoc, Id, IdLoc,
                                          genericParams, CurDeclContext);
  TAD->getUnderlyingTypeLoc() = UnderlyingTy.getPtrOrNull();
  TAD->getAttrs() = Attributes;

  // Exit the scope introduced for the generic parameters.
  GenericsScope.reset();

  addToScope(TAD);
  return DCC.fixupParserResult(Status, TAD);
}

/// \brief Parse an associatedtype decl.
///
/// \verbatim
///   decl-associatedtype:
///     'associatedtype' identifier inheritance? ('=' type)? where-clause?
/// \endverbatim

ParserResult<TypeDecl> Parser::parseDeclAssociatedType(Parser::ParseDeclOptions Flags,
                                                       DeclAttributes &Attributes) {
  SourceLoc AssociatedTypeLoc;
  ParserStatus Status;
  Identifier Id;
  SourceLoc IdLoc;
  
  // Look for 'typealias' here and diagnose a fixit because parseDeclTypeAlias can
  // ask us to fix up leftover Swift 2 code intending to be an associatedtype.
  if (Tok.is(tok::kw_typealias)) {
    AssociatedTypeLoc = consumeToken(tok::kw_typealias);
    diagnose(AssociatedTypeLoc, diag::typealias_inside_protocol_without_type)
        .fixItReplace(AssociatedTypeLoc, "associatedtype");
  } else {
    AssociatedTypeLoc = consumeToken(tok::kw_associatedtype);
  }
  
  Status = parseIdentifierDeclName(*this, Id, IdLoc, "associatedtype",
                                   tok::colon, tok::equal);
  if (Status.isError())
    return nullptr;
  
  DebuggerContextChange DCC(*this, Id, DeclKind::AssociatedType);
  
  // Reject generic parameters with a specific error.
  if (startsWithLess(Tok)) {
    // Introduce a throwaway scope to capture the generic parameters. We
    // don't want them visible anywhere!
    Scope S(this, ScopeKind::Generics);

    if (auto genericParams = parseGenericParameters().getPtrOrNull()) {
      diagnose(genericParams->getLAngleLoc(),
               diag::associated_type_generic_parameter_list)
      .fixItRemove(genericParams->getSourceRange());
    }
  }
  
  // Parse optional inheritance clause.
  // FIXME: Allow class requirements here.
  SmallVector<TypeLoc, 2> Inherited;
  if (Tok.is(tok::colon))
    Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
  
  ParserResult<TypeRepr> UnderlyingTy;
  if (Tok.is(tok::equal)) {
    consumeToken(tok::equal);
    UnderlyingTy = parseType(diag::expected_type_in_associatedtype);
    Status |= UnderlyingTy;
    if (UnderlyingTy.isNull())
      return Status;
  }

  TrailingWhereClause *TrailingWhere = nullptr;
  // Parse a 'where' clause if present.
  if (Tok.is(tok::kw_where)) {
    auto whereStatus = parseProtocolOrAssociatedTypeWhereClause(
        TrailingWhere, /*isProtocol=*/false);
    if (whereStatus.shouldStopParsing())
      return whereStatus;
  }

  if (!Flags.contains(PD_InProtocol)) {
    diagnose(AssociatedTypeLoc, diag::associatedtype_outside_protocol)
        .fixItReplace(AssociatedTypeLoc, "typealias");
    Status.setIsParseError();
    return Status;
  }

  auto assocType = new (Context)
      AssociatedTypeDecl(CurDeclContext, AssociatedTypeLoc, Id, IdLoc,
                         UnderlyingTy.getPtrOrNull(), TrailingWhere);
  assocType->getAttrs() = Attributes;
  if (!Inherited.empty())
    assocType->setInherited(Context.AllocateCopy(Inherited));
  addToScope(assocType);
  return makeParserResult(Status, assocType);
}

/// This function creates an accessor function (with no body) for a computed
/// property or subscript.
static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, ParameterList *param,
                                    GenericParamList *GenericParams,
                                    ParameterList *Indices,
                                    TypeLoc ElementTy,
                                    SourceLoc StaticLoc,
                                    Parser::ParseDeclOptions Flags,
                                    AccessorKind Kind,
                                    AddressorKind addressorKind,
                                    Parser *P, SourceLoc AccessorKeywordLoc) {
  // First task, set up the value argument list.  This is the "newValue" name
  // (for setters) followed by the index list (for subscripts).  For
  // non-subscript getters, this degenerates down to "()".
  //
  // We put the 'newValue' argument before the subscript index list as a
  // micro-optimization for Objective-C thunk generation.
  ParameterList *ValueArg;
  {
    SmallVector<ParamDecl*, 2> ValueArgElements;
    SourceLoc StartLoc, EndLoc;
    if (param) {
      assert(param->size() == 1 &&
             "Should only have a single parameter in the list");
      ValueArgElements.push_back(param->get(0));
      StartLoc = param->getStartLoc();
      EndLoc = param->getEndLoc();
    }

    if (Indices) {
      Indices = Indices->clone(P->Context, ParameterList::Implicit);
      ValueArgElements.append(Indices->begin(), Indices->end());
      if (StartLoc.isInvalid()) {
        StartLoc = Indices->getStartLoc();
        EndLoc = Indices->getEndLoc();
      }
    }

    ValueArg = ParameterList::create(P->Context, StartLoc, ValueArgElements,
                                     EndLoc);
  }


  // Create the parameter list(s) for the getter.
  SmallVector<ParameterList*, 4> Params;
  
  // Add the implicit 'self' to Params, if needed.
  if (Flags & Parser::PD_HasContainerType)
    Params.push_back(ParameterList::createUnboundSelf(DeclLoc, P->CurDeclContext));
  
  // Add the "(value)" and subscript indices parameter clause.
  Params.push_back(ValueArg);

  TypeLoc ReturnType;

  // Getters return the value type.
  if (Kind == AccessorKind::IsGetter) {
    ReturnType = ElementTy.clone(P->Context);

  // Addressors return Unsafe{,Mutable}Pointer<T>, plus sometimes an
  // owner or pinned owner.
  } else if (Kind == AccessorKind::IsAddressor ||
             Kind == AccessorKind::IsMutableAddressor) {

    // If we don't have a declared type, we will diagnose later,
    // so skip this to avoid crashing.
    if (ElementTy.getTypeRepr()) {
      // Construct "Unsafe{,Mutable}Pointer<T>".
      
      TypeRepr *args[] = { ElementTy.clone(P->Context).getTypeRepr() };

      // FIXME: the fact that this could resolve in the local scope is dumb.
      bool isMutable = (Kind == AccessorKind::IsMutableAddressor);
      Identifier name = P->Context.getIdentifier(
                      isMutable ? "UnsafeMutablePointer" : "UnsafePointer");

      TypeRepr *resultType =
        new (P->Context) GenericIdentTypeRepr(SourceLoc(), name,
                                              P->Context.AllocateCopy(args),
                                              SourceRange());

      auto makeKnownType = [&](Type type) -> TypeRepr* {
        return new (P->Context) FixedTypeRepr(type, SourceLoc());
      };
      auto makePairType = [&](TypeRepr *fst, TypeRepr *snd) -> TypeRepr* {
        return TupleTypeRepr::create(P->Context, {fst, snd}, SourceRange());
      };

      switch (addressorKind) {
      case AddressorKind::NotAddressor:
        llvm_unreachable("not an addressor!");

      // For unsafe addressors, that's all we've got.
      case AddressorKind::Unsafe:
        break;

      // For non-native owning addressors, the return type is actually
      //   (Unsafe{,Mutable}Pointer<T>, Builtin.UnknownObject)
      case AddressorKind::Owning:
        resultType = makePairType(resultType,
                                  makeKnownType(P->Context.TheUnknownObjectType));
        break;

      // For native owning addressors, the return type is actually
      //   (Unsafe{,Mutable}Pointer<T>, Builtin.NativeObject)
      case AddressorKind::NativeOwning:
        resultType = makePairType(resultType,
                                  makeKnownType(P->Context.TheNativeObjectType));
        break;

      // For native pinning addressors, the return type is actually
      //   (Unsafe{,Mutable}Pointer<T>, Builtin.NativeObject?)
      case AddressorKind::NativePinning: {
        auto optNativePtr = new (P->Context) OptionalTypeRepr(
            makeKnownType(P->Context.TheNativeObjectType),
            SourceLoc());
        resultType = makePairType(resultType, optNativePtr);
        break;
      }
      }

      ReturnType = resultType;
    }

  // Everything else returns ().
  } else {
    ReturnType = TypeLoc::withoutLoc(TupleType::getEmpty(P->Context));
  }

  // Start the function.
  auto *D = FuncDecl::create(P->Context, StaticLoc, StaticSpellingKind::None,
                             /*FIXME FuncLoc=*/DeclLoc, Identifier(),
                             /*NameLoc=*/DeclLoc, /*Throws=*/false,
                             /*ThrowsLoc=*/SourceLoc(), AccessorKeywordLoc,
                             (GenericParams
                              ? GenericParams->clone(P->CurDeclContext)
                              : nullptr),
                             Params, ReturnType,
                             P->CurDeclContext);

  // Non-static set/willSet/didSet/materializeForSet/mutableAddress
  // default to mutating.  get/address default to
  // non-mutating.
  if (!D->isStatic()) {
    switch (Kind) {
    case AccessorKind::IsAddressor:
      D->setAddressorKind(addressorKind);
      break;

    case AccessorKind::IsGetter:
      break;

    case AccessorKind::IsMutableAddressor:
      D->setAddressorKind(addressorKind);
      LLVM_FALLTHROUGH;

    case AccessorKind::IsSetter:
    case AccessorKind::IsWillSet:
    case AccessorKind::IsDidSet:
      D->setMutating();
      break;

    case AccessorKind::IsMaterializeForSet:
    case AccessorKind::NotAccessor:
      llvm_unreachable("not parseable accessors");
    }
  }

  return D;
}

static ParamDecl *
createSetterAccessorArgument(SourceLoc nameLoc, Identifier name,
                             TypeLoc elementTy, AccessorKind accessorKind,
                             Parser &P) {
  // Add the parameter. If no name was specified, the name defaults to
  // 'value'.
  bool isNameImplicit = name.empty();
  if (isNameImplicit) {
    const char *implName =
      accessorKind == AccessorKind::IsDidSet ? "oldValue" : "newValue";
    name = P.Context.getIdentifier(implName);
  }

  auto result = new (P.Context) ParamDecl(/*IsLet*/true,SourceLoc(),SourceLoc(),
                                          Identifier(), nameLoc, name,
                                          Type(), P.CurDeclContext);
  if (isNameImplicit)
    result->setImplicit();

  result->getTypeLoc() = elementTy.clone(P.Context);
  
  // AST Walker shouldn't go into the type recursively.
  result->setIsTypeLocImplicit(true);
  return result;
}

/// Parse a "(value)" specifier for "set" or "willSet" if present.  Create a
/// parameter list to represent the spelled argument or return null if none is
/// present.
static ParameterList *
parseOptionalAccessorArgument(SourceLoc SpecifierLoc, TypeLoc ElementTy,
                              Parser &P, AccessorKind Kind) {
  // 'set' and 'willSet' have a (value) parameter, 'didSet' takes an (oldValue)
  // parameter and 'get' and always takes a () parameter.
  if (Kind != AccessorKind::IsSetter && Kind != AccessorKind::IsWillSet &&
      Kind != AccessorKind::IsDidSet)
    return nullptr;

  SourceLoc StartLoc, NameLoc, EndLoc;
  Identifier Name;

  // If the SpecifierLoc is invalid, then the caller just wants us to synthesize
  // the default, not actually try to parse something.
  if (SpecifierLoc.isValid() && P.Tok.is(tok::l_paren)) {
    StartLoc = P.consumeToken(tok::l_paren);
    if (P.Tok.isNot(tok::identifier)) {
      P.diagnose(P.Tok, diag::expected_accessor_name, (unsigned)Kind);
      P.skipUntil(tok::r_paren, tok::l_brace);
      if (P.Tok.is(tok::r_paren))
        EndLoc = P.consumeToken();
      else
        EndLoc = StartLoc;
    } else {
      // We have a name.
      Name = P.Context.getIdentifier(P.Tok.getText());
      NameLoc = P.consumeToken();

      auto DiagID =
         Kind == AccessorKind::IsSetter ? diag::expected_rparen_set_name :
         Kind == AccessorKind::IsWillSet ? diag::expected_rparen_willSet_name :
          diag::expected_rparen_didSet_name;
      
      // Look for the closing ')'.
      P.parseMatchingToken(tok::r_paren, EndLoc, DiagID, StartLoc);
    }
  }

  if (Name.empty()) NameLoc = SpecifierLoc;
  auto param = createSetterAccessorArgument(NameLoc, Name, ElementTy, Kind, P);
  return ParameterList::create(P.Context, StartLoc, param, EndLoc);
}

static unsigned skipUntilMatchingRBrace(Parser &P) {
  unsigned OpenBraces = 1;
  while (OpenBraces != 0 && P.Tok.isNot(tok::eof)) {
    if (P.consumeIf(tok::l_brace)) {
      OpenBraces++;
      continue;
    }
    if (OpenBraces == 1 && P.Tok.is(tok::r_brace))
      break;
    if (P.consumeIf(tok::r_brace)) {
      OpenBraces--;
      continue;
    }
    P.consumeToken();
  }
  return OpenBraces;
}

static unsigned skipBracedBlock(Parser &P) {
  P.consumeToken(tok::l_brace);
  unsigned OpenBraces = skipUntilMatchingRBrace(P);
  if (P.consumeIf(tok::r_brace))
    OpenBraces--;
  return OpenBraces;
}

void Parser::consumeGetSetBody(AbstractFunctionDecl *AFD,
                               SourceLoc LBLoc) {
  SourceLoc SavedPreviousLoc = PreviousLoc;

  SourceRange BodyRange;
  BodyRange.Start = Tok.getLoc();

  // Skip until the next '}' at the correct nesting level.
  unsigned OpenBraces = skipUntilMatchingRBrace(*this);

  if (OpenBraces != 1) {
    // FIXME: implement some error recovery?
  }

  BodyRange.End = PreviousLoc;

  if (DelayedParseCB->shouldDelayFunctionBodyParsing(
          *this, AFD, AFD->getAttrs(), BodyRange)) {
    State->delayAccessorBodyParsing(AFD, BodyRange, SavedPreviousLoc, LBLoc);
    AFD->setBodyDelayed(BodyRange);
  } else {
    AFD->setBodySkipped(BodyRange);
  }
}

static AddressorKind getImmutableAddressorKind(Token &tok) {
  if (tok.isContextualKeyword("unsafeAddress")) {
    return AddressorKind::Unsafe;
  } else if (tok.isContextualKeyword("addressWithOwner")) {
    return AddressorKind::Owning;
  } else if (tok.isContextualKeyword("addressWithNativeOwner")) {
    return AddressorKind::NativeOwning;
  } else if (tok.isContextualKeyword("addressWithPinnedNativeOwner")) {
    return AddressorKind::NativePinning;
  } else {
    return AddressorKind::NotAddressor;
  }
}
static AddressorKind getMutableAddressorKind(Token &tok) {
  if (tok.isContextualKeyword("unsafeMutableAddress")) {
    return AddressorKind::Unsafe;
  } else if (tok.isContextualKeyword("mutableAddressWithOwner")) {
    return AddressorKind::Owning;
  } else if (tok.isContextualKeyword("mutableAddressWithNativeOwner")) {
    return AddressorKind::NativeOwning;
  } else if (tok.isContextualKeyword("mutableAddressWithPinnedNativeOwner")) {
    return AddressorKind::NativePinning;
  } else {
    return AddressorKind::NotAddressor;
  }
}

/// Returns an accessor kind that 
static StringRef getAccessorNameForDiagnostic(AccessorKind accessorKind,
                                              AddressorKind addressorKind) {
  switch (accessorKind) {
  case AccessorKind::NotAccessor: llvm_unreachable("invalid");
  case AccessorKind::IsGetter: return "getter";
  case AccessorKind::IsSetter: return "setter";
  case AccessorKind::IsDidSet: return "didSet";
  case AccessorKind::IsWillSet: return "willSet";
  case AccessorKind::IsMaterializeForSet: return "materializeForSet";
  case AccessorKind::IsAddressor:
    switch (addressorKind) {
    case AddressorKind::NotAddressor: llvm_unreachable("invalid");
    case AddressorKind::Unsafe: return "unsafeAddress";
    case AddressorKind::Owning: return "addressWithOwner";
    case AddressorKind::NativeOwning: return "addressWithNativeOwner";
    case AddressorKind::NativePinning: return "addressWithPinnedNativeOwner";
    }
    llvm_unreachable("bad addressor kind");
  case AccessorKind::IsMutableAddressor:
    switch (addressorKind) {
    case AddressorKind::NotAddressor: llvm_unreachable("invalid");
    case AddressorKind::Unsafe: return "unsafeMutableAddress";
    case AddressorKind::Owning: return "mutableAddressWithOwner";
    case AddressorKind::NativeOwning: return "mutableAddressWithNativeOwner";
    case AddressorKind::NativePinning: return "mutableAddressWithPinnedNativeOwner";
    }
    llvm_unreachable("bad addressor kind");
  }
  llvm_unreachable("bad accessor kind");  
}

static void diagnoseRedundantAccessors(Parser &P, SourceLoc loc,
                                       AccessorKind accessorKind,
                                       AddressorKind addressorKind,
                                       bool isSubscript,
                                       FuncDecl *previousDecl) {
  // Different addressor safety kinds still count as the same addressor.
  if (previousDecl->getAddressorKind() != addressorKind) {
    assert(accessorKind == AccessorKind::IsAddressor ||
           accessorKind == AccessorKind::IsMutableAddressor);
    P.diagnose(loc, diag::conflicting_property_addressor,
               unsigned(isSubscript),
               unsigned(accessorKind == AccessorKind::IsMutableAddressor));

    // Be less specific about the previous definition.
    P.diagnose(previousDecl->getLoc(), diag::previous_accessor,
               accessorKind == AccessorKind::IsMutableAddressor
                 ? "mutable addressor" : "addressor");
    return;
  }

  P.diagnose(loc, diag::duplicate_property_accessor,
             getAccessorNameForDiagnostic(accessorKind, addressorKind));
  P.diagnose(previousDecl->getLoc(), diag::previous_accessor,
             getAccessorNameForDiagnostic(accessorKind, addressorKind));
}

/// \brief Parse a get-set clause, optionally containing a getter, setter,
/// willSet, and/or didSet clauses.  'Indices' is a paren or tuple pattern,
/// specifying the index list for a subscript.
bool Parser::parseGetSetImpl(ParseDeclOptions Flags,
                             GenericParamList *GenericParams,
                             ParameterList *Indices,
                             TypeLoc ElementTy, ParsedAccessors &accessors,
                             SourceLoc &LastValidLoc, SourceLoc StaticLoc,
                             SourceLoc VarLBLoc,
                             SmallVectorImpl<Decl *> &Decls) {

  // Properties in protocols use sufficiently limited syntax that we have a
  // special parsing loop for them.  SIL mode uses the same syntax.
  if (Flags.contains(PD_InProtocol) || isInSILMode()) {
    while (Tok.isNot(tok::r_brace)) {
      if (Tok.is(tok::eof))
        return true;

      // Parse any leading attributes.
      DeclAttributes Attributes;
      bool FoundCCToken;
      parseDeclAttributeList(Attributes, FoundCCToken);

      // Parse the contextual keywords for 'mutating' and 'nonmutating' before
      // get and set.
      if (Tok.isContextualKeyword("mutating")) {
        parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Mutating);
      } else if (Tok.isContextualKeyword("nonmutating")) {
        parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_NonMutating);
      }

      AccessorKind Kind;
      AddressorKind addressorKind = AddressorKind::NotAddressor;
      FuncDecl **TheDeclPtr;
      SourceLoc AccessorKeywordLoc = Tok.getLoc();
      if (Tok.isContextualKeyword("get")) {
        Kind = AccessorKind::IsGetter;
        TheDeclPtr = &accessors.Get;
      } else if (Tok.isContextualKeyword("set")) {
        Kind = AccessorKind::IsSetter;
        TheDeclPtr = &accessors.Set;
      } else if (!Flags.contains(PD_InProtocol) &&
                 (addressorKind = getImmutableAddressorKind(Tok))
                   != AddressorKind::NotAddressor) {
        Kind = AccessorKind::IsAddressor;
        TheDeclPtr = &accessors.Addressor;
      } else if (!Flags.contains(PD_InProtocol) &&
                 (addressorKind = getMutableAddressorKind(Tok))
                   != AddressorKind::NotAddressor) {
        Kind = AccessorKind::IsMutableAddressor;
        TheDeclPtr = &accessors.MutableAddressor;
      } else {
        AccessorKeywordLoc = SourceLoc();
        diagnose(Tok, diag::expected_getset_in_protocol);
        return true;
      }

      FuncDecl *&TheDecl = *TheDeclPtr;
      SourceLoc Loc = consumeToken();

      // Have we already parsed this kind of clause?
      if (TheDecl) {
        diagnoseRedundantAccessors(*this, Loc, Kind, addressorKind,
                                   /*subscript*/Indices != nullptr, TheDecl);

        // Forget the previous decl.
        Decls.erase(std::find(Decls.begin(), Decls.end(), TheDecl));
        TheDecl = nullptr;  // Forget the previous decl.
      }

      // "set" could have a name associated with it.  This isn't valid in a
      // protocol, but we parse and then reject it, for better QoI.
      if (Tok.is(tok::l_paren))
        diagnose(Loc, diag::protocol_setter_name);

      auto *ValueNameParams
        = parseOptionalAccessorArgument(Loc, ElementTy, *this, Kind);

      // Set up a function declaration.
      TheDecl = createAccessorFunc(Loc, ValueNameParams,
                                   GenericParams, Indices, ElementTy,
                                   StaticLoc, Flags, Kind, addressorKind, this,
                                   AccessorKeywordLoc);
      TheDecl->getAttrs() = Attributes;
      
      Decls.push_back(TheDecl);
    }

    return false;
  }


  // Otherwise, we have a normal var or subscript declaration, parse the full
  // complement of specifiers, along with their bodies.

  // If the body is completely empty, preserve it.  This is at best a getter with
  // an implicit fallthrough off the end.
  if (Tok.is(tok::r_brace)) {
    diagnose(Tok, diag::computed_property_no_accessors);
    return true;
  }

  bool IsFirstAccessor = true;
  while (Tok.isNot(tok::r_brace)) {
    if (Tok.is(tok::eof))
      return true;

    // If there are any attributes, we are going to parse them.  Because these
    // attributes might not be appertaining to the accessor, but to the first
    // declaration inside the implicit getter, we need to save the parser
    // position and restore it later.
    ParserPosition BeginParserPosition;
    if (Tok.is(tok::at_sign))
      BeginParserPosition = getParserPosition();

    // Parse any leading attributes.
    DeclAttributes Attributes;
    bool FoundCCToken;
    parseDeclAttributeList(Attributes, FoundCCToken);

    // Parse the contextual keywords for 'mutating' and 'nonmutating' before
    // get and set.
    if (Tok.isContextualKeyword("mutating")) {
      parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Mutating);
    } else if (Tok.isContextualKeyword("nonmutating")) {
      parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_NonMutating);
    }
    
    bool isImplicitGet = false;
    AccessorKind Kind;
    AddressorKind addressorKind = AddressorKind::NotAddressor;
    FuncDecl **TheDeclPtr;
    SourceLoc AccessorKeywordLoc =  Tok.getLoc();
    if (Tok.isContextualKeyword("get")) {
      Kind = AccessorKind::IsGetter;
      TheDeclPtr = &accessors.Get;
    } else if (Tok.isContextualKeyword("set")) {
      Kind = AccessorKind::IsSetter;
      TheDeclPtr = &accessors.Set;
    } else if (Tok.isContextualKeyword("willSet")) {
      Kind = AccessorKind::IsWillSet;
      TheDeclPtr = &accessors.WillSet;
    } else if (Tok.isContextualKeyword("didSet")) {
      Kind = AccessorKind::IsDidSet;
      TheDeclPtr = &accessors.DidSet;
    } else if ((addressorKind = getImmutableAddressorKind(Tok))
                 != AddressorKind::NotAddressor) {
      Kind = AccessorKind::IsAddressor;
      TheDeclPtr = &accessors.Addressor;
    } else if ((addressorKind = getMutableAddressorKind(Tok))
                 != AddressorKind::NotAddressor) {
      Kind = AccessorKind::IsMutableAddressor;
      TheDeclPtr = &accessors.MutableAddressor;
    } else {
      AccessorKeywordLoc = SourceLoc();
      // This is an implicit getter.  Might be not valid in this position,
      // though.  Anyway, go back to the beginning of the getter code to ensure
      // that the diagnostics point to correct tokens.
      if (BeginParserPosition.isValid()) {
        backtrackToPosition(BeginParserPosition);
        Attributes = DeclAttributes();
      }
      if (!IsFirstAccessor) {
        // Cannot have an implicit getter after other accessor.
        diagnose(Tok, diag::expected_accessor_kw);
        skipUntil(tok::r_brace);
        // Don't signal an error since we recovered.
        return false;
      }
      Kind = AccessorKind::IsGetter;
      TheDeclPtr = &accessors.Get;
      isImplicitGet = true;
    }

    IsFirstAccessor = false;

    // Consume the contextual keyword, if present.
    SourceLoc Loc = isImplicitGet ? VarLBLoc : consumeToken();

    FuncDecl *&TheDecl = *TheDeclPtr;

    // Have we already parsed this kind of clause?
    if (TheDecl) {
      diagnoseRedundantAccessors(*this, Loc, Kind, addressorKind,
                                 /*subscript*/Indices != nullptr, TheDecl);

      // Forget the previous decl.
      Decls.erase(std::find(Decls.begin(), Decls.end(), TheDecl));
      TheDecl = nullptr;
    }

    // 'set' and 'willSet' can have an optional name.
    //
    //     set-name    ::= '(' identifier ')'
    auto *ValueNamePattern =
      parseOptionalAccessorArgument(Loc, ElementTy, *this, Kind);

    SourceLoc LBLoc = isImplicitGet ? VarLBLoc : Tok.getLoc();
    // FIXME: Use outer '{' loc if isImplicitGet.
    bool ExternalAsmName = false;
    if (!isImplicitGet && !consumeIf(tok::l_brace)) {
      // _silgen_name'd accessors don't need bodies.
      if (!Attributes.hasAttribute<SILGenNameAttr>()) {
        diagnose(Tok, diag::expected_lbrace_accessor,
                 getAccessorNameForDiagnostic(Kind, addressorKind));
        return true;
      }
      ExternalAsmName = true;
    }

    // Set up a function declaration.
    TheDecl = createAccessorFunc(Loc, ValueNamePattern,
                                 GenericParams, Indices, ElementTy,
                                 StaticLoc, Flags, Kind, addressorKind, this,
                                 AccessorKeywordLoc);
    TheDecl->getAttrs() = Attributes;

    // Parse the body, if any.
    if (ExternalAsmName) {
      LastValidLoc = Loc;
    } else {
      Scope S(this, ScopeKind::FunctionBody);
      for (auto PL : TheDecl->getParameterLists())
        addParametersToScope(PL);

      if (TheDecl->isGeneric())
        for (auto *GP : TheDecl->getGenericParams()->getParams())
          addToScope(GP);

      // Establish the new context.
      ParseFunctionBody CC(*this, TheDecl);

      // Parse the body.
      SmallVector<ASTNode, 16> Entries;
      {
        llvm::SaveAndRestore<bool> T(IsParsingInterfaceTokens, false);
        if (!isDelayedParsingEnabled())
          parseBraceItems(Entries);
        else
          consumeGetSetBody(TheDecl, LBLoc);
      }

      SourceLoc RBLoc;
      if (!isImplicitGet) {
        parseMatchingToken(tok::r_brace, RBLoc, diag::expected_rbrace_in_getset,
                           LBLoc);
      } else {
        RBLoc = Tok.is(tok::r_brace) ? Tok.getLoc() : PreviousLoc;
      }

      if (!isDelayedParsingEnabled()) {
        BraceStmt *Body = BraceStmt::create(Context, LBLoc, Entries, RBLoc);
        TheDecl->setBody(Body);
      }
      LastValidLoc = RBLoc;
    }

    Decls.push_back(TheDecl);
  }

  return false;
}

bool Parser::parseGetSet(ParseDeclOptions Flags,
                         GenericParamList *GenericParams,
                         ParameterList *Indices,
                         TypeLoc ElementTy, ParsedAccessors &accessors,
                         SourceLoc StaticLoc,
                         SmallVectorImpl<Decl *> &Decls) {
  accessors.LBLoc = consumeToken(tok::l_brace);
  SourceLoc LastValidLoc = accessors.LBLoc;
  bool Invalid = parseGetSetImpl(Flags, GenericParams, Indices, ElementTy,
                                 accessors, LastValidLoc, StaticLoc,
                                 accessors.LBLoc, Decls);

  // Parse the final '}'.
  if (Invalid)
    skipUntil(tok::r_brace);

  parseMatchingToken(tok::r_brace, accessors.RBLoc,
                     diag::expected_rbrace_in_getset, accessors.LBLoc);
  return Invalid;
}

void Parser::parseAccessorBodyDelayed(AbstractFunctionDecl *AFD) {
  assert(!AFD->getBody() && "function should not have a parsed body");
  assert(AFD->getBodyKind() == AbstractFunctionDecl::BodyKind::Unparsed &&
         "function body should be delayed");

  auto AccessorParserState = State->takeAccessorBodyState(AFD);
  assert(AccessorParserState.get() && "should have a valid state");

  auto BeginParserPosition = getParserPosition(AccessorParserState->BodyPos);
  auto EndLexerState = L->getStateForEndOfTokenLoc(AFD->getEndLoc());

  // ParserPositionRAII needs a primed parser to restore to.
  if (Tok.is(tok::NUM_TOKENS))
    consumeToken();

  // Ensure that we restore the parser state at exit.
  ParserPositionRAII PPR(*this);

  // Create a lexer that cannot go past the end state.
  Lexer LocalLex(*L, BeginParserPosition.LS, EndLexerState);

  // Temporarily swap out the parser's current lexer with our new one.
  llvm::SaveAndRestore<Lexer *> T(L, &LocalLex);

  // Rewind to the first token of the accessor body.
  restoreParserPosition(BeginParserPosition);

  // Re-enter the lexical scope.
  Scope S(this, AccessorParserState->takeScope());
  ParseFunctionBody CC(*this, AFD);

  SmallVector<ASTNode, 16> Entries;
  parseBraceItems(Entries);
  BraceStmt *Body =
      BraceStmt::create(Context, AccessorParserState->LBLoc, Entries,
                        Tok.getLoc());
  AFD->setBody(Body);
}

/// \brief Parse the brace-enclosed getter and setter for a variable.
VarDecl *Parser::parseDeclVarGetSet(Pattern *pattern,
                                    ParseDeclOptions Flags,
                                    SourceLoc StaticLoc, bool hasInitializer,
                                    const DeclAttributes &Attributes,
                                    SmallVectorImpl<Decl *> &Decls) {
  bool Invalid = false;
  
  // The grammar syntactically requires a simple identifier for the variable
  // name. Complain if that isn't what we got.
  VarDecl *PrimaryVar = nullptr;
  {
    Pattern *PrimaryPattern = pattern;
    if (auto *Typed = dyn_cast<TypedPattern>(PrimaryPattern))
      PrimaryPattern = Typed->getSubPattern();
    if (auto *Named = dyn_cast<NamedPattern>(PrimaryPattern)) {
      PrimaryVar = Named->getDecl();
    }
  }

  if (!PrimaryVar) {
    diagnose(pattern->getLoc(), diag::getset_nontrivial_pattern);
    Invalid = true;
  } else {
    setLocalDiscriminator(PrimaryVar);
  }

  TypeLoc TyLoc;
  if (auto *TP = dyn_cast<TypedPattern>(pattern)) {
    TyLoc = TP->getTypeLoc();
  } else if (!PrimaryVar) {
    TyLoc = TypeLoc::withoutLoc(ErrorType::get(Context));
  }

  // Parse getter and setter.
  ParsedAccessors accessors;
  if (parseGetSet(Flags, /*GenericParams=*/nullptr,
                  /*Indices=*/nullptr, TyLoc, accessors, StaticLoc,
                  Decls))
    Invalid = true;

  // If we have an invalid case, bail out now.
  if (!PrimaryVar)
    return nullptr;

  if (!TyLoc.hasLocation()) {
    if (accessors.Get || accessors.Set || accessors.Addressor ||
        accessors.MutableAddressor) {
      SourceLoc locAfterPattern = pattern->getLoc().getAdvancedLoc(
        pattern->getBoundName().getLength());
      diagnose(pattern->getLoc(), diag::computed_property_missing_type)
        .fixItInsert(locAfterPattern, ": <# Type #>");
      Invalid = true;
    }
  }

  // Reject accessors on 'let's after parsing them (for better recovery).
  if (PrimaryVar->isLet() && !Attributes.hasAttribute<SILStoredAttr>()) {
    if (accessors.WillSet || accessors.DidSet)
      diagnose(accessors.LBLoc, diag::let_cannot_be_observing_property);
    else if (accessors.Addressor || accessors.MutableAddressor)
      diagnose(accessors.LBLoc, diag::let_cannot_be_addressed_property);
    else
      diagnose(accessors.LBLoc, diag::let_cannot_be_computed_property);
    PrimaryVar->setLet(false);
    Invalid = true;
  }

  // Lazy var should not have explicit getter/setter.
  // For error-recovery, we mark them as invalid.
  if (Attributes.hasAttribute<LazyAttr>()){
    if (accessors.Get)
      accessors.Get->setInvalid();
    if (accessors.Set)
      accessors.Set->setInvalid();
  }

  accessors.record(*this, PrimaryVar, Invalid, Flags, StaticLoc,
                   Attributes, TyLoc, /*indices*/ nullptr, Decls);

  return PrimaryVar;
}

/// Record a bunch of parsed accessors into the given abstract storage decl.
void Parser::ParsedAccessors::record(Parser &P, AbstractStorageDecl *storage,
                                     bool invalid, ParseDeclOptions flags,
                                     SourceLoc staticLoc,
                                     const DeclAttributes &attrs,
                                     TypeLoc elementTy, ParameterList *indices,
                                     SmallVectorImpl<Decl *> &decls) {
  auto flagInvalidAccessor = [&](FuncDecl *&func) {
    if (func) {
      func->setInvalid();
    }
  };
  auto ignoreInvalidAccessor = [&](FuncDecl *&func) {
    if (func) {
      flagInvalidAccessor(func);

      // Forget the decl being invalidated
      auto PositionInDecls = std::find(decls.begin(), decls.end(), func);
      assert(PositionInDecls != decls.end());
      decls.erase(PositionInDecls);

      func = nullptr;
    }
  };

  GenericParamList *genericParams = nullptr;
  if (auto *subscript = dyn_cast<SubscriptDecl>(storage))
    genericParams = subscript->getGenericParams();

  // Create an implicit accessor declaration.
  auto createImplicitAccessor =
  [&](AccessorKind kind, AddressorKind addressorKind,
      ParameterList *argList) -> FuncDecl* {
    auto accessor = createAccessorFunc(SourceLoc(), argList,
                                       genericParams, indices, elementTy,
                                       staticLoc, flags, kind, addressorKind,
                                       &P, SourceLoc());
    accessor->setImplicit();
    decls.push_back(accessor);
    return accessor;
  };

  // 'address' is exclusive with 'get', and 'mutableAddress' is
  // exclusive with 'set'.
  if (Addressor || MutableAddressor) {
    // Require either a 'get' or an 'address' accessor if there's
    // a 'mutableAddress' accessor.  In principle, we could synthesize
    // 'address' from 'mutableAddress', but for now we'll enforce this.
    if (!Addressor && !Get) {
      P.diagnose(MutableAddressor->getLoc(),
                 diag::mutableaddressor_without_address,
                 isa<SubscriptDecl>(storage));

      Addressor = createImplicitAccessor(AccessorKind::IsAddressor,
                                         AddressorKind::Unsafe,
                                         nullptr);

    // Don't allow both.
    } else if (Addressor && Get) {
      P.diagnose(Addressor->getLoc(), diag::addressor_with_getter,
                 isa<SubscriptDecl>(storage));      
      ignoreInvalidAccessor(Get);
    }

    // Disallow mutableAddress+set.
    //
    // Currently we don't allow the address+set combination either.
    // In principle, this is an unnecessary restriction, and you can
    // imagine caches that might want to vend this combination of
    // accessors.  But we assume that in-place gets aren't all that
    // important.  (For example, we don't make any effort to optimize
    // them for polymorphic accesses.)
    if (Set) {
      if (MutableAddressor) {
        P.diagnose(MutableAddressor->getLoc(), diag::mutableaddressor_with_setter,
                   isa<SubscriptDecl>(storage));
      } else {
        P.diagnose(Set->getLoc(), diag::addressor_with_setter,
                   isa<SubscriptDecl>(storage));
      }
      ignoreInvalidAccessor(Set);
    }
  }

  // For now, we don't support the observing accessors on subscripts.
  if (isa<SubscriptDecl>(storage) && (WillSet || DidSet)) {
    P.diagnose(DidSet ? DidSet->getLoc() : WillSet->getLoc(),
               diag::observingproperty_in_subscript, bool(DidSet));
    ignoreInvalidAccessor(WillSet);
    ignoreInvalidAccessor(DidSet);
  }
  
  // If this decl is invalid, mark any parsed accessors as invalid to avoid
  // tripping up later invariants.
  if (invalid) {
    flagInvalidAccessor(Get);
    flagInvalidAccessor(Set);
    flagInvalidAccessor(Addressor);
    flagInvalidAccessor(MutableAddressor);
    flagInvalidAccessor(WillSet);
    flagInvalidAccessor(DidSet);
  }

  // If this is a willSet/didSet observing property, record this and we're done.
  if (WillSet || DidSet) {
    if (Get || Set) {
      P.diagnose(Get ? Get->getLoc() : Set->getLoc(),
                 diag::observingproperty_with_getset, bool(DidSet), bool(Set));
      ignoreInvalidAccessor(Get);
      ignoreInvalidAccessor(Set);
    }

    if (Addressor) {
      if (!MutableAddressor) {
        P.diagnose(WillSet ? WillSet->getLoc() : DidSet->getLoc(),
                   diag::observingproperty_without_mutableaddress,
                   bool(DidSet));
        MutableAddressor =
          createImplicitAccessor(AccessorKind::IsMutableAddressor,
                                 AddressorKind::Unsafe, nullptr);
      }

      storage->makeAddressedWithObservers(LBLoc, Addressor, MutableAddressor,
                                          WillSet, DidSet, RBLoc);
    } else if (attrs.hasAttribute<OverrideAttr>()) {
      storage->makeInheritedWithObservers(LBLoc, WillSet, DidSet, RBLoc);
    } else {
      storage->makeStoredWithObservers(LBLoc, WillSet, DidSet, RBLoc);
    }

    // Observing properties will have getters and setters synthesized by sema.
    // Create their prototypes now.
    Get = createImplicitAccessor(AccessorKind::IsGetter,
                                 AddressorKind::NotAddressor, nullptr);

    auto argFunc = (WillSet ? WillSet : DidSet);
    auto argLoc = argFunc->getParameterLists().back()->getStartLoc();

    auto argument = createSetterAccessorArgument(argLoc, Identifier(),elementTy,
                                                 AccessorKind::IsSetter, P);
    auto argList = ParameterList::create(P.Context, argument);
    Set = createImplicitAccessor(AccessorKind::IsSetter,
                                 AddressorKind::NotAddressor, argList);

    storage->setObservingAccessors(Get, Set, nullptr);
    return;
  }

  // If we have addressors, at this point mark it as addressed.
  if (Addressor) {
    assert(!Get && !Set);
    storage->makeAddressed(LBLoc, Addressor, MutableAddressor, RBLoc);
    return;
  }

  // If this is a get+mutableAddress property, synthesize an implicit
  // setter and record what we've got.
  if (MutableAddressor) {
    assert(Get && !Set);
    auto argument =
      createSetterAccessorArgument(MutableAddressor->getLoc(), Identifier(),
                                   elementTy, AccessorKind::IsSetter, P);
    auto argList = ParameterList::create(P.Context, argument);
    Set = createImplicitAccessor(AccessorKind::IsSetter,
                                 AddressorKind::NotAddressor, argList);

    storage->makeComputedWithMutableAddress(LBLoc, Get, Set, nullptr,
                                            MutableAddressor, RBLoc);
    return;
  } 

  // Otherwise, this must be a get/set property.  The set is optional,
  // but get is not.
  if (!Get) {
    // Subscripts always have to have *something*; they can't be
    // purely stored.
    if (isa<SubscriptDecl>(storage)) {
      if (!invalid) P.diagnose(LBLoc, diag::subscript_without_get);
      // Create a getter so we don't break downstream invariants by having a
      // setter without a getter.
      Get = createImplicitAccessor(AccessorKind::IsGetter,
                                   AddressorKind::NotAddressor, nullptr);
    } else if (Set) {
      if (!invalid) P.diagnose(Set->getLoc(), diag::var_set_without_get);
      // Create a getter so we don't break downstream invariants by having a
      // setter without a getter.
      Get = createImplicitAccessor(AccessorKind::IsGetter,
                                   AddressorKind::NotAddressor, nullptr);
    }
  }

  if (Set || Get) {
    if (attrs.hasAttribute<SILStoredAttr>())
      // Turn this into a stored property with trivial accessors.
      storage->addTrivialAccessors(Get, Set, nullptr);
    else
      // Turn this into a computed variable.
      storage->makeComputed(LBLoc, Get, Set, nullptr, RBLoc);
  } else {
    // Otherwise this decl is invalid and the accessors have been rejected above.
    // Make sure to at least record the braces range in the AST.
    storage->setInvalidBracesRange(SourceRange(LBLoc, RBLoc));
  }
}


/// \brief Parse a 'var' or 'let' declaration, doing no token skipping on error.
ParserResult<PatternBindingDecl>
Parser::parseDeclVar(ParseDeclOptions Flags,
                     DeclAttributes &Attributes,
                     SmallVectorImpl<Decl *> &Decls,
                     SourceLoc StaticLoc,
                     StaticSpellingKind StaticSpelling,
                     SourceLoc TryLoc) {
  assert(StaticLoc.isInvalid() || StaticSpelling != StaticSpellingKind::None);

  if (StaticLoc.isValid()) {
    if (!Flags.contains(PD_HasContainerType)) {
      diagnose(Tok, diag::static_var_decl_global_scope, StaticSpelling)
          .fixItRemove(StaticLoc);
      StaticLoc = SourceLoc();
      StaticSpelling = StaticSpellingKind::None;
    } else if (Flags.contains(PD_InStruct) || Flags.contains(PD_InEnum) ||
               Flags.contains(PD_InProtocol)) {
      if (StaticSpelling == StaticSpellingKind::KeywordClass)
        diagnose(Tok, diag::class_var_not_in_class)
            .fixItReplace(StaticLoc, "static");
    }
  }

  bool isLet = Tok.is(tok::kw_let);
  assert(Tok.getKind() == tok::kw_let || Tok.getKind() == tok::kw_var);
  SourceLoc VarLoc = consumeToken();

  // If this is a var in the top-level of script/repl source file, wrap the
  // PatternBindingDecl in a TopLevelCodeDecl, since it represents executable
  // code.  The VarDecl and any accessor decls (for computed properties) go in
  // CurDeclContext.
  //
  TopLevelCodeDecl *topLevelDecl = nullptr;
  if (allowTopLevelCode() && CurDeclContext->isModuleScopeContext()) {
    // The body of topLevelDecl will get set later.
    topLevelDecl = new (Context) TopLevelCodeDecl(CurDeclContext);
  }

  bool HasAccessors = false;  // Syntactically has accessor {}'s.
  ParserStatus Status;

  unsigned NumDeclsInResult = Decls.size();
  
  // In var/let decl with multiple patterns, accumulate them all in this list
  // so we can build our singular PatternBindingDecl at the end.
  SmallVector<PatternBindingEntry, 4> PBDEntries;
  auto BaseContext = CurDeclContext;

  // No matter what error path we take, make sure the
  // PatternBindingDecl/TopLevel code block are added.
  auto makeResult =
    [&](ParserStatus Status) -> ParserResult<PatternBindingDecl> {

    // If we didn't parse any patterns, don't create the pattern binding decl.
    if (PBDEntries.empty())
      return Status;
    
    // Now that we've parsed all of our patterns, initializers and accessors, we
    // can finally create our PatternBindingDecl to represent the
    // pattern/initializer pairs.
    auto PBD = PatternBindingDecl::create(Context, StaticLoc, StaticSpelling,
                                          VarLoc, PBDEntries, BaseContext);

    // Wire up any initializer contexts we needed.
    for (unsigned i : indices(PBDEntries)) {
      if (auto initContext = PBDEntries[i].getInitContext())
        cast<PatternBindingInitializer>(initContext)->setBinding(PBD, i);
    }

    // If we're setting up a TopLevelCodeDecl, configure it by setting up the
    // body that holds PBD and we're done.  The TopLevelCodeDecl is already set
    // up in Decls to be returned to caller.
    if (topLevelDecl) {
      PBD->setDeclContext(topLevelDecl);
      auto range = PBD->getSourceRange();
      topLevelDecl->setBody(BraceStmt::create(Context, range.Start,
                                              ASTNode(PBD), range.End, true));
      Decls.insert(Decls.begin()+NumDeclsInResult, topLevelDecl);
      return makeParserResult(Status, PBD);
    }

    // Otherwise return the PBD in "Decls" to the caller.  We add it at a
    // specific spot to get it in before any accessors, which SILGen seems to
    // want.
    Decls.insert(Decls.begin()+NumDeclsInResult, PBD);

    // Always return the result for PBD.
    return makeParserResult(Status, PBD);
  };
  
  do {
    Pattern *pattern;
    {
      // In our recursive parse, remember that we're in a var/let pattern.
      llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
      T(InVarOrLetPattern, isLet ? IVOLP_InLet : IVOLP_InVar);

      auto patternRes = parseTypedPattern();
      if (patternRes.hasCodeCompletion())
        return makeResult(makeParserCodeCompletionStatus());
      if (patternRes.isNull())
        return makeResult(makeParserError());

      pattern = patternRes.get();
    }
    
    // Configure all vars with attributes, 'static' and parent pattern.
    pattern->forEachVariable([&](VarDecl *VD) {
      VD->setStatic(StaticLoc.isValid());
      VD->getAttrs() = Attributes;
      Decls.push_back(VD);
    });

    // Remember this pattern/init pair for our ultimate PatternBindingDecl. The
    // Initializer will be added later when/if it is parsed.
    PBDEntries.push_back({pattern, nullptr, nullptr});

    Expr *PatternInit = nullptr;
    
    // Parse an initializer if present.
    if (Tok.is(tok::equal)) {
      // If we're not in a local context, we'll need a context to parse initializers
      // into (should we have one).  This happens for properties and global
      // variables in libraries.
      PatternBindingInitializer *initContext = nullptr;

      // Record the variables that we're trying to initialize.  This allows us
      // to cleanly reject "var x = x" when "x" isn't bound to an enclosing
      // decl (even though names aren't injected into scope when the initializer
      // is parsed).
      SmallVector<VarDecl *, 4> Vars;
      Vars.append(DisabledVars.begin(), DisabledVars.end());
      pattern->collectVariables(Vars);
      
      llvm::SaveAndRestore<decltype(DisabledVars)>
      RestoreCurVars(DisabledVars, Vars);

      llvm::SaveAndRestore<decltype(DisabledVarReason)>
      RestoreReason(DisabledVarReason, diag::var_init_self_referential);
      
      // If we have no local context to parse the initial value into, create one
      // for the PBD we'll eventually create.  This allows us to have reasonable
      // DeclContexts for any closures that may live inside of initializers.
      if (!CurDeclContext->isLocalContext() && !topLevelDecl && !initContext)
        initContext = new (Context) PatternBindingInitializer(CurDeclContext);

      // If we're using a local context (either a TopLevelCodeDecl or a
      // PatternBindingContext) install it now so that CurDeclContext is set
      // right when parsing the initializer.
      Optional<ParseFunctionBody> initParser;
      Optional<ContextChange> topLevelParser;
      if (topLevelDecl)
        topLevelParser.emplace(*this, topLevelDecl,
                               &State->getTopLevelContext());
      if (initContext)
        initParser.emplace(*this, initContext);

      
      SourceLoc EqualLoc = consumeToken(tok::equal);
      ParserResult<Expr> init = parseExpr(diag::expected_init_value);
      
      // If this Pattern binding was not supposed to have an initializer, but it
      // did, diagnose this and remove it.
      if (Flags & PD_DisallowInit && init.isNonNull()) {
        diagnose(EqualLoc, diag::disallowed_init);
        init = nullptr;
      }
      
      // Otherwise, if this pattern binding *was* supposed (or allowed) to have
      // an initializer, but it was a parse error, replace it with ErrorExpr so
      // that downstream clients know that it was present (well, at least the =
      // was present).  This silences downstream diagnostics checking to make
      // sure that some PBD's that require initializers actually had them.
      if (!(Flags & PD_DisallowInit) && init.isNull())
        init = makeParserResult(init, new (Context) ErrorExpr(EqualLoc));
      
      
      // Remember this init for the PatternBindingDecl.
      PatternInit = init.getPtrOrNull();
      PBDEntries.back().setInit(PatternInit);

      // If we set up an initialization context for a property or module-level
      // global, record it.
      PBDEntries.back().setInitContext(initContext);

      // If we are doing second pass of code completion, we don't want to
      // suddenly cut off parsing and throw away the declaration.
      if (init.hasCodeCompletion() && isCodeCompletionFirstPass()) {

        // Register the end of the init as the end of the delayed parsing.
        DelayedDeclEnd
          = init.getPtrOrNull() ? init.get()->getEndLoc() : SourceLoc();
        return makeResult(makeParserCodeCompletionStatus());
      }

      if (init.isNull())
        return makeResult(makeParserError());
    }
    
    // Parse a behavior block if present.
    if (Context.LangOpts.EnableExperimentalPropertyBehaviors
        && Tok.is(tok::identifier)
        && Tok.getRawText().equals("__behavior")) {
      consumeToken(tok::identifier);
      auto type = parseType(diag::expected_behavior_name,
                            /*handle completion*/ true);
      if (type.isParseError())
        return makeResult(makeParserError());
      if (type.hasCodeCompletion())
        return makeResult(makeParserCodeCompletionStatus());
      
      // Parse a following trailing closure argument.
      // FIXME: Handle generalized parameters.
      Expr *paramExpr = nullptr;
      if (Tok.is(tok::l_brace)) {
        // If we're not in a local context, we'll need a context to parse initializers
        // into (should we have one).  This happens for properties and global
        // variables in libraries.
        PatternBindingInitializer *initContext = nullptr;

        // Record the variables that we're trying to set up.  This allows us
        // to cleanly reject "var x = x" when "x" isn't bound to an enclosing
        // decl (even though names aren't injected into scope when the parameter
        // is parsed).
        SmallVector<VarDecl *, 4> Vars;
        Vars.append(DisabledVars.begin(), DisabledVars.end());
        pattern->collectVariables(Vars);
        
        llvm::SaveAndRestore<decltype(DisabledVars)>
        RestoreCurVars(DisabledVars, Vars);
        
        llvm::SaveAndRestore<decltype(DisabledVarReason)>
        RestoreReason(DisabledVarReason, diag::var_init_self_referential);

        // Set up a decl context for the closure.
        // This will be recontextualized to a method we synthesize during
        // type checking.
        if (!CurDeclContext->isLocalContext() && !topLevelDecl && !initContext)
          initContext = new (Context) PatternBindingInitializer(CurDeclContext);
        Optional<ParseFunctionBody> initParser;
        Optional<ContextChange> topLevelParser;
        if (topLevelDecl)
          topLevelParser.emplace(*this, topLevelDecl,
                                 &State->getTopLevelContext());
        if (initContext)
          initParser.emplace(*this, initContext);

        auto closure = parseExprClosure();
        PBDEntries.back().setInitContext(initContext);

        if (closure.isParseError())
          return makeResult(makeParserError());
        if (closure.hasCodeCompletion())
          return makeResult(makeParserCodeCompletionStatus());
        paramExpr = closure.get();
      }

      unsigned numVars = 0;
      pattern->forEachVariable([&](VarDecl *VD) {
        ++numVars;
        // TODO: Support parameter closure with multiple vars. This is tricky
        // since the behavior's parameter type may be dependent on the
        // property type, so we'd need to clone the closure expr for each var
        // to re-type-check it.
        if (numVars > 1 && paramExpr) {
          diagnose(paramExpr->getLoc(), diag::behavior_multiple_vars);
          paramExpr = nullptr;
        }
        
        VD->addBehavior(type.get(), paramExpr);
      });
    // If we syntactically match the second decl-var production, with a
    // var-get-set clause, parse the var-get-set clause.
    } else if (Tok.is(tok::l_brace) && !Flags.contains(PD_InLoop)) {
      HasAccessors = true;
      
      if (auto *boundVar = parseDeclVarGetSet(pattern, Flags, StaticLoc,
                                              PatternInit != nullptr,
                                              Attributes, Decls)) {
        if (PatternInit && !boundVar->hasStorage()) {
          diagnose(pattern->getLoc(), diag::getset_init)
            .highlight(PatternInit->getSourceRange());
          PatternInit = nullptr;
        }
      }
    }
    
    // Add all parsed vardecls to this scope.
    addPatternVariablesToScope(pattern);
    
    // Propagate back types for simple patterns, like "var A, B : T".
    if (auto *TP = dyn_cast<TypedPattern>(pattern)) {
      if (isa<NamedPattern>(TP->getSubPattern()) && PatternInit == nullptr) {
        for (unsigned i = PBDEntries.size() - 1; i != 0; --i) {
          Pattern *PrevPat = PBDEntries[i-1].getPattern();
          if (!isa<NamedPattern>(PrevPat) || PBDEntries[i-1].getInit())
            break;
          if (HasAccessors) {
            // FIXME -- offer a fixit to explicitly specify the type
            diagnose(PrevPat->getLoc(), diag::getset_cannot_be_implied);
            Status.setIsParseError();
          }

          TypedPattern *NewTP = new (Context) TypedPattern(PrevPat,
                                                           TP->getTypeLoc());
          NewTP->setPropagatedType();
          PBDEntries[i-1].setPattern(NewTP);
        }
      }
    }
  } while (consumeIf(tok::comma));
  
  if (HasAccessors && PBDEntries.size() > 1) {
    diagnose(VarLoc, diag::disallowed_var_multiple_getset);
    Status.setIsParseError();
  }

  if (TryLoc.isValid()) {
    auto inFlightDiag = diagnose(TryLoc, diag::try_on_var_let);

    if (PBDEntries.size() == 1 && PBDEntries.front().getInit() &&
        !isa<ErrorExpr>(PBDEntries.front().getInit())) {
      auto *init = PBDEntries.front().getInit();
      inFlightDiag.fixItRemoveChars(TryLoc, VarLoc);
      inFlightDiag.fixItInsert(init->getStartLoc(), "try ");

      // Note: We can't use TryLoc here because it's outside the PBD source
      // range.
      PBDEntries.front().setInit(new (Context) TryExpr(init->getStartLoc(),
                                                       init));
    }
  }

  return makeResult(Status);
}

void Parser::consumeAbstractFunctionBody(AbstractFunctionDecl *AFD,
                                         const DeclAttributes &Attrs) {
  auto BeginParserPosition = getParserPosition();
  SourceRange BodyRange;
  BodyRange.Start = Tok.getLoc();

  // Consume the '{', and find the matching '}'.
  unsigned OpenBraces = skipBracedBlock(*this);
  if (OpenBraces != 0 && Tok.isNot(tok::code_complete)) {
    assert(Tok.is(tok::eof));
    // We hit EOF, and not every brace has a pair.  Recover by searching
    // for the next decl except variable decls and cutting off before
    // that point.
    backtrackToPosition(BeginParserPosition);
    consumeToken(tok::l_brace);
    while (Tok.is(tok::kw_var) || Tok.is(tok::kw_let) ||
           (Tok.isNot(tok::eof) && !isStartOfDecl())) {
      consumeToken();
    }
  }

  BodyRange.End = PreviousLoc;

  if (DelayedParseCB->shouldDelayFunctionBodyParsing(*this, AFD, Attrs,
                                                     BodyRange)) {
    State->delayFunctionBodyParsing(AFD, BodyRange,
                                    BeginParserPosition.PreviousLoc);
    AFD->setBodyDelayed(BodyRange);
  } else {
    AFD->setBodySkipped(BodyRange);
  }
}

/// \brief Parse a 'func' declaration, returning null on error.  The caller
/// handles this case and does recovery as appropriate.
///
/// \verbatim
///   decl-func:
///     attribute-list? ('static' | 'class')? 'mutating'? 'func' 
///               any-identifier generic-params? func-signature where-clause?
///               stmt-brace?
/// \endverbatim
///
/// \note The caller of this method must ensure that the next token is 'func'.
ParserResult<FuncDecl>
Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
                      ParseDeclOptions Flags, DeclAttributes &Attributes) {
  assert(StaticLoc.isInvalid() || StaticSpelling != StaticSpellingKind::None);

  bool HasContainerType = Flags.contains(PD_HasContainerType);

  if (StaticLoc.isValid()) {
    if (!HasContainerType) {
      // Reject static functions at global scope.
      diagnose(Tok, diag::static_func_decl_global_scope, StaticSpelling)
          .fixItRemove(StaticLoc);
      StaticLoc = SourceLoc();
      StaticSpelling = StaticSpellingKind::None;
    } else if (Flags.contains(PD_InStruct) || Flags.contains(PD_InEnum) ||
               Flags.contains(PD_InProtocol)) {
      if (StaticSpelling == StaticSpellingKind::KeywordClass) {
        diagnose(Tok, diag::class_func_not_in_class)
            .fixItReplace(StaticLoc, "static");

        StaticSpelling = StaticSpellingKind::KeywordStatic;
      }
    }
  }

  SourceLoc FuncLoc = consumeToken(tok::kw_func);

  // Forgive the lexer
  if (Tok.is(tok::amp_prefix)) {
    Tok.setKind(tok::oper_prefix);
  }
  Identifier SimpleName;
  Token NameTok = Tok;
  SourceLoc NameLoc;

  if (Tok.isAny(tok::identifier, tok::integer_literal, tok::floating_literal,
                tok::unknown) ||
      Tok.isKeyword()) {
    // This non-operator path is quite accepting of what tokens might be a name,
    // because we're aggressive about recovering/providing good diagnostics for
    // beginners.
    ParserStatus NameStatus =
        parseIdentifierDeclName(*this, SimpleName, NameLoc, "function",
                                tok::l_paren, tok::arrow, tok::l_brace,
                                TokenProperty::StartsWithLess);
    if (NameStatus.isError())
      return nullptr;
  } else {
    // May be operator.
    if (parseAnyIdentifier(SimpleName, NameLoc,
                           diag::expected_identifier_in_decl, "function")) {
      return nullptr;
    }
    assert(SimpleName.isOperator());
    // Within a protocol, recover from a missing 'static'.
    if (Flags & PD_InProtocol) {
      switch (StaticSpelling) {
      case StaticSpellingKind::None: {
        auto Message = Context.isSwiftVersion3()
                           ? diag::swift3_operator_static_in_protocol
                           : diag::operator_static_in_protocol;
        diagnose(NameLoc, Message, SimpleName.str())
            .fixItInsert(FuncLoc, "static ");
        StaticSpelling = StaticSpellingKind::KeywordStatic;
        break;
      }

      case StaticSpellingKind::KeywordStatic:
        // Okay, this is correct.
        break;

      case StaticSpellingKind::KeywordClass:
        llvm_unreachable("should have been fixed above");
      }
    }
  }

  DebuggerContextChange DCC(*this, SimpleName, DeclKind::Func);
  
  // Parse the generic-params, if present.
  Optional<Scope> GenericsScope;
  GenericsScope.emplace(this, ScopeKind::Generics);
  GenericParamList *GenericParams;
  bool GPHasCodeCompletion = false;
  // If the name is an operator token that ends in '<' and the following token
  // is an identifier, split the '<' off as a separate token. This allows things
  // like 'func ==<T>(x:T, y:T) {}' to parse as '==' with generic type variable
  // '<T>' as expected.
  if (SimpleName.str().size() > 1 && SimpleName.str().back() == '<'
      && Tok.is(tok::identifier)) {
    SimpleName = Context.getIdentifier(SimpleName.str().
                                       slice(0, SimpleName.str().size() - 1));
    SourceLoc LAngleLoc = NameLoc.getAdvancedLoc(SimpleName.str().size());
    auto Result = parseGenericParameters(LAngleLoc);
    GenericParams = Result.getPtrOrNull();
    GPHasCodeCompletion |= Result.hasCodeCompletion();

    auto NameTokText = NameTok.getRawText();
    markSplitToken(tok::identifier,
                   NameTokText.substr(0, NameTokText.size() - 1));
    markSplitToken(tok::oper_binary_unspaced,
                   NameTokText.substr(NameTokText.size() - 1));

  } else {
    auto Result = maybeParseGenericParams();
    GenericParams = Result.getPtrOrNull();
    GPHasCodeCompletion |= Result.hasCodeCompletion();
  }
  if (GPHasCodeCompletion && !CodeCompletion)
    return makeParserCodeCompletionStatus();

  SmallVector<ParameterList*, 8> BodyParams;
  
  // If we're within a container, add an implicit first pattern to match the
  // container type as an element named 'self'.
  //
  // This turns an instance function "(int)->int" on FooTy into
  // "(inout self: FooTy)->(int)->int", and a static function
  // "(int)->int" on FooTy into "(self: FooTy.Type)->(int)->int".
  // Note that we can't actually compute the type here until Sema.
  if (HasContainerType)
    BodyParams.push_back(ParameterList::createUnboundSelf(NameLoc, CurDeclContext));

  DefaultArgumentInfo DefaultArgs(HasContainerType);
  TypeRepr *FuncRetTy = nullptr;
  DeclName FullName;
  SourceLoc throwsLoc;
  bool rethrows;
  ParserStatus SignatureStatus =
      parseFunctionSignature(SimpleName, FullName, BodyParams, DefaultArgs,
                             throwsLoc, rethrows, FuncRetTy);

  if (SignatureStatus.hasCodeCompletion() && !CodeCompletion) {
    // Trigger delayed parsing, no need to continue.
    return SignatureStatus;
  }

  diagnoseWhereClauseInGenericParamList(GenericParams);

  // Parse a 'where' clause if present, adding it to our GenericParamList.
  if (Tok.is(tok::kw_where)) {
    auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
    if (whereStatus.shouldStopParsing())
      return whereStatus;
  }
  
  // Protocol method arguments may not have default values.
  if (Flags.contains(PD_InProtocol) && DefaultArgs.HasDefaultArgument) {
    diagnose(FuncLoc, diag::protocol_method_argument_init);
    return nullptr;
  }

  // Add the 'rethrows' attribute.
  if (rethrows) {
    Attributes.add(new (Context) RethrowsAttr(throwsLoc));
  }
  
  // Enter the arguments for the function into a new function-body scope.  We
  // need this even if there is no function body to detect argument name
  // duplication.
  FuncDecl *FD;
  {
    Scope S(this, ScopeKind::FunctionBody);

    // Create the decl for the func and add it to the parent scope.
    FD = FuncDecl::create(Context, StaticLoc, StaticSpelling,
                          FuncLoc, FullName, NameLoc,
                          /*Throws=*/throwsLoc.isValid(), throwsLoc,
                          /*AccessorKeywordLoc=*/SourceLoc(),
                          GenericParams, BodyParams, FuncRetTy,
                          CurDeclContext);
    
    diagnoseOperatorFixityAttributes(*this, Attributes, FD);
    
    // Add the attributes here so if we need them while parsing the body
    // they are available.
    FD->getAttrs() = Attributes;

    // Code completion for the generic type params.
    if (GPHasCodeCompletion)
      CodeCompletion->setDelayedParsedDecl(FD);

    // Pass the function signature to code completion.
    if (SignatureStatus.hasCodeCompletion())
      CodeCompletion->setDelayedParsedDecl(FD);

    DefaultArgs.setFunctionContext(FD);
    for (auto PL : FD->getParameterLists())
      addParametersToScope(PL);
    setLocalDiscriminator(FD);
    
    // Establish the new context.
    ParseFunctionBody CC(*this, FD);

    // Check to see if we have a "{" to start a brace statement.
    if (Tok.is(tok::l_brace)) {
      // Record the curly braces but nothing inside.
      SF.recordInterfaceToken("{");
      SF.recordInterfaceToken("}");
      llvm::SaveAndRestore<bool> T(IsParsingInterfaceTokens, false);

      if (Flags.contains(PD_InProtocol)) {
        diagnose(Tok, diag::protocol_method_with_body);
        skipUntilDeclRBrace();
      } else if (!isDelayedParsingEnabled()) {
        ParserResult<BraceStmt> Body =
            parseBraceItemList(diag::func_decl_without_brace);
        if (Body.isNull()) {
          // FIXME: Should do some sort of error recovery here?
        } else if (SignatureStatus.hasCodeCompletion()) {
          // Code completion was inside the signature, don't attach the body.
          FD->setBodySkipped(Body.get()->getSourceRange());
        } else {
          FD->setBody(Body.get());
        }
      } else {
        consumeAbstractFunctionBody(FD, Attributes);
      }
    } else {
      checkForInputIncomplete();
    }
  }

  // Exit the scope introduced for the generic parameters.
  GenericsScope.reset();

  addToScope(FD);
  return DCC.fixupParserResult(FD);
}

bool Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) {
  assert(!AFD->getBody() && "function should not have a parsed body");
  assert(AFD->getBodyKind() == AbstractFunctionDecl::BodyKind::Unparsed &&
         "function body should be delayed");

  auto FunctionParserState = State->takeFunctionBodyState(AFD);
  assert(FunctionParserState.get() && "should have a valid state");

  auto BeginParserPosition = getParserPosition(FunctionParserState->BodyPos);
  auto EndLexerState = L->getStateForEndOfTokenLoc(AFD->getEndLoc());

  // ParserPositionRAII needs a primed parser to restore to.
  if (Tok.is(tok::NUM_TOKENS))
    consumeToken();

  // Ensure that we restore the parser state at exit.
  ParserPositionRAII PPR(*this);

  // Create a lexer that cannot go past the end state.
  Lexer LocalLex(*L, BeginParserPosition.LS, EndLexerState);

  // Temporarily swap out the parser's current lexer with our new one.
  llvm::SaveAndRestore<Lexer *> T(L, &LocalLex);

  // Rewind to '{' of the function body.
  restoreParserPosition(BeginParserPosition);

  // Re-enter the lexical scope.
  Scope S(this, FunctionParserState->takeScope());
  ParseFunctionBody CC(*this, AFD);

  ParserResult<BraceStmt> Body =
      parseBraceItemList(diag::func_decl_without_brace);
  if (Body.isNull()) {
    // FIXME: Should do some sort of error recovery here?
    return true;
  } else {
    AFD->setBody(Body.get());
  }

  return false;
}

/// \brief Parse a 'enum' declaration, returning true (and doing no token
/// skipping) on error.
///
/// \verbatim
///   decl-enum:
///      'enum' attribute-list identifier generic-params? inheritance?
///          where-clause? '{' decl-enum-body '}'
///   decl-enum-body:
///      decl*
/// \endverbatim
ParserResult<EnumDecl> Parser::parseDeclEnum(ParseDeclOptions Flags,
                                             DeclAttributes &Attributes) {
  SourceLoc EnumLoc = consumeToken(tok::kw_enum);

  Identifier EnumName;
  SourceLoc EnumNameLoc;
  ParserStatus Status;

  Status |= parseIdentifierDeclName(*this, EnumName, EnumNameLoc, "enum",
                                    tok::colon, tok::l_brace,
                                    TokenProperty::StartsWithLess);
  if (Status.isError())
    return nullptr;

  DebuggerContextChange DCC(*this, EnumName, DeclKind::Enum);
  
  // Parse the generic-params, if present.
  GenericParamList *GenericParams = nullptr;
  {
    Scope S(this, ScopeKind::Generics);
    auto Result = maybeParseGenericParams();
    GenericParams = Result.getPtrOrNull();
    if (Result.hasCodeCompletion())
      return makeParserCodeCompletionStatus();
  }

  EnumDecl *ED = new (Context) EnumDecl(EnumLoc, EnumName, EnumNameLoc,
                                        { }, GenericParams, CurDeclContext);
  setLocalDiscriminator(ED);
  ED->getAttrs() = Attributes;

  // Parse optional inheritance clause within the context of the enum.
  if (Tok.is(tok::colon)) {
    ContextChange CC(*this, ED);
    SmallVector<TypeLoc, 2> Inherited;
    Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
    ED->setInherited(Context.AllocateCopy(Inherited));
  }

  diagnoseWhereClauseInGenericParamList(GenericParams);
  
  // Parse a 'where' clause if present, adding it to our GenericParamList.
  if (Tok.is(tok::kw_where)) {
    auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
    if (whereStatus.shouldStopParsing())
      return whereStatus;
    ED->setGenericParams(GenericParams);
  }

  SourceLoc LBLoc, RBLoc;
  if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_enum)) {
    LBLoc = PreviousLoc;
    RBLoc = LBLoc;
    Status.setIsParseError();
  } else {
    ContextChange CC(*this, ED);
    Scope S(this, ScopeKind::ClassBody);
    ParseDeclOptions Options(PD_HasContainerType | PD_AllowEnumElement | PD_InEnum);
    if (parseDeclList(LBLoc, RBLoc, diag::expected_rbrace_enum,
                      Options, [&] (Decl *D) { ED->addMember(D); }))
      Status.setIsParseError();
  }

  ED->setBraces({LBLoc, RBLoc});

  addToScope(ED);

  return DCC.fixupParserResult(Status, ED);
}

/// \brief Parse a 'case' of an enum.
///
/// \verbatim
///   enum-case:
///      identifier type-tuple?
///   decl-enum-element:
///      'case' attribute-list enum-case (',' enum-case)*
/// \endverbatim
ParserResult<EnumCaseDecl>
Parser::parseDeclEnumCase(ParseDeclOptions Flags,
                          DeclAttributes &Attributes,
                          llvm::SmallVectorImpl<Decl *> &Decls) {
  ParserStatus Status;
  SourceLoc CaseLoc = consumeToken(tok::kw_case);

  // Parse comma-separated enum elements.
  SmallVector<EnumElementDecl*, 4> Elements;
  
  SourceLoc CommaLoc;
  for (;;) {
    Identifier Name;
    SourceLoc NameLoc;

    // Consume an extraneous '.' so we can recover the case name.
    SourceLoc DotLoc;
    consumeIf(tok::period_prefix, DotLoc);

    // Handle the likely case someone typed 'case X, case Y'.
    if (Tok.is(tok::kw_case) && CommaLoc.isValid()) {
      diagnose(Tok, diag::expected_identifier_after_case_comma);
      Status.setIsParseError();
      return Status;
    }

    if (Tok.is(tok::identifier)) {
      Status |= parseIdentifierDeclName(*this, Name, NameLoc, "enum 'case'",
                                        tok::l_paren, tok::kw_case, tok::colon,
                                        tok::r_brace);
      assert(Status.isSuccess());
      if (DotLoc.isValid())
        diagnose(DotLoc, diag::enum_case_dot_prefix)
          .fixItRemove(DotLoc);
    } else {
      NameLoc = CaseLoc;
      bool NameIsKeyword = Tok.isKeyword();
      SourceLoc TokLoc = Tok.getLoc();
      StringRef TokText = Tok.getText();

      // For recovery, see if the user typed something resembling a switch
      // "case" label.
      llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
      T(InVarOrLetPattern, Parser::IVOLP_InMatchingPattern);
      parseMatchingPattern(/*isExprBasic*/false);

      if (consumeIf(tok::colon)) {
        diagnose(CaseLoc, diag::case_outside_of_switch, "case");
        Status.setIsParseError();
        return Status;
      }
      if (CommaLoc.isValid()) {
        diagnose(Tok, diag::expected_identifier_after_case_comma);
        Status.setIsParseError();
        return Status;
      }
      if (NameIsKeyword) {
        diagnose(TokLoc, diag::keyword_cant_be_identifier, TokText);
        diagnose(TokLoc, diag::backticks_to_escape)
          .fixItReplace(TokLoc, "`" + TokText.str() + "`");
      } else {
        diagnose(CaseLoc, diag::expected_identifier_in_decl, "enum 'case'");
      }
    }

    // See if there's a following argument type.
    ParserResult<TypeRepr> ArgType;
    if (Tok.isFollowingLParen()) {
      ArgType = parseTypeTupleBody();
      if (ArgType.hasCodeCompletion()) {
        Status.setHasCodeCompletion();
        return Status;
      }
      if (ArgType.isNull()) {
        Status.setIsParseError();
        return Status;
      }
    }
    
    // See if there's a raw value expression.
    SourceLoc EqualsLoc;
    ParserResult<Expr> RawValueExpr;
    LiteralExpr *LiteralRawValueExpr = nullptr;
    if (Tok.is(tok::equal)) {
      EqualsLoc = consumeToken();
      {
        CodeCompletionCallbacks::InEnumElementRawValueRAII
            InEnumElementRawValue(CodeCompletion);
        if (!CurLocalContext) {
          // A local context is needed for parsing closures. We want to parse
          // them anyways for proper diagnosis.
          LocalContext tempContext{};
          CurLocalContext = &tempContext;
          RawValueExpr = parseExpr(diag::expected_expr_enum_case_raw_value);
          CurLocalContext = nullptr;
        } else {
          RawValueExpr = parseExpr(diag::expected_expr_enum_case_raw_value);
        }
      }
      if (RawValueExpr.hasCodeCompletion()) {
        Status.setHasCodeCompletion();
        return Status;
      }
      if (RawValueExpr.isNull()) {
        Status.setIsParseError();
        return Status;
      }
      // The raw value must be syntactically a simple literal.
      LiteralRawValueExpr = dyn_cast<LiteralExpr>(RawValueExpr.getPtrOrNull());
      if (!LiteralRawValueExpr
          || isa<InterpolatedStringLiteralExpr>(LiteralRawValueExpr)) {
        diagnose(RawValueExpr.getPtrOrNull()->getLoc(),
                 diag::nonliteral_enum_case_raw_value);
        LiteralRawValueExpr = nullptr;
      }
    }
    
    // For recovery, again make sure the user didn't try to spell a switch
    // case label:
    // 'case Identifier:' or
    // 'case Identifier where ...:'
    if (Tok.is(tok::colon) || Tok.is(tok::kw_where)) {
      diagnose(CaseLoc, diag::case_outside_of_switch, "case");
      skipUntilDeclRBrace();
      Status.setIsParseError();
      return Status;
    }
    
    // Create the element.
    TypeRepr *ArgTR = ArgType.getPtrOrNull();
    auto *result = new (Context) EnumElementDecl(NameLoc, Name,
                                                 ArgTR,
                                                 ArgTR != nullptr,
                                                 EqualsLoc,
                                                 LiteralRawValueExpr,
                                                 CurDeclContext);
    if (NameLoc == CaseLoc) {
      result->setImplicit(); // Parse error
    }

    result->getAttrs() = Attributes;
    Elements.push_back(result);
    
    // Continue through the comma-separated list.
    if (!Tok.is(tok::comma))
      break;
    CommaLoc = consumeToken(tok::comma);
  }
  
  if (!(Flags & PD_AllowEnumElement)) {
    diagnose(CaseLoc, diag::disallowed_enum_element);
    // Don't add the EnumElementDecls unless the current context
    // is allowed to have EnumElementDecls.
    Status.setIsParseError();
    return Status;
  }

  // Create and insert the EnumCaseDecl containing all the elements.
  auto TheCase = EnumCaseDecl::create(CaseLoc, Elements, CurDeclContext);
  Decls.push_back(TheCase);
  
  // Insert the element decls.
  std::copy(Elements.begin(), Elements.end(), std::back_inserter(Decls));
  return makeParserResult(Status, TheCase);
}

/// \brief Parse a 'struct' declaration, returning true (and doing no token
/// skipping) on error.
///
/// \verbatim
///   decl-struct:
///      'struct' attribute-list identifier generic-params? inheritance?
///          where-clause? '{' decl-struct-body '}
///   decl-struct-body:
///      decl*
/// \endverbatim
ParserResult<StructDecl> Parser::parseDeclStruct(ParseDeclOptions Flags,
                                                 DeclAttributes &Attributes) {
  SourceLoc StructLoc = consumeToken(tok::kw_struct);
  
  Identifier StructName;
  SourceLoc StructNameLoc;
  ParserStatus Status;

  Status |= parseIdentifierDeclName(*this, StructName, StructNameLoc, "struct",
                                    tok::colon, tok::l_brace,
                                    TokenProperty::StartsWithLess);
  if (Status.isError())
    return nullptr;

  DebuggerContextChange DCC (*this, StructName, DeclKind::Struct);
  
  // Parse the generic-params, if present.
  GenericParamList *GenericParams = nullptr;
  {
    Scope S(this, ScopeKind::Generics);
    auto Result = maybeParseGenericParams();
    GenericParams = Result.getPtrOrNull();
    if (Result.hasCodeCompletion())
      return makeParserCodeCompletionStatus();
  }

  StructDecl *SD = new (Context) StructDecl(StructLoc, StructName,
                                            StructNameLoc,
                                            { },
                                            GenericParams,
                                            CurDeclContext);
  setLocalDiscriminator(SD);
  SD->getAttrs() = Attributes;

  // Parse optional inheritance clause within the context of the struct.
  if (Tok.is(tok::colon)) {
    ContextChange CC(*this, SD);
    SmallVector<TypeLoc, 2> Inherited;
    Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
    SD->setInherited(Context.AllocateCopy(Inherited));
  }

  diagnoseWhereClauseInGenericParamList(GenericParams);

  // Parse a 'where' clause if present, adding it to our GenericParamList.
  if (Tok.is(tok::kw_where)) {
    auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
    if (whereStatus.shouldStopParsing())
      return whereStatus;
    SD->setGenericParams(GenericParams);
  }

  
  SourceLoc LBLoc, RBLoc;
  if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_struct)) {
    LBLoc = PreviousLoc;
    RBLoc = LBLoc;
    Status.setIsParseError();
  } else {
    // Parse the body.
    ContextChange CC(*this, SD);
    Scope S(this, ScopeKind::StructBody);
    ParseDeclOptions Options(PD_HasContainerType | PD_InStruct);
    if (parseDeclList(LBLoc, RBLoc, diag::expected_rbrace_struct,
                      Options, [&](Decl *D) {SD->addMember(D);}))
      Status.setIsParseError();
  }

  SD->setBraces({LBLoc, RBLoc});

  addToScope(SD);

  return DCC.fixupParserResult(Status, SD);
}

/// \brief Parse a 'class' declaration, doing no token skipping on error.
///
/// \verbatim
///   decl-class:
///      'class' attribute-list identifier generic-params? inheritance?
///          where-clause? '{' decl-class-body '}
///   decl-class-body:
///      decl*
/// \endverbatim
ParserResult<ClassDecl> Parser::parseDeclClass(SourceLoc ClassLoc,
                                               ParseDeclOptions Flags,
                                               DeclAttributes &Attributes) {
  Identifier ClassName;
  SourceLoc ClassNameLoc;
  ParserStatus Status;

  Status |= parseIdentifierDeclName(*this, ClassName, ClassNameLoc, "class",
                                    tok::colon, tok::l_brace,
                                    TokenProperty::StartsWithLess);
  if (Status.isError())
    return nullptr;

  DebuggerContextChange DCC (*this, ClassName, DeclKind::Class);
  
  // Parse the generic-params, if present.
  GenericParamList *GenericParams = nullptr;
  {
    Scope S(this, ScopeKind::Generics);
    auto Result = maybeParseGenericParams();
    GenericParams = Result.getPtrOrNull();
    if (Result.hasCodeCompletion())
      return makeParserCodeCompletionStatus();
  }

  // Create the class.
  ClassDecl *CD = new (Context) ClassDecl(ClassLoc, ClassName, ClassNameLoc,
                                          { }, GenericParams, CurDeclContext);
  setLocalDiscriminator(CD);

  // Attach attributes.
  CD->getAttrs() = Attributes;

  // Parse optional inheritance clause within the context of the class.
  if (Tok.is(tok::colon)) {
    ContextChange CC(*this, CD);
    SmallVector<TypeLoc, 2> Inherited;
    Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
    CD->setInherited(Context.AllocateCopy(Inherited));
  }

  diagnoseWhereClauseInGenericParamList(GenericParams);

  // Parse a 'where' clause if present, adding it to our GenericParamList.
  if (Tok.is(tok::kw_where)) {
    auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
    if (whereStatus.shouldStopParsing())
      return whereStatus;
    CD->setGenericParams(GenericParams);
  }

  SourceLoc LBLoc, RBLoc;
  if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_class)) {
    LBLoc = PreviousLoc;
    RBLoc = LBLoc;
    Status.setIsParseError();
  } else {
    // Parse the body.
    ContextChange CC(*this, CD);
    Scope S(this, ScopeKind::ClassBody);
    ParseDeclOptions Options(PD_HasContainerType | PD_AllowDestructor |
                             PD_InClass);
    auto Handler = [&] (Decl *D) {
      CD->addMember(D);
      if (isa<DestructorDecl>(D))
        CD->setHasDestructor();
    };
    if (parseDeclList(LBLoc, RBLoc, diag::expected_rbrace_class,
                      Options, Handler))
      Status.setIsParseError();
  }

  CD->setBraces({LBLoc, RBLoc});

  addToScope(CD);

  return DCC.fixupParserResult(Status, CD);
}

/// \brief Parse a 'protocol' declaration, doing no token skipping on error.
///
/// \verbatim
///   decl-protocol:
///      protocol-head '{' protocol-member* '}'
///
///   protocol-head:
///     'protocol' attribute-list identifier inheritance? 
///
///   protocol-member:
///      decl-func
///      decl-var-simple
///      decl-typealias
/// \endverbatim
ParserResult<ProtocolDecl> Parser::
parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {
  SourceLoc ProtocolLoc = consumeToken(tok::kw_protocol);
  
  SourceLoc NameLoc;
  Identifier ProtocolName;
  ParserStatus Status;

  Status |= parseIdentifierDeclName(*this, ProtocolName, NameLoc, "protocol",
                                    tok::colon, tok::l_brace);
  if (Status.isError())
    return nullptr;

  // Protocols don't support generic parameters, but people often want them and
  // we want to have good error recovery if they try them out.  Parse them and
  // produce a specific diagnostic if present.
  if (startsWithLess(Tok)) {
    diagnose(Tok, diag::generic_arguments_protocol);
    Scope S(this, ScopeKind::Generics);
    maybeParseGenericParams();
  }

  DebuggerContextChange DCC (*this);
  
  // Parse optional inheritance clause.
  SmallVector<TypeLoc, 4> InheritedProtocols;
  SourceLoc classRequirementLoc;
  SourceLoc colonLoc;
  if (Tok.is(tok::colon)) {
    colonLoc = Tok.getLoc();
    Status |= parseInheritance(InheritedProtocols, &classRequirementLoc);
  }

  TrailingWhereClause *TrailingWhere = nullptr;
  // Parse a 'where' clause if present.
  if (Tok.is(tok::kw_where)) {
    auto whereStatus = parseProtocolOrAssociatedTypeWhereClause(
        TrailingWhere, /*isProtocol=*/true);
    if (whereStatus.shouldStopParsing())
      return whereStatus;
  }

  ProtocolDecl *Proto = new (Context)
      ProtocolDecl(CurDeclContext, ProtocolLoc, NameLoc, ProtocolName,
                   Context.AllocateCopy(InheritedProtocols), TrailingWhere);
  // No need to setLocalDiscriminator: protocols can't appear in local contexts.

  // If there was a 'class' requirement, mark this as a class-bounded protocol.
  if (classRequirementLoc.isValid())
    Proto->setClassBounded(classRequirementLoc);

  Proto->getAttrs() = Attributes;

  ContextChange CC(*this, Proto);
  Scope ProtocolBodyScope(this, ScopeKind::ProtocolBody);

  // Parse the body.
  {
    SourceLoc LBraceLoc;
    SourceLoc RBraceLoc;
    if (parseToken(tok::l_brace, LBraceLoc, diag::expected_lbrace_protocol)) {
      LBraceLoc = PreviousLoc;
      RBraceLoc = LBraceLoc;
      Status.setIsParseError();
    } else {
      // Parse the members.
      ParseDeclOptions Options(PD_HasContainerType |
                               PD_DisallowInit |
                               PD_InProtocol);
      if (parseDeclList(LBraceLoc, RBraceLoc, diag::expected_rbrace_protocol,
                        Options, [&](Decl *D) {Proto->addMember(D);}))
        Status.setIsParseError();
    }

    // Install the protocol elements.
    Proto->setBraces({LBraceLoc, RBraceLoc});
  }
  
  return DCC.fixupParserResult(Status, Proto);
}

/// \brief Parse a 'subscript' declaration.
///
/// \verbatim
///   decl-subscript:
///     subscript-head get-set
///   subscript-head
///     attribute-list? 'subscript' parameter-clause '->' type
/// \endverbatim
ParserResult<SubscriptDecl>
Parser::parseDeclSubscript(ParseDeclOptions Flags,
                           DeclAttributes &Attributes,
                           SmallVectorImpl<Decl *> &Decls) {
  ParserStatus Status;
  SourceLoc SubscriptLoc = consumeToken(tok::kw_subscript);

  // Parse the generic-params, if present.
  Optional<Scope> GenericsScope;
  GenericsScope.emplace(this, ScopeKind::Generics);
  GenericParamList *GenericParams;
  bool GPHasCodeCompletion = false;

  auto Result = maybeParseGenericParams();
  GenericParams = Result.getPtrOrNull();
  GPHasCodeCompletion |= Result.hasCodeCompletion();

  if (GPHasCodeCompletion && !CodeCompletion)
    return makeParserCodeCompletionStatus();

  // Parse the parameter list.
  SmallVector<Identifier, 4> argumentNames;
  ParserResult<ParameterList> Indices
    = parseSingleParameterClause(ParameterContextKind::Subscript,
                                 &argumentNames);
  if (Indices.isNull() || Indices.hasCodeCompletion())
    return ParserStatus(Indices);
  
  // '->'
  if (!Tok.is(tok::arrow)) {
    if (!Indices.isParseError())
      diagnose(Tok, diag::expected_arrow_subscript);
    return makeParserError();
  }
  SourceLoc ArrowLoc = consumeToken();
  
  // type
  ParserResult<TypeRepr> ElementTy = parseType(diag::expected_type_subscript);
  if (ElementTy.isNull() || ElementTy.hasCodeCompletion())
    return ParserStatus(ElementTy);

  diagnoseWhereClauseInGenericParamList(GenericParams);

  // Parse a 'where' clause if present, adding it to our GenericParamList.
  if (Tok.is(tok::kw_where)) {
    auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
    if (whereStatus.shouldStopParsing())
      return whereStatus;
  }

  // Build an AST for the subscript declaration.
  DeclName name = DeclName(Context, Context.Id_subscript, argumentNames);
  auto *Subscript = new (Context) SubscriptDecl(name,
                                                SubscriptLoc, Indices.get(),
                                                ArrowLoc, ElementTy.get(),
                                                CurDeclContext,
                                                GenericParams);
  Subscript->getAttrs() = Attributes;

  // Code completion for the generic type params.
  //
  // FIXME: What is this?
  if (GPHasCodeCompletion)
    CodeCompletion->setDelayedParsedDecl(Subscript);

  Decls.push_back(Subscript);

  // '{'
  // Parse getter and setter.
  ParsedAccessors accessors;
  if (Tok.isNot(tok::l_brace)) {
    // Subscript declarations must always have at least a getter, so they need
    // to be followed by a {.
    if (Flags.contains(PD_InProtocol))
      diagnose(Tok, diag::expected_lbrace_subscript_protocol)
        .fixItInsertAfter(ElementTy.get()->getEndLoc(), " { get set }");
    else
      diagnose(Tok, diag::expected_lbrace_subscript);
    Status.setIsParseError();
  } else {
    if (parseGetSet(Flags, GenericParams,
                    Indices.get(), ElementTy.get(),
                    accessors, /*StaticLoc=*/SourceLoc(), Decls))
      Status.setIsParseError();
  }

  bool Invalid = false;
  // Reject 'subscript' functions outside of type decls
  if (!(Flags & PD_HasContainerType)) {
    diagnose(SubscriptLoc, diag::subscript_decl_wrong_scope);
    Invalid = true;
  }

  accessors.record(*this, Subscript, (Invalid || !Status.isSuccess()),
                   Flags, /*static*/ SourceLoc(), Attributes,
                   ElementTy.get(), Indices.get(), Decls);

  if (Invalid) {
    Subscript->setInterfaceType(ErrorType::get(Context));
    Subscript->setInvalid();
  }

  // No need to setLocalDiscriminator because subscripts cannot
  // validly appear outside of type decls.
  return makeParserResult(Status, Subscript);
}

ParserResult<ConstructorDecl>
Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
  assert(Tok.is(tok::kw_init));
  SourceLoc ConstructorLoc = consumeToken();
  OptionalTypeKind Failability = OTK_None;
  SourceLoc FailabilityLoc;

  const bool ConstructorsNotAllowed = !(Flags & PD_HasContainerType);

  // Reject constructors outside of types.
  if (ConstructorsNotAllowed) {
    diagnose(Tok, diag::initializer_decl_wrong_scope);
  }

  // Parse the '!' or '?' for a failable initializer.
  if (Tok.isAny(tok::exclaim_postfix, tok::sil_exclamation) ||
      (Tok.isAnyOperator() && Tok.getText() == "!")) {
    Failability = OTK_ImplicitlyUnwrappedOptional;
    FailabilityLoc = consumeToken();
  } else if (Tok.isAny(tok::question_postfix, tok::question_infix)) {
    Failability = OTK_Optional;
    FailabilityLoc = consumeToken();
  }

  // Parse the generic-params, if present.
  Scope S(this, ScopeKind::Generics);
  auto GPResult = maybeParseGenericParams();
  GenericParamList *GenericParams = GPResult.getPtrOrNull();
  if (GPResult.hasCodeCompletion())
    return makeParserCodeCompletionStatus();

  // Parse the parameters.
  DefaultArgumentInfo DefaultArgs(/*inTypeContext*/true);
  llvm::SmallVector<Identifier, 4> namePieces;
  ParserResult<ParameterList> Params
    = parseSingleParameterClause(ParameterContextKind::Initializer,
                                 &namePieces, &DefaultArgs);

  if (Params.hasCodeCompletion() && !CodeCompletion) {
    // Trigger delayed parsing, no need to continue.
    return makeParserCodeCompletionStatus();
  }

  // Protocol initializer arguments may not have default values.
  if (Flags.contains(PD_InProtocol) && DefaultArgs.HasDefaultArgument) {
    diagnose(ConstructorLoc, diag::protocol_init_argument_init);
    return nullptr;
  }

  // Parse 'throws' or 'rethrows'.
  SourceLoc throwsLoc;
  if (consumeIf(tok::kw_throws, throwsLoc)) {
    // okay
  } else if (consumeIf(tok::kw_rethrows, throwsLoc)) {
    Attributes.add(new (Context) RethrowsAttr(throwsLoc));
  }

  diagnoseWhereClauseInGenericParamList(GenericParams);

  // Parse a 'where' clause if present, adding it to our GenericParamList.
  if (Tok.is(tok::kw_where)) {
    auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
    if (whereStatus.shouldStopParsing())
      return whereStatus;
  }
  
  auto *SelfDecl = ParamDecl::createUnboundSelf(ConstructorLoc, CurDeclContext);
  DeclName FullName(Context, Context.Id_init, namePieces);

  Scope S2(this, ScopeKind::ConstructorBody);
  auto *CD = new (Context) ConstructorDecl(FullName, ConstructorLoc,
                                           Failability, FailabilityLoc,
                                           throwsLoc.isValid(), throwsLoc,
                                           SelfDecl, Params.get(),
                                           GenericParams,
                                           CurDeclContext);
  
  CtorInitializerKind initKind = CtorInitializerKind::Designated;
  if (Attributes.hasAttribute<ConvenienceAttr>())
    initKind = CtorInitializerKind::Convenience;
  CD->setInitKind(initKind);

  // No need to setLocalDiscriminator.

  DefaultArgs.setFunctionContext(CD);

  // Pass the function signature to code completion.
  if (Params.hasCodeCompletion())
    CodeCompletion->setDelayedParsedDecl(CD);

  if (ConstructorsNotAllowed || Params.isParseError()) {
    // Tell the type checker not to touch this constructor.
    CD->setInvalid();
  }
  
  addToScope(SelfDecl);
  addParametersToScope(Params.get());

  // '{'
  if (Tok.is(tok::l_brace)) {
    // Record the curly braces but nothing inside.
    SF.recordInterfaceToken("{");
    SF.recordInterfaceToken("}");
    llvm::SaveAndRestore<bool> T(IsParsingInterfaceTokens, false);

    if (Flags.contains(PD_InProtocol)) {
      diagnose(Tok, diag::protocol_init_with_body);
      skipUntilDeclRBrace();
    } else {
      // Parse the body.
      ParseFunctionBody CC(*this, CD);

      if (!isDelayedParsingEnabled()) {
        ParserResult<BraceStmt> Body =
          parseBraceItemList(diag::invalid_diagnostic);

        if (!Body.isNull())
          CD->setBody(Body.get());
      } else {
        consumeAbstractFunctionBody(CD, Attributes);
      }
    }
  }

  CD->getAttrs() = Attributes;

  return makeParserResult(CD);
}

ParserResult<DestructorDecl> Parser::
parseDeclDeinit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
  SourceLoc DestructorLoc = consumeToken(tok::kw_deinit);

  // Parse extraneous parentheses and remove them with a fixit.
  if (Tok.is(tok::l_paren)) {
    SourceRange ParenRange;
    SourceLoc LParenLoc = consumeToken();
    SourceLoc RParenLoc;
    skipUntil(tok::r_paren);

    if (Tok.is(tok::r_paren)) {
      SourceLoc RParenLoc = consumeToken();
      ParenRange = SourceRange(LParenLoc, RParenLoc);
      
      diagnose(ParenRange.Start, diag::destructor_params)
      .fixItRemoveChars(Lexer::getLocForEndOfToken(Context.SourceMgr,
                                                   DestructorLoc),
                        Lexer::getLocForEndOfToken(Context.SourceMgr,
                                                   ParenRange.End));
    } else {
      diagnose(Tok, diag::opened_destructor_expected_rparen);
      diagnose(LParenLoc, diag::opening_paren);
    }
  }

  // '{'
  if (!Tok.is(tok::l_brace)) {
    if (!Tok.is(tok::l_brace) && !isInSILMode()) {
      if (Tok.is(tok::identifier)) {
        diagnose(Tok, diag::destructor_has_name).fixItRemove(Tok.getLoc());
      } else
        diagnose(Tok, diag::expected_lbrace_destructor);
      return nullptr;
    }
  }

  auto *SelfDecl = ParamDecl::createUnboundSelf(DestructorLoc, CurDeclContext);

  Scope S(this, ScopeKind::DestructorBody);
  auto *DD = new (Context) DestructorDecl(Context.Id_deinit, DestructorLoc,
                                          SelfDecl, CurDeclContext);

  // Parse the body.
  if (Tok.is(tok::l_brace)) {
    // Record the curly braces but nothing inside.
    SF.recordInterfaceToken("{");
    SF.recordInterfaceToken("}");
    llvm::SaveAndRestore<bool> T(IsParsingInterfaceTokens, false);

    ParseFunctionBody CC(*this, DD);
    if (!isDelayedParsingEnabled()) {
      ParserResult<BraceStmt> Body=parseBraceItemList(diag::invalid_diagnostic);

      if (!Body.isNull())
        DD->setBody(Body.get());
    } else {
      consumeAbstractFunctionBody(DD, Attributes);
    }
  }

  DD->getAttrs() = Attributes;

  // Reject 'destructor' functions outside of classes
  if (!(Flags & PD_AllowDestructor)) {
    diagnose(DestructorLoc, diag::destructor_decl_outside_class);

    // Tell the type checker not to touch this destructor.
    DD->setInvalid();
  }

  return makeParserResult(DD);
}

ParserResult<OperatorDecl> 
Parser::parseDeclOperator(ParseDeclOptions Flags, DeclAttributes &Attributes) {
  SourceLoc OperatorLoc = consumeToken(tok::kw_operator);
  bool AllowTopLevel = Flags.contains(PD_AllowTopLevel);

  if (!Tok.isAnyOperator() && !Tok.is(tok::exclaim_postfix)) {
    // A common error is to try to define an operator with something in the
    // unicode plane considered to be an operator, or to try to define an
    // operator like "not".  Diagnose this specifically.
    if (Tok.is(tok::identifier))
      diagnose(Tok, diag::identifier_when_expecting_operator,
               Context.getIdentifier(Tok.getText()));
    else
      diagnose(Tok, diag::expected_operator_name_after_operator);

    // To improve recovery, check to see if we have a { right after this token.
    // If so, swallow until the end } to avoid tripping over the body of the
    // malformed operator decl.
    if (peekToken().is(tok::l_brace)) {
      consumeToken();
      skipSingle();
    }

    return nullptr;
  }

  DebuggerContextChange DCC (*this);
  
  Identifier Name = Context.getIdentifier(Tok.getText());
  SourceLoc NameLoc = consumeToken();
    
  if (Attributes.hasAttribute<PostfixAttr>()) {
    if (!Name.empty() && (Name.get()[0] == '?' || Name.get()[0] == '!'))
      diagnose(NameLoc, diag::expected_operator_name_after_operator);      
  }
  
  auto Result = parseDeclOperatorImpl(OperatorLoc, Name, NameLoc, Attributes);

  if (!DCC.movedToTopLevel() && !AllowTopLevel) {
    diagnose(OperatorLoc, diag::operator_decl_inner_scope);
    return nullptr;
  }
  
  return DCC.fixupParserResult(Result);
}

ParserResult<OperatorDecl>
Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name,
                                SourceLoc NameLoc, DeclAttributes &Attributes) {
  bool isPrefix = Attributes.hasAttribute<PrefixAttr>();
  bool isInfix = Attributes.hasAttribute<InfixAttr>();
  bool isPostfix = Attributes.hasAttribute<PostfixAttr>();
  
  // Parse (or diagnose) a specified precedence group.
  SourceLoc colonLoc;
  Identifier precedenceGroupName;
  SourceLoc precedenceGroupNameLoc;
  if (consumeIf(tok::colon, colonLoc)) {
    if (Tok.is(tok::identifier)) {
      precedenceGroupName = Context.getIdentifier(Tok.getText());
      precedenceGroupNameLoc = consumeToken(tok::identifier);
      
      if (isPrefix || isPostfix)
        diagnose(colonLoc, diag::precedencegroup_not_infix)
          .fixItRemove({colonLoc, precedenceGroupNameLoc});
    }
  }
  
  // Diagnose deprecated operator body syntax `operator + { ... }`.
  SourceLoc lBraceLoc;
  if (consumeIf(tok::l_brace, lBraceLoc)) {
    if (isInfix && !Tok.is(tok::r_brace)) {
      auto message = Context.isSwiftVersion3()
                         ? diag::swift3_deprecated_operator_body_use_group
                         : diag::deprecated_operator_body_use_group;
      diagnose(lBraceLoc, message);
    } else {
      auto message = Context.isSwiftVersion3()
                         ? diag::swift3_deprecated_operator_body
                         : diag::deprecated_operator_body;
      auto Diag = diagnose(lBraceLoc, message);
      if (Tok.is(tok::r_brace)) {
        SourceLoc lastGoodLoc = precedenceGroupNameLoc;
        if (lastGoodLoc.isInvalid())
          lastGoodLoc = NameLoc;
        SourceLoc lastGoodLocEnd = Lexer::getLocForEndOfToken(SourceMgr,
                                                              lastGoodLoc);
        SourceLoc rBraceEnd = Lexer::getLocForEndOfToken(SourceMgr, Tok.getLoc());
        Diag.fixItRemoveChars(lastGoodLocEnd, rBraceEnd);
      }
    }

    skipUntilDeclRBrace();
    (void) consumeIf(tok::r_brace);
  }
  
  OperatorDecl *res;
  if (Attributes.hasAttribute<PrefixAttr>())
    res = new (Context) PrefixOperatorDecl(CurDeclContext, OperatorLoc,
                                           Name, NameLoc);
  else if (Attributes.hasAttribute<PostfixAttr>())
    res = new (Context) PostfixOperatorDecl(CurDeclContext, OperatorLoc,
                                            Name, NameLoc);
  else
    res = new (Context) InfixOperatorDecl(CurDeclContext, OperatorLoc,
                                          Name, NameLoc, colonLoc,
                                          precedenceGroupName,
                                          precedenceGroupNameLoc);
  
  diagnoseOperatorFixityAttributes(*this, Attributes, res);
  
  res->getAttrs() = Attributes;
  return makeParserResult(res);
}

ParserResult<PrecedenceGroupDecl>
Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags,
                                 DeclAttributes &attributes) {
  SourceLoc precedenceGroupLoc = consumeToken(tok::kw_precedencegroup);
  DebuggerContextChange DCC (*this);

  if (!CodeCompletion && !DCC.movedToTopLevel() && !(flags & PD_AllowTopLevel))
  {
    diagnose(precedenceGroupLoc, diag::decl_inner_scope);
    return nullptr;
  }

  Identifier name;
  SourceLoc nameLoc;
  if (parseIdentifier(name, nameLoc, diag::expected_precedencegroup_name)) {
    // If the identifier is missing or a keyword or something, try to skip
    // skip the entire body.
    if (consumeIf(tok::l_brace)) {
      skipUntilDeclRBrace();
      (void) consumeIf(tok::r_brace);
    } else if (Tok.isNot(tok::eof) && peekToken().is(tok::l_brace)) {
      consumeToken();
      skipBracedBlock(*this);
    }
    return nullptr;
  }

  SourceLoc lbraceLoc, rbraceLoc;
  SourceLoc associativityKeywordLoc, associativityValueLoc;
  SourceLoc assignmentKeywordLoc, assignmentValueLoc;
  SourceLoc higherThanKeywordLoc, lowerThanKeywordLoc;
  SmallVector<PrecedenceGroupDecl::Relation, 4> higherThan, lowerThan;
  Associativity associativity = Associativity::None;
  bool assignment = false;
  bool invalid = false;

  // Helper functions.
  auto create = [&] {
    auto result = PrecedenceGroupDecl::create(CurDeclContext,
                                              precedenceGroupLoc,
                                              nameLoc, name, lbraceLoc,
                                              associativityKeywordLoc,
                                              associativityValueLoc,
                                              associativity,
                                              assignmentKeywordLoc,
                                              assignmentValueLoc,
                                              assignment,
                                              higherThanKeywordLoc, higherThan,
                                              lowerThanKeywordLoc, lowerThan,
                                              rbraceLoc);
    result->getAttrs() = attributes;
    return result;
  };
  auto createInvalid = [&] {
    // Use the last consumed token location as the rbrace to satisfy
    // the AST invariant about a decl's source range including all of
    // its components.
    if (!rbraceLoc.isValid()) rbraceLoc = PreviousLoc;

    auto result = create();
    result->setInvalid();
    return makeParserErrorResult(result);
  };

  // Expect the body to start here.
  if (!consumeIf(tok::l_brace, lbraceLoc)) {
    diagnose(Tok, diag::expected_precedencegroup_lbrace);
    return createInvalid();
  }

  auto abortBody = [&] {
    skipUntilDeclRBrace();
    (void) consumeIf(tok::r_brace, rbraceLoc);
    return createInvalid();
  };

  auto parseAttributePrefix = [&](SourceLoc &attrKeywordLoc) {
    auto attrName = Tok.getText(); 
    if (attrKeywordLoc.isValid()) {
      diagnose(Tok, diag::precedencegroup_attribute_redeclared, attrName);
      // We want to continue parsing after this.
      invalid = true;
    }
    attrKeywordLoc = consumeToken(tok::identifier);
    if (!consumeIf(tok::colon)) {
      diagnose(Tok, diag::expected_precedencegroup_attribute_colon, attrName);
      // Try to recover by allowing the colon to be missing.
    }
  };

  // Parse the attributes in the body.
  while (!consumeIf(tok::r_brace, rbraceLoc)) {
    if (!Tok.is(tok::identifier)) {
      diagnose(Tok, diag::expected_precedencegroup_attribute);
      return abortBody();
    }

    auto attrName = Tok.getText();

    if (attrName == "associativity") {
      parseAttributePrefix(associativityKeywordLoc);

      if (!Tok.is(tok::identifier)) {
        diagnose(Tok, diag::expected_precedencegroup_associativity);
        return abortBody();
      }
      auto parsedAssociativity
        = llvm::StringSwitch<Optional<Associativity>>(Tok.getText())
          .Case("none", Associativity::None)
          .Case("left", Associativity::Left)
          .Case("right", Associativity::Right)
          .Default(None);
      if (!parsedAssociativity) {
        diagnose(Tok, diag::expected_precedencegroup_associativity);
        parsedAssociativity = Associativity::None;
        invalid = true;
      }
      associativity = *parsedAssociativity;
      associativityValueLoc = consumeToken();
      continue;
    }
    
    if (attrName == "assignment") {
      parseAttributePrefix(assignmentKeywordLoc);

      if (consumeIf(tok::kw_true, assignmentValueLoc)) {
        assignment = true;
      } else if (consumeIf(tok::kw_false, assignmentValueLoc)) {
        assignment = false;
      } else {
        diagnose(Tok, diag::expected_precedencegroup_assignment);
        return abortBody();
      }
      continue;
    }

    bool isLowerThan = false;
    if (attrName == "higherThan" ||
        (isLowerThan = (attrName == "lowerThan"))) {
      parseAttributePrefix(isLowerThan ? lowerThanKeywordLoc
                                       : higherThanKeywordLoc);
      auto &relations = (isLowerThan ? lowerThan : higherThan);

      do {
        if (!Tok.is(tok::identifier)) {
          diagnose(Tok, diag::expected_precedencegroup_relation, attrName);
          return abortBody();
        }
        auto name = Context.getIdentifier(Tok.getText());
        auto loc = consumeToken();
        relations.push_back({loc, name, nullptr});
      } while (consumeIf(tok::comma));
      continue;
    }
    
    diagnose(Tok, diag::unknown_precedencegroup_attribute, attrName);
    return abortBody();
  }

  auto result = create();
  if (invalid) result->setInvalid();
  return makeParserResult(result);
}
