diff options
Diffstat (limited to 'clang/lib/Parse/ParseExprCXX.cpp')
| -rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 3588 |
1 files changed, 3588 insertions, 0 deletions
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp new file mode 100644 index 0000000000000..a064e4b175877 --- /dev/null +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -0,0 +1,3588 @@ +//===--- 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/DeclTemplate.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) { + 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; + } + + if (Tok.is(tok::annot_template_id)) { + // If the current token is an annotated template id, it may already have + // a scope specifier. Restore it. + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + SS = TemplateId->SS; + } + + // 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, + 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) && + !Actions.isNonTypeNestedNameSpecifier(getCurScope(), SS, IdInfo)) { + *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. + 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 && 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, 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); + + 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(); + } + + PrototypeScope.Exit(); + + WarnIfHasCUDATargetAttr(); + + 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), + std::move(Attr), DeclEndLoc); + } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute, + tok::kw_constexpr, tok::kw_consteval) || + (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) { + // It's common to forget that one needs '()' before 'mutable', an attribute + // specifier, or the result type. 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::l_square: TokKind = 2; break; + case tok::kw_constexpr: TokKind = 3; break; + case tok::kw_consteval: TokKind = 4; 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(); + } + + WarnIfHasCUDATargetAttr(); + + 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); + } + + // 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. +/// +/// postfix-expression: [C++ 5.2] +/// postfix-expression . pseudo-destructor-name +/// postfix-expression -> pseudo-destructor-name +/// +/// pseudo-destructor-name: +/// ::[opt] nested-name-specifier[opt] type-name :: ~type-name +/// ::[opt] nested-name-specifier template simple-template-id :: +/// ~type-name +/// ::[opt] nested-name-specifier[opt] ~type-name +/// +ExprResult +Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + ParsedType ObjectType) { + // We're parsing either a pseudo-destructor-name or a dependent + // member access that has the same form as a + // pseudo-destructor-name. We parse both in the same way and let + // the action model sort them out. + // + // Note that the ::[opt] nested-name-specifier[opt] has already + // been parsed, and if there was a simple-template-id, it has + // been coalesced into a template-id annotation token. + 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)) { + // FIXME: retrieve TemplateKWLoc from template-id annotation and + // store it in the pseudo-dtor node (to be used when instantiating it). + FirstTypeName.setTemplateId( + (TemplateIdAnnotation *)Tok.getAnnotationValue()); + ConsumeAnnotationToken(); + assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail"); + CCLoc = ConsumeToken(); + } else { + 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() && SS.isEmpty()) { + 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)) { + 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 = 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(&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 = 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( + SS, 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(); + 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(false)); + if (Operand.isInvalid()) + return Operand; + + return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.get()); +} + +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(false/*isUnaryExpression*/, + 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()); +} |
