llvm/clang/lib/Parse/ParseExprCXX.cpp

//===--- 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() {}