//===--- 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/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TokenKinds.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaCodeCompletion.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include <numeric> usingnamespaceclang; static int SelectDigraphErrorMessage(tok::TokenKind Kind) { … } // Are the two tokens adjacent in the same source file? bool Parser::areTokensAdjacent(const Token &First, const Token &Second) { … } // Suggest fixit for "<::" after a cast. static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken, Token &ColonToken, tok::TokenKind Kind, bool AtDigraph) { … } // 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) { … } /// 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 ObjectHadErrors if this unqualified-id occurs within a member access /// expression, indicates whether the original subexpressions had any errors. /// When true, diagnostics for missing 'template' keyword will be supressed. /// /// \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. Moreover, /// 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 ObjectHadErrors, bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename, const IdentifierInfo **LastII, bool OnlyNamespace, bool InUsingDeclaration, bool Disambiguation) { … } ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand, Token &Replacement) { … } ExprResult Parser::ParseCXXPackIndexingExpression(ExprResult PackIdExpression) { … } ExprResult Parser::tryParseCXXPackIndexingExpression(ExprResult PackIdExpression) { … } /// 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) { … } /// ParseLambdaExpression - Parse a C++11 lambda expression. /// /// lambda-expression: /// lambda-introducer lambda-declarator compound-statement /// lambda-introducer '<' template-parameter-list '>' /// requires-clause[opt] lambda-declarator 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: /// lambda-specifiers [C++23] /// '(' parameter-declaration-clause ')' lambda-specifiers /// requires-clause[opt] /// /// lambda-specifiers: /// decl-specifier-seq[opt] noexcept-specifier[opt] /// attribute-specifier-seq[opt] trailing-return-type[opt] /// ExprResult Parser::ParseLambdaExpression() { … } /// 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() { … } /// 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) { … } static void tryConsumeLambdaSpecifierToken(Parser &P, SourceLocation &MutableLoc, SourceLocation &StaticLoc, SourceLocation &ConstexprLoc, SourceLocation &ConstevalLoc, SourceLocation &DeclEndLoc) { … } static void addStaticToLambdaDeclSpecifier(Parser &P, SourceLocation StaticLoc, DeclSpec &DS) { … } static void addConstexprToLambdaDeclSpecifier(Parser &P, SourceLocation ConstexprLoc, DeclSpec &DS) { … } static void addConstevalToLambdaDeclSpecifier(Parser &P, SourceLocation ConstevalLoc, DeclSpec &DS) { … } static void DiagnoseStaticSpecifierRestrictions(Parser &P, SourceLocation StaticLoc, SourceLocation MutableLoc, const LambdaIntroducer &Intro) { … } /// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda /// expression. ExprResult Parser::ParseLambdaExpressionAfterIntroducer( LambdaIntroducer &Intro) { … } /// 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 ')' /// /// C++ for OpenCL s2.3.1 adds: /// 'addrspace_cast' '<' type-name '>' '(' expression ')' ExprResult Parser::ParseCXXCasts() { … } /// ParseCXXTypeid - This handles the C++ typeid expression. /// /// postfix-expression: [C++ 5.2p1] /// 'typeid' '(' expression ')' /// 'typeid' '(' type-id ')' /// ExprResult Parser::ParseCXXTypeid() { … } /// ParseCXXUuidof - This handles the Microsoft C++ __uuidof expression. /// /// '__uuidof' '(' expression ')' /// '__uuidof' '(' type-id ')' /// ExprResult Parser::ParseCXXUuidof() { … } /// Parse a C++ pseudo-destructor expression after the base, /// . or -> operator, and nested-name-specifier have already been /// parsed. We're handling this fragment of the grammar: /// /// postfix-expression: [C++2a expr.post] /// postfix-expression . template[opt] id-expression /// postfix-expression -> template[opt] id-expression /// /// id-expression: /// qualified-id /// unqualified-id /// /// qualified-id: /// nested-name-specifier template[opt] unqualified-id /// /// nested-name-specifier: /// type-name :: /// decltype-specifier :: FIXME: not implemented, but probably only /// allowed in C++ grammar by accident /// nested-name-specifier identifier :: /// nested-name-specifier template[opt] simple-template-id :: /// [...] /// /// unqualified-id: /// ~ type-name /// ~ decltype-specifier /// [...] /// /// ... where the all but the last component of the nested-name-specifier /// has already been parsed, and the base expression is not of a non-dependent /// class type. ExprResult Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, ParsedType ObjectType) { … } /// ParseCXXBoolLiteral - This handles the C++ Boolean literals. /// /// boolean-literal: [C++ 2.13.5] /// 'true' /// 'false' ExprResult Parser::ParseCXXBoolLiteral() { … } /// ParseThrowExpression - This handles the C++ throw expression. /// /// throw-expression: [C++ 15] /// 'throw' assignment-expression[opt] ExprResult Parser::ParseThrowExpression() { … } /// Parse the C++ Coroutines co_yield expression. /// /// co_yield-expression: /// 'co_yield' assignment-expression[opt] ExprResult Parser::ParseCoyieldExpression() { … } /// 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() { … } /// 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) { … } Parser::DeclGroupPtrTy Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context, ParsedAttributes &Attrs) { … } /// 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 MissingOK Whether an empty condition is acceptable here. Otherwise /// it is considered an error to be recovered from. /// /// \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. /// /// \param EnterForConditionScope If true, enter a continue/break scope at the /// appropriate moment for a 'for' loop. /// /// \returns The parsed condition. Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, Sema::ConditionKind CK, bool MissingOK, ForRangeInfo *FRI, bool EnterForConditionScope) { … } /// 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) { … } /// 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, DeclaratorContext Context) { … } /// 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 ObjectType if this unqualified-id occurs within a member access /// expression, the type of the base object whose member is being accessed. /// /// \param ObjectHadErrors this unqualified-id occurs within a member access /// expression, indicates whether the original subexpressions had any errors. /// /// \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 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, ParsedType ObjectType, bool ObjectHadErrors, SourceLocation TemplateKWLoc, IdentifierInfo *Name, SourceLocation NameLoc, bool EnteringContext, UnqualifiedId &Id, bool AssumeTemplateId) { … } /// 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) { … } /// 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 ObjectType if this unqualified-id occurs within a member access /// expression, the type of the base object whose member is being accessed. /// /// \param ObjectHadErrors if this unqualified-id occurs within a member access /// expression, indicates whether the original subexpressions had any errors. /// When true, diagnostics for missing 'template' keyword will be supressed. /// /// \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 Result on a successful parse, contains the parsed unqualified-id. /// /// \returns true if parsing fails, false otherwise. bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors, bool EnteringContext, bool AllowDestructorName, bool AllowConstructorName, bool AllowDeductionGuide, SourceLocation *TemplateKWLoc, UnqualifiedId &Result) { … } /// 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) { … } /// 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) { … } /// 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) { … } /// 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) { … } /// ParseRequiresExpression - Parse a C++2a requires-expression. /// C++2a [expr.prim.req]p1 /// A requires-expression provides a concise way to express requirements on /// template arguments. A requirement is one that can be checked by name /// lookup (6.4) or by checking properties of types and expressions. /// /// requires-expression: /// 'requires' requirement-parameter-list[opt] requirement-body /// /// requirement-parameter-list: /// '(' parameter-declaration-clause[opt] ')' /// /// requirement-body: /// '{' requirement-seq '}' /// /// requirement-seq: /// requirement /// requirement-seq requirement /// /// requirement: /// simple-requirement /// type-requirement /// compound-requirement /// nested-requirement ExprResult Parser::ParseRequiresExpression() { … } static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) { … } static ArrayTypeTrait ArrayTypeTraitFromTokKind(tok::TokenKind kind) { … } static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) { … } /// 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() { … } /// 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() { … } /// ParseExpressionTrait - Parse built-in expression-trait /// pseudo-functions like __is_lvalue_expr( xxx ). /// /// primary-expression: /// [Embarcadero] expression-trait '(' expression ')' /// ExprResult Parser::ParseExpressionTrait() { … } /// 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) { … } /// Parse a __builtin_bit_cast(T, E). ExprResult Parser::ParseBuiltinBitCast() { … }