forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			3930 lines
		
	
	
		
			142 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			3930 lines
		
	
	
		
			142 KiB
		
	
	
	
		
			C++
		
	
	
	
//===--- ParseExprCXX.cpp - C++ Expression Parsing ------------------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// This file implements the Expression parsing implementation for C++.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
#include "clang/Parse/Parser.h"
 | 
						|
#include "clang/AST/ASTContext.h"
 | 
						|
#include "clang/AST/Decl.h"
 | 
						|
#include "clang/AST/DeclTemplate.h"
 | 
						|
#include "clang/AST/ExprCXX.h"
 | 
						|
#include "clang/Basic/PrettyStackTrace.h"
 | 
						|
#include "clang/Lex/LiteralSupport.h"
 | 
						|
#include "clang/Parse/ParseDiagnostic.h"
 | 
						|
#include "clang/Parse/RAIIObjectsForParser.h"
 | 
						|
#include "clang/Sema/DeclSpec.h"
 | 
						|
#include "clang/Sema/ParsedTemplate.h"
 | 
						|
#include "clang/Sema/Scope.h"
 | 
						|
#include "llvm/Support/ErrorHandling.h"
 | 
						|
#include <numeric>
 | 
						|
 | 
						|
using namespace clang;
 | 
						|
 | 
						|
static int SelectDigraphErrorMessage(tok::TokenKind Kind) {
 | 
						|
  switch (Kind) {
 | 
						|
    // template name
 | 
						|
    case tok::unknown:             return 0;
 | 
						|
    // casts
 | 
						|
    case tok::kw_const_cast:       return 1;
 | 
						|
    case tok::kw_dynamic_cast:     return 2;
 | 
						|
    case tok::kw_reinterpret_cast: return 3;
 | 
						|
    case tok::kw_static_cast:      return 4;
 | 
						|
    default:
 | 
						|
      llvm_unreachable("Unknown type for digraph error message.");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Are the two tokens adjacent in the same source file?
 | 
						|
bool Parser::areTokensAdjacent(const Token &First, const Token &Second) {
 | 
						|
  SourceManager &SM = PP.getSourceManager();
 | 
						|
  SourceLocation FirstLoc = SM.getSpellingLoc(First.getLocation());
 | 
						|
  SourceLocation FirstEnd = FirstLoc.getLocWithOffset(First.getLength());
 | 
						|
  return FirstEnd == SM.getSpellingLoc(Second.getLocation());
 | 
						|
}
 | 
						|
 | 
						|
// Suggest fixit for "<::" after a cast.
 | 
						|
static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken,
 | 
						|
                       Token &ColonToken, tok::TokenKind Kind, bool AtDigraph) {
 | 
						|
  // Pull '<:' and ':' off token stream.
 | 
						|
  if (!AtDigraph)
 | 
						|
    PP.Lex(DigraphToken);
 | 
						|
  PP.Lex(ColonToken);
 | 
						|
 | 
						|
  SourceRange Range;
 | 
						|
  Range.setBegin(DigraphToken.getLocation());
 | 
						|
  Range.setEnd(ColonToken.getLocation());
 | 
						|
  P.Diag(DigraphToken.getLocation(), diag::err_missing_whitespace_digraph)
 | 
						|
      << SelectDigraphErrorMessage(Kind)
 | 
						|
      << FixItHint::CreateReplacement(Range, "< ::");
 | 
						|
 | 
						|
  // Update token information to reflect their change in token type.
 | 
						|
  ColonToken.setKind(tok::coloncolon);
 | 
						|
  ColonToken.setLocation(ColonToken.getLocation().getLocWithOffset(-1));
 | 
						|
  ColonToken.setLength(2);
 | 
						|
  DigraphToken.setKind(tok::less);
 | 
						|
  DigraphToken.setLength(1);
 | 
						|
 | 
						|
  // Push new tokens back to token stream.
 | 
						|
  PP.EnterToken(ColonToken, /*IsReinject*/ true);
 | 
						|
  if (!AtDigraph)
 | 
						|
    PP.EnterToken(DigraphToken, /*IsReinject*/ true);
 | 
						|
}
 | 
						|
 | 
						|
// Check for '<::' which should be '< ::' instead of '[:' when following
 | 
						|
// a template name.
 | 
						|
void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType,
 | 
						|
                                        bool EnteringContext,
 | 
						|
                                        IdentifierInfo &II, CXXScopeSpec &SS) {
 | 
						|
  if (!Next.is(tok::l_square) || Next.getLength() != 2)
 | 
						|
    return;
 | 
						|
 | 
						|
  Token SecondToken = GetLookAheadToken(2);
 | 
						|
  if (!SecondToken.is(tok::colon) || !areTokensAdjacent(Next, SecondToken))
 | 
						|
    return;
 | 
						|
 | 
						|
  TemplateTy Template;
 | 
						|
  UnqualifiedId TemplateName;
 | 
						|
  TemplateName.setIdentifier(&II, Tok.getLocation());
 | 
						|
  bool MemberOfUnknownSpecialization;
 | 
						|
  if (!Actions.isTemplateName(getCurScope(), SS, /*hasTemplateKeyword=*/false,
 | 
						|
                              TemplateName, ObjectType, EnteringContext,
 | 
						|
                              Template, MemberOfUnknownSpecialization))
 | 
						|
    return;
 | 
						|
 | 
						|
  FixDigraph(*this, PP, Next, SecondToken, tok::unknown,
 | 
						|
             /*AtDigraph*/false);
 | 
						|
}
 | 
						|
 | 
						|
/// Parse global scope or nested-name-specifier if present.
 | 
						|
///
 | 
						|
/// Parses a C++ global scope specifier ('::') or nested-name-specifier (which
 | 
						|
/// may be preceded by '::'). Note that this routine will not parse ::new or
 | 
						|
/// ::delete; it will just leave them in the token stream.
 | 
						|
///
 | 
						|
///       '::'[opt] nested-name-specifier
 | 
						|
///       '::'
 | 
						|
///
 | 
						|
///       nested-name-specifier:
 | 
						|
///         type-name '::'
 | 
						|
///         namespace-name '::'
 | 
						|
///         nested-name-specifier identifier '::'
 | 
						|
///         nested-name-specifier 'template'[opt] simple-template-id '::'
 | 
						|
///
 | 
						|
///
 | 
						|
/// \param SS the scope specifier that will be set to the parsed
 | 
						|
/// nested-name-specifier (or empty)
 | 
						|
///
 | 
						|
/// \param ObjectType if this nested-name-specifier is being parsed following
 | 
						|
/// the "." or "->" of a member access expression, this parameter provides the
 | 
						|
/// type of the object whose members are being accessed.
 | 
						|
///
 | 
						|
/// \param EnteringContext whether we will be entering into the context of
 | 
						|
/// the nested-name-specifier after parsing it.
 | 
						|
///
 | 
						|
/// \param MayBePseudoDestructor When non-NULL, points to a flag that
 | 
						|
/// indicates whether this nested-name-specifier may be part of a
 | 
						|
/// pseudo-destructor name. In this case, the flag will be set false
 | 
						|
/// if we don't actually end up parsing a destructor name. Moreorover,
 | 
						|
/// if we do end up determining that we are parsing a destructor name,
 | 
						|
/// the last component of the nested-name-specifier is not parsed as
 | 
						|
/// part of the scope specifier.
 | 
						|
///
 | 
						|
/// \param IsTypename If \c true, this nested-name-specifier is known to be
 | 
						|
/// part of a type name. This is used to improve error recovery.
 | 
						|
///
 | 
						|
/// \param LastII When non-NULL, points to an IdentifierInfo* that will be
 | 
						|
/// filled in with the leading identifier in the last component of the
 | 
						|
/// nested-name-specifier, if any.
 | 
						|
///
 | 
						|
/// \param OnlyNamespace If true, only considers namespaces in lookup.
 | 
						|
///
 | 
						|
///
 | 
						|
/// \returns true if there was an error parsing a scope specifier
 | 
						|
bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
 | 
						|
                                            ParsedType ObjectType,
 | 
						|
                                            bool EnteringContext,
 | 
						|
                                            bool *MayBePseudoDestructor,
 | 
						|
                                            bool IsTypename,
 | 
						|
                                            IdentifierInfo **LastII,
 | 
						|
                                            bool OnlyNamespace,
 | 
						|
                                            bool InUsingDeclaration) {
 | 
						|
  assert(getLangOpts().CPlusPlus &&
 | 
						|
         "Call sites of this function should be guarded by checking for C++");
 | 
						|
 | 
						|
  if (Tok.is(tok::annot_cxxscope)) {
 | 
						|
    assert(!LastII && "want last identifier but have already annotated scope");
 | 
						|
    assert(!MayBePseudoDestructor && "unexpected annot_cxxscope");
 | 
						|
    Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
 | 
						|
                                                 Tok.getAnnotationRange(),
 | 
						|
                                                 SS);
 | 
						|
    ConsumeAnnotationToken();
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Has to happen before any "return false"s in this function.
 | 
						|
  bool CheckForDestructor = false;
 | 
						|
  if (MayBePseudoDestructor && *MayBePseudoDestructor) {
 | 
						|
    CheckForDestructor = true;
 | 
						|
    *MayBePseudoDestructor = false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (LastII)
 | 
						|
    *LastII = nullptr;
 | 
						|
 | 
						|
  bool HasScopeSpecifier = false;
 | 
						|
 | 
						|
  if (Tok.is(tok::coloncolon)) {
 | 
						|
    // ::new and ::delete aren't nested-name-specifiers.
 | 
						|
    tok::TokenKind NextKind = NextToken().getKind();
 | 
						|
    if (NextKind == tok::kw_new || NextKind == tok::kw_delete)
 | 
						|
      return false;
 | 
						|
 | 
						|
    if (NextKind == tok::l_brace) {
 | 
						|
      // It is invalid to have :: {, consume the scope qualifier and pretend
 | 
						|
      // like we never saw it.
 | 
						|
      Diag(ConsumeToken(), diag::err_expected) << tok::identifier;
 | 
						|
    } else {
 | 
						|
      // '::' - Global scope qualifier.
 | 
						|
      if (Actions.ActOnCXXGlobalScopeSpecifier(ConsumeToken(), SS))
 | 
						|
        return true;
 | 
						|
 | 
						|
      HasScopeSpecifier = true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Tok.is(tok::kw___super)) {
 | 
						|
    SourceLocation SuperLoc = ConsumeToken();
 | 
						|
    if (!Tok.is(tok::coloncolon)) {
 | 
						|
      Diag(Tok.getLocation(), diag::err_expected_coloncolon_after_super);
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    return Actions.ActOnSuperScopeSpecifier(SuperLoc, ConsumeToken(), SS);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!HasScopeSpecifier &&
 | 
						|
      Tok.isOneOf(tok::kw_decltype, tok::annot_decltype)) {
 | 
						|
    DeclSpec DS(AttrFactory);
 | 
						|
    SourceLocation DeclLoc = Tok.getLocation();
 | 
						|
    SourceLocation EndLoc  = ParseDecltypeSpecifier(DS);
 | 
						|
 | 
						|
    SourceLocation CCLoc;
 | 
						|
    // Work around a standard defect: 'decltype(auto)::' is not a
 | 
						|
    // nested-name-specifier.
 | 
						|
    if (DS.getTypeSpecType() == DeclSpec::TST_decltype_auto ||
 | 
						|
        !TryConsumeToken(tok::coloncolon, CCLoc)) {
 | 
						|
      AnnotateExistingDecltypeSpecifier(DS, DeclLoc, EndLoc);
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Actions.ActOnCXXNestedNameSpecifierDecltype(SS, DS, CCLoc))
 | 
						|
      SS.SetInvalid(SourceRange(DeclLoc, CCLoc));
 | 
						|
 | 
						|
    HasScopeSpecifier = true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Preferred type might change when parsing qualifiers, we need the original.
 | 
						|
  auto SavedType = PreferredType;
 | 
						|
  while (true) {
 | 
						|
    if (HasScopeSpecifier) {
 | 
						|
      if (Tok.is(tok::code_completion)) {
 | 
						|
        // Code completion for a nested-name-specifier, where the code
 | 
						|
        // completion token follows the '::'.
 | 
						|
        Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext,
 | 
						|
                                        InUsingDeclaration, ObjectType.get(),
 | 
						|
                                        SavedType.get(SS.getBeginLoc()));
 | 
						|
        // Include code completion token into the range of the scope otherwise
 | 
						|
        // when we try to annotate the scope tokens the dangling code completion
 | 
						|
        // token will cause assertion in
 | 
						|
        // Preprocessor::AnnotatePreviousCachedTokens.
 | 
						|
        SS.setEndLoc(Tok.getLocation());
 | 
						|
        cutOffParsing();
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
 | 
						|
      // C++ [basic.lookup.classref]p5:
 | 
						|
      //   If the qualified-id has the form
 | 
						|
      //
 | 
						|
      //       ::class-name-or-namespace-name::...
 | 
						|
      //
 | 
						|
      //   the class-name-or-namespace-name is looked up in global scope as a
 | 
						|
      //   class-name or namespace-name.
 | 
						|
      //
 | 
						|
      // To implement this, we clear out the object type as soon as we've
 | 
						|
      // seen a leading '::' or part of a nested-name-specifier.
 | 
						|
      ObjectType = nullptr;
 | 
						|
    }
 | 
						|
 | 
						|
    // nested-name-specifier:
 | 
						|
    //   nested-name-specifier 'template'[opt] simple-template-id '::'
 | 
						|
 | 
						|
    // Parse the optional 'template' keyword, then make sure we have
 | 
						|
    // 'identifier <' after it.
 | 
						|
    if (Tok.is(tok::kw_template)) {
 | 
						|
      // If we don't have a scope specifier or an object type, this isn't a
 | 
						|
      // nested-name-specifier, since they aren't allowed to start with
 | 
						|
      // 'template'.
 | 
						|
      if (!HasScopeSpecifier && !ObjectType)
 | 
						|
        break;
 | 
						|
 | 
						|
      TentativeParsingAction TPA(*this);
 | 
						|
      SourceLocation TemplateKWLoc = ConsumeToken();
 | 
						|
 | 
						|
      UnqualifiedId TemplateName;
 | 
						|
      if (Tok.is(tok::identifier)) {
 | 
						|
        // Consume the identifier.
 | 
						|
        TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
 | 
						|
        ConsumeToken();
 | 
						|
      } else if (Tok.is(tok::kw_operator)) {
 | 
						|
        // We don't need to actually parse the unqualified-id in this case,
 | 
						|
        // because a simple-template-id cannot start with 'operator', but
 | 
						|
        // go ahead and parse it anyway for consistency with the case where
 | 
						|
        // we already annotated the template-id.
 | 
						|
        if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType,
 | 
						|
                                       TemplateName)) {
 | 
						|
          TPA.Commit();
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        if (TemplateName.getKind() != UnqualifiedIdKind::IK_OperatorFunctionId &&
 | 
						|
            TemplateName.getKind() != UnqualifiedIdKind::IK_LiteralOperatorId) {
 | 
						|
          Diag(TemplateName.getSourceRange().getBegin(),
 | 
						|
               diag::err_id_after_template_in_nested_name_spec)
 | 
						|
            << TemplateName.getSourceRange();
 | 
						|
          TPA.Commit();
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        TPA.Revert();
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      // If the next token is not '<', we have a qualified-id that refers
 | 
						|
      // to a template name, such as T::template apply, but is not a
 | 
						|
      // template-id.
 | 
						|
      if (Tok.isNot(tok::less)) {
 | 
						|
        TPA.Revert();
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      // Commit to parsing the template-id.
 | 
						|
      TPA.Commit();
 | 
						|
      TemplateTy Template;
 | 
						|
      if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName(
 | 
						|
              getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType,
 | 
						|
              EnteringContext, Template, /*AllowInjectedClassName*/ true)) {
 | 
						|
        if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc,
 | 
						|
                                    TemplateName, false))
 | 
						|
          return true;
 | 
						|
      } else
 | 
						|
        return true;
 | 
						|
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) {
 | 
						|
      // We have
 | 
						|
      //
 | 
						|
      //   template-id '::'
 | 
						|
      //
 | 
						|
      // So we need to check whether the template-id is a simple-template-id of
 | 
						|
      // the right kind (it should name a type or be dependent), and then
 | 
						|
      // convert it into a type within the nested-name-specifier.
 | 
						|
      TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
 | 
						|
      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
 | 
						|
        *MayBePseudoDestructor = true;
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      if (LastII)
 | 
						|
        *LastII = TemplateId->Name;
 | 
						|
 | 
						|
      // Consume the template-id token.
 | 
						|
      ConsumeAnnotationToken();
 | 
						|
 | 
						|
      assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
 | 
						|
      SourceLocation CCLoc = ConsumeToken();
 | 
						|
 | 
						|
      HasScopeSpecifier = true;
 | 
						|
 | 
						|
      ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
 | 
						|
                                         TemplateId->NumArgs);
 | 
						|
 | 
						|
      if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(),
 | 
						|
                                              SS,
 | 
						|
                                              TemplateId->TemplateKWLoc,
 | 
						|
                                              TemplateId->Template,
 | 
						|
                                              TemplateId->TemplateNameLoc,
 | 
						|
                                              TemplateId->LAngleLoc,
 | 
						|
                                              TemplateArgsPtr,
 | 
						|
                                              TemplateId->RAngleLoc,
 | 
						|
                                              CCLoc,
 | 
						|
                                              EnteringContext)) {
 | 
						|
        SourceLocation StartLoc
 | 
						|
          = SS.getBeginLoc().isValid()? SS.getBeginLoc()
 | 
						|
                                      : TemplateId->TemplateNameLoc;
 | 
						|
        SS.SetInvalid(SourceRange(StartLoc, CCLoc));
 | 
						|
      }
 | 
						|
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    // The rest of the nested-name-specifier possibilities start with
 | 
						|
    // tok::identifier.
 | 
						|
    if (Tok.isNot(tok::identifier))
 | 
						|
      break;
 | 
						|
 | 
						|
    IdentifierInfo &II = *Tok.getIdentifierInfo();
 | 
						|
 | 
						|
    // nested-name-specifier:
 | 
						|
    //   type-name '::'
 | 
						|
    //   namespace-name '::'
 | 
						|
    //   nested-name-specifier identifier '::'
 | 
						|
    Token Next = NextToken();
 | 
						|
    Sema::NestedNameSpecInfo IdInfo(&II, Tok.getLocation(), Next.getLocation(),
 | 
						|
                                    ObjectType);
 | 
						|
 | 
						|
    // If we get foo:bar, this is almost certainly a typo for foo::bar.  Recover
 | 
						|
    // and emit a fixit hint for it.
 | 
						|
    if (Next.is(tok::colon) && !ColonIsSacred) {
 | 
						|
      if (Actions.IsInvalidUnlessNestedName(getCurScope(), SS, IdInfo,
 | 
						|
                                            EnteringContext) &&
 | 
						|
          // If the token after the colon isn't an identifier, it's still an
 | 
						|
          // error, but they probably meant something else strange so don't
 | 
						|
          // recover like this.
 | 
						|
          PP.LookAhead(1).is(tok::identifier)) {
 | 
						|
        Diag(Next, diag::err_unexpected_colon_in_nested_name_spec)
 | 
						|
          << FixItHint::CreateReplacement(Next.getLocation(), "::");
 | 
						|
        // Recover as if the user wrote '::'.
 | 
						|
        Next.setKind(tok::coloncolon);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (Next.is(tok::coloncolon) && GetLookAheadToken(2).is(tok::l_brace)) {
 | 
						|
      // It is invalid to have :: {, consume the scope qualifier and pretend
 | 
						|
      // like we never saw it.
 | 
						|
      Token Identifier = Tok; // Stash away the identifier.
 | 
						|
      ConsumeToken();         // Eat the identifier, current token is now '::'.
 | 
						|
      Diag(PP.getLocForEndOfToken(ConsumeToken()), diag::err_expected)
 | 
						|
          << tok::identifier;
 | 
						|
      UnconsumeToken(Identifier); // Stick the identifier back.
 | 
						|
      Next = NextToken();         // Point Next at the '{' token.
 | 
						|
    }
 | 
						|
 | 
						|
    if (Next.is(tok::coloncolon)) {
 | 
						|
      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
 | 
						|
        *MayBePseudoDestructor = true;
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      if (ColonIsSacred) {
 | 
						|
        const Token &Next2 = GetLookAheadToken(2);
 | 
						|
        if (Next2.is(tok::kw_private) || Next2.is(tok::kw_protected) ||
 | 
						|
            Next2.is(tok::kw_public) || Next2.is(tok::kw_virtual)) {
 | 
						|
          Diag(Next2, diag::err_unexpected_token_in_nested_name_spec)
 | 
						|
              << Next2.getName()
 | 
						|
              << FixItHint::CreateReplacement(Next.getLocation(), ":");
 | 
						|
          Token ColonColon;
 | 
						|
          PP.Lex(ColonColon);
 | 
						|
          ColonColon.setKind(tok::colon);
 | 
						|
          PP.EnterToken(ColonColon, /*IsReinject*/ true);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (LastII)
 | 
						|
        *LastII = &II;
 | 
						|
 | 
						|
      // We have an identifier followed by a '::'. Lookup this name
 | 
						|
      // as the name in a nested-name-specifier.
 | 
						|
      Token Identifier = Tok;
 | 
						|
      SourceLocation IdLoc = ConsumeToken();
 | 
						|
      assert(Tok.isOneOf(tok::coloncolon, tok::colon) &&
 | 
						|
             "NextToken() not working properly!");
 | 
						|
      Token ColonColon = Tok;
 | 
						|
      SourceLocation CCLoc = ConsumeToken();
 | 
						|
 | 
						|
      bool IsCorrectedToColon = false;
 | 
						|
      bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : nullptr;
 | 
						|
      if (Actions.ActOnCXXNestedNameSpecifier(
 | 
						|
              getCurScope(), IdInfo, EnteringContext, SS, false,
 | 
						|
              CorrectionFlagPtr, OnlyNamespace)) {
 | 
						|
        // Identifier is not recognized as a nested name, but we can have
 | 
						|
        // mistyped '::' instead of ':'.
 | 
						|
        if (CorrectionFlagPtr && IsCorrectedToColon) {
 | 
						|
          ColonColon.setKind(tok::colon);
 | 
						|
          PP.EnterToken(Tok, /*IsReinject*/ true);
 | 
						|
          PP.EnterToken(ColonColon, /*IsReinject*/ true);
 | 
						|
          Tok = Identifier;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        SS.SetInvalid(SourceRange(IdLoc, CCLoc));
 | 
						|
      }
 | 
						|
      HasScopeSpecifier = true;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    CheckForTemplateAndDigraph(Next, ObjectType, EnteringContext, II, SS);
 | 
						|
 | 
						|
    // nested-name-specifier:
 | 
						|
    //   type-name '<'
 | 
						|
    if (Next.is(tok::less)) {
 | 
						|
 | 
						|
      TemplateTy Template;
 | 
						|
      UnqualifiedId TemplateName;
 | 
						|
      TemplateName.setIdentifier(&II, Tok.getLocation());
 | 
						|
      bool MemberOfUnknownSpecialization;
 | 
						|
      if (TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS,
 | 
						|
                                              /*hasTemplateKeyword=*/false,
 | 
						|
                                                        TemplateName,
 | 
						|
                                                        ObjectType,
 | 
						|
                                                        EnteringContext,
 | 
						|
                                                        Template,
 | 
						|
                                              MemberOfUnknownSpecialization)) {
 | 
						|
        // If lookup didn't find anything, we treat the name as a template-name
 | 
						|
        // anyway. C++20 requires this, and in prior language modes it improves
 | 
						|
        // error recovery. But before we commit to this, check that we actually
 | 
						|
        // have something that looks like a template-argument-list next.
 | 
						|
        if (!IsTypename && TNK == TNK_Undeclared_template &&
 | 
						|
            isTemplateArgumentList(1) == TPResult::False)
 | 
						|
          break;
 | 
						|
 | 
						|
        // We have found a template name, so annotate this token
 | 
						|
        // with a template-id annotation. We do not permit the
 | 
						|
        // template-id to be translated into a type annotation,
 | 
						|
        // because some clients (e.g., the parsing of class template
 | 
						|
        // specializations) still want to see the original template-id
 | 
						|
        // token, and it might not be a type at all (e.g. a concept name in a
 | 
						|
        // type-constraint).
 | 
						|
        ConsumeToken();
 | 
						|
        if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
 | 
						|
                                    TemplateName, false))
 | 
						|
          return true;
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) &&
 | 
						|
          (IsTypename || isTemplateArgumentList(1) == TPResult::True)) {
 | 
						|
        // We have something like t::getAs<T>, where getAs is a
 | 
						|
        // member of an unknown specialization. However, this will only
 | 
						|
        // parse correctly as a template, so suggest the keyword 'template'
 | 
						|
        // before 'getAs' and treat this as a dependent template name.
 | 
						|
        unsigned DiagID = diag::err_missing_dependent_template_keyword;
 | 
						|
        if (getLangOpts().MicrosoftExt)
 | 
						|
          DiagID = diag::warn_missing_dependent_template_keyword;
 | 
						|
 | 
						|
        Diag(Tok.getLocation(), DiagID)
 | 
						|
          << II.getName()
 | 
						|
          << FixItHint::CreateInsertion(Tok.getLocation(), "template ");
 | 
						|
 | 
						|
        if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName(
 | 
						|
                getCurScope(), SS, Tok.getLocation(), TemplateName, ObjectType,
 | 
						|
                EnteringContext, Template, /*AllowInjectedClassName*/ true)) {
 | 
						|
          // Consume the identifier.
 | 
						|
          ConsumeToken();
 | 
						|
          if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
 | 
						|
                                      TemplateName, false))
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
        else
 | 
						|
          return true;
 | 
						|
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // We don't have any tokens that form the beginning of a
 | 
						|
    // nested-name-specifier, so we're done.
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  // Even if we didn't see any pieces of a nested-name-specifier, we
 | 
						|
  // still check whether there is a tilde in this position, which
 | 
						|
  // indicates a potential pseudo-destructor.
 | 
						|
  if (CheckForDestructor && !HasScopeSpecifier && Tok.is(tok::tilde))
 | 
						|
    *MayBePseudoDestructor = true;
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS,
 | 
						|
                                           bool isAddressOfOperand,
 | 
						|
                                           Token &Replacement) {
 | 
						|
  ExprResult E;
 | 
						|
 | 
						|
  // We may have already annotated this id-expression.
 | 
						|
  switch (Tok.getKind()) {
 | 
						|
  case tok::annot_non_type: {
 | 
						|
    NamedDecl *ND = getNonTypeAnnotation(Tok);
 | 
						|
    SourceLocation Loc = ConsumeAnnotationToken();
 | 
						|
    E = Actions.ActOnNameClassifiedAsNonType(getCurScope(), SS, ND, Loc, Tok);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  case tok::annot_non_type_dependent: {
 | 
						|
    IdentifierInfo *II = getIdentifierAnnotation(Tok);
 | 
						|
    SourceLocation Loc = ConsumeAnnotationToken();
 | 
						|
 | 
						|
    // This is only the direct operand of an & operator if it is not
 | 
						|
    // followed by a postfix-expression suffix.
 | 
						|
    if (isAddressOfOperand && isPostfixExpressionSuffixStart())
 | 
						|
      isAddressOfOperand = false;
 | 
						|
 | 
						|
    E = Actions.ActOnNameClassifiedAsDependentNonType(SS, II, Loc,
 | 
						|
                                                      isAddressOfOperand);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  case tok::annot_non_type_undeclared: {
 | 
						|
    assert(SS.isEmpty() &&
 | 
						|
           "undeclared non-type annotation should be unqualified");
 | 
						|
    IdentifierInfo *II = getIdentifierAnnotation(Tok);
 | 
						|
    SourceLocation Loc = ConsumeAnnotationToken();
 | 
						|
    E = Actions.ActOnNameClassifiedAsUndeclaredNonType(II, Loc);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  default:
 | 
						|
    SourceLocation TemplateKWLoc;
 | 
						|
    UnqualifiedId Name;
 | 
						|
    if (ParseUnqualifiedId(SS,
 | 
						|
                           /*EnteringContext=*/false,
 | 
						|
                           /*AllowDestructorName=*/false,
 | 
						|
                           /*AllowConstructorName=*/false,
 | 
						|
                           /*AllowDeductionGuide=*/false,
 | 
						|
                           /*ObjectType=*/nullptr, &TemplateKWLoc, Name))
 | 
						|
      return ExprError();
 | 
						|
 | 
						|
    // This is only the direct operand of an & operator if it is not
 | 
						|
    // followed by a postfix-expression suffix.
 | 
						|
    if (isAddressOfOperand && isPostfixExpressionSuffixStart())
 | 
						|
      isAddressOfOperand = false;
 | 
						|
 | 
						|
    E = Actions.ActOnIdExpression(
 | 
						|
        getCurScope(), SS, TemplateKWLoc, Name, Tok.is(tok::l_paren),
 | 
						|
        isAddressOfOperand, /*CCC=*/nullptr, /*IsInlineAsmIdentifier=*/false,
 | 
						|
        &Replacement);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!E.isInvalid() && !E.isUnset() && Tok.is(tok::less))
 | 
						|
    checkPotentialAngleBracket(E);
 | 
						|
  return E;
 | 
						|
}
 | 
						|
 | 
						|
/// ParseCXXIdExpression - Handle id-expression.
 | 
						|
///
 | 
						|
///       id-expression:
 | 
						|
///         unqualified-id
 | 
						|
///         qualified-id
 | 
						|
///
 | 
						|
///       qualified-id:
 | 
						|
///         '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
 | 
						|
///         '::' identifier
 | 
						|
///         '::' operator-function-id
 | 
						|
///         '::' template-id
 | 
						|
///
 | 
						|
/// NOTE: The standard specifies that, for qualified-id, the parser does not
 | 
						|
/// expect:
 | 
						|
///
 | 
						|
///   '::' conversion-function-id
 | 
						|
///   '::' '~' class-name
 | 
						|
///
 | 
						|
/// This may cause a slight inconsistency on diagnostics:
 | 
						|
///
 | 
						|
/// class C {};
 | 
						|
/// namespace A {}
 | 
						|
/// void f() {
 | 
						|
///   :: A :: ~ C(); // Some Sema error about using destructor with a
 | 
						|
///                  // namespace.
 | 
						|
///   :: ~ C(); // Some Parser error like 'unexpected ~'.
 | 
						|
/// }
 | 
						|
///
 | 
						|
/// We simplify the parser a bit and make it work like:
 | 
						|
///
 | 
						|
///       qualified-id:
 | 
						|
///         '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
 | 
						|
///         '::' unqualified-id
 | 
						|
///
 | 
						|
/// That way Sema can handle and report similar errors for namespaces and the
 | 
						|
/// global scope.
 | 
						|
///
 | 
						|
/// The isAddressOfOperand parameter indicates that this id-expression is a
 | 
						|
/// direct operand of the address-of operator. This is, besides member contexts,
 | 
						|
/// the only place where a qualified-id naming a non-static class member may
 | 
						|
/// appear.
 | 
						|
///
 | 
						|
ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
 | 
						|
  // qualified-id:
 | 
						|
  //   '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
 | 
						|
  //   '::' unqualified-id
 | 
						|
  //
 | 
						|
  CXXScopeSpec SS;
 | 
						|
  ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);
 | 
						|
 | 
						|
  Token Replacement;
 | 
						|
  ExprResult Result =
 | 
						|
      tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement);
 | 
						|
  if (Result.isUnset()) {
 | 
						|
    // If the ExprResult is valid but null, then typo correction suggested a
 | 
						|
    // keyword replacement that needs to be reparsed.
 | 
						|
    UnconsumeToken(Replacement);
 | 
						|
    Result = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement);
 | 
						|
  }
 | 
						|
  assert(!Result.isUnset() && "Typo correction suggested a keyword replacement "
 | 
						|
                              "for a previous keyword suggestion");
 | 
						|
  return Result;
 | 
						|
}
 | 
						|
 | 
						|
/// ParseLambdaExpression - Parse a C++11 lambda expression.
 | 
						|
///
 | 
						|
///       lambda-expression:
 | 
						|
///         lambda-introducer lambda-declarator[opt] compound-statement
 | 
						|
///         lambda-introducer '<' template-parameter-list '>'
 | 
						|
///             lambda-declarator[opt] compound-statement
 | 
						|
///
 | 
						|
///       lambda-introducer:
 | 
						|
///         '[' lambda-capture[opt] ']'
 | 
						|
///
 | 
						|
///       lambda-capture:
 | 
						|
///         capture-default
 | 
						|
///         capture-list
 | 
						|
///         capture-default ',' capture-list
 | 
						|
///
 | 
						|
///       capture-default:
 | 
						|
///         '&'
 | 
						|
///         '='
 | 
						|
///
 | 
						|
///       capture-list:
 | 
						|
///         capture
 | 
						|
///         capture-list ',' capture
 | 
						|
///
 | 
						|
///       capture:
 | 
						|
///         simple-capture
 | 
						|
///         init-capture     [C++1y]
 | 
						|
///
 | 
						|
///       simple-capture:
 | 
						|
///         identifier
 | 
						|
///         '&' identifier
 | 
						|
///         'this'
 | 
						|
///
 | 
						|
///       init-capture:      [C++1y]
 | 
						|
///         identifier initializer
 | 
						|
///         '&' identifier initializer
 | 
						|
///
 | 
						|
///       lambda-declarator:
 | 
						|
///         '(' parameter-declaration-clause ')' attribute-specifier[opt]
 | 
						|
///           'mutable'[opt] exception-specification[opt]
 | 
						|
///           trailing-return-type[opt]
 | 
						|
///
 | 
						|
ExprResult Parser::ParseLambdaExpression() {
 | 
						|
  // Parse lambda-introducer.
 | 
						|
  LambdaIntroducer Intro;
 | 
						|
  if (ParseLambdaIntroducer(Intro)) {
 | 
						|
    SkipUntil(tok::r_square, StopAtSemi);
 | 
						|
    SkipUntil(tok::l_brace, StopAtSemi);
 | 
						|
    SkipUntil(tok::r_brace, StopAtSemi);
 | 
						|
    return ExprError();
 | 
						|
  }
 | 
						|
 | 
						|
  return ParseLambdaExpressionAfterIntroducer(Intro);
 | 
						|
}
 | 
						|
 | 
						|
/// Use lookahead and potentially tentative parsing to determine if we are
 | 
						|
/// looking at a C++11 lambda expression, and parse it if we are.
 | 
						|
///
 | 
						|
/// If we are not looking at a lambda expression, returns ExprError().
 | 
						|
ExprResult Parser::TryParseLambdaExpression() {
 | 
						|
  assert(getLangOpts().CPlusPlus11
 | 
						|
         && Tok.is(tok::l_square)
 | 
						|
         && "Not at the start of a possible lambda expression.");
 | 
						|
 | 
						|
  const Token Next = NextToken();
 | 
						|
  if (Next.is(tok::eof)) // Nothing else to lookup here...
 | 
						|
    return ExprEmpty();
 | 
						|
 | 
						|
  const Token After = GetLookAheadToken(2);
 | 
						|
  // If lookahead indicates this is a lambda...
 | 
						|
  if (Next.is(tok::r_square) ||     // []
 | 
						|
      Next.is(tok::equal) ||        // [=
 | 
						|
      (Next.is(tok::amp) &&         // [&] or [&,
 | 
						|
       After.isOneOf(tok::r_square, tok::comma)) ||
 | 
						|
      (Next.is(tok::identifier) &&  // [identifier]
 | 
						|
       After.is(tok::r_square)) ||
 | 
						|
      Next.is(tok::ellipsis)) {     // [...
 | 
						|
    return ParseLambdaExpression();
 | 
						|
  }
 | 
						|
 | 
						|
  // If lookahead indicates an ObjC message send...
 | 
						|
  // [identifier identifier
 | 
						|
  if (Next.is(tok::identifier) && After.is(tok::identifier))
 | 
						|
    return ExprEmpty();
 | 
						|
 | 
						|
  // Here, we're stuck: lambda introducers and Objective-C message sends are
 | 
						|
  // unambiguous, but it requires arbitrary lookhead.  [a,b,c,d,e,f,g] is a
 | 
						|
  // lambda, and [a,b,c,d,e,f,g h] is a Objective-C message send.  Instead of
 | 
						|
  // writing two routines to parse a lambda introducer, just try to parse
 | 
						|
  // a lambda introducer first, and fall back if that fails.
 | 
						|
  LambdaIntroducer Intro;
 | 
						|
  {
 | 
						|
    TentativeParsingAction TPA(*this);
 | 
						|
    LambdaIntroducerTentativeParse Tentative;
 | 
						|
    if (ParseLambdaIntroducer(Intro, &Tentative)) {
 | 
						|
      TPA.Commit();
 | 
						|
      return ExprError();
 | 
						|
    }
 | 
						|
 | 
						|
    switch (Tentative) {
 | 
						|
    case LambdaIntroducerTentativeParse::Success:
 | 
						|
      TPA.Commit();
 | 
						|
      break;
 | 
						|
 | 
						|
    case LambdaIntroducerTentativeParse::Incomplete:
 | 
						|
      // Didn't fully parse the lambda-introducer, try again with a
 | 
						|
      // non-tentative parse.
 | 
						|
      TPA.Revert();
 | 
						|
      Intro = LambdaIntroducer();
 | 
						|
      if (ParseLambdaIntroducer(Intro))
 | 
						|
        return ExprError();
 | 
						|
      break;
 | 
						|
 | 
						|
    case LambdaIntroducerTentativeParse::MessageSend:
 | 
						|
    case LambdaIntroducerTentativeParse::Invalid:
 | 
						|
      // Not a lambda-introducer, might be a message send.
 | 
						|
      TPA.Revert();
 | 
						|
      return ExprEmpty();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return ParseLambdaExpressionAfterIntroducer(Intro);
 | 
						|
}
 | 
						|
 | 
						|
/// Parse a lambda introducer.
 | 
						|
/// \param Intro A LambdaIntroducer filled in with information about the
 | 
						|
///        contents of the lambda-introducer.
 | 
						|
/// \param Tentative If non-null, we are disambiguating between a
 | 
						|
///        lambda-introducer and some other construct. In this mode, we do not
 | 
						|
///        produce any diagnostics or take any other irreversible action unless
 | 
						|
///        we're sure that this is a lambda-expression.
 | 
						|
/// \return \c true if parsing (or disambiguation) failed with a diagnostic and
 | 
						|
///         the caller should bail out / recover.
 | 
						|
bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
 | 
						|
                                   LambdaIntroducerTentativeParse *Tentative) {
 | 
						|
  if (Tentative)
 | 
						|
    *Tentative = LambdaIntroducerTentativeParse::Success;
 | 
						|
 | 
						|
  assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['.");
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_square);
 | 
						|
  T.consumeOpen();
 | 
						|
 | 
						|
  Intro.Range.setBegin(T.getOpenLocation());
 | 
						|
 | 
						|
  bool First = true;
 | 
						|
 | 
						|
  // Produce a diagnostic if we're not tentatively parsing; otherwise track
 | 
						|
  // that our parse has failed.
 | 
						|
  auto Invalid = [&](llvm::function_ref<void()> Action) {
 | 
						|
    if (Tentative) {
 | 
						|
      *Tentative = LambdaIntroducerTentativeParse::Invalid;
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    Action();
 | 
						|
    return true;
 | 
						|
  };
 | 
						|
 | 
						|
  // Perform some irreversible action if this is a non-tentative parse;
 | 
						|
  // otherwise note that our actions were incomplete.
 | 
						|
  auto NonTentativeAction = [&](llvm::function_ref<void()> Action) {
 | 
						|
    if (Tentative)
 | 
						|
      *Tentative = LambdaIntroducerTentativeParse::Incomplete;
 | 
						|
    else
 | 
						|
      Action();
 | 
						|
  };
 | 
						|
 | 
						|
  // Parse capture-default.
 | 
						|
  if (Tok.is(tok::amp) &&
 | 
						|
      (NextToken().is(tok::comma) || NextToken().is(tok::r_square))) {
 | 
						|
    Intro.Default = LCD_ByRef;
 | 
						|
    Intro.DefaultLoc = ConsumeToken();
 | 
						|
    First = false;
 | 
						|
    if (!Tok.getIdentifierInfo()) {
 | 
						|
      // This can only be a lambda; no need for tentative parsing any more.
 | 
						|
      // '[[and]]' can still be an attribute, though.
 | 
						|
      Tentative = nullptr;
 | 
						|
    }
 | 
						|
  } else if (Tok.is(tok::equal)) {
 | 
						|
    Intro.Default = LCD_ByCopy;
 | 
						|
    Intro.DefaultLoc = ConsumeToken();
 | 
						|
    First = false;
 | 
						|
    Tentative = nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  while (Tok.isNot(tok::r_square)) {
 | 
						|
    if (!First) {
 | 
						|
      if (Tok.isNot(tok::comma)) {
 | 
						|
        // Provide a completion for a lambda introducer here. Except
 | 
						|
        // in Objective-C, where this is Almost Surely meant to be a message
 | 
						|
        // send. In that case, fail here and let the ObjC message
 | 
						|
        // expression parser perform the completion.
 | 
						|
        if (Tok.is(tok::code_completion) &&
 | 
						|
            !(getLangOpts().ObjC && Tentative)) {
 | 
						|
          Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
 | 
						|
                                               /*AfterAmpersand=*/false);
 | 
						|
          cutOffParsing();
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        return Invalid([&] {
 | 
						|
          Diag(Tok.getLocation(), diag::err_expected_comma_or_rsquare);
 | 
						|
        });
 | 
						|
      }
 | 
						|
      ConsumeToken();
 | 
						|
    }
 | 
						|
 | 
						|
    if (Tok.is(tok::code_completion)) {
 | 
						|
      // If we're in Objective-C++ and we have a bare '[', then this is more
 | 
						|
      // likely to be a message receiver.
 | 
						|
      if (getLangOpts().ObjC && Tentative && First)
 | 
						|
        Actions.CodeCompleteObjCMessageReceiver(getCurScope());
 | 
						|
      else
 | 
						|
        Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
 | 
						|
                                             /*AfterAmpersand=*/false);
 | 
						|
      cutOffParsing();
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    First = false;
 | 
						|
 | 
						|
    // Parse capture.
 | 
						|
    LambdaCaptureKind Kind = LCK_ByCopy;
 | 
						|
    LambdaCaptureInitKind InitKind = LambdaCaptureInitKind::NoInit;
 | 
						|
    SourceLocation Loc;
 | 
						|
    IdentifierInfo *Id = nullptr;
 | 
						|
    SourceLocation EllipsisLocs[4];
 | 
						|
    ExprResult Init;
 | 
						|
    SourceLocation LocStart = Tok.getLocation();
 | 
						|
 | 
						|
    if (Tok.is(tok::star)) {
 | 
						|
      Loc = ConsumeToken();
 | 
						|
      if (Tok.is(tok::kw_this)) {
 | 
						|
        ConsumeToken();
 | 
						|
        Kind = LCK_StarThis;
 | 
						|
      } else {
 | 
						|
        return Invalid([&] {
 | 
						|
          Diag(Tok.getLocation(), diag::err_expected_star_this_capture);
 | 
						|
        });
 | 
						|
      }
 | 
						|
    } else if (Tok.is(tok::kw_this)) {
 | 
						|
      Kind = LCK_This;
 | 
						|
      Loc = ConsumeToken();
 | 
						|
    } else {
 | 
						|
      TryConsumeToken(tok::ellipsis, EllipsisLocs[0]);
 | 
						|
 | 
						|
      if (Tok.is(tok::amp)) {
 | 
						|
        Kind = LCK_ByRef;
 | 
						|
        ConsumeToken();
 | 
						|
 | 
						|
        if (Tok.is(tok::code_completion)) {
 | 
						|
          Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
 | 
						|
                                               /*AfterAmpersand=*/true);
 | 
						|
          cutOffParsing();
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      TryConsumeToken(tok::ellipsis, EllipsisLocs[1]);
 | 
						|
 | 
						|
      if (Tok.is(tok::identifier)) {
 | 
						|
        Id = Tok.getIdentifierInfo();
 | 
						|
        Loc = ConsumeToken();
 | 
						|
      } else if (Tok.is(tok::kw_this)) {
 | 
						|
        return Invalid([&] {
 | 
						|
          // FIXME: Suggest a fixit here.
 | 
						|
          Diag(Tok.getLocation(), diag::err_this_captured_by_reference);
 | 
						|
        });
 | 
						|
      } else {
 | 
						|
        return Invalid([&] {
 | 
						|
          Diag(Tok.getLocation(), diag::err_expected_capture);
 | 
						|
        });
 | 
						|
      }
 | 
						|
 | 
						|
      TryConsumeToken(tok::ellipsis, EllipsisLocs[2]);
 | 
						|
 | 
						|
      if (Tok.is(tok::l_paren)) {
 | 
						|
        BalancedDelimiterTracker Parens(*this, tok::l_paren);
 | 
						|
        Parens.consumeOpen();
 | 
						|
 | 
						|
        InitKind = LambdaCaptureInitKind::DirectInit;
 | 
						|
 | 
						|
        ExprVector Exprs;
 | 
						|
        CommaLocsTy Commas;
 | 
						|
        if (Tentative) {
 | 
						|
          Parens.skipToEnd();
 | 
						|
          *Tentative = LambdaIntroducerTentativeParse::Incomplete;
 | 
						|
        } else if (ParseExpressionList(Exprs, Commas)) {
 | 
						|
          Parens.skipToEnd();
 | 
						|
          Init = ExprError();
 | 
						|
        } else {
 | 
						|
          Parens.consumeClose();
 | 
						|
          Init = Actions.ActOnParenListExpr(Parens.getOpenLocation(),
 | 
						|
                                            Parens.getCloseLocation(),
 | 
						|
                                            Exprs);
 | 
						|
        }
 | 
						|
      } else if (Tok.isOneOf(tok::l_brace, tok::equal)) {
 | 
						|
        // Each lambda init-capture forms its own full expression, which clears
 | 
						|
        // Actions.MaybeODRUseExprs. So create an expression evaluation context
 | 
						|
        // to save the necessary state, and restore it later.
 | 
						|
        EnterExpressionEvaluationContext EC(
 | 
						|
            Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
 | 
						|
 | 
						|
        if (TryConsumeToken(tok::equal))
 | 
						|
          InitKind = LambdaCaptureInitKind::CopyInit;
 | 
						|
        else
 | 
						|
          InitKind = LambdaCaptureInitKind::ListInit;
 | 
						|
 | 
						|
        if (!Tentative) {
 | 
						|
          Init = ParseInitializer();
 | 
						|
        } else if (Tok.is(tok::l_brace)) {
 | 
						|
          BalancedDelimiterTracker Braces(*this, tok::l_brace);
 | 
						|
          Braces.consumeOpen();
 | 
						|
          Braces.skipToEnd();
 | 
						|
          *Tentative = LambdaIntroducerTentativeParse::Incomplete;
 | 
						|
        } else {
 | 
						|
          // We're disambiguating this:
 | 
						|
          //
 | 
						|
          //   [..., x = expr
 | 
						|
          //
 | 
						|
          // We need to find the end of the following expression in order to
 | 
						|
          // determine whether this is an Obj-C message send's receiver, a
 | 
						|
          // C99 designator, or a lambda init-capture.
 | 
						|
          //
 | 
						|
          // Parse the expression to find where it ends, and annotate it back
 | 
						|
          // onto the tokens. We would have parsed this expression the same way
 | 
						|
          // in either case: both the RHS of an init-capture and the RHS of an
 | 
						|
          // assignment expression are parsed as an initializer-clause, and in
 | 
						|
          // neither case can anything be added to the scope between the '[' and
 | 
						|
          // here.
 | 
						|
          //
 | 
						|
          // FIXME: This is horrible. Adding a mechanism to skip an expression
 | 
						|
          // would be much cleaner.
 | 
						|
          // FIXME: If there is a ',' before the next ']' or ':', we can skip to
 | 
						|
          // that instead. (And if we see a ':' with no matching '?', we can
 | 
						|
          // classify this as an Obj-C message send.)
 | 
						|
          SourceLocation StartLoc = Tok.getLocation();
 | 
						|
          InMessageExpressionRAIIObject MaybeInMessageExpression(*this, true);
 | 
						|
          Init = ParseInitializer();
 | 
						|
          if (!Init.isInvalid())
 | 
						|
            Init = Actions.CorrectDelayedTyposInExpr(Init.get());
 | 
						|
 | 
						|
          if (Tok.getLocation() != StartLoc) {
 | 
						|
            // Back out the lexing of the token after the initializer.
 | 
						|
            PP.RevertCachedTokens(1);
 | 
						|
 | 
						|
            // Replace the consumed tokens with an appropriate annotation.
 | 
						|
            Tok.setLocation(StartLoc);
 | 
						|
            Tok.setKind(tok::annot_primary_expr);
 | 
						|
            setExprAnnotation(Tok, Init);
 | 
						|
            Tok.setAnnotationEndLoc(PP.getLastCachedTokenLocation());
 | 
						|
            PP.AnnotateCachedTokens(Tok);
 | 
						|
 | 
						|
            // Consume the annotated initializer.
 | 
						|
            ConsumeAnnotationToken();
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      TryConsumeToken(tok::ellipsis, EllipsisLocs[3]);
 | 
						|
    }
 | 
						|
 | 
						|
    // Check if this is a message send before we act on a possible init-capture.
 | 
						|
    if (Tentative && Tok.is(tok::identifier) &&
 | 
						|
        NextToken().isOneOf(tok::colon, tok::r_square)) {
 | 
						|
      // This can only be a message send. We're done with disambiguation.
 | 
						|
      *Tentative = LambdaIntroducerTentativeParse::MessageSend;
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    // Ensure that any ellipsis was in the right place.
 | 
						|
    SourceLocation EllipsisLoc;
 | 
						|
    if (std::any_of(std::begin(EllipsisLocs), std::end(EllipsisLocs),
 | 
						|
                    [](SourceLocation Loc) { return Loc.isValid(); })) {
 | 
						|
      // The '...' should appear before the identifier in an init-capture, and
 | 
						|
      // after the identifier otherwise.
 | 
						|
      bool InitCapture = InitKind != LambdaCaptureInitKind::NoInit;
 | 
						|
      SourceLocation *ExpectedEllipsisLoc =
 | 
						|
          !InitCapture      ? &EllipsisLocs[2] :
 | 
						|
          Kind == LCK_ByRef ? &EllipsisLocs[1] :
 | 
						|
                              &EllipsisLocs[0];
 | 
						|
      EllipsisLoc = *ExpectedEllipsisLoc;
 | 
						|
 | 
						|
      unsigned DiagID = 0;
 | 
						|
      if (EllipsisLoc.isInvalid()) {
 | 
						|
        DiagID = diag::err_lambda_capture_misplaced_ellipsis;
 | 
						|
        for (SourceLocation Loc : EllipsisLocs) {
 | 
						|
          if (Loc.isValid())
 | 
						|
            EllipsisLoc = Loc;
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        unsigned NumEllipses = std::accumulate(
 | 
						|
            std::begin(EllipsisLocs), std::end(EllipsisLocs), 0,
 | 
						|
            [](int N, SourceLocation Loc) { return N + Loc.isValid(); });
 | 
						|
        if (NumEllipses > 1)
 | 
						|
          DiagID = diag::err_lambda_capture_multiple_ellipses;
 | 
						|
      }
 | 
						|
      if (DiagID) {
 | 
						|
        NonTentativeAction([&] {
 | 
						|
          // Point the diagnostic at the first misplaced ellipsis.
 | 
						|
          SourceLocation DiagLoc;
 | 
						|
          for (SourceLocation &Loc : EllipsisLocs) {
 | 
						|
            if (&Loc != ExpectedEllipsisLoc && Loc.isValid()) {
 | 
						|
              DiagLoc = Loc;
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          }
 | 
						|
          assert(DiagLoc.isValid() && "no location for diagnostic");
 | 
						|
 | 
						|
          // Issue the diagnostic and produce fixits showing where the ellipsis
 | 
						|
          // should have been written.
 | 
						|
          auto &&D = Diag(DiagLoc, DiagID);
 | 
						|
          if (DiagID == diag::err_lambda_capture_misplaced_ellipsis) {
 | 
						|
            SourceLocation ExpectedLoc =
 | 
						|
                InitCapture ? Loc
 | 
						|
                            : Lexer::getLocForEndOfToken(
 | 
						|
                                  Loc, 0, PP.getSourceManager(), getLangOpts());
 | 
						|
            D << InitCapture << FixItHint::CreateInsertion(ExpectedLoc, "...");
 | 
						|
          }
 | 
						|
          for (SourceLocation &Loc : EllipsisLocs) {
 | 
						|
            if (&Loc != ExpectedEllipsisLoc && Loc.isValid())
 | 
						|
              D << FixItHint::CreateRemoval(Loc);
 | 
						|
          }
 | 
						|
        });
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // Process the init-capture initializers now rather than delaying until we
 | 
						|
    // form the lambda-expression so that they can be handled in the context
 | 
						|
    // enclosing the lambda-expression, rather than in the context of the
 | 
						|
    // lambda-expression itself.
 | 
						|
    ParsedType InitCaptureType;
 | 
						|
    if (Init.isUsable())
 | 
						|
      Init = Actions.CorrectDelayedTyposInExpr(Init.get());
 | 
						|
    if (Init.isUsable()) {
 | 
						|
      NonTentativeAction([&] {
 | 
						|
        // Get the pointer and store it in an lvalue, so we can use it as an
 | 
						|
        // out argument.
 | 
						|
        Expr *InitExpr = Init.get();
 | 
						|
        // This performs any lvalue-to-rvalue conversions if necessary, which
 | 
						|
        // can affect what gets captured in the containing decl-context.
 | 
						|
        InitCaptureType = Actions.actOnLambdaInitCaptureInitialization(
 | 
						|
            Loc, Kind == LCK_ByRef, EllipsisLoc, Id, InitKind, InitExpr);
 | 
						|
        Init = InitExpr;
 | 
						|
      });
 | 
						|
    }
 | 
						|
 | 
						|
    SourceLocation LocEnd = PrevTokLocation;
 | 
						|
 | 
						|
    Intro.addCapture(Kind, Loc, Id, EllipsisLoc, InitKind, Init,
 | 
						|
                     InitCaptureType, SourceRange(LocStart, LocEnd));
 | 
						|
  }
 | 
						|
 | 
						|
  T.consumeClose();
 | 
						|
  Intro.Range.setEnd(T.getCloseLocation());
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
static void tryConsumeLambdaSpecifierToken(Parser &P,
 | 
						|
                                           SourceLocation &MutableLoc,
 | 
						|
                                           SourceLocation &ConstexprLoc,
 | 
						|
                                           SourceLocation &ConstevalLoc,
 | 
						|
                                           SourceLocation &DeclEndLoc) {
 | 
						|
  assert(MutableLoc.isInvalid());
 | 
						|
  assert(ConstexprLoc.isInvalid());
 | 
						|
  // Consume constexpr-opt mutable-opt in any sequence, and set the DeclEndLoc
 | 
						|
  // to the final of those locations. Emit an error if we have multiple
 | 
						|
  // copies of those keywords and recover.
 | 
						|
 | 
						|
  while (true) {
 | 
						|
    switch (P.getCurToken().getKind()) {
 | 
						|
    case tok::kw_mutable: {
 | 
						|
      if (MutableLoc.isValid()) {
 | 
						|
        P.Diag(P.getCurToken().getLocation(),
 | 
						|
               diag::err_lambda_decl_specifier_repeated)
 | 
						|
            << 0 << FixItHint::CreateRemoval(P.getCurToken().getLocation());
 | 
						|
      }
 | 
						|
      MutableLoc = P.ConsumeToken();
 | 
						|
      DeclEndLoc = MutableLoc;
 | 
						|
      break /*switch*/;
 | 
						|
    }
 | 
						|
    case tok::kw_constexpr:
 | 
						|
      if (ConstexprLoc.isValid()) {
 | 
						|
        P.Diag(P.getCurToken().getLocation(),
 | 
						|
               diag::err_lambda_decl_specifier_repeated)
 | 
						|
            << 1 << FixItHint::CreateRemoval(P.getCurToken().getLocation());
 | 
						|
      }
 | 
						|
      ConstexprLoc = P.ConsumeToken();
 | 
						|
      DeclEndLoc = ConstexprLoc;
 | 
						|
      break /*switch*/;
 | 
						|
    case tok::kw_consteval:
 | 
						|
      if (ConstevalLoc.isValid()) {
 | 
						|
        P.Diag(P.getCurToken().getLocation(),
 | 
						|
               diag::err_lambda_decl_specifier_repeated)
 | 
						|
            << 2 << FixItHint::CreateRemoval(P.getCurToken().getLocation());
 | 
						|
      }
 | 
						|
      ConstevalLoc = P.ConsumeToken();
 | 
						|
      DeclEndLoc = ConstevalLoc;
 | 
						|
      break /*switch*/;
 | 
						|
    default:
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
addConstexprToLambdaDeclSpecifier(Parser &P, SourceLocation ConstexprLoc,
 | 
						|
                                  DeclSpec &DS) {
 | 
						|
  if (ConstexprLoc.isValid()) {
 | 
						|
    P.Diag(ConstexprLoc, !P.getLangOpts().CPlusPlus17
 | 
						|
                             ? diag::ext_constexpr_on_lambda_cxx17
 | 
						|
                             : diag::warn_cxx14_compat_constexpr_on_lambda);
 | 
						|
    const char *PrevSpec = nullptr;
 | 
						|
    unsigned DiagID = 0;
 | 
						|
    DS.SetConstexprSpec(CSK_constexpr, ConstexprLoc, PrevSpec, DiagID);
 | 
						|
    assert(PrevSpec == nullptr && DiagID == 0 &&
 | 
						|
           "Constexpr cannot have been set previously!");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void addConstevalToLambdaDeclSpecifier(Parser &P,
 | 
						|
                                              SourceLocation ConstevalLoc,
 | 
						|
                                              DeclSpec &DS) {
 | 
						|
  if (ConstevalLoc.isValid()) {
 | 
						|
    P.Diag(ConstevalLoc, diag::warn_cxx20_compat_consteval);
 | 
						|
    const char *PrevSpec = nullptr;
 | 
						|
    unsigned DiagID = 0;
 | 
						|
    DS.SetConstexprSpec(CSK_consteval, ConstevalLoc, PrevSpec, DiagID);
 | 
						|
    if (DiagID != 0)
 | 
						|
      P.Diag(ConstevalLoc, DiagID) << PrevSpec;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda
 | 
						|
/// expression.
 | 
						|
ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
 | 
						|
                     LambdaIntroducer &Intro) {
 | 
						|
  SourceLocation LambdaBeginLoc = Intro.Range.getBegin();
 | 
						|
  Diag(LambdaBeginLoc, diag::warn_cxx98_compat_lambda);
 | 
						|
 | 
						|
  PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc,
 | 
						|
                                "lambda expression parsing");
 | 
						|
 | 
						|
 | 
						|
 | 
						|
  // FIXME: Call into Actions to add any init-capture declarations to the
 | 
						|
  // scope while parsing the lambda-declarator and compound-statement.
 | 
						|
 | 
						|
  // Parse lambda-declarator[opt].
 | 
						|
  DeclSpec DS(AttrFactory);
 | 
						|
  Declarator D(DS, DeclaratorContext::LambdaExprContext);
 | 
						|
  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
 | 
						|
  Actions.PushLambdaScope();
 | 
						|
 | 
						|
  ParsedAttributes Attr(AttrFactory);
 | 
						|
  SourceLocation DeclLoc = Tok.getLocation();
 | 
						|
  if (getLangOpts().CUDA) {
 | 
						|
    // In CUDA code, GNU attributes are allowed to appear immediately after the
 | 
						|
    // "[...]", even if there is no "(...)" before the lambda body.
 | 
						|
    MaybeParseGNUAttributes(D);
 | 
						|
  }
 | 
						|
 | 
						|
  // Helper to emit a warning if we see a CUDA host/device/global attribute
 | 
						|
  // after '(...)'. nvcc doesn't accept this.
 | 
						|
  auto WarnIfHasCUDATargetAttr = [&] {
 | 
						|
    if (getLangOpts().CUDA)
 | 
						|
      for (const ParsedAttr &A : Attr)
 | 
						|
        if (A.getKind() == ParsedAttr::AT_CUDADevice ||
 | 
						|
            A.getKind() == ParsedAttr::AT_CUDAHost ||
 | 
						|
            A.getKind() == ParsedAttr::AT_CUDAGlobal)
 | 
						|
          Diag(A.getLoc(), diag::warn_cuda_attr_lambda_position)
 | 
						|
              << A.getAttrName()->getName();
 | 
						|
  };
 | 
						|
 | 
						|
  // FIXME: Consider allowing this as an extension for GCC compatibiblity.
 | 
						|
  const bool HasExplicitTemplateParams = Tok.is(tok::less);
 | 
						|
  ParseScope TemplateParamScope(this, Scope::TemplateParamScope,
 | 
						|
                                /*EnteredScope=*/HasExplicitTemplateParams);
 | 
						|
  if (HasExplicitTemplateParams) {
 | 
						|
    Diag(Tok, getLangOpts().CPlusPlus2a
 | 
						|
                  ? diag::warn_cxx17_compat_lambda_template_parameter_list
 | 
						|
                  : diag::ext_lambda_template_parameter_list);
 | 
						|
 | 
						|
    SmallVector<NamedDecl*, 4> TemplateParams;
 | 
						|
    SourceLocation LAngleLoc, RAngleLoc;
 | 
						|
    if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
 | 
						|
                                TemplateParams, LAngleLoc, RAngleLoc)) {
 | 
						|
      Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
 | 
						|
      return ExprError();
 | 
						|
    }
 | 
						|
 | 
						|
    if (TemplateParams.empty()) {
 | 
						|
      Diag(RAngleLoc,
 | 
						|
           diag::err_lambda_template_parameter_list_empty);
 | 
						|
    } else {
 | 
						|
      Actions.ActOnLambdaExplicitTemplateParameterList(
 | 
						|
          LAngleLoc, TemplateParams, RAngleLoc);
 | 
						|
      ++CurTemplateDepthTracker;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  TypeResult TrailingReturnType;
 | 
						|
  if (Tok.is(tok::l_paren)) {
 | 
						|
    ParseScope PrototypeScope(this,
 | 
						|
                              Scope::FunctionPrototypeScope |
 | 
						|
                              Scope::FunctionDeclarationScope |
 | 
						|
                              Scope::DeclScope);
 | 
						|
 | 
						|
    BalancedDelimiterTracker T(*this, tok::l_paren);
 | 
						|
    T.consumeOpen();
 | 
						|
    SourceLocation LParenLoc = T.getOpenLocation();
 | 
						|
 | 
						|
    // Parse parameter-declaration-clause.
 | 
						|
    SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
 | 
						|
    SourceLocation EllipsisLoc;
 | 
						|
 | 
						|
    if (Tok.isNot(tok::r_paren)) {
 | 
						|
      Actions.RecordParsingTemplateParameterDepth(
 | 
						|
          CurTemplateDepthTracker.getOriginalDepth());
 | 
						|
 | 
						|
      ParseParameterDeclarationClause(D.getContext(), Attr, ParamInfo,
 | 
						|
                                      EllipsisLoc);
 | 
						|
      // For a generic lambda, each 'auto' within the parameter declaration
 | 
						|
      // clause creates a template type parameter, so increment the depth.
 | 
						|
      // If we've parsed any explicit template parameters, then the depth will
 | 
						|
      // have already been incremented. So we make sure that at most a single
 | 
						|
      // depth level is added.
 | 
						|
      if (Actions.getCurGenericLambda())
 | 
						|
        CurTemplateDepthTracker.setAddedDepth(1);
 | 
						|
    }
 | 
						|
 | 
						|
    T.consumeClose();
 | 
						|
    SourceLocation RParenLoc = T.getCloseLocation();
 | 
						|
    SourceLocation DeclEndLoc = RParenLoc;
 | 
						|
 | 
						|
    // GNU-style attributes must be parsed before the mutable specifier to be
 | 
						|
    // compatible with GCC.
 | 
						|
    MaybeParseGNUAttributes(Attr, &DeclEndLoc);
 | 
						|
 | 
						|
    // MSVC-style attributes must be parsed before the mutable specifier to be
 | 
						|
    // compatible with MSVC.
 | 
						|
    MaybeParseMicrosoftDeclSpecs(Attr, &DeclEndLoc);
 | 
						|
 | 
						|
    // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update the
 | 
						|
    // DeclEndLoc.
 | 
						|
    SourceLocation MutableLoc;
 | 
						|
    SourceLocation ConstexprLoc;
 | 
						|
    SourceLocation ConstevalLoc;
 | 
						|
    tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc,
 | 
						|
                                   ConstevalLoc, DeclEndLoc);
 | 
						|
 | 
						|
    addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
 | 
						|
    addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
 | 
						|
    // Parse exception-specification[opt].
 | 
						|
    ExceptionSpecificationType ESpecType = EST_None;
 | 
						|
    SourceRange ESpecRange;
 | 
						|
    SmallVector<ParsedType, 2> DynamicExceptions;
 | 
						|
    SmallVector<SourceRange, 2> DynamicExceptionRanges;
 | 
						|
    ExprResult NoexceptExpr;
 | 
						|
    CachedTokens *ExceptionSpecTokens;
 | 
						|
    ESpecType = tryParseExceptionSpecification(/*Delayed=*/false,
 | 
						|
                                               ESpecRange,
 | 
						|
                                               DynamicExceptions,
 | 
						|
                                               DynamicExceptionRanges,
 | 
						|
                                               NoexceptExpr,
 | 
						|
                                               ExceptionSpecTokens);
 | 
						|
 | 
						|
    if (ESpecType != EST_None)
 | 
						|
      DeclEndLoc = ESpecRange.getEnd();
 | 
						|
 | 
						|
    // Parse attribute-specifier[opt].
 | 
						|
    MaybeParseCXX11Attributes(Attr, &DeclEndLoc);
 | 
						|
 | 
						|
    // Parse OpenCL addr space attribute.
 | 
						|
    if (Tok.isOneOf(tok::kw___private, tok::kw___global, tok::kw___local,
 | 
						|
                    tok::kw___constant, tok::kw___generic)) {
 | 
						|
      ParseOpenCLQualifiers(DS.getAttributes());
 | 
						|
      ConsumeToken();
 | 
						|
    }
 | 
						|
 | 
						|
    SourceLocation FunLocalRangeEnd = DeclEndLoc;
 | 
						|
 | 
						|
    // Parse trailing-return-type[opt].
 | 
						|
    if (Tok.is(tok::arrow)) {
 | 
						|
      FunLocalRangeEnd = Tok.getLocation();
 | 
						|
      SourceRange Range;
 | 
						|
      TrailingReturnType =
 | 
						|
          ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit*/ false);
 | 
						|
      if (Range.getEnd().isValid())
 | 
						|
        DeclEndLoc = Range.getEnd();
 | 
						|
    }
 | 
						|
 | 
						|
    SourceLocation NoLoc;
 | 
						|
    D.AddTypeInfo(DeclaratorChunk::getFunction(
 | 
						|
                      /*HasProto=*/true,
 | 
						|
                      /*IsAmbiguous=*/false, LParenLoc, ParamInfo.data(),
 | 
						|
                      ParamInfo.size(), EllipsisLoc, RParenLoc,
 | 
						|
                      /*RefQualifierIsLvalueRef=*/true,
 | 
						|
                      /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType,
 | 
						|
                      ESpecRange, DynamicExceptions.data(),
 | 
						|
                      DynamicExceptionRanges.data(), DynamicExceptions.size(),
 | 
						|
                      NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr,
 | 
						|
                      /*ExceptionSpecTokens*/ nullptr,
 | 
						|
                      /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D,
 | 
						|
                      TrailingReturnType, &DS),
 | 
						|
                  std::move(Attr), DeclEndLoc);
 | 
						|
 | 
						|
    // Parse requires-clause[opt].
 | 
						|
    if (Tok.is(tok::kw_requires))
 | 
						|
      ParseTrailingRequiresClause(D);
 | 
						|
 | 
						|
    PrototypeScope.Exit();
 | 
						|
 | 
						|
    WarnIfHasCUDATargetAttr();
 | 
						|
  } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute,
 | 
						|
                         tok::kw_constexpr, tok::kw_consteval,
 | 
						|
                         tok::kw___private, tok::kw___global, tok::kw___local,
 | 
						|
                         tok::kw___constant, tok::kw___generic,
 | 
						|
                         tok::kw_requires) ||
 | 
						|
             (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
 | 
						|
    // It's common to forget that one needs '()' before 'mutable', an attribute
 | 
						|
    // specifier, the result type, or the requires clause. Deal with this.
 | 
						|
    unsigned TokKind = 0;
 | 
						|
    switch (Tok.getKind()) {
 | 
						|
    case tok::kw_mutable: TokKind = 0; break;
 | 
						|
    case tok::arrow: TokKind = 1; break;
 | 
						|
    case tok::kw___attribute:
 | 
						|
    case tok::kw___private:
 | 
						|
    case tok::kw___global:
 | 
						|
    case tok::kw___local:
 | 
						|
    case tok::kw___constant:
 | 
						|
    case tok::kw___generic:
 | 
						|
    case tok::l_square: TokKind = 2; break;
 | 
						|
    case tok::kw_constexpr: TokKind = 3; break;
 | 
						|
    case tok::kw_consteval: TokKind = 4; break;
 | 
						|
    case tok::kw_requires: TokKind = 5; break;
 | 
						|
    default: llvm_unreachable("Unknown token kind");
 | 
						|
    }
 | 
						|
 | 
						|
    Diag(Tok, diag::err_lambda_missing_parens)
 | 
						|
      << TokKind
 | 
						|
      << FixItHint::CreateInsertion(Tok.getLocation(), "() ");
 | 
						|
    SourceLocation DeclEndLoc = DeclLoc;
 | 
						|
 | 
						|
    // GNU-style attributes must be parsed before the mutable specifier to be
 | 
						|
    // compatible with GCC.
 | 
						|
    MaybeParseGNUAttributes(Attr, &DeclEndLoc);
 | 
						|
 | 
						|
    // Parse 'mutable', if it's there.
 | 
						|
    SourceLocation MutableLoc;
 | 
						|
    if (Tok.is(tok::kw_mutable)) {
 | 
						|
      MutableLoc = ConsumeToken();
 | 
						|
      DeclEndLoc = MutableLoc;
 | 
						|
    }
 | 
						|
 | 
						|
    // Parse attribute-specifier[opt].
 | 
						|
    MaybeParseCXX11Attributes(Attr, &DeclEndLoc);
 | 
						|
 | 
						|
    // Parse the return type, if there is one.
 | 
						|
    if (Tok.is(tok::arrow)) {
 | 
						|
      SourceRange Range;
 | 
						|
      TrailingReturnType =
 | 
						|
          ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit*/ false);
 | 
						|
      if (Range.getEnd().isValid())
 | 
						|
        DeclEndLoc = Range.getEnd();
 | 
						|
    }
 | 
						|
 | 
						|
    SourceLocation NoLoc;
 | 
						|
    D.AddTypeInfo(DeclaratorChunk::getFunction(
 | 
						|
                      /*HasProto=*/true,
 | 
						|
                      /*IsAmbiguous=*/false,
 | 
						|
                      /*LParenLoc=*/NoLoc,
 | 
						|
                      /*Params=*/nullptr,
 | 
						|
                      /*NumParams=*/0,
 | 
						|
                      /*EllipsisLoc=*/NoLoc,
 | 
						|
                      /*RParenLoc=*/NoLoc,
 | 
						|
                      /*RefQualifierIsLvalueRef=*/true,
 | 
						|
                      /*RefQualifierLoc=*/NoLoc, MutableLoc, EST_None,
 | 
						|
                      /*ESpecRange=*/SourceRange(),
 | 
						|
                      /*Exceptions=*/nullptr,
 | 
						|
                      /*ExceptionRanges=*/nullptr,
 | 
						|
                      /*NumExceptions=*/0,
 | 
						|
                      /*NoexceptExpr=*/nullptr,
 | 
						|
                      /*ExceptionSpecTokens=*/nullptr,
 | 
						|
                      /*DeclsInPrototype=*/None, DeclLoc, DeclEndLoc, D,
 | 
						|
                      TrailingReturnType),
 | 
						|
                  std::move(Attr), DeclEndLoc);
 | 
						|
 | 
						|
    // Parse the requires-clause, if present.
 | 
						|
    if (Tok.is(tok::kw_requires))
 | 
						|
      ParseTrailingRequiresClause(D);
 | 
						|
 | 
						|
    WarnIfHasCUDATargetAttr();
 | 
						|
  }
 | 
						|
 | 
						|
  // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
 | 
						|
  // it.
 | 
						|
  unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope |
 | 
						|
                        Scope::CompoundStmtScope;
 | 
						|
  ParseScope BodyScope(this, ScopeFlags);
 | 
						|
 | 
						|
  Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope());
 | 
						|
 | 
						|
  // Parse compound-statement.
 | 
						|
  if (!Tok.is(tok::l_brace)) {
 | 
						|
    Diag(Tok, diag::err_expected_lambda_body);
 | 
						|
    Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
 | 
						|
    return ExprError();
 | 
						|
  }
 | 
						|
 | 
						|
  StmtResult Stmt(ParseCompoundStatementBody());
 | 
						|
  BodyScope.Exit();
 | 
						|
  TemplateParamScope.Exit();
 | 
						|
 | 
						|
  if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid())
 | 
						|
    return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope());
 | 
						|
 | 
						|
  Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
 | 
						|
  return ExprError();
 | 
						|
}
 | 
						|
 | 
						|
/// ParseCXXCasts - This handles the various ways to cast expressions to another
 | 
						|
/// type.
 | 
						|
///
 | 
						|
///       postfix-expression: [C++ 5.2p1]
 | 
						|
///         'dynamic_cast' '<' type-name '>' '(' expression ')'
 | 
						|
///         'static_cast' '<' type-name '>' '(' expression ')'
 | 
						|
///         'reinterpret_cast' '<' type-name '>' '(' expression ')'
 | 
						|
///         'const_cast' '<' type-name '>' '(' expression ')'
 | 
						|
///
 | 
						|
ExprResult Parser::ParseCXXCasts() {
 | 
						|
  tok::TokenKind Kind = Tok.getKind();
 | 
						|
  const char *CastName = nullptr; // For error messages
 | 
						|
 | 
						|
  switch (Kind) {
 | 
						|
  default: llvm_unreachable("Unknown C++ cast!");
 | 
						|
  case tok::kw_const_cast:       CastName = "const_cast";       break;
 | 
						|
  case tok::kw_dynamic_cast:     CastName = "dynamic_cast";     break;
 | 
						|
  case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break;
 | 
						|
  case tok::kw_static_cast:      CastName = "static_cast";      break;
 | 
						|
  }
 | 
						|
 | 
						|
  SourceLocation OpLoc = ConsumeToken();
 | 
						|
  SourceLocation LAngleBracketLoc = Tok.getLocation();
 | 
						|
 | 
						|
  // Check for "<::" which is parsed as "[:".  If found, fix token stream,
 | 
						|
  // diagnose error, suggest fix, and recover parsing.
 | 
						|
  if (Tok.is(tok::l_square) && Tok.getLength() == 2) {
 | 
						|
    Token Next = NextToken();
 | 
						|
    if (Next.is(tok::colon) && areTokensAdjacent(Tok, Next))
 | 
						|
      FixDigraph(*this, PP, Tok, Next, Kind, /*AtDigraph*/true);
 | 
						|
  }
 | 
						|
 | 
						|
  if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
 | 
						|
    return ExprError();
 | 
						|
 | 
						|
  // Parse the common declaration-specifiers piece.
 | 
						|
  DeclSpec DS(AttrFactory);
 | 
						|
  ParseSpecifierQualifierList(DS);
 | 
						|
 | 
						|
  // Parse the abstract-declarator, if present.
 | 
						|
  Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext);
 | 
						|
  ParseDeclarator(DeclaratorInfo);
 | 
						|
 | 
						|
  SourceLocation RAngleBracketLoc = Tok.getLocation();
 | 
						|
 | 
						|
  if (ExpectAndConsume(tok::greater))
 | 
						|
    return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << tok::less);
 | 
						|
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren);
 | 
						|
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after, CastName))
 | 
						|
    return ExprError();
 | 
						|
 | 
						|
  ExprResult Result = ParseExpression();
 | 
						|
 | 
						|
  // Match the ')'.
 | 
						|
  T.consumeClose();
 | 
						|
 | 
						|
  if (!Result.isInvalid() && !DeclaratorInfo.isInvalidType())
 | 
						|
    Result = Actions.ActOnCXXNamedCast(OpLoc, Kind,
 | 
						|
                                       LAngleBracketLoc, DeclaratorInfo,
 | 
						|
                                       RAngleBracketLoc,
 | 
						|
                                       T.getOpenLocation(), Result.get(),
 | 
						|
                                       T.getCloseLocation());
 | 
						|
 | 
						|
  return Result;
 | 
						|
}
 | 
						|
 | 
						|
/// ParseCXXTypeid - This handles the C++ typeid expression.
 | 
						|
///
 | 
						|
///       postfix-expression: [C++ 5.2p1]
 | 
						|
///         'typeid' '(' expression ')'
 | 
						|
///         'typeid' '(' type-id ')'
 | 
						|
///
 | 
						|
ExprResult Parser::ParseCXXTypeid() {
 | 
						|
  assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!");
 | 
						|
 | 
						|
  SourceLocation OpLoc = ConsumeToken();
 | 
						|
  SourceLocation LParenLoc, RParenLoc;
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren);
 | 
						|
 | 
						|
  // typeid expressions are always parenthesized.
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after, "typeid"))
 | 
						|
    return ExprError();
 | 
						|
  LParenLoc = T.getOpenLocation();
 | 
						|
 | 
						|
  ExprResult Result;
 | 
						|
 | 
						|
  // C++0x [expr.typeid]p3:
 | 
						|
  //   When typeid is applied to an expression other than an lvalue of a
 | 
						|
  //   polymorphic class type [...] The expression is an unevaluated
 | 
						|
  //   operand (Clause 5).
 | 
						|
  //
 | 
						|
  // Note that we can't tell whether the expression is an lvalue of a
 | 
						|
  // polymorphic class type until after we've parsed the expression; we
 | 
						|
  // speculatively assume the subexpression is unevaluated, and fix it up
 | 
						|
  // later.
 | 
						|
  //
 | 
						|
  // We enter the unevaluated context before trying to determine whether we
 | 
						|
  // have a type-id, because the tentative parse logic will try to resolve
 | 
						|
  // names, and must treat them as unevaluated.
 | 
						|
  EnterExpressionEvaluationContext Unevaluated(
 | 
						|
      Actions, Sema::ExpressionEvaluationContext::Unevaluated,
 | 
						|
      Sema::ReuseLambdaContextDecl);
 | 
						|
 | 
						|
  if (isTypeIdInParens()) {
 | 
						|
    TypeResult Ty = ParseTypeName();
 | 
						|
 | 
						|
    // Match the ')'.
 | 
						|
    T.consumeClose();
 | 
						|
    RParenLoc = T.getCloseLocation();
 | 
						|
    if (Ty.isInvalid() || RParenLoc.isInvalid())
 | 
						|
      return ExprError();
 | 
						|
 | 
						|
    Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true,
 | 
						|
                                    Ty.get().getAsOpaquePtr(), RParenLoc);
 | 
						|
  } else {
 | 
						|
    Result = ParseExpression();
 | 
						|
 | 
						|
    // Match the ')'.
 | 
						|
    if (Result.isInvalid())
 | 
						|
      SkipUntil(tok::r_paren, StopAtSemi);
 | 
						|
    else {
 | 
						|
      T.consumeClose();
 | 
						|
      RParenLoc = T.getCloseLocation();
 | 
						|
      if (RParenLoc.isInvalid())
 | 
						|
        return ExprError();
 | 
						|
 | 
						|
      Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false,
 | 
						|
                                      Result.get(), RParenLoc);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Result;
 | 
						|
}
 | 
						|
 | 
						|
/// ParseCXXUuidof - This handles the Microsoft C++ __uuidof expression.
 | 
						|
///
 | 
						|
///         '__uuidof' '(' expression ')'
 | 
						|
///         '__uuidof' '(' type-id ')'
 | 
						|
///
 | 
						|
ExprResult Parser::ParseCXXUuidof() {
 | 
						|
  assert(Tok.is(tok::kw___uuidof) && "Not '__uuidof'!");
 | 
						|
 | 
						|
  SourceLocation OpLoc = ConsumeToken();
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren);
 | 
						|
 | 
						|
  // __uuidof expressions are always parenthesized.
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after, "__uuidof"))
 | 
						|
    return ExprError();
 | 
						|
 | 
						|
  ExprResult Result;
 | 
						|
 | 
						|
  if (isTypeIdInParens()) {
 | 
						|
    TypeResult Ty = ParseTypeName();
 | 
						|
 | 
						|
    // Match the ')'.
 | 
						|
    T.consumeClose();
 | 
						|
 | 
						|
    if (Ty.isInvalid())
 | 
						|
      return ExprError();
 | 
						|
 | 
						|
    Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(), /*isType=*/true,
 | 
						|
                                    Ty.get().getAsOpaquePtr(),
 | 
						|
                                    T.getCloseLocation());
 | 
						|
  } else {
 | 
						|
    EnterExpressionEvaluationContext Unevaluated(
 | 
						|
        Actions, Sema::ExpressionEvaluationContext::Unevaluated);
 | 
						|
    Result = ParseExpression();
 | 
						|
 | 
						|
    // Match the ')'.
 | 
						|
    if (Result.isInvalid())
 | 
						|
      SkipUntil(tok::r_paren, StopAtSemi);
 | 
						|
    else {
 | 
						|
      T.consumeClose();
 | 
						|
 | 
						|
      Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(),
 | 
						|
                                      /*isType=*/false,
 | 
						|
                                      Result.get(), T.getCloseLocation());
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Result;
 | 
						|
}
 | 
						|
 | 
						|
/// Parse a C++ pseudo-destructor expression after the base,
 | 
						|
/// . or -> operator, and nested-name-specifier have already been
 | 
						|
/// parsed. We're handling this fragment of the grammar:
 | 
						|
///
 | 
						|
///       postfix-expression: [C++2a expr.post]
 | 
						|
///         postfix-expression . template[opt] id-expression
 | 
						|
///         postfix-expression -> template[opt] id-expression
 | 
						|
///
 | 
						|
///       id-expression:
 | 
						|
///         qualified-id
 | 
						|
///         unqualified-id
 | 
						|
///
 | 
						|
///       qualified-id:
 | 
						|
///         nested-name-specifier template[opt] unqualified-id
 | 
						|
///
 | 
						|
///       nested-name-specifier:
 | 
						|
///         type-name ::
 | 
						|
///         decltype-specifier ::    FIXME: not implemented, but probably only
 | 
						|
///                                         allowed in C++ grammar by accident
 | 
						|
///         nested-name-specifier identifier ::
 | 
						|
///         nested-name-specifier template[opt] simple-template-id ::
 | 
						|
///         [...]
 | 
						|
///
 | 
						|
///       unqualified-id:
 | 
						|
///         ~ type-name
 | 
						|
///         ~ decltype-specifier
 | 
						|
///         [...]
 | 
						|
///
 | 
						|
/// ... where the all but the last component of the nested-name-specifier
 | 
						|
/// has already been parsed, and the base expression is not of a non-dependent
 | 
						|
/// class type.
 | 
						|
ExprResult
 | 
						|
Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
 | 
						|
                                 tok::TokenKind OpKind,
 | 
						|
                                 CXXScopeSpec &SS,
 | 
						|
                                 ParsedType ObjectType) {
 | 
						|
  // If the last component of the (optional) nested-name-specifier is
 | 
						|
  // template[opt] simple-template-id, it has already been annotated.
 | 
						|
  UnqualifiedId FirstTypeName;
 | 
						|
  SourceLocation CCLoc;
 | 
						|
  if (Tok.is(tok::identifier)) {
 | 
						|
    FirstTypeName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
 | 
						|
    ConsumeToken();
 | 
						|
    assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
 | 
						|
    CCLoc = ConsumeToken();
 | 
						|
  } else if (Tok.is(tok::annot_template_id)) {
 | 
						|
    FirstTypeName.setTemplateId(
 | 
						|
                              (TemplateIdAnnotation *)Tok.getAnnotationValue());
 | 
						|
    ConsumeAnnotationToken();
 | 
						|
    assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
 | 
						|
    CCLoc = ConsumeToken();
 | 
						|
  } else {
 | 
						|
    assert(SS.isEmpty() && "missing last component of nested name specifier");
 | 
						|
    FirstTypeName.setIdentifier(nullptr, SourceLocation());
 | 
						|
  }
 | 
						|
 | 
						|
  // Parse the tilde.
 | 
						|
  assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail");
 | 
						|
  SourceLocation TildeLoc = ConsumeToken();
 | 
						|
 | 
						|
  if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid()) {
 | 
						|
    DeclSpec DS(AttrFactory);
 | 
						|
    ParseDecltypeSpecifier(DS);
 | 
						|
    if (DS.getTypeSpecType() == TST_error)
 | 
						|
      return ExprError();
 | 
						|
    return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind,
 | 
						|
                                             TildeLoc, DS);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!Tok.is(tok::identifier)) {
 | 
						|
    Diag(Tok, diag::err_destructor_tilde_identifier);
 | 
						|
    return ExprError();
 | 
						|
  }
 | 
						|
 | 
						|
  // Parse the second type.
 | 
						|
  UnqualifiedId SecondTypeName;
 | 
						|
  IdentifierInfo *Name = Tok.getIdentifierInfo();
 | 
						|
  SourceLocation NameLoc = ConsumeToken();
 | 
						|
  SecondTypeName.setIdentifier(Name, NameLoc);
 | 
						|
 | 
						|
  // If there is a '<', the second type name is a template-id. Parse
 | 
						|
  // it as such.
 | 
						|
  if (Tok.is(tok::less) &&
 | 
						|
      ParseUnqualifiedIdTemplateId(SS, SourceLocation(),
 | 
						|
                                   Name, NameLoc,
 | 
						|
                                   false, ObjectType, SecondTypeName,
 | 
						|
                                   /*AssumeTemplateId=*/true))
 | 
						|
    return ExprError();
 | 
						|
 | 
						|
  return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind,
 | 
						|
                                           SS, FirstTypeName, CCLoc, TildeLoc,
 | 
						|
                                           SecondTypeName);
 | 
						|
}
 | 
						|
 | 
						|
/// ParseCXXBoolLiteral - This handles the C++ Boolean literals.
 | 
						|
///
 | 
						|
///       boolean-literal: [C++ 2.13.5]
 | 
						|
///         'true'
 | 
						|
///         'false'
 | 
						|
ExprResult Parser::ParseCXXBoolLiteral() {
 | 
						|
  tok::TokenKind Kind = Tok.getKind();
 | 
						|
  return Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind);
 | 
						|
}
 | 
						|
 | 
						|
/// ParseThrowExpression - This handles the C++ throw expression.
 | 
						|
///
 | 
						|
///       throw-expression: [C++ 15]
 | 
						|
///         'throw' assignment-expression[opt]
 | 
						|
ExprResult Parser::ParseThrowExpression() {
 | 
						|
  assert(Tok.is(tok::kw_throw) && "Not throw!");
 | 
						|
  SourceLocation ThrowLoc = ConsumeToken();           // Eat the throw token.
 | 
						|
 | 
						|
  // If the current token isn't the start of an assignment-expression,
 | 
						|
  // then the expression is not present.  This handles things like:
 | 
						|
  //   "C ? throw : (void)42", which is crazy but legal.
 | 
						|
  switch (Tok.getKind()) {  // FIXME: move this predicate somewhere common.
 | 
						|
  case tok::semi:
 | 
						|
  case tok::r_paren:
 | 
						|
  case tok::r_square:
 | 
						|
  case tok::r_brace:
 | 
						|
  case tok::colon:
 | 
						|
  case tok::comma:
 | 
						|
    return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, nullptr);
 | 
						|
 | 
						|
  default:
 | 
						|
    ExprResult Expr(ParseAssignmentExpression());
 | 
						|
    if (Expr.isInvalid()) return Expr;
 | 
						|
    return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, Expr.get());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/// Parse the C++ Coroutines co_yield expression.
 | 
						|
///
 | 
						|
///       co_yield-expression:
 | 
						|
///         'co_yield' assignment-expression[opt]
 | 
						|
ExprResult Parser::ParseCoyieldExpression() {
 | 
						|
  assert(Tok.is(tok::kw_co_yield) && "Not co_yield!");
 | 
						|
 | 
						|
  SourceLocation Loc = ConsumeToken();
 | 
						|
  ExprResult Expr = Tok.is(tok::l_brace) ? ParseBraceInitializer()
 | 
						|
                                         : ParseAssignmentExpression();
 | 
						|
  if (!Expr.isInvalid())
 | 
						|
    Expr = Actions.ActOnCoyieldExpr(getCurScope(), Loc, Expr.get());
 | 
						|
  return Expr;
 | 
						|
}
 | 
						|
 | 
						|
/// ParseCXXThis - This handles the C++ 'this' pointer.
 | 
						|
///
 | 
						|
/// C++ 9.3.2: In the body of a non-static member function, the keyword this is
 | 
						|
/// a non-lvalue expression whose value is the address of the object for which
 | 
						|
/// the function is called.
 | 
						|
ExprResult Parser::ParseCXXThis() {
 | 
						|
  assert(Tok.is(tok::kw_this) && "Not 'this'!");
 | 
						|
  SourceLocation ThisLoc = ConsumeToken();
 | 
						|
  return Actions.ActOnCXXThis(ThisLoc);
 | 
						|
}
 | 
						|
 | 
						|
/// ParseCXXTypeConstructExpression - Parse construction of a specified type.
 | 
						|
/// Can be interpreted either as function-style casting ("int(x)")
 | 
						|
/// or class type construction ("ClassType(x,y,z)")
 | 
						|
/// or creation of a value-initialized type ("int()").
 | 
						|
/// See [C++ 5.2.3].
 | 
						|
///
 | 
						|
///       postfix-expression: [C++ 5.2p1]
 | 
						|
///         simple-type-specifier '(' expression-list[opt] ')'
 | 
						|
/// [C++0x] simple-type-specifier braced-init-list
 | 
						|
///         typename-specifier '(' expression-list[opt] ')'
 | 
						|
/// [C++0x] typename-specifier braced-init-list
 | 
						|
///
 | 
						|
/// In C++1z onwards, the type specifier can also be a template-name.
 | 
						|
ExprResult
 | 
						|
Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
 | 
						|
  Declarator DeclaratorInfo(DS, DeclaratorContext::FunctionalCastContext);
 | 
						|
  ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get();
 | 
						|
 | 
						|
  assert((Tok.is(tok::l_paren) ||
 | 
						|
          (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)))
 | 
						|
         && "Expected '(' or '{'!");
 | 
						|
 | 
						|
  if (Tok.is(tok::l_brace)) {
 | 
						|
    PreferredType.enterTypeCast(Tok.getLocation(), TypeRep.get());
 | 
						|
    ExprResult Init = ParseBraceInitializer();
 | 
						|
    if (Init.isInvalid())
 | 
						|
      return Init;
 | 
						|
    Expr *InitList = Init.get();
 | 
						|
    return Actions.ActOnCXXTypeConstructExpr(
 | 
						|
        TypeRep, InitList->getBeginLoc(), MultiExprArg(&InitList, 1),
 | 
						|
        InitList->getEndLoc(), /*ListInitialization=*/true);
 | 
						|
  } else {
 | 
						|
    BalancedDelimiterTracker T(*this, tok::l_paren);
 | 
						|
    T.consumeOpen();
 | 
						|
 | 
						|
    PreferredType.enterTypeCast(Tok.getLocation(), TypeRep.get());
 | 
						|
 | 
						|
    ExprVector Exprs;
 | 
						|
    CommaLocsTy CommaLocs;
 | 
						|
 | 
						|
    auto RunSignatureHelp = [&]() {
 | 
						|
      QualType PreferredType;
 | 
						|
      if (TypeRep)
 | 
						|
        PreferredType = Actions.ProduceConstructorSignatureHelp(
 | 
						|
            getCurScope(), TypeRep.get()->getCanonicalTypeInternal(),
 | 
						|
            DS.getEndLoc(), Exprs, T.getOpenLocation());
 | 
						|
      CalledSignatureHelp = true;
 | 
						|
      return PreferredType;
 | 
						|
    };
 | 
						|
 | 
						|
    if (Tok.isNot(tok::r_paren)) {
 | 
						|
      if (ParseExpressionList(Exprs, CommaLocs, [&] {
 | 
						|
            PreferredType.enterFunctionArgument(Tok.getLocation(),
 | 
						|
                                                RunSignatureHelp);
 | 
						|
          })) {
 | 
						|
        if (PP.isCodeCompletionReached() && !CalledSignatureHelp)
 | 
						|
          RunSignatureHelp();
 | 
						|
        SkipUntil(tok::r_paren, StopAtSemi);
 | 
						|
        return ExprError();
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // Match the ')'.
 | 
						|
    T.consumeClose();
 | 
						|
 | 
						|
    // TypeRep could be null, if it references an invalid typedef.
 | 
						|
    if (!TypeRep)
 | 
						|
      return ExprError();
 | 
						|
 | 
						|
    assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
 | 
						|
           "Unexpected number of commas!");
 | 
						|
    return Actions.ActOnCXXTypeConstructExpr(TypeRep, T.getOpenLocation(),
 | 
						|
                                             Exprs, T.getCloseLocation(),
 | 
						|
                                             /*ListInitialization=*/false);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/// ParseCXXCondition - if/switch/while condition expression.
 | 
						|
///
 | 
						|
///       condition:
 | 
						|
///         expression
 | 
						|
///         type-specifier-seq declarator '=' assignment-expression
 | 
						|
/// [C++11] type-specifier-seq declarator '=' initializer-clause
 | 
						|
/// [C++11] type-specifier-seq declarator braced-init-list
 | 
						|
/// [Clang] type-specifier-seq ref-qualifier[opt] '[' identifier-list ']'
 | 
						|
///             brace-or-equal-initializer
 | 
						|
/// [GNU]   type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
 | 
						|
///             '=' assignment-expression
 | 
						|
///
 | 
						|
/// In C++1z, a condition may in some contexts be preceded by an
 | 
						|
/// optional init-statement. This function will parse that too.
 | 
						|
///
 | 
						|
/// \param InitStmt If non-null, an init-statement is permitted, and if present
 | 
						|
/// will be parsed and stored here.
 | 
						|
///
 | 
						|
/// \param Loc The location of the start of the statement that requires this
 | 
						|
/// condition, e.g., the "for" in a for loop.
 | 
						|
///
 | 
						|
/// \param FRI If non-null, a for range declaration is permitted, and if
 | 
						|
/// present will be parsed and stored here, and a null result will be returned.
 | 
						|
///
 | 
						|
/// \returns The parsed condition.
 | 
						|
Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
 | 
						|
                                                SourceLocation Loc,
 | 
						|
                                                Sema::ConditionKind CK,
 | 
						|
                                                ForRangeInfo *FRI) {
 | 
						|
  ParenBraceBracketBalancer BalancerRAIIObj(*this);
 | 
						|
  PreferredType.enterCondition(Actions, Tok.getLocation());
 | 
						|
 | 
						|
  if (Tok.is(tok::code_completion)) {
 | 
						|
    Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition);
 | 
						|
    cutOffParsing();
 | 
						|
    return Sema::ConditionError();
 | 
						|
  }
 | 
						|
 | 
						|
  ParsedAttributesWithRange attrs(AttrFactory);
 | 
						|
  MaybeParseCXX11Attributes(attrs);
 | 
						|
 | 
						|
  const auto WarnOnInit = [this, &CK] {
 | 
						|
    Diag(Tok.getLocation(), getLangOpts().CPlusPlus17
 | 
						|
                                ? diag::warn_cxx14_compat_init_statement
 | 
						|
                                : diag::ext_init_statement)
 | 
						|
        << (CK == Sema::ConditionKind::Switch);
 | 
						|
  };
 | 
						|
 | 
						|
  // Determine what kind of thing we have.
 | 
						|
  switch (isCXXConditionDeclarationOrInitStatement(InitStmt, FRI)) {
 | 
						|
  case ConditionOrInitStatement::Expression: {
 | 
						|
    ProhibitAttributes(attrs);
 | 
						|
 | 
						|
    // We can have an empty expression here.
 | 
						|
    //   if (; true);
 | 
						|
    if (InitStmt && Tok.is(tok::semi)) {
 | 
						|
      WarnOnInit();
 | 
						|
      SourceLocation SemiLoc = Tok.getLocation();
 | 
						|
      if (!Tok.hasLeadingEmptyMacro() && !SemiLoc.isMacroID()) {
 | 
						|
        Diag(SemiLoc, diag::warn_empty_init_statement)
 | 
						|
            << (CK == Sema::ConditionKind::Switch)
 | 
						|
            << FixItHint::CreateRemoval(SemiLoc);
 | 
						|
      }
 | 
						|
      ConsumeToken();
 | 
						|
      *InitStmt = Actions.ActOnNullStmt(SemiLoc);
 | 
						|
      return ParseCXXCondition(nullptr, Loc, CK);
 | 
						|
    }
 | 
						|
 | 
						|
    // Parse the expression.
 | 
						|
    ExprResult Expr = ParseExpression(); // expression
 | 
						|
    if (Expr.isInvalid())
 | 
						|
      return Sema::ConditionError();
 | 
						|
 | 
						|
    if (InitStmt && Tok.is(tok::semi)) {
 | 
						|
      WarnOnInit();
 | 
						|
      *InitStmt = Actions.ActOnExprStmt(Expr.get());
 | 
						|
      ConsumeToken();
 | 
						|
      return ParseCXXCondition(nullptr, Loc, CK);
 | 
						|
    }
 | 
						|
 | 
						|
    return Actions.ActOnCondition(getCurScope(), Loc, Expr.get(), CK);
 | 
						|
  }
 | 
						|
 | 
						|
  case ConditionOrInitStatement::InitStmtDecl: {
 | 
						|
    WarnOnInit();
 | 
						|
    SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
 | 
						|
    DeclGroupPtrTy DG =
 | 
						|
        ParseSimpleDeclaration(DeclaratorContext::InitStmtContext, DeclEnd,
 | 
						|
                               attrs, /*RequireSemi=*/true);
 | 
						|
    *InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd);
 | 
						|
    return ParseCXXCondition(nullptr, Loc, CK);
 | 
						|
  }
 | 
						|
 | 
						|
  case ConditionOrInitStatement::ForRangeDecl: {
 | 
						|
    assert(FRI && "should not parse a for range declaration here");
 | 
						|
    SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
 | 
						|
    DeclGroupPtrTy DG = ParseSimpleDeclaration(
 | 
						|
        DeclaratorContext::ForContext, DeclEnd, attrs, false, FRI);
 | 
						|
    FRI->LoopVar = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
 | 
						|
    return Sema::ConditionResult();
 | 
						|
  }
 | 
						|
 | 
						|
  case ConditionOrInitStatement::ConditionDecl:
 | 
						|
  case ConditionOrInitStatement::Error:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  // type-specifier-seq
 | 
						|
  DeclSpec DS(AttrFactory);
 | 
						|
  DS.takeAttributesFrom(attrs);
 | 
						|
  ParseSpecifierQualifierList(DS, AS_none, DeclSpecContext::DSC_condition);
 | 
						|
 | 
						|
  // declarator
 | 
						|
  Declarator DeclaratorInfo(DS, DeclaratorContext::ConditionContext);
 | 
						|
  ParseDeclarator(DeclaratorInfo);
 | 
						|
 | 
						|
  // simple-asm-expr[opt]
 | 
						|
  if (Tok.is(tok::kw_asm)) {
 | 
						|
    SourceLocation Loc;
 | 
						|
    ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc));
 | 
						|
    if (AsmLabel.isInvalid()) {
 | 
						|
      SkipUntil(tok::semi, StopAtSemi);
 | 
						|
      return Sema::ConditionError();
 | 
						|
    }
 | 
						|
    DeclaratorInfo.setAsmLabel(AsmLabel.get());
 | 
						|
    DeclaratorInfo.SetRangeEnd(Loc);
 | 
						|
  }
 | 
						|
 | 
						|
  // If attributes are present, parse them.
 | 
						|
  MaybeParseGNUAttributes(DeclaratorInfo);
 | 
						|
 | 
						|
  // Type-check the declaration itself.
 | 
						|
  DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(getCurScope(),
 | 
						|
                                                        DeclaratorInfo);
 | 
						|
  if (Dcl.isInvalid())
 | 
						|
    return Sema::ConditionError();
 | 
						|
  Decl *DeclOut = Dcl.get();
 | 
						|
 | 
						|
  // '=' assignment-expression
 | 
						|
  // If a '==' or '+=' is found, suggest a fixit to '='.
 | 
						|
  bool CopyInitialization = isTokenEqualOrEqualTypo();
 | 
						|
  if (CopyInitialization)
 | 
						|
    ConsumeToken();
 | 
						|
 | 
						|
  ExprResult InitExpr = ExprError();
 | 
						|
  if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
 | 
						|
    Diag(Tok.getLocation(),
 | 
						|
         diag::warn_cxx98_compat_generalized_initializer_lists);
 | 
						|
    InitExpr = ParseBraceInitializer();
 | 
						|
  } else if (CopyInitialization) {
 | 
						|
    PreferredType.enterVariableInit(Tok.getLocation(), DeclOut);
 | 
						|
    InitExpr = ParseAssignmentExpression();
 | 
						|
  } else if (Tok.is(tok::l_paren)) {
 | 
						|
    // This was probably an attempt to initialize the variable.
 | 
						|
    SourceLocation LParen = ConsumeParen(), RParen = LParen;
 | 
						|
    if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch))
 | 
						|
      RParen = ConsumeParen();
 | 
						|
    Diag(DeclOut->getLocation(),
 | 
						|
         diag::err_expected_init_in_condition_lparen)
 | 
						|
      << SourceRange(LParen, RParen);
 | 
						|
  } else {
 | 
						|
    Diag(DeclOut->getLocation(), diag::err_expected_init_in_condition);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!InitExpr.isInvalid())
 | 
						|
    Actions.AddInitializerToDecl(DeclOut, InitExpr.get(), !CopyInitialization);
 | 
						|
  else
 | 
						|
    Actions.ActOnInitializerError(DeclOut);
 | 
						|
 | 
						|
  Actions.FinalizeDeclaration(DeclOut);
 | 
						|
  return Actions.ActOnConditionVariable(DeclOut, Loc, CK);
 | 
						|
}
 | 
						|
 | 
						|
/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
 | 
						|
/// This should only be called when the current token is known to be part of
 | 
						|
/// simple-type-specifier.
 | 
						|
///
 | 
						|
///       simple-type-specifier:
 | 
						|
///         '::'[opt] nested-name-specifier[opt] type-name
 | 
						|
///         '::'[opt] nested-name-specifier 'template' simple-template-id [TODO]
 | 
						|
///         char
 | 
						|
///         wchar_t
 | 
						|
///         bool
 | 
						|
///         short
 | 
						|
///         int
 | 
						|
///         long
 | 
						|
///         signed
 | 
						|
///         unsigned
 | 
						|
///         float
 | 
						|
///         double
 | 
						|
///         void
 | 
						|
/// [GNU]   typeof-specifier
 | 
						|
/// [C++0x] auto               [TODO]
 | 
						|
///
 | 
						|
///       type-name:
 | 
						|
///         class-name
 | 
						|
///         enum-name
 | 
						|
///         typedef-name
 | 
						|
///
 | 
						|
void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
 | 
						|
  DS.SetRangeStart(Tok.getLocation());
 | 
						|
  const char *PrevSpec;
 | 
						|
  unsigned DiagID;
 | 
						|
  SourceLocation Loc = Tok.getLocation();
 | 
						|
  const clang::PrintingPolicy &Policy =
 | 
						|
      Actions.getASTContext().getPrintingPolicy();
 | 
						|
 | 
						|
  switch (Tok.getKind()) {
 | 
						|
  case tok::identifier:   // foo::bar
 | 
						|
  case tok::coloncolon:   // ::foo::bar
 | 
						|
    llvm_unreachable("Annotation token should already be formed!");
 | 
						|
  default:
 | 
						|
    llvm_unreachable("Not a simple-type-specifier token!");
 | 
						|
 | 
						|
  // type-name
 | 
						|
  case tok::annot_typename: {
 | 
						|
    if (getTypeAnnotation(Tok))
 | 
						|
      DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID,
 | 
						|
                         getTypeAnnotation(Tok), Policy);
 | 
						|
    else
 | 
						|
      DS.SetTypeSpecError();
 | 
						|
 | 
						|
    DS.SetRangeEnd(Tok.getAnnotationEndLoc());
 | 
						|
    ConsumeAnnotationToken();
 | 
						|
 | 
						|
    DS.Finish(Actions, Policy);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // builtin types
 | 
						|
  case tok::kw_short:
 | 
						|
    DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw_long:
 | 
						|
    DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw___int64:
 | 
						|
    DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw_signed:
 | 
						|
    DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID);
 | 
						|
    break;
 | 
						|
  case tok::kw_unsigned:
 | 
						|
    DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, DiagID);
 | 
						|
    break;
 | 
						|
  case tok::kw_void:
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw_char:
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw_int:
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw___int128:
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw_half:
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw_float:
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw_double:
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw__Float16:
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_float16, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw___float128:
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_float128, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw_wchar_t:
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw_char8_t:
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_char8, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw_char16_t:
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw_char32_t:
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
  case tok::kw_bool:
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID, Policy);
 | 
						|
    break;
 | 
						|
#define GENERIC_IMAGE_TYPE(ImgType, Id)                                        \
 | 
						|
  case tok::kw_##ImgType##_t:                                                  \
 | 
						|
    DS.SetTypeSpecType(DeclSpec::TST_##ImgType##_t, Loc, PrevSpec, DiagID,     \
 | 
						|
                       Policy);                                                \
 | 
						|
    break;
 | 
						|
#include "clang/Basic/OpenCLImageTypes.def"
 | 
						|
 | 
						|
  case tok::annot_decltype:
 | 
						|
  case tok::kw_decltype:
 | 
						|
    DS.SetRangeEnd(ParseDecltypeSpecifier(DS));
 | 
						|
    return DS.Finish(Actions, Policy);
 | 
						|
 | 
						|
  // GNU typeof support.
 | 
						|
  case tok::kw_typeof:
 | 
						|
    ParseTypeofSpecifier(DS);
 | 
						|
    DS.Finish(Actions, Policy);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  ConsumeAnyToken();
 | 
						|
  DS.SetRangeEnd(PrevTokLocation);
 | 
						|
  DS.Finish(Actions, Policy);
 | 
						|
}
 | 
						|
 | 
						|
/// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++
 | 
						|
/// [dcl.name]), which is a non-empty sequence of type-specifiers,
 | 
						|
/// e.g., "const short int". Note that the DeclSpec is *not* finished
 | 
						|
/// by parsing the type-specifier-seq, because these sequences are
 | 
						|
/// typically followed by some form of declarator. Returns true and
 | 
						|
/// emits diagnostics if this is not a type-specifier-seq, false
 | 
						|
/// otherwise.
 | 
						|
///
 | 
						|
///   type-specifier-seq: [C++ 8.1]
 | 
						|
///     type-specifier type-specifier-seq[opt]
 | 
						|
///
 | 
						|
bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
 | 
						|
  ParseSpecifierQualifierList(DS, AS_none, DeclSpecContext::DSC_type_specifier);
 | 
						|
  DS.Finish(Actions, Actions.getASTContext().getPrintingPolicy());
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
/// Finish parsing a C++ unqualified-id that is a template-id of
 | 
						|
/// some form.
 | 
						|
///
 | 
						|
/// This routine is invoked when a '<' is encountered after an identifier or
 | 
						|
/// operator-function-id is parsed by \c ParseUnqualifiedId() to determine
 | 
						|
/// whether the unqualified-id is actually a template-id. This routine will
 | 
						|
/// then parse the template arguments and form the appropriate template-id to
 | 
						|
/// return to the caller.
 | 
						|
///
 | 
						|
/// \param SS the nested-name-specifier that precedes this template-id, if
 | 
						|
/// we're actually parsing a qualified-id.
 | 
						|
///
 | 
						|
/// \param Name for constructor and destructor names, this is the actual
 | 
						|
/// identifier that may be a template-name.
 | 
						|
///
 | 
						|
/// \param NameLoc the location of the class-name in a constructor or
 | 
						|
/// destructor.
 | 
						|
///
 | 
						|
/// \param EnteringContext whether we're entering the scope of the
 | 
						|
/// nested-name-specifier.
 | 
						|
///
 | 
						|
/// \param ObjectType if this unqualified-id occurs within a member access
 | 
						|
/// expression, the type of the base object whose member is being accessed.
 | 
						|
///
 | 
						|
/// \param Id as input, describes the template-name or operator-function-id
 | 
						|
/// that precedes the '<'. If template arguments were parsed successfully,
 | 
						|
/// will be updated with the template-id.
 | 
						|
///
 | 
						|
/// \param AssumeTemplateId When true, this routine will assume that the name
 | 
						|
/// refers to a template without performing name lookup to verify.
 | 
						|
///
 | 
						|
/// \returns true if a parse error occurred, false otherwise.
 | 
						|
bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
 | 
						|
                                          SourceLocation TemplateKWLoc,
 | 
						|
                                          IdentifierInfo *Name,
 | 
						|
                                          SourceLocation NameLoc,
 | 
						|
                                          bool EnteringContext,
 | 
						|
                                          ParsedType ObjectType,
 | 
						|
                                          UnqualifiedId &Id,
 | 
						|
                                          bool AssumeTemplateId) {
 | 
						|
  assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id");
 | 
						|
 | 
						|
  TemplateTy Template;
 | 
						|
  TemplateNameKind TNK = TNK_Non_template;
 | 
						|
  switch (Id.getKind()) {
 | 
						|
  case UnqualifiedIdKind::IK_Identifier:
 | 
						|
  case UnqualifiedIdKind::IK_OperatorFunctionId:
 | 
						|
  case UnqualifiedIdKind::IK_LiteralOperatorId:
 | 
						|
    if (AssumeTemplateId) {
 | 
						|
      // We defer the injected-class-name checks until we've found whether
 | 
						|
      // this template-id is used to form a nested-name-specifier or not.
 | 
						|
      TNK = Actions.ActOnDependentTemplateName(
 | 
						|
          getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext,
 | 
						|
          Template, /*AllowInjectedClassName*/ true);
 | 
						|
      if (TNK == TNK_Non_template)
 | 
						|
        return true;
 | 
						|
    } else {
 | 
						|
      bool MemberOfUnknownSpecialization;
 | 
						|
      TNK = Actions.isTemplateName(getCurScope(), SS,
 | 
						|
                                   TemplateKWLoc.isValid(), Id,
 | 
						|
                                   ObjectType, EnteringContext, Template,
 | 
						|
                                   MemberOfUnknownSpecialization);
 | 
						|
      // If lookup found nothing but we're assuming that this is a template
 | 
						|
      // name, double-check that makes sense syntactically before committing
 | 
						|
      // to it.
 | 
						|
      if (TNK == TNK_Undeclared_template &&
 | 
						|
          isTemplateArgumentList(0) == TPResult::False)
 | 
						|
        return false;
 | 
						|
 | 
						|
      if (TNK == TNK_Non_template && MemberOfUnknownSpecialization &&
 | 
						|
          ObjectType && isTemplateArgumentList(0) == TPResult::True) {
 | 
						|
        // We have something like t->getAs<T>(), where getAs is a
 | 
						|
        // member of an unknown specialization. However, this will only
 | 
						|
        // parse correctly as a template, so suggest the keyword 'template'
 | 
						|
        // before 'getAs' and treat this as a dependent template name.
 | 
						|
        std::string Name;
 | 
						|
        if (Id.getKind() == UnqualifiedIdKind::IK_Identifier)
 | 
						|
          Name = std::string(Id.Identifier->getName());
 | 
						|
        else {
 | 
						|
          Name = "operator ";
 | 
						|
          if (Id.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId)
 | 
						|
            Name += getOperatorSpelling(Id.OperatorFunctionId.Operator);
 | 
						|
          else
 | 
						|
            Name += Id.Identifier->getName();
 | 
						|
        }
 | 
						|
        Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword)
 | 
						|
          << Name
 | 
						|
          << FixItHint::CreateInsertion(Id.StartLocation, "template ");
 | 
						|
        TNK = Actions.ActOnDependentTemplateName(
 | 
						|
            getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext,
 | 
						|
            Template, /*AllowInjectedClassName*/ true);
 | 
						|
        if (TNK == TNK_Non_template)
 | 
						|
          return true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    break;
 | 
						|
 | 
						|
  case UnqualifiedIdKind::IK_ConstructorName: {
 | 
						|
    UnqualifiedId TemplateName;
 | 
						|
    bool MemberOfUnknownSpecialization;
 | 
						|
    TemplateName.setIdentifier(Name, NameLoc);
 | 
						|
    TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(),
 | 
						|
                                 TemplateName, ObjectType,
 | 
						|
                                 EnteringContext, Template,
 | 
						|
                                 MemberOfUnknownSpecialization);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  case UnqualifiedIdKind::IK_DestructorName: {
 | 
						|
    UnqualifiedId TemplateName;
 | 
						|
    bool MemberOfUnknownSpecialization;
 | 
						|
    TemplateName.setIdentifier(Name, NameLoc);
 | 
						|
    if (ObjectType) {
 | 
						|
      TNK = Actions.ActOnDependentTemplateName(
 | 
						|
          getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType,
 | 
						|
          EnteringContext, Template, /*AllowInjectedClassName*/ true);
 | 
						|
      if (TNK == TNK_Non_template)
 | 
						|
        return true;
 | 
						|
    } else {
 | 
						|
      TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(),
 | 
						|
                                   TemplateName, ObjectType,
 | 
						|
                                   EnteringContext, Template,
 | 
						|
                                   MemberOfUnknownSpecialization);
 | 
						|
 | 
						|
      if (TNK == TNK_Non_template && !Id.DestructorName.get()) {
 | 
						|
        Diag(NameLoc, diag::err_destructor_template_id)
 | 
						|
          << Name << SS.getRange();
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  default:
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (TNK == TNK_Non_template)
 | 
						|
    return false;
 | 
						|
 | 
						|
  // Parse the enclosed template argument list.
 | 
						|
  SourceLocation LAngleLoc, RAngleLoc;
 | 
						|
  TemplateArgList TemplateArgs;
 | 
						|
  if (ParseTemplateIdAfterTemplateName(true, LAngleLoc, TemplateArgs,
 | 
						|
                                       RAngleLoc))
 | 
						|
    return true;
 | 
						|
 | 
						|
  if (Id.getKind() == UnqualifiedIdKind::IK_Identifier ||
 | 
						|
      Id.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId ||
 | 
						|
      Id.getKind() == UnqualifiedIdKind::IK_LiteralOperatorId) {
 | 
						|
    // Form a parsed representation of the template-id to be stored in the
 | 
						|
    // UnqualifiedId.
 | 
						|
 | 
						|
    // FIXME: Store name for literal operator too.
 | 
						|
    IdentifierInfo *TemplateII =
 | 
						|
        Id.getKind() == UnqualifiedIdKind::IK_Identifier ? Id.Identifier
 | 
						|
                                                         : nullptr;
 | 
						|
    OverloadedOperatorKind OpKind =
 | 
						|
        Id.getKind() == UnqualifiedIdKind::IK_Identifier
 | 
						|
            ? OO_None
 | 
						|
            : Id.OperatorFunctionId.Operator;
 | 
						|
 | 
						|
    TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
 | 
						|
        TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK,
 | 
						|
        LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
 | 
						|
 | 
						|
    Id.setTemplateId(TemplateId);
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Bundle the template arguments together.
 | 
						|
  ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs);
 | 
						|
 | 
						|
  // Constructor and destructor names.
 | 
						|
  TypeResult Type = Actions.ActOnTemplateIdType(
 | 
						|
      getCurScope(), SS, TemplateKWLoc, Template, Name, NameLoc, LAngleLoc,
 | 
						|
      TemplateArgsPtr, RAngleLoc, /*IsCtorOrDtorName=*/true);
 | 
						|
  if (Type.isInvalid())
 | 
						|
    return true;
 | 
						|
 | 
						|
  if (Id.getKind() == UnqualifiedIdKind::IK_ConstructorName)
 | 
						|
    Id.setConstructorName(Type.get(), NameLoc, RAngleLoc);
 | 
						|
  else
 | 
						|
    Id.setDestructorName(Id.StartLocation, Type.get(), RAngleLoc);
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
/// Parse an operator-function-id or conversion-function-id as part
 | 
						|
/// of a C++ unqualified-id.
 | 
						|
///
 | 
						|
/// This routine is responsible only for parsing the operator-function-id or
 | 
						|
/// conversion-function-id; it does not handle template arguments in any way.
 | 
						|
///
 | 
						|
/// \code
 | 
						|
///       operator-function-id: [C++ 13.5]
 | 
						|
///         'operator' operator
 | 
						|
///
 | 
						|
///       operator: one of
 | 
						|
///            new   delete  new[]   delete[]
 | 
						|
///            +     -    *  /    %  ^    &   |   ~
 | 
						|
///            !     =    <  >    += -=   *=  /=  %=
 | 
						|
///            ^=    &=   |= <<   >> >>= <<=  ==  !=
 | 
						|
///            <=    >=   && ||   ++ --   ,   ->* ->
 | 
						|
///            ()    []   <=>
 | 
						|
///
 | 
						|
///       conversion-function-id: [C++ 12.3.2]
 | 
						|
///         operator conversion-type-id
 | 
						|
///
 | 
						|
///       conversion-type-id:
 | 
						|
///         type-specifier-seq conversion-declarator[opt]
 | 
						|
///
 | 
						|
///       conversion-declarator:
 | 
						|
///         ptr-operator conversion-declarator[opt]
 | 
						|
/// \endcode
 | 
						|
///
 | 
						|
/// \param SS The nested-name-specifier that preceded this unqualified-id. If
 | 
						|
/// non-empty, then we are parsing the unqualified-id of a qualified-id.
 | 
						|
///
 | 
						|
/// \param EnteringContext whether we are entering the scope of the
 | 
						|
/// nested-name-specifier.
 | 
						|
///
 | 
						|
/// \param ObjectType if this unqualified-id occurs within a member access
 | 
						|
/// expression, the type of the base object whose member is being accessed.
 | 
						|
///
 | 
						|
/// \param Result on a successful parse, contains the parsed unqualified-id.
 | 
						|
///
 | 
						|
/// \returns true if parsing fails, false otherwise.
 | 
						|
bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
 | 
						|
                                        ParsedType ObjectType,
 | 
						|
                                        UnqualifiedId &Result) {
 | 
						|
  assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
 | 
						|
 | 
						|
  // Consume the 'operator' keyword.
 | 
						|
  SourceLocation KeywordLoc = ConsumeToken();
 | 
						|
 | 
						|
  // Determine what kind of operator name we have.
 | 
						|
  unsigned SymbolIdx = 0;
 | 
						|
  SourceLocation SymbolLocations[3];
 | 
						|
  OverloadedOperatorKind Op = OO_None;
 | 
						|
  switch (Tok.getKind()) {
 | 
						|
    case tok::kw_new:
 | 
						|
    case tok::kw_delete: {
 | 
						|
      bool isNew = Tok.getKind() == tok::kw_new;
 | 
						|
      // Consume the 'new' or 'delete'.
 | 
						|
      SymbolLocations[SymbolIdx++] = ConsumeToken();
 | 
						|
      // Check for array new/delete.
 | 
						|
      if (Tok.is(tok::l_square) &&
 | 
						|
          (!getLangOpts().CPlusPlus11 || NextToken().isNot(tok::l_square))) {
 | 
						|
        // Consume the '[' and ']'.
 | 
						|
        BalancedDelimiterTracker T(*this, tok::l_square);
 | 
						|
        T.consumeOpen();
 | 
						|
        T.consumeClose();
 | 
						|
        if (T.getCloseLocation().isInvalid())
 | 
						|
          return true;
 | 
						|
 | 
						|
        SymbolLocations[SymbolIdx++] = T.getOpenLocation();
 | 
						|
        SymbolLocations[SymbolIdx++] = T.getCloseLocation();
 | 
						|
        Op = isNew? OO_Array_New : OO_Array_Delete;
 | 
						|
      } else {
 | 
						|
        Op = isNew? OO_New : OO_Delete;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
 | 
						|
    case tok::Token:                                                     \
 | 
						|
      SymbolLocations[SymbolIdx++] = ConsumeToken();                     \
 | 
						|
      Op = OO_##Name;                                                    \
 | 
						|
      break;
 | 
						|
#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
 | 
						|
#include "clang/Basic/OperatorKinds.def"
 | 
						|
 | 
						|
    case tok::l_paren: {
 | 
						|
      // Consume the '(' and ')'.
 | 
						|
      BalancedDelimiterTracker T(*this, tok::l_paren);
 | 
						|
      T.consumeOpen();
 | 
						|
      T.consumeClose();
 | 
						|
      if (T.getCloseLocation().isInvalid())
 | 
						|
        return true;
 | 
						|
 | 
						|
      SymbolLocations[SymbolIdx++] = T.getOpenLocation();
 | 
						|
      SymbolLocations[SymbolIdx++] = T.getCloseLocation();
 | 
						|
      Op = OO_Call;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    case tok::l_square: {
 | 
						|
      // Consume the '[' and ']'.
 | 
						|
      BalancedDelimiterTracker T(*this, tok::l_square);
 | 
						|
      T.consumeOpen();
 | 
						|
      T.consumeClose();
 | 
						|
      if (T.getCloseLocation().isInvalid())
 | 
						|
        return true;
 | 
						|
 | 
						|
      SymbolLocations[SymbolIdx++] = T.getOpenLocation();
 | 
						|
      SymbolLocations[SymbolIdx++] = T.getCloseLocation();
 | 
						|
      Op = OO_Subscript;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    case tok::code_completion: {
 | 
						|
      // Code completion for the operator name.
 | 
						|
      Actions.CodeCompleteOperatorName(getCurScope());
 | 
						|
      cutOffParsing();
 | 
						|
      // Don't try to parse any further.
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Op != OO_None) {
 | 
						|
    // We have parsed an operator-function-id.
 | 
						|
    Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations);
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Parse a literal-operator-id.
 | 
						|
  //
 | 
						|
  //   literal-operator-id: C++11 [over.literal]
 | 
						|
  //     operator string-literal identifier
 | 
						|
  //     operator user-defined-string-literal
 | 
						|
 | 
						|
  if (getLangOpts().CPlusPlus11 && isTokenStringLiteral()) {
 | 
						|
    Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator);
 | 
						|
 | 
						|
    SourceLocation DiagLoc;
 | 
						|
    unsigned DiagId = 0;
 | 
						|
 | 
						|
    // We're past translation phase 6, so perform string literal concatenation
 | 
						|
    // before checking for "".
 | 
						|
    SmallVector<Token, 4> Toks;
 | 
						|
    SmallVector<SourceLocation, 4> TokLocs;
 | 
						|
    while (isTokenStringLiteral()) {
 | 
						|
      if (!Tok.is(tok::string_literal) && !DiagId) {
 | 
						|
        // C++11 [over.literal]p1:
 | 
						|
        //   The string-literal or user-defined-string-literal in a
 | 
						|
        //   literal-operator-id shall have no encoding-prefix [...].
 | 
						|
        DiagLoc = Tok.getLocation();
 | 
						|
        DiagId = diag::err_literal_operator_string_prefix;
 | 
						|
      }
 | 
						|
      Toks.push_back(Tok);
 | 
						|
      TokLocs.push_back(ConsumeStringToken());
 | 
						|
    }
 | 
						|
 | 
						|
    StringLiteralParser Literal(Toks, PP);
 | 
						|
    if (Literal.hadError)
 | 
						|
      return true;
 | 
						|
 | 
						|
    // Grab the literal operator's suffix, which will be either the next token
 | 
						|
    // or a ud-suffix from the string literal.
 | 
						|
    IdentifierInfo *II = nullptr;
 | 
						|
    SourceLocation SuffixLoc;
 | 
						|
    if (!Literal.getUDSuffix().empty()) {
 | 
						|
      II = &PP.getIdentifierTable().get(Literal.getUDSuffix());
 | 
						|
      SuffixLoc =
 | 
						|
        Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()],
 | 
						|
                                       Literal.getUDSuffixOffset(),
 | 
						|
                                       PP.getSourceManager(), getLangOpts());
 | 
						|
    } else if (Tok.is(tok::identifier)) {
 | 
						|
      II = Tok.getIdentifierInfo();
 | 
						|
      SuffixLoc = ConsumeToken();
 | 
						|
      TokLocs.push_back(SuffixLoc);
 | 
						|
    } else {
 | 
						|
      Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    // The string literal must be empty.
 | 
						|
    if (!Literal.GetString().empty() || Literal.Pascal) {
 | 
						|
      // C++11 [over.literal]p1:
 | 
						|
      //   The string-literal or user-defined-string-literal in a
 | 
						|
      //   literal-operator-id shall [...] contain no characters
 | 
						|
      //   other than the implicit terminating '\0'.
 | 
						|
      DiagLoc = TokLocs.front();
 | 
						|
      DiagId = diag::err_literal_operator_string_not_empty;
 | 
						|
    }
 | 
						|
 | 
						|
    if (DiagId) {
 | 
						|
      // This isn't a valid literal-operator-id, but we think we know
 | 
						|
      // what the user meant. Tell them what they should have written.
 | 
						|
      SmallString<32> Str;
 | 
						|
      Str += "\"\"";
 | 
						|
      Str += II->getName();
 | 
						|
      Diag(DiagLoc, DiagId) << FixItHint::CreateReplacement(
 | 
						|
          SourceRange(TokLocs.front(), TokLocs.back()), Str);
 | 
						|
    }
 | 
						|
 | 
						|
    Result.setLiteralOperatorId(II, KeywordLoc, SuffixLoc);
 | 
						|
 | 
						|
    return Actions.checkLiteralOperatorId(SS, Result);
 | 
						|
  }
 | 
						|
 | 
						|
  // Parse a conversion-function-id.
 | 
						|
  //
 | 
						|
  //   conversion-function-id: [C++ 12.3.2]
 | 
						|
  //     operator conversion-type-id
 | 
						|
  //
 | 
						|
  //   conversion-type-id:
 | 
						|
  //     type-specifier-seq conversion-declarator[opt]
 | 
						|
  //
 | 
						|
  //   conversion-declarator:
 | 
						|
  //     ptr-operator conversion-declarator[opt]
 | 
						|
 | 
						|
  // Parse the type-specifier-seq.
 | 
						|
  DeclSpec DS(AttrFactory);
 | 
						|
  if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType?
 | 
						|
    return true;
 | 
						|
 | 
						|
  // Parse the conversion-declarator, which is merely a sequence of
 | 
						|
  // ptr-operators.
 | 
						|
  Declarator D(DS, DeclaratorContext::ConversionIdContext);
 | 
						|
  ParseDeclaratorInternal(D, /*DirectDeclParser=*/nullptr);
 | 
						|
 | 
						|
  // Finish up the type.
 | 
						|
  TypeResult Ty = Actions.ActOnTypeName(getCurScope(), D);
 | 
						|
  if (Ty.isInvalid())
 | 
						|
    return true;
 | 
						|
 | 
						|
  // Note that this is a conversion-function-id.
 | 
						|
  Result.setConversionFunctionId(KeywordLoc, Ty.get(),
 | 
						|
                                 D.getSourceRange().getEnd());
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
/// Parse a C++ unqualified-id (or a C identifier), which describes the
 | 
						|
/// name of an entity.
 | 
						|
///
 | 
						|
/// \code
 | 
						|
///       unqualified-id: [C++ expr.prim.general]
 | 
						|
///         identifier
 | 
						|
///         operator-function-id
 | 
						|
///         conversion-function-id
 | 
						|
/// [C++0x] literal-operator-id [TODO]
 | 
						|
///         ~ class-name
 | 
						|
///         template-id
 | 
						|
///
 | 
						|
/// \endcode
 | 
						|
///
 | 
						|
/// \param SS The nested-name-specifier that preceded this unqualified-id. If
 | 
						|
/// non-empty, then we are parsing the unqualified-id of a qualified-id.
 | 
						|
///
 | 
						|
/// \param EnteringContext whether we are entering the scope of the
 | 
						|
/// nested-name-specifier.
 | 
						|
///
 | 
						|
/// \param AllowDestructorName whether we allow parsing of a destructor name.
 | 
						|
///
 | 
						|
/// \param AllowConstructorName whether we allow parsing a constructor name.
 | 
						|
///
 | 
						|
/// \param AllowDeductionGuide whether we allow parsing a deduction guide name.
 | 
						|
///
 | 
						|
/// \param ObjectType if this unqualified-id occurs within a member access
 | 
						|
/// expression, the type of the base object whose member is being accessed.
 | 
						|
///
 | 
						|
/// \param Result on a successful parse, contains the parsed unqualified-id.
 | 
						|
///
 | 
						|
/// \returns true if parsing fails, false otherwise.
 | 
						|
bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
 | 
						|
                                bool AllowDestructorName,
 | 
						|
                                bool AllowConstructorName,
 | 
						|
                                bool AllowDeductionGuide,
 | 
						|
                                ParsedType ObjectType,
 | 
						|
                                SourceLocation *TemplateKWLoc,
 | 
						|
                                UnqualifiedId &Result) {
 | 
						|
  if (TemplateKWLoc)
 | 
						|
    *TemplateKWLoc = SourceLocation();
 | 
						|
 | 
						|
  // Handle 'A::template B'. This is for template-ids which have not
 | 
						|
  // already been annotated by ParseOptionalCXXScopeSpecifier().
 | 
						|
  bool TemplateSpecified = false;
 | 
						|
  if (Tok.is(tok::kw_template)) {
 | 
						|
    if (TemplateKWLoc && (ObjectType || SS.isSet())) {
 | 
						|
      TemplateSpecified = true;
 | 
						|
      *TemplateKWLoc = ConsumeToken();
 | 
						|
    } else {
 | 
						|
      SourceLocation TemplateLoc = ConsumeToken();
 | 
						|
      Diag(TemplateLoc, diag::err_unexpected_template_in_unqualified_id)
 | 
						|
        << FixItHint::CreateRemoval(TemplateLoc);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // unqualified-id:
 | 
						|
  //   identifier
 | 
						|
  //   template-id (when it hasn't already been annotated)
 | 
						|
  if (Tok.is(tok::identifier)) {
 | 
						|
    // Consume the identifier.
 | 
						|
    IdentifierInfo *Id = Tok.getIdentifierInfo();
 | 
						|
    SourceLocation IdLoc = ConsumeToken();
 | 
						|
 | 
						|
    if (!getLangOpts().CPlusPlus) {
 | 
						|
      // If we're not in C++, only identifiers matter. Record the
 | 
						|
      // identifier and return.
 | 
						|
      Result.setIdentifier(Id, IdLoc);
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    ParsedTemplateTy TemplateName;
 | 
						|
    if (AllowConstructorName &&
 | 
						|
        Actions.isCurrentClassName(*Id, getCurScope(), &SS)) {
 | 
						|
      // We have parsed a constructor name.
 | 
						|
      ParsedType Ty = Actions.getConstructorName(*Id, IdLoc, getCurScope(), SS,
 | 
						|
                                                 EnteringContext);
 | 
						|
      if (!Ty)
 | 
						|
        return true;
 | 
						|
      Result.setConstructorName(Ty, IdLoc, IdLoc);
 | 
						|
    } else if (getLangOpts().CPlusPlus17 &&
 | 
						|
               AllowDeductionGuide && SS.isEmpty() &&
 | 
						|
               Actions.isDeductionGuideName(getCurScope(), *Id, IdLoc,
 | 
						|
                                            &TemplateName)) {
 | 
						|
      // We have parsed a template-name naming a deduction guide.
 | 
						|
      Result.setDeductionGuideName(TemplateName, IdLoc);
 | 
						|
    } else {
 | 
						|
      // We have parsed an identifier.
 | 
						|
      Result.setIdentifier(Id, IdLoc);
 | 
						|
    }
 | 
						|
 | 
						|
    // If the next token is a '<', we may have a template.
 | 
						|
    TemplateTy Template;
 | 
						|
    if (Tok.is(tok::less))
 | 
						|
      return ParseUnqualifiedIdTemplateId(
 | 
						|
          SS, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), Id, IdLoc,
 | 
						|
          EnteringContext, ObjectType, Result, TemplateSpecified);
 | 
						|
    else if (TemplateSpecified &&
 | 
						|
             Actions.ActOnDependentTemplateName(
 | 
						|
                 getCurScope(), SS, *TemplateKWLoc, Result, ObjectType,
 | 
						|
                 EnteringContext, Template,
 | 
						|
                 /*AllowInjectedClassName*/ true) == TNK_Non_template)
 | 
						|
      return true;
 | 
						|
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // unqualified-id:
 | 
						|
  //   template-id (already parsed and annotated)
 | 
						|
  if (Tok.is(tok::annot_template_id)) {
 | 
						|
    TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
 | 
						|
 | 
						|
    // If the template-name names the current class, then this is a constructor
 | 
						|
    if (AllowConstructorName && TemplateId->Name &&
 | 
						|
        Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) {
 | 
						|
      if (SS.isSet()) {
 | 
						|
        // C++ [class.qual]p2 specifies that a qualified template-name
 | 
						|
        // is taken as the constructor name where a constructor can be
 | 
						|
        // declared. Thus, the template arguments are extraneous, so
 | 
						|
        // complain about them and remove them entirely.
 | 
						|
        Diag(TemplateId->TemplateNameLoc,
 | 
						|
             diag::err_out_of_line_constructor_template_id)
 | 
						|
          << TemplateId->Name
 | 
						|
          << FixItHint::CreateRemoval(
 | 
						|
                    SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc));
 | 
						|
        ParsedType Ty = Actions.getConstructorName(
 | 
						|
            *TemplateId->Name, TemplateId->TemplateNameLoc, getCurScope(), SS,
 | 
						|
            EnteringContext);
 | 
						|
        if (!Ty)
 | 
						|
          return true;
 | 
						|
        Result.setConstructorName(Ty, TemplateId->TemplateNameLoc,
 | 
						|
                                  TemplateId->RAngleLoc);
 | 
						|
        ConsumeAnnotationToken();
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      Result.setConstructorTemplateId(TemplateId);
 | 
						|
      ConsumeAnnotationToken();
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    // We have already parsed a template-id; consume the annotation token as
 | 
						|
    // our unqualified-id.
 | 
						|
    Result.setTemplateId(TemplateId);
 | 
						|
    SourceLocation TemplateLoc = TemplateId->TemplateKWLoc;
 | 
						|
    if (TemplateLoc.isValid()) {
 | 
						|
      if (TemplateKWLoc && (ObjectType || SS.isSet()))
 | 
						|
        *TemplateKWLoc = TemplateLoc;
 | 
						|
      else
 | 
						|
        Diag(TemplateLoc, diag::err_unexpected_template_in_unqualified_id)
 | 
						|
            << FixItHint::CreateRemoval(TemplateLoc);
 | 
						|
    }
 | 
						|
    ConsumeAnnotationToken();
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // unqualified-id:
 | 
						|
  //   operator-function-id
 | 
						|
  //   conversion-function-id
 | 
						|
  if (Tok.is(tok::kw_operator)) {
 | 
						|
    if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result))
 | 
						|
      return true;
 | 
						|
 | 
						|
    // If we have an operator-function-id or a literal-operator-id and the next
 | 
						|
    // token is a '<', we may have a
 | 
						|
    //
 | 
						|
    //   template-id:
 | 
						|
    //     operator-function-id < template-argument-list[opt] >
 | 
						|
    TemplateTy Template;
 | 
						|
    if ((Result.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId ||
 | 
						|
         Result.getKind() == UnqualifiedIdKind::IK_LiteralOperatorId) &&
 | 
						|
        Tok.is(tok::less))
 | 
						|
      return ParseUnqualifiedIdTemplateId(
 | 
						|
          SS, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), nullptr,
 | 
						|
          SourceLocation(), EnteringContext, ObjectType, Result,
 | 
						|
          TemplateSpecified);
 | 
						|
    else if (TemplateSpecified &&
 | 
						|
             Actions.ActOnDependentTemplateName(
 | 
						|
                 getCurScope(), SS, *TemplateKWLoc, Result, ObjectType,
 | 
						|
                 EnteringContext, Template,
 | 
						|
                 /*AllowInjectedClassName*/ true) == TNK_Non_template)
 | 
						|
      return true;
 | 
						|
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (getLangOpts().CPlusPlus &&
 | 
						|
      (AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) {
 | 
						|
    // C++ [expr.unary.op]p10:
 | 
						|
    //   There is an ambiguity in the unary-expression ~X(), where X is a
 | 
						|
    //   class-name. The ambiguity is resolved in favor of treating ~ as a
 | 
						|
    //    unary complement rather than treating ~X as referring to a destructor.
 | 
						|
 | 
						|
    // Parse the '~'.
 | 
						|
    SourceLocation TildeLoc = ConsumeToken();
 | 
						|
 | 
						|
    if (SS.isEmpty() && Tok.is(tok::kw_decltype)) {
 | 
						|
      DeclSpec DS(AttrFactory);
 | 
						|
      SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
 | 
						|
      if (ParsedType Type =
 | 
						|
              Actions.getDestructorTypeForDecltype(DS, ObjectType)) {
 | 
						|
        Result.setDestructorName(TildeLoc, Type, EndLoc);
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    // Parse the class-name.
 | 
						|
    if (Tok.isNot(tok::identifier)) {
 | 
						|
      Diag(Tok, diag::err_destructor_tilde_identifier);
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    // If the user wrote ~T::T, correct it to T::~T.
 | 
						|
    DeclaratorScopeObj DeclScopeObj(*this, SS);
 | 
						|
    if (!TemplateSpecified && NextToken().is(tok::coloncolon)) {
 | 
						|
      // Don't let ParseOptionalCXXScopeSpecifier() "correct"
 | 
						|
      // `int A; struct { ~A::A(); };` to `int A; struct { ~A:A(); };`,
 | 
						|
      // it will confuse this recovery logic.
 | 
						|
      ColonProtectionRAIIObject ColonRAII(*this, false);
 | 
						|
 | 
						|
      if (SS.isSet()) {
 | 
						|
        AnnotateScopeToken(SS, /*NewAnnotation*/true);
 | 
						|
        SS.clear();
 | 
						|
      }
 | 
						|
      if (ParseOptionalCXXScopeSpecifier(SS, ObjectType, EnteringContext))
 | 
						|
        return true;
 | 
						|
      if (SS.isNotEmpty())
 | 
						|
        ObjectType = nullptr;
 | 
						|
      if (Tok.isNot(tok::identifier) || NextToken().is(tok::coloncolon) ||
 | 
						|
          !SS.isSet()) {
 | 
						|
        Diag(TildeLoc, diag::err_destructor_tilde_scope);
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
 | 
						|
      // Recover as if the tilde had been written before the identifier.
 | 
						|
      Diag(TildeLoc, diag::err_destructor_tilde_scope)
 | 
						|
        << FixItHint::CreateRemoval(TildeLoc)
 | 
						|
        << FixItHint::CreateInsertion(Tok.getLocation(), "~");
 | 
						|
 | 
						|
      // Temporarily enter the scope for the rest of this function.
 | 
						|
      if (Actions.ShouldEnterDeclaratorScope(getCurScope(), SS))
 | 
						|
        DeclScopeObj.EnterDeclaratorScope();
 | 
						|
    }
 | 
						|
 | 
						|
    // Parse the class-name (or template-name in a simple-template-id).
 | 
						|
    IdentifierInfo *ClassName = Tok.getIdentifierInfo();
 | 
						|
    SourceLocation ClassNameLoc = ConsumeToken();
 | 
						|
 | 
						|
    if (Tok.is(tok::less)) {
 | 
						|
      Result.setDestructorName(TildeLoc, nullptr, ClassNameLoc);
 | 
						|
      return ParseUnqualifiedIdTemplateId(
 | 
						|
          SS, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), ClassName,
 | 
						|
          ClassNameLoc, EnteringContext, ObjectType, Result, TemplateSpecified);
 | 
						|
    }
 | 
						|
 | 
						|
    // Note that this is a destructor name.
 | 
						|
    ParsedType Ty = Actions.getDestructorName(TildeLoc, *ClassName,
 | 
						|
                                              ClassNameLoc, getCurScope(),
 | 
						|
                                              SS, ObjectType,
 | 
						|
                                              EnteringContext);
 | 
						|
    if (!Ty)
 | 
						|
      return true;
 | 
						|
 | 
						|
    Result.setDestructorName(TildeLoc, Ty, ClassNameLoc);
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  Diag(Tok, diag::err_expected_unqualified_id)
 | 
						|
    << getLangOpts().CPlusPlus;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
/// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate
 | 
						|
/// memory in a typesafe manner and call constructors.
 | 
						|
///
 | 
						|
/// This method is called to parse the new expression after the optional :: has
 | 
						|
/// been already parsed.  If the :: was present, "UseGlobal" is true and "Start"
 | 
						|
/// is its location.  Otherwise, "Start" is the location of the 'new' token.
 | 
						|
///
 | 
						|
///        new-expression:
 | 
						|
///                   '::'[opt] 'new' new-placement[opt] new-type-id
 | 
						|
///                                     new-initializer[opt]
 | 
						|
///                   '::'[opt] 'new' new-placement[opt] '(' type-id ')'
 | 
						|
///                                     new-initializer[opt]
 | 
						|
///
 | 
						|
///        new-placement:
 | 
						|
///                   '(' expression-list ')'
 | 
						|
///
 | 
						|
///        new-type-id:
 | 
						|
///                   type-specifier-seq new-declarator[opt]
 | 
						|
/// [GNU]             attributes type-specifier-seq new-declarator[opt]
 | 
						|
///
 | 
						|
///        new-declarator:
 | 
						|
///                   ptr-operator new-declarator[opt]
 | 
						|
///                   direct-new-declarator
 | 
						|
///
 | 
						|
///        new-initializer:
 | 
						|
///                   '(' expression-list[opt] ')'
 | 
						|
/// [C++0x]           braced-init-list
 | 
						|
///
 | 
						|
ExprResult
 | 
						|
Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
 | 
						|
  assert(Tok.is(tok::kw_new) && "expected 'new' token");
 | 
						|
  ConsumeToken();   // Consume 'new'
 | 
						|
 | 
						|
  // A '(' now can be a new-placement or the '(' wrapping the type-id in the
 | 
						|
  // second form of new-expression. It can't be a new-type-id.
 | 
						|
 | 
						|
  ExprVector PlacementArgs;
 | 
						|
  SourceLocation PlacementLParen, PlacementRParen;
 | 
						|
 | 
						|
  SourceRange TypeIdParens;
 | 
						|
  DeclSpec DS(AttrFactory);
 | 
						|
  Declarator DeclaratorInfo(DS, DeclaratorContext::CXXNewContext);
 | 
						|
  if (Tok.is(tok::l_paren)) {
 | 
						|
    // If it turns out to be a placement, we change the type location.
 | 
						|
    BalancedDelimiterTracker T(*this, tok::l_paren);
 | 
						|
    T.consumeOpen();
 | 
						|
    PlacementLParen = T.getOpenLocation();
 | 
						|
    if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) {
 | 
						|
      SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
 | 
						|
      return ExprError();
 | 
						|
    }
 | 
						|
 | 
						|
    T.consumeClose();
 | 
						|
    PlacementRParen = T.getCloseLocation();
 | 
						|
    if (PlacementRParen.isInvalid()) {
 | 
						|
      SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
 | 
						|
      return ExprError();
 | 
						|
    }
 | 
						|
 | 
						|
    if (PlacementArgs.empty()) {
 | 
						|
      // Reset the placement locations. There was no placement.
 | 
						|
      TypeIdParens = T.getRange();
 | 
						|
      PlacementLParen = PlacementRParen = SourceLocation();
 | 
						|
    } else {
 | 
						|
      // We still need the type.
 | 
						|
      if (Tok.is(tok::l_paren)) {
 | 
						|
        BalancedDelimiterTracker T(*this, tok::l_paren);
 | 
						|
        T.consumeOpen();
 | 
						|
        MaybeParseGNUAttributes(DeclaratorInfo);
 | 
						|
        ParseSpecifierQualifierList(DS);
 | 
						|
        DeclaratorInfo.SetSourceRange(DS.getSourceRange());
 | 
						|
        ParseDeclarator(DeclaratorInfo);
 | 
						|
        T.consumeClose();
 | 
						|
        TypeIdParens = T.getRange();
 | 
						|
      } else {
 | 
						|
        MaybeParseGNUAttributes(DeclaratorInfo);
 | 
						|
        if (ParseCXXTypeSpecifierSeq(DS))
 | 
						|
          DeclaratorInfo.setInvalidType(true);
 | 
						|
        else {
 | 
						|
          DeclaratorInfo.SetSourceRange(DS.getSourceRange());
 | 
						|
          ParseDeclaratorInternal(DeclaratorInfo,
 | 
						|
                                  &Parser::ParseDirectNewDeclarator);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    // A new-type-id is a simplified type-id, where essentially the
 | 
						|
    // direct-declarator is replaced by a direct-new-declarator.
 | 
						|
    MaybeParseGNUAttributes(DeclaratorInfo);
 | 
						|
    if (ParseCXXTypeSpecifierSeq(DS))
 | 
						|
      DeclaratorInfo.setInvalidType(true);
 | 
						|
    else {
 | 
						|
      DeclaratorInfo.SetSourceRange(DS.getSourceRange());
 | 
						|
      ParseDeclaratorInternal(DeclaratorInfo,
 | 
						|
                              &Parser::ParseDirectNewDeclarator);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (DeclaratorInfo.isInvalidType()) {
 | 
						|
    SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
 | 
						|
    return ExprError();
 | 
						|
  }
 | 
						|
 | 
						|
  ExprResult Initializer;
 | 
						|
 | 
						|
  if (Tok.is(tok::l_paren)) {
 | 
						|
    SourceLocation ConstructorLParen, ConstructorRParen;
 | 
						|
    ExprVector ConstructorArgs;
 | 
						|
    BalancedDelimiterTracker T(*this, tok::l_paren);
 | 
						|
    T.consumeOpen();
 | 
						|
    ConstructorLParen = T.getOpenLocation();
 | 
						|
    if (Tok.isNot(tok::r_paren)) {
 | 
						|
      CommaLocsTy CommaLocs;
 | 
						|
      auto RunSignatureHelp = [&]() {
 | 
						|
        ParsedType TypeRep =
 | 
						|
            Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get();
 | 
						|
        assert(TypeRep && "invalid types should be handled before");
 | 
						|
        QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
 | 
						|
            getCurScope(), TypeRep.get()->getCanonicalTypeInternal(),
 | 
						|
            DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen);
 | 
						|
        CalledSignatureHelp = true;
 | 
						|
        return PreferredType;
 | 
						|
      };
 | 
						|
      if (ParseExpressionList(ConstructorArgs, CommaLocs, [&] {
 | 
						|
            PreferredType.enterFunctionArgument(Tok.getLocation(),
 | 
						|
                                                RunSignatureHelp);
 | 
						|
          })) {
 | 
						|
        if (PP.isCodeCompletionReached() && !CalledSignatureHelp)
 | 
						|
          RunSignatureHelp();
 | 
						|
        SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
 | 
						|
        return ExprError();
 | 
						|
      }
 | 
						|
    }
 | 
						|
    T.consumeClose();
 | 
						|
    ConstructorRParen = T.getCloseLocation();
 | 
						|
    if (ConstructorRParen.isInvalid()) {
 | 
						|
      SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
 | 
						|
      return ExprError();
 | 
						|
    }
 | 
						|
    Initializer = Actions.ActOnParenListExpr(ConstructorLParen,
 | 
						|
                                             ConstructorRParen,
 | 
						|
                                             ConstructorArgs);
 | 
						|
  } else if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus11) {
 | 
						|
    Diag(Tok.getLocation(),
 | 
						|
         diag::warn_cxx98_compat_generalized_initializer_lists);
 | 
						|
    Initializer = ParseBraceInitializer();
 | 
						|
  }
 | 
						|
  if (Initializer.isInvalid())
 | 
						|
    return Initializer;
 | 
						|
 | 
						|
  return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
 | 
						|
                             PlacementArgs, PlacementRParen,
 | 
						|
                             TypeIdParens, DeclaratorInfo, Initializer.get());
 | 
						|
}
 | 
						|
 | 
						|
/// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be
 | 
						|
/// passed to ParseDeclaratorInternal.
 | 
						|
///
 | 
						|
///        direct-new-declarator:
 | 
						|
///                   '[' expression[opt] ']'
 | 
						|
///                   direct-new-declarator '[' constant-expression ']'
 | 
						|
///
 | 
						|
void Parser::ParseDirectNewDeclarator(Declarator &D) {
 | 
						|
  // Parse the array dimensions.
 | 
						|
  bool First = true;
 | 
						|
  while (Tok.is(tok::l_square)) {
 | 
						|
    // An array-size expression can't start with a lambda.
 | 
						|
    if (CheckProhibitedCXX11Attribute())
 | 
						|
      continue;
 | 
						|
 | 
						|
    BalancedDelimiterTracker T(*this, tok::l_square);
 | 
						|
    T.consumeOpen();
 | 
						|
 | 
						|
    ExprResult Size =
 | 
						|
        First ? (Tok.is(tok::r_square) ? ExprResult() : ParseExpression())
 | 
						|
              : ParseConstantExpression();
 | 
						|
    if (Size.isInvalid()) {
 | 
						|
      // Recover
 | 
						|
      SkipUntil(tok::r_square, StopAtSemi);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    First = false;
 | 
						|
 | 
						|
    T.consumeClose();
 | 
						|
 | 
						|
    // Attributes here appertain to the array type. C++11 [expr.new]p5.
 | 
						|
    ParsedAttributes Attrs(AttrFactory);
 | 
						|
    MaybeParseCXX11Attributes(Attrs);
 | 
						|
 | 
						|
    D.AddTypeInfo(DeclaratorChunk::getArray(0,
 | 
						|
                                            /*isStatic=*/false, /*isStar=*/false,
 | 
						|
                                            Size.get(), T.getOpenLocation(),
 | 
						|
                                            T.getCloseLocation()),
 | 
						|
                  std::move(Attrs), T.getCloseLocation());
 | 
						|
 | 
						|
    if (T.getCloseLocation().isInvalid())
 | 
						|
      return;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/// ParseExpressionListOrTypeId - Parse either an expression-list or a type-id.
 | 
						|
/// This ambiguity appears in the syntax of the C++ new operator.
 | 
						|
///
 | 
						|
///        new-expression:
 | 
						|
///                   '::'[opt] 'new' new-placement[opt] '(' type-id ')'
 | 
						|
///                                     new-initializer[opt]
 | 
						|
///
 | 
						|
///        new-placement:
 | 
						|
///                   '(' expression-list ')'
 | 
						|
///
 | 
						|
bool Parser::ParseExpressionListOrTypeId(
 | 
						|
                                   SmallVectorImpl<Expr*> &PlacementArgs,
 | 
						|
                                         Declarator &D) {
 | 
						|
  // The '(' was already consumed.
 | 
						|
  if (isTypeIdInParens()) {
 | 
						|
    ParseSpecifierQualifierList(D.getMutableDeclSpec());
 | 
						|
    D.SetSourceRange(D.getDeclSpec().getSourceRange());
 | 
						|
    ParseDeclarator(D);
 | 
						|
    return D.isInvalidType();
 | 
						|
  }
 | 
						|
 | 
						|
  // It's not a type, it has to be an expression list.
 | 
						|
  // Discard the comma locations - ActOnCXXNew has enough parameters.
 | 
						|
  CommaLocsTy CommaLocs;
 | 
						|
  return ParseExpressionList(PlacementArgs, CommaLocs);
 | 
						|
}
 | 
						|
 | 
						|
/// ParseCXXDeleteExpression - Parse a C++ delete-expression. Delete is used
 | 
						|
/// to free memory allocated by new.
 | 
						|
///
 | 
						|
/// This method is called to parse the 'delete' expression after the optional
 | 
						|
/// '::' has been already parsed.  If the '::' was present, "UseGlobal" is true
 | 
						|
/// and "Start" is its location.  Otherwise, "Start" is the location of the
 | 
						|
/// 'delete' token.
 | 
						|
///
 | 
						|
///        delete-expression:
 | 
						|
///                   '::'[opt] 'delete' cast-expression
 | 
						|
///                   '::'[opt] 'delete' '[' ']' cast-expression
 | 
						|
ExprResult
 | 
						|
Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
 | 
						|
  assert(Tok.is(tok::kw_delete) && "Expected 'delete' keyword");
 | 
						|
  ConsumeToken(); // Consume 'delete'
 | 
						|
 | 
						|
  // Array delete?
 | 
						|
  bool ArrayDelete = false;
 | 
						|
  if (Tok.is(tok::l_square) && NextToken().is(tok::r_square)) {
 | 
						|
    // C++11 [expr.delete]p1:
 | 
						|
    //   Whenever the delete keyword is followed by empty square brackets, it
 | 
						|
    //   shall be interpreted as [array delete].
 | 
						|
    //   [Footnote: A lambda expression with a lambda-introducer that consists
 | 
						|
    //              of empty square brackets can follow the delete keyword if
 | 
						|
    //              the lambda expression is enclosed in parentheses.]
 | 
						|
 | 
						|
    const Token Next = GetLookAheadToken(2);
 | 
						|
 | 
						|
    // Basic lookahead to check if we have a lambda expression.
 | 
						|
    if (Next.isOneOf(tok::l_brace, tok::less) ||
 | 
						|
        (Next.is(tok::l_paren) &&
 | 
						|
         (GetLookAheadToken(3).is(tok::r_paren) ||
 | 
						|
          (GetLookAheadToken(3).is(tok::identifier) &&
 | 
						|
           GetLookAheadToken(4).is(tok::identifier))))) {
 | 
						|
      TentativeParsingAction TPA(*this);
 | 
						|
      SourceLocation LSquareLoc = Tok.getLocation();
 | 
						|
      SourceLocation RSquareLoc = NextToken().getLocation();
 | 
						|
 | 
						|
      // SkipUntil can't skip pairs of </*...*/>; don't emit a FixIt in this
 | 
						|
      // case.
 | 
						|
      SkipUntil({tok::l_brace, tok::less}, StopBeforeMatch);
 | 
						|
      SourceLocation RBraceLoc;
 | 
						|
      bool EmitFixIt = false;
 | 
						|
      if (Tok.is(tok::l_brace)) {
 | 
						|
        ConsumeBrace();
 | 
						|
        SkipUntil(tok::r_brace, StopBeforeMatch);
 | 
						|
        RBraceLoc = Tok.getLocation();
 | 
						|
        EmitFixIt = true;
 | 
						|
      }
 | 
						|
 | 
						|
      TPA.Revert();
 | 
						|
 | 
						|
      if (EmitFixIt)
 | 
						|
        Diag(Start, diag::err_lambda_after_delete)
 | 
						|
            << SourceRange(Start, RSquareLoc)
 | 
						|
            << FixItHint::CreateInsertion(LSquareLoc, "(")
 | 
						|
            << FixItHint::CreateInsertion(
 | 
						|
                   Lexer::getLocForEndOfToken(
 | 
						|
                       RBraceLoc, 0, Actions.getSourceManager(), getLangOpts()),
 | 
						|
                   ")");
 | 
						|
      else
 | 
						|
        Diag(Start, diag::err_lambda_after_delete)
 | 
						|
            << SourceRange(Start, RSquareLoc);
 | 
						|
 | 
						|
      // Warn that the non-capturing lambda isn't surrounded by parentheses
 | 
						|
      // to disambiguate it from 'delete[]'.
 | 
						|
      ExprResult Lambda = ParseLambdaExpression();
 | 
						|
      if (Lambda.isInvalid())
 | 
						|
        return ExprError();
 | 
						|
 | 
						|
      // Evaluate any postfix expressions used on the lambda.
 | 
						|
      Lambda = ParsePostfixExpressionSuffix(Lambda);
 | 
						|
      if (Lambda.isInvalid())
 | 
						|
        return ExprError();
 | 
						|
      return Actions.ActOnCXXDelete(Start, UseGlobal, /*ArrayForm=*/false,
 | 
						|
                                    Lambda.get());
 | 
						|
    }
 | 
						|
 | 
						|
    ArrayDelete = true;
 | 
						|
    BalancedDelimiterTracker T(*this, tok::l_square);
 | 
						|
 | 
						|
    T.consumeOpen();
 | 
						|
    T.consumeClose();
 | 
						|
    if (T.getCloseLocation().isInvalid())
 | 
						|
      return ExprError();
 | 
						|
  }
 | 
						|
 | 
						|
  ExprResult Operand(ParseCastExpression(AnyCastExpr));
 | 
						|
  if (Operand.isInvalid())
 | 
						|
    return Operand;
 | 
						|
 | 
						|
  return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.get());
 | 
						|
}
 | 
						|
 | 
						|
/// ParseRequiresExpression - Parse a C++2a requires-expression.
 | 
						|
/// C++2a [expr.prim.req]p1
 | 
						|
///     A requires-expression provides a concise way to express requirements on
 | 
						|
///     template arguments. A requirement is one that can be checked by name
 | 
						|
///     lookup (6.4) or by checking properties of types and expressions.
 | 
						|
///
 | 
						|
///     requires-expression:
 | 
						|
///         'requires' requirement-parameter-list[opt] requirement-body
 | 
						|
///
 | 
						|
///     requirement-parameter-list:
 | 
						|
///         '(' parameter-declaration-clause[opt] ')'
 | 
						|
///
 | 
						|
///     requirement-body:
 | 
						|
///         '{' requirement-seq '}'
 | 
						|
///
 | 
						|
///     requirement-seq:
 | 
						|
///         requirement
 | 
						|
///         requirement-seq requirement
 | 
						|
///
 | 
						|
///     requirement:
 | 
						|
///         simple-requirement
 | 
						|
///         type-requirement
 | 
						|
///         compound-requirement
 | 
						|
///         nested-requirement
 | 
						|
ExprResult Parser::ParseRequiresExpression() {
 | 
						|
  assert(Tok.is(tok::kw_requires) && "Expected 'requires' keyword");
 | 
						|
  SourceLocation RequiresKWLoc = ConsumeToken(); // Consume 'requires'
 | 
						|
 | 
						|
  llvm::SmallVector<ParmVarDecl *, 2> LocalParameterDecls;
 | 
						|
  if (Tok.is(tok::l_paren)) {
 | 
						|
    // requirement parameter list is present.
 | 
						|
    ParseScope LocalParametersScope(this, Scope::FunctionPrototypeScope |
 | 
						|
                                    Scope::DeclScope);
 | 
						|
    BalancedDelimiterTracker Parens(*this, tok::l_paren);
 | 
						|
    Parens.consumeOpen();
 | 
						|
    if (!Tok.is(tok::r_paren)) {
 | 
						|
      ParsedAttributes FirstArgAttrs(getAttrFactory());
 | 
						|
      SourceLocation EllipsisLoc;
 | 
						|
      llvm::SmallVector<DeclaratorChunk::ParamInfo, 2> LocalParameters;
 | 
						|
      DiagnosticErrorTrap Trap(Diags);
 | 
						|
      ParseParameterDeclarationClause(DeclaratorContext::RequiresExprContext,
 | 
						|
                                      FirstArgAttrs, LocalParameters,
 | 
						|
                                      EllipsisLoc);
 | 
						|
      if (EllipsisLoc.isValid())
 | 
						|
        Diag(EllipsisLoc, diag::err_requires_expr_parameter_list_ellipsis);
 | 
						|
      for (auto &ParamInfo : LocalParameters)
 | 
						|
        LocalParameterDecls.push_back(cast<ParmVarDecl>(ParamInfo.Param));
 | 
						|
      if (Trap.hasErrorOccurred())
 | 
						|
        SkipUntil(tok::r_paren, StopBeforeMatch);
 | 
						|
    }
 | 
						|
    Parens.consumeClose();
 | 
						|
  }
 | 
						|
 | 
						|
  BalancedDelimiterTracker Braces(*this, tok::l_brace);
 | 
						|
  if (Braces.expectAndConsume())
 | 
						|
    return ExprError();
 | 
						|
 | 
						|
  // Start of requirement list
 | 
						|
  llvm::SmallVector<concepts::Requirement *, 2> Requirements;
 | 
						|
 | 
						|
  // C++2a [expr.prim.req]p2
 | 
						|
  //   Expressions appearing within a requirement-body are unevaluated operands.
 | 
						|
  EnterExpressionEvaluationContext Ctx(
 | 
						|
      Actions, Sema::ExpressionEvaluationContext::Unevaluated);
 | 
						|
 | 
						|
  ParseScope BodyScope(this, Scope::DeclScope);
 | 
						|
  RequiresExprBodyDecl *Body = Actions.ActOnStartRequiresExpr(
 | 
						|
      RequiresKWLoc, LocalParameterDecls, getCurScope());
 | 
						|
 | 
						|
  if (Tok.is(tok::r_brace)) {
 | 
						|
    // Grammar does not allow an empty body.
 | 
						|
    // requirement-body:
 | 
						|
    //   { requirement-seq }
 | 
						|
    // requirement-seq:
 | 
						|
    //   requirement
 | 
						|
    //   requirement-seq requirement
 | 
						|
    Diag(Tok, diag::err_empty_requires_expr);
 | 
						|
    // Continue anyway and produce a requires expr with no requirements.
 | 
						|
  } else {
 | 
						|
    while (!Tok.is(tok::r_brace)) {
 | 
						|
      switch (Tok.getKind()) {
 | 
						|
      case tok::l_brace: {
 | 
						|
        // Compound requirement
 | 
						|
        // C++ [expr.prim.req.compound]
 | 
						|
        //     compound-requirement:
 | 
						|
        //         '{' expression '}' 'noexcept'[opt]
 | 
						|
        //             return-type-requirement[opt] ';'
 | 
						|
        //     return-type-requirement:
 | 
						|
        //         trailing-return-type
 | 
						|
        //         '->' cv-qualifier-seq[opt] constrained-parameter
 | 
						|
        //             cv-qualifier-seq[opt] abstract-declarator[opt]
 | 
						|
        BalancedDelimiterTracker ExprBraces(*this, tok::l_brace);
 | 
						|
        ExprBraces.consumeOpen();
 | 
						|
        ExprResult Expression =
 | 
						|
            Actions.CorrectDelayedTyposInExpr(ParseExpression());
 | 
						|
        if (!Expression.isUsable()) {
 | 
						|
          ExprBraces.skipToEnd();
 | 
						|
          SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        if (ExprBraces.consumeClose())
 | 
						|
          ExprBraces.skipToEnd();
 | 
						|
 | 
						|
        concepts::Requirement *Req = nullptr;
 | 
						|
        SourceLocation NoexceptLoc;
 | 
						|
        TryConsumeToken(tok::kw_noexcept, NoexceptLoc);
 | 
						|
        if (Tok.is(tok::semi)) {
 | 
						|
          Req = Actions.ActOnCompoundRequirement(Expression.get(), NoexceptLoc);
 | 
						|
          if (Req)
 | 
						|
            Requirements.push_back(Req);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        if (!TryConsumeToken(tok::arrow))
 | 
						|
          // User probably forgot the arrow, remind them and try to continue.
 | 
						|
          Diag(Tok, diag::err_requires_expr_missing_arrow)
 | 
						|
              << FixItHint::CreateInsertion(Tok.getLocation(), "->");
 | 
						|
        // Try to parse a 'type-constraint'
 | 
						|
        if (TryAnnotateTypeConstraint()) {
 | 
						|
          SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        if (!isTypeConstraintAnnotation()) {
 | 
						|
          Diag(Tok, diag::err_requires_expr_expected_type_constraint);
 | 
						|
          SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        CXXScopeSpec SS;
 | 
						|
        if (Tok.is(tok::annot_cxxscope)) {
 | 
						|
          Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
 | 
						|
                                                       Tok.getAnnotationRange(),
 | 
						|
                                                       SS);
 | 
						|
          ConsumeAnnotationToken();
 | 
						|
        }
 | 
						|
 | 
						|
        Req = Actions.ActOnCompoundRequirement(
 | 
						|
            Expression.get(), NoexceptLoc, SS, takeTemplateIdAnnotation(Tok),
 | 
						|
            TemplateParameterDepth);
 | 
						|
        ConsumeAnnotationToken();
 | 
						|
        if (Req)
 | 
						|
          Requirements.push_back(Req);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      default: {
 | 
						|
        bool PossibleRequiresExprInSimpleRequirement = false;
 | 
						|
        if (Tok.is(tok::kw_requires)) {
 | 
						|
          auto IsNestedRequirement = [&] {
 | 
						|
            RevertingTentativeParsingAction TPA(*this);
 | 
						|
            ConsumeToken(); // 'requires'
 | 
						|
            if (Tok.is(tok::l_brace))
 | 
						|
              // This is a requires expression
 | 
						|
              // requires (T t) {
 | 
						|
              //   requires { t++; };
 | 
						|
              //   ...      ^
 | 
						|
              // }
 | 
						|
              return false;
 | 
						|
            if (Tok.is(tok::l_paren)) {
 | 
						|
              // This might be the parameter list of a requires expression
 | 
						|
              ConsumeParen();
 | 
						|
              auto Res = TryParseParameterDeclarationClause();
 | 
						|
              if (Res != TPResult::False) {
 | 
						|
                // Skip to the closing parenthesis
 | 
						|
                // FIXME: Don't traverse these tokens twice (here and in
 | 
						|
                //  TryParseParameterDeclarationClause).
 | 
						|
                unsigned Depth = 1;
 | 
						|
                while (Depth != 0) {
 | 
						|
                  if (Tok.is(tok::l_paren))
 | 
						|
                    Depth++;
 | 
						|
                  else if (Tok.is(tok::r_paren))
 | 
						|
                    Depth--;
 | 
						|
                  ConsumeAnyToken();
 | 
						|
                }
 | 
						|
                // requires (T t) {
 | 
						|
                //   requires () ?
 | 
						|
                //   ...         ^
 | 
						|
                //   - OR -
 | 
						|
                //   requires (int x) ?
 | 
						|
                //   ...              ^
 | 
						|
                // }
 | 
						|
                if (Tok.is(tok::l_brace))
 | 
						|
                  // requires (...) {
 | 
						|
                  //                ^ - a requires expression as a
 | 
						|
                  //                    simple-requirement.
 | 
						|
                  return false;
 | 
						|
              }
 | 
						|
            }
 | 
						|
            return true;
 | 
						|
          };
 | 
						|
          if (IsNestedRequirement()) {
 | 
						|
            ConsumeToken();
 | 
						|
            // Nested requirement
 | 
						|
            // C++ [expr.prim.req.nested]
 | 
						|
            //     nested-requirement:
 | 
						|
            //         'requires' constraint-expression ';'
 | 
						|
            ExprResult ConstraintExpr =
 | 
						|
                Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression());
 | 
						|
            if (ConstraintExpr.isInvalid() || !ConstraintExpr.isUsable()) {
 | 
						|
              SkipUntil(tok::semi, tok::r_brace,
 | 
						|
                        SkipUntilFlags::StopBeforeMatch);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
            if (auto *Req =
 | 
						|
                    Actions.ActOnNestedRequirement(ConstraintExpr.get()))
 | 
						|
              Requirements.push_back(Req);
 | 
						|
            else {
 | 
						|
              SkipUntil(tok::semi, tok::r_brace,
 | 
						|
                        SkipUntilFlags::StopBeforeMatch);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
            break;
 | 
						|
          } else
 | 
						|
            PossibleRequiresExprInSimpleRequirement = true;
 | 
						|
        } else if (Tok.is(tok::kw_typename)) {
 | 
						|
          // This might be 'typename T::value_type;' (a type requirement) or
 | 
						|
          // 'typename T::value_type{};' (a simple requirement).
 | 
						|
          TentativeParsingAction TPA(*this);
 | 
						|
 | 
						|
          // We need to consume the typename to allow 'requires { typename a; }'
 | 
						|
          SourceLocation TypenameKWLoc = ConsumeToken();
 | 
						|
          if (TryAnnotateCXXScopeToken()) {
 | 
						|
            TPA.Commit();
 | 
						|
            SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
 | 
						|
            break;
 | 
						|
          }
 | 
						|
          CXXScopeSpec SS;
 | 
						|
          if (Tok.is(tok::annot_cxxscope)) {
 | 
						|
            Actions.RestoreNestedNameSpecifierAnnotation(
 | 
						|
                Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS);
 | 
						|
            ConsumeAnnotationToken();
 | 
						|
          }
 | 
						|
 | 
						|
          if (Tok.isOneOf(tok::identifier, tok::annot_template_id) &&
 | 
						|
              !NextToken().isOneOf(tok::l_brace, tok::l_paren)) {
 | 
						|
            TPA.Commit();
 | 
						|
            SourceLocation NameLoc = Tok.getLocation();
 | 
						|
            IdentifierInfo *II = nullptr;
 | 
						|
            TemplateIdAnnotation *TemplateId = nullptr;
 | 
						|
            if (Tok.is(tok::identifier)) {
 | 
						|
              II = Tok.getIdentifierInfo();
 | 
						|
              ConsumeToken();
 | 
						|
            } else {
 | 
						|
              TemplateId = takeTemplateIdAnnotation(Tok);
 | 
						|
              ConsumeAnnotationToken();
 | 
						|
            }
 | 
						|
 | 
						|
            if (auto *Req = Actions.ActOnTypeRequirement(TypenameKWLoc, SS,
 | 
						|
                                                         NameLoc, II,
 | 
						|
                                                         TemplateId)) {
 | 
						|
              Requirements.push_back(Req);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
          }
 | 
						|
          TPA.Revert();
 | 
						|
        }
 | 
						|
        // Simple requirement
 | 
						|
        // C++ [expr.prim.req.simple]
 | 
						|
        //     simple-requirement:
 | 
						|
        //         expression ';'
 | 
						|
        SourceLocation StartLoc = Tok.getLocation();
 | 
						|
        ExprResult Expression =
 | 
						|
            Actions.CorrectDelayedTyposInExpr(ParseExpression());
 | 
						|
        if (!Expression.isUsable()) {
 | 
						|
          SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        if (!Expression.isInvalid() && PossibleRequiresExprInSimpleRequirement)
 | 
						|
          Diag(StartLoc, diag::warn_requires_expr_in_simple_requirement)
 | 
						|
              << FixItHint::CreateInsertion(StartLoc, "requires");
 | 
						|
        if (auto *Req = Actions.ActOnSimpleRequirement(Expression.get()))
 | 
						|
          Requirements.push_back(Req);
 | 
						|
        else {
 | 
						|
          SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        // User may have tried to put some compound requirement stuff here
 | 
						|
        if (Tok.is(tok::kw_noexcept)) {
 | 
						|
          Diag(Tok, diag::err_requires_expr_simple_requirement_noexcept)
 | 
						|
              << FixItHint::CreateInsertion(StartLoc, "{")
 | 
						|
              << FixItHint::CreateInsertion(Tok.getLocation(), "}");
 | 
						|
          SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      }
 | 
						|
      if (ExpectAndConsumeSemi(diag::err_expected_semi_requirement)) {
 | 
						|
        SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
 | 
						|
        TryConsumeToken(tok::semi);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (Requirements.empty()) {
 | 
						|
      // Don't emit an empty requires expr here to avoid confusing the user with
 | 
						|
      // other diagnostics quoting an empty requires expression they never
 | 
						|
      // wrote.
 | 
						|
      Braces.consumeClose();
 | 
						|
      Actions.ActOnFinishRequiresExpr();
 | 
						|
      return ExprError();
 | 
						|
    }
 | 
						|
  }
 | 
						|
  Braces.consumeClose();
 | 
						|
  Actions.ActOnFinishRequiresExpr();
 | 
						|
  return Actions.ActOnRequiresExpr(RequiresKWLoc, Body, LocalParameterDecls,
 | 
						|
                                   Requirements, Braces.getCloseLocation());
 | 
						|
}
 | 
						|
 | 
						|
static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) {
 | 
						|
  switch (kind) {
 | 
						|
  default: llvm_unreachable("Not a known type trait");
 | 
						|
#define TYPE_TRAIT_1(Spelling, Name, Key) \
 | 
						|
case tok::kw_ ## Spelling: return UTT_ ## Name;
 | 
						|
#define TYPE_TRAIT_2(Spelling, Name, Key) \
 | 
						|
case tok::kw_ ## Spelling: return BTT_ ## Name;
 | 
						|
#include "clang/Basic/TokenKinds.def"
 | 
						|
#define TYPE_TRAIT_N(Spelling, Name, Key) \
 | 
						|
  case tok::kw_ ## Spelling: return TT_ ## Name;
 | 
						|
#include "clang/Basic/TokenKinds.def"
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static ArrayTypeTrait ArrayTypeTraitFromTokKind(tok::TokenKind kind) {
 | 
						|
  switch(kind) {
 | 
						|
  default: llvm_unreachable("Not a known binary type trait");
 | 
						|
  case tok::kw___array_rank:                 return ATT_ArrayRank;
 | 
						|
  case tok::kw___array_extent:               return ATT_ArrayExtent;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) {
 | 
						|
  switch(kind) {
 | 
						|
  default: llvm_unreachable("Not a known unary expression trait.");
 | 
						|
  case tok::kw___is_lvalue_expr:             return ET_IsLValueExpr;
 | 
						|
  case tok::kw___is_rvalue_expr:             return ET_IsRValueExpr;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static unsigned TypeTraitArity(tok::TokenKind kind) {
 | 
						|
  switch (kind) {
 | 
						|
    default: llvm_unreachable("Not a known type trait");
 | 
						|
#define TYPE_TRAIT(N,Spelling,K) case tok::kw_##Spelling: return N;
 | 
						|
#include "clang/Basic/TokenKinds.def"
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/// Parse the built-in type-trait pseudo-functions that allow
 | 
						|
/// implementation of the TR1/C++11 type traits templates.
 | 
						|
///
 | 
						|
///       primary-expression:
 | 
						|
///          unary-type-trait '(' type-id ')'
 | 
						|
///          binary-type-trait '(' type-id ',' type-id ')'
 | 
						|
///          type-trait '(' type-id-seq ')'
 | 
						|
///
 | 
						|
///       type-id-seq:
 | 
						|
///          type-id ...[opt] type-id-seq[opt]
 | 
						|
///
 | 
						|
ExprResult Parser::ParseTypeTrait() {
 | 
						|
  tok::TokenKind Kind = Tok.getKind();
 | 
						|
  unsigned Arity = TypeTraitArity(Kind);
 | 
						|
 | 
						|
  SourceLocation Loc = ConsumeToken();
 | 
						|
 | 
						|
  BalancedDelimiterTracker Parens(*this, tok::l_paren);
 | 
						|
  if (Parens.expectAndConsume())
 | 
						|
    return ExprError();
 | 
						|
 | 
						|
  SmallVector<ParsedType, 2> Args;
 | 
						|
  do {
 | 
						|
    // Parse the next type.
 | 
						|
    TypeResult Ty = ParseTypeName();
 | 
						|
    if (Ty.isInvalid()) {
 | 
						|
      Parens.skipToEnd();
 | 
						|
      return ExprError();
 | 
						|
    }
 | 
						|
 | 
						|
    // Parse the ellipsis, if present.
 | 
						|
    if (Tok.is(tok::ellipsis)) {
 | 
						|
      Ty = Actions.ActOnPackExpansion(Ty.get(), ConsumeToken());
 | 
						|
      if (Ty.isInvalid()) {
 | 
						|
        Parens.skipToEnd();
 | 
						|
        return ExprError();
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // Add this type to the list of arguments.
 | 
						|
    Args.push_back(Ty.get());
 | 
						|
  } while (TryConsumeToken(tok::comma));
 | 
						|
 | 
						|
  if (Parens.consumeClose())
 | 
						|
    return ExprError();
 | 
						|
 | 
						|
  SourceLocation EndLoc = Parens.getCloseLocation();
 | 
						|
 | 
						|
  if (Arity && Args.size() != Arity) {
 | 
						|
    Diag(EndLoc, diag::err_type_trait_arity)
 | 
						|
      << Arity << 0 << (Arity > 1) << (int)Args.size() << SourceRange(Loc);
 | 
						|
    return ExprError();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!Arity && Args.empty()) {
 | 
						|
    Diag(EndLoc, diag::err_type_trait_arity)
 | 
						|
      << 1 << 1 << 1 << (int)Args.size() << SourceRange(Loc);
 | 
						|
    return ExprError();
 | 
						|
  }
 | 
						|
 | 
						|
  return Actions.ActOnTypeTrait(TypeTraitFromTokKind(Kind), Loc, Args, EndLoc);
 | 
						|
}
 | 
						|
 | 
						|
/// ParseArrayTypeTrait - Parse the built-in array type-trait
 | 
						|
/// pseudo-functions.
 | 
						|
///
 | 
						|
///       primary-expression:
 | 
						|
/// [Embarcadero]     '__array_rank' '(' type-id ')'
 | 
						|
/// [Embarcadero]     '__array_extent' '(' type-id ',' expression ')'
 | 
						|
///
 | 
						|
ExprResult Parser::ParseArrayTypeTrait() {
 | 
						|
  ArrayTypeTrait ATT = ArrayTypeTraitFromTokKind(Tok.getKind());
 | 
						|
  SourceLocation Loc = ConsumeToken();
 | 
						|
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren);
 | 
						|
  if (T.expectAndConsume())
 | 
						|
    return ExprError();
 | 
						|
 | 
						|
  TypeResult Ty = ParseTypeName();
 | 
						|
  if (Ty.isInvalid()) {
 | 
						|
    SkipUntil(tok::comma, StopAtSemi);
 | 
						|
    SkipUntil(tok::r_paren, StopAtSemi);
 | 
						|
    return ExprError();
 | 
						|
  }
 | 
						|
 | 
						|
  switch (ATT) {
 | 
						|
  case ATT_ArrayRank: {
 | 
						|
    T.consumeClose();
 | 
						|
    return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), nullptr,
 | 
						|
                                       T.getCloseLocation());
 | 
						|
  }
 | 
						|
  case ATT_ArrayExtent: {
 | 
						|
    if (ExpectAndConsume(tok::comma)) {
 | 
						|
      SkipUntil(tok::r_paren, StopAtSemi);
 | 
						|
      return ExprError();
 | 
						|
    }
 | 
						|
 | 
						|
    ExprResult DimExpr = ParseExpression();
 | 
						|
    T.consumeClose();
 | 
						|
 | 
						|
    return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(),
 | 
						|
                                       T.getCloseLocation());
 | 
						|
  }
 | 
						|
  }
 | 
						|
  llvm_unreachable("Invalid ArrayTypeTrait!");
 | 
						|
}
 | 
						|
 | 
						|
/// ParseExpressionTrait - Parse built-in expression-trait
 | 
						|
/// pseudo-functions like __is_lvalue_expr( xxx ).
 | 
						|
///
 | 
						|
///       primary-expression:
 | 
						|
/// [Embarcadero]     expression-trait '(' expression ')'
 | 
						|
///
 | 
						|
ExprResult Parser::ParseExpressionTrait() {
 | 
						|
  ExpressionTrait ET = ExpressionTraitFromTokKind(Tok.getKind());
 | 
						|
  SourceLocation Loc = ConsumeToken();
 | 
						|
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren);
 | 
						|
  if (T.expectAndConsume())
 | 
						|
    return ExprError();
 | 
						|
 | 
						|
  ExprResult Expr = ParseExpression();
 | 
						|
 | 
						|
  T.consumeClose();
 | 
						|
 | 
						|
  return Actions.ActOnExpressionTrait(ET, Loc, Expr.get(),
 | 
						|
                                      T.getCloseLocation());
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a
 | 
						|
/// parenthesized ambiguous type-id. This uses tentative parsing to disambiguate
 | 
						|
/// based on the context past the parens.
 | 
						|
ExprResult
 | 
						|
Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
 | 
						|
                                         ParsedType &CastTy,
 | 
						|
                                         BalancedDelimiterTracker &Tracker,
 | 
						|
                                         ColonProtectionRAIIObject &ColonProt) {
 | 
						|
  assert(getLangOpts().CPlusPlus && "Should only be called for C++!");
 | 
						|
  assert(ExprType == CastExpr && "Compound literals are not ambiguous!");
 | 
						|
  assert(isTypeIdInParens() && "Not a type-id!");
 | 
						|
 | 
						|
  ExprResult Result(true);
 | 
						|
  CastTy = nullptr;
 | 
						|
 | 
						|
  // We need to disambiguate a very ugly part of the C++ syntax:
 | 
						|
  //
 | 
						|
  // (T())x;  - type-id
 | 
						|
  // (T())*x; - type-id
 | 
						|
  // (T())/x; - expression
 | 
						|
  // (T());   - expression
 | 
						|
  //
 | 
						|
  // The bad news is that we cannot use the specialized tentative parser, since
 | 
						|
  // it can only verify that the thing inside the parens can be parsed as
 | 
						|
  // type-id, it is not useful for determining the context past the parens.
 | 
						|
  //
 | 
						|
  // The good news is that the parser can disambiguate this part without
 | 
						|
  // making any unnecessary Action calls.
 | 
						|
  //
 | 
						|
  // It uses a scheme similar to parsing inline methods. The parenthesized
 | 
						|
  // tokens are cached, the context that follows is determined (possibly by
 | 
						|
  // parsing a cast-expression), and then we re-introduce the cached tokens
 | 
						|
  // into the token stream and parse them appropriately.
 | 
						|
 | 
						|
  ParenParseOption ParseAs;
 | 
						|
  CachedTokens Toks;
 | 
						|
 | 
						|
  // Store the tokens of the parentheses. We will parse them after we determine
 | 
						|
  // the context that follows them.
 | 
						|
  if (!ConsumeAndStoreUntil(tok::r_paren, Toks)) {
 | 
						|
    // We didn't find the ')' we expected.
 | 
						|
    Tracker.consumeClose();
 | 
						|
    return ExprError();
 | 
						|
  }
 | 
						|
 | 
						|
  if (Tok.is(tok::l_brace)) {
 | 
						|
    ParseAs = CompoundLiteral;
 | 
						|
  } else {
 | 
						|
    bool NotCastExpr;
 | 
						|
    if (Tok.is(tok::l_paren) && NextToken().is(tok::r_paren)) {
 | 
						|
      NotCastExpr = true;
 | 
						|
    } else {
 | 
						|
      // Try parsing the cast-expression that may follow.
 | 
						|
      // If it is not a cast-expression, NotCastExpr will be true and no token
 | 
						|
      // will be consumed.
 | 
						|
      ColonProt.restore();
 | 
						|
      Result = ParseCastExpression(AnyCastExpr,
 | 
						|
                                   false/*isAddressofOperand*/,
 | 
						|
                                   NotCastExpr,
 | 
						|
                                   // type-id has priority.
 | 
						|
                                   IsTypeCast);
 | 
						|
    }
 | 
						|
 | 
						|
    // If we parsed a cast-expression, it's really a type-id, otherwise it's
 | 
						|
    // an expression.
 | 
						|
    ParseAs = NotCastExpr ? SimpleExpr : CastExpr;
 | 
						|
  }
 | 
						|
 | 
						|
  // Create a fake EOF to mark end of Toks buffer.
 | 
						|
  Token AttrEnd;
 | 
						|
  AttrEnd.startToken();
 | 
						|
  AttrEnd.setKind(tok::eof);
 | 
						|
  AttrEnd.setLocation(Tok.getLocation());
 | 
						|
  AttrEnd.setEofData(Toks.data());
 | 
						|
  Toks.push_back(AttrEnd);
 | 
						|
 | 
						|
  // The current token should go after the cached tokens.
 | 
						|
  Toks.push_back(Tok);
 | 
						|
  // Re-enter the stored parenthesized tokens into the token stream, so we may
 | 
						|
  // parse them now.
 | 
						|
  PP.EnterTokenStream(Toks, /*DisableMacroExpansion*/ true,
 | 
						|
                      /*IsReinject*/ true);
 | 
						|
  // Drop the current token and bring the first cached one. It's the same token
 | 
						|
  // as when we entered this function.
 | 
						|
  ConsumeAnyToken();
 | 
						|
 | 
						|
  if (ParseAs >= CompoundLiteral) {
 | 
						|
    // Parse the type declarator.
 | 
						|
    DeclSpec DS(AttrFactory);
 | 
						|
    Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext);
 | 
						|
    {
 | 
						|
      ColonProtectionRAIIObject InnerColonProtection(*this);
 | 
						|
      ParseSpecifierQualifierList(DS);
 | 
						|
      ParseDeclarator(DeclaratorInfo);
 | 
						|
    }
 | 
						|
 | 
						|
    // Match the ')'.
 | 
						|
    Tracker.consumeClose();
 | 
						|
    ColonProt.restore();
 | 
						|
 | 
						|
    // Consume EOF marker for Toks buffer.
 | 
						|
    assert(Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData());
 | 
						|
    ConsumeAnyToken();
 | 
						|
 | 
						|
    if (ParseAs == CompoundLiteral) {
 | 
						|
      ExprType = CompoundLiteral;
 | 
						|
      if (DeclaratorInfo.isInvalidType())
 | 
						|
        return ExprError();
 | 
						|
 | 
						|
      TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
 | 
						|
      return ParseCompoundLiteralExpression(Ty.get(),
 | 
						|
                                            Tracker.getOpenLocation(),
 | 
						|
                                            Tracker.getCloseLocation());
 | 
						|
    }
 | 
						|
 | 
						|
    // We parsed '(' type-id ')' and the thing after it wasn't a '{'.
 | 
						|
    assert(ParseAs == CastExpr);
 | 
						|
 | 
						|
    if (DeclaratorInfo.isInvalidType())
 | 
						|
      return ExprError();
 | 
						|
 | 
						|
    // Result is what ParseCastExpression returned earlier.
 | 
						|
    if (!Result.isInvalid())
 | 
						|
      Result = Actions.ActOnCastExpr(getCurScope(), Tracker.getOpenLocation(),
 | 
						|
                                    DeclaratorInfo, CastTy,
 | 
						|
                                    Tracker.getCloseLocation(), Result.get());
 | 
						|
    return Result;
 | 
						|
  }
 | 
						|
 | 
						|
  // Not a compound literal, and not followed by a cast-expression.
 | 
						|
  assert(ParseAs == SimpleExpr);
 | 
						|
 | 
						|
  ExprType = SimpleExpr;
 | 
						|
  Result = ParseExpression();
 | 
						|
  if (!Result.isInvalid() && Tok.is(tok::r_paren))
 | 
						|
    Result = Actions.ActOnParenExpr(Tracker.getOpenLocation(),
 | 
						|
                                    Tok.getLocation(), Result.get());
 | 
						|
 | 
						|
  // Match the ')'.
 | 
						|
  if (Result.isInvalid()) {
 | 
						|
    while (Tok.isNot(tok::eof))
 | 
						|
      ConsumeAnyToken();
 | 
						|
    assert(Tok.getEofData() == AttrEnd.getEofData());
 | 
						|
    ConsumeAnyToken();
 | 
						|
    return ExprError();
 | 
						|
  }
 | 
						|
 | 
						|
  Tracker.consumeClose();
 | 
						|
  // Consume EOF marker for Toks buffer.
 | 
						|
  assert(Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData());
 | 
						|
  ConsumeAnyToken();
 | 
						|
  return Result;
 | 
						|
}
 | 
						|
 | 
						|
/// Parse a __builtin_bit_cast(T, E).
 | 
						|
ExprResult Parser::ParseBuiltinBitCast() {
 | 
						|
  SourceLocation KWLoc = ConsumeToken();
 | 
						|
 | 
						|
  BalancedDelimiterTracker T(*this, tok::l_paren);
 | 
						|
  if (T.expectAndConsume(diag::err_expected_lparen_after, "__builtin_bit_cast"))
 | 
						|
    return ExprError();
 | 
						|
 | 
						|
  // Parse the common declaration-specifiers piece.
 | 
						|
  DeclSpec DS(AttrFactory);
 | 
						|
  ParseSpecifierQualifierList(DS);
 | 
						|
 | 
						|
  // Parse the abstract-declarator, if present.
 | 
						|
  Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext);
 | 
						|
  ParseDeclarator(DeclaratorInfo);
 | 
						|
 | 
						|
  if (ExpectAndConsume(tok::comma)) {
 | 
						|
    Diag(Tok.getLocation(), diag::err_expected) << tok::comma;
 | 
						|
    SkipUntil(tok::r_paren, StopAtSemi);
 | 
						|
    return ExprError();
 | 
						|
  }
 | 
						|
 | 
						|
  ExprResult Operand = ParseExpression();
 | 
						|
 | 
						|
  if (T.consumeClose())
 | 
						|
    return ExprError();
 | 
						|
 | 
						|
  if (Operand.isInvalid() || DeclaratorInfo.isInvalidType())
 | 
						|
    return ExprError();
 | 
						|
 | 
						|
  return Actions.ActOnBuiltinBitCastExpr(KWLoc, DeclaratorInfo, Operand,
 | 
						|
                                         T.getCloseLocation());
 | 
						|
}
 |