//===--- ParseDeclCXX.cpp - C++ Declaration Parsing -------------*- C++ -*-===// // // 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 C++ Declaration portions of the Parser interfaces. // //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/PrettyDeclStackTrace.h" #include "clang/Basic/AttributeCommonInfo.h" #include "clang/Basic/Attributes.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/TargetInfo.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/ADT/SmallString.h" #include "llvm/Support/TimeProfiler.h" #include <optional> usingnamespaceclang; /// ParseNamespace - We know that the current token is a namespace keyword. This /// may either be a top level namespace or a block-level namespace alias. If /// there was an inline keyword, it has already been parsed. /// /// namespace-definition: [C++: namespace.def] /// named-namespace-definition /// unnamed-namespace-definition /// nested-namespace-definition /// /// named-namespace-definition: /// 'inline'[opt] 'namespace' attributes[opt] identifier '{' /// namespace-body '}' /// /// unnamed-namespace-definition: /// 'inline'[opt] 'namespace' attributes[opt] '{' namespace-body '}' /// /// nested-namespace-definition: /// 'namespace' enclosing-namespace-specifier '::' 'inline'[opt] /// identifier '{' namespace-body '}' /// /// enclosing-namespace-specifier: /// identifier /// enclosing-namespace-specifier '::' 'inline'[opt] identifier /// /// namespace-alias-definition: [C++ 7.3.2: namespace.alias] /// 'namespace' identifier '=' qualified-namespace-specifier ';' /// Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context, SourceLocation &DeclEnd, SourceLocation InlineLoc) { … } /// ParseInnerNamespace - Parse the contents of a namespace. void Parser::ParseInnerNamespace(const InnerNamespaceInfoList &InnerNSs, unsigned int index, SourceLocation &InlineLoc, ParsedAttributes &attrs, BalancedDelimiterTracker &Tracker) { … } /// ParseNamespaceAlias - Parse the part after the '=' in a namespace /// alias definition. /// Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, SourceLocation &DeclEnd) { … } /// ParseLinkage - We know that the current token is a string_literal /// and just before that, that extern was seen. /// /// linkage-specification: [C++ 7.5p2: dcl.link] /// 'extern' string-literal '{' declaration-seq[opt] '}' /// 'extern' string-literal declaration /// Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) { … } /// Parse a standard C++ Modules export-declaration. /// /// export-declaration: /// 'export' declaration /// 'export' '{' declaration-seq[opt] '}' /// /// HLSL: Parse export function declaration. /// /// export-function-declaration: /// 'export' function-declaration /// /// export-declaration-group: /// 'export' '{' function-declaration-seq[opt] '}' /// Decl *Parser::ParseExportDeclaration() { … } /// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or /// using-directive. Assumes that current token is 'using'. Parser::DeclGroupPtrTy Parser::ParseUsingDirectiveOrDeclaration( DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, SourceLocation &DeclEnd, ParsedAttributes &Attrs) { … } /// ParseUsingDirective - Parse C++ using-directive, assumes /// that current token is 'namespace' and 'using' was already parsed. /// /// using-directive: [C++ 7.3.p4: namespace.udir] /// 'using' 'namespace' ::[opt] nested-name-specifier[opt] /// namespace-name ; /// [GNU] using-directive: /// 'using' 'namespace' ::[opt] nested-name-specifier[opt] /// namespace-name attributes[opt] ; /// Decl *Parser::ParseUsingDirective(DeclaratorContext Context, SourceLocation UsingLoc, SourceLocation &DeclEnd, ParsedAttributes &attrs) { … } /// Parse a using-declarator (or the identifier in a C++11 alias-declaration). /// /// using-declarator: /// 'typename'[opt] nested-name-specifier unqualified-id /// bool Parser::ParseUsingDeclarator(DeclaratorContext Context, UsingDeclarator &D) { … } /// ParseUsingDeclaration - Parse C++ using-declaration or alias-declaration. /// Assumes that 'using' was already seen. /// /// using-declaration: [C++ 7.3.p3: namespace.udecl] /// 'using' using-declarator-list[opt] ; /// /// using-declarator-list: [C++1z] /// using-declarator '...'[opt] /// using-declarator-list ',' using-declarator '...'[opt] /// /// using-declarator-list: [C++98-14] /// using-declarator /// /// alias-declaration: C++11 [dcl.dcl]p1 /// 'using' identifier attribute-specifier-seq[opt] = type-id ; /// /// using-enum-declaration: [C++20, dcl.enum] /// 'using' elaborated-enum-specifier ; /// The terminal name of the elaborated-enum-specifier undergoes /// type-only lookup /// /// elaborated-enum-specifier: /// 'enum' nested-name-specifier[opt] identifier Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration( DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, SourceLocation &DeclEnd, ParsedAttributes &PrefixAttrs, AccessSpecifier AS) { … } Decl *Parser::ParseAliasDeclarationAfterDeclarator( const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, UsingDeclarator &D, SourceLocation &DeclEnd, AccessSpecifier AS, ParsedAttributes &Attrs, Decl **OwnedType) { … } static FixItHint getStaticAssertNoMessageFixIt(const Expr *AssertExpr, SourceLocation EndExprLoc) { … } /// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration. /// /// [C++0x] static_assert-declaration: /// static_assert ( constant-expression , string-literal ) ; /// /// [C11] static_assert-declaration: /// _Static_assert ( constant-expression , string-literal ) ; /// Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd) { … } /// ParseDecltypeSpecifier - Parse a C++11 decltype specifier. /// /// 'decltype' ( expression ) /// 'decltype' ( 'auto' ) [C++1y] /// SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { … } void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec &DS, SourceLocation StartLoc, SourceLocation EndLoc) { … } SourceLocation Parser::ParsePackIndexingType(DeclSpec &DS) { … } void Parser::AnnotateExistingIndexedTypeNamePack(ParsedType T, SourceLocation StartLoc, SourceLocation EndLoc) { … } DeclSpec::TST Parser::TypeTransformTokToDeclSpec() { … } bool Parser::MaybeParseTypeTransformTypeSpecifier(DeclSpec &DS) { … } /// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a /// class name or decltype-specifier. Note that we only check that the result /// names a type; semantic analysis will need to verify that the type names a /// class. The result is either a type or null, depending on whether a type /// name was found. /// /// base-type-specifier: [C++11 class.derived] /// class-or-decltype /// class-or-decltype: [C++11 class.derived] /// nested-name-specifier[opt] class-name /// decltype-specifier /// class-name: [C++ class.name] /// identifier /// simple-template-id /// /// In C++98, instead of base-type-specifier, we have: /// /// ::[opt] nested-name-specifier[opt] class-name TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, SourceLocation &EndLocation) { … } void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) { … } void Parser::ParseNullabilityClassAttributes(ParsedAttributes &attrs) { … } /// Determine whether the following tokens are valid after a type-specifier /// which could be a standalone declaration. This will conservatively return /// true if there's any doubt, and is appropriate for insert-';' fixits. bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { … } /// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or /// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which /// until we reach the start of a definition or see a token that /// cannot start a definition. /// /// class-specifier: [C++ class] /// class-head '{' member-specification[opt] '}' /// class-head '{' member-specification[opt] '}' attributes[opt] /// class-head: /// class-key identifier[opt] base-clause[opt] /// class-key nested-name-specifier identifier base-clause[opt] /// class-key nested-name-specifier[opt] simple-template-id /// base-clause[opt] /// [GNU] class-key attributes[opt] identifier[opt] base-clause[opt] /// [GNU] class-key attributes[opt] nested-name-specifier /// identifier base-clause[opt] /// [GNU] class-key attributes[opt] nested-name-specifier[opt] /// simple-template-id base-clause[opt] /// class-key: /// 'class' /// 'struct' /// 'union' /// /// elaborated-type-specifier: [C++ dcl.type.elab] /// class-key ::[opt] nested-name-specifier[opt] identifier /// class-key ::[opt] nested-name-specifier[opt] 'template'[opt] /// simple-template-id /// /// Note that the C++ class-specifier and elaborated-type-specifier, /// together, subsume the C99 struct-or-union-specifier: /// /// struct-or-union-specifier: [C99 6.7.2.1] /// struct-or-union identifier[opt] '{' struct-contents '}' /// struct-or-union identifier /// [GNU] struct-or-union attributes[opt] identifier[opt] '{' struct-contents /// '}' attributes[opt] /// [GNU] struct-or-union attributes[opt] identifier /// struct-or-union: /// 'struct' /// 'union' void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation StartLoc, DeclSpec &DS, ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, bool EnteringContext, DeclSpecContext DSC, ParsedAttributes &Attributes) { … } /// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived]. /// /// base-clause : [C++ class.derived] /// ':' base-specifier-list /// base-specifier-list: /// base-specifier '...'[opt] /// base-specifier-list ',' base-specifier '...'[opt] void Parser::ParseBaseClause(Decl *ClassDecl) { … } /// ParseBaseSpecifier - Parse a C++ base-specifier. A base-specifier is /// one entry in the base class list of a class specifier, for example: /// class foo : public bar, virtual private baz { /// 'public bar' and 'virtual private baz' are each base-specifiers. /// /// base-specifier: [C++ class.derived] /// attribute-specifier-seq[opt] base-type-specifier /// attribute-specifier-seq[opt] 'virtual' access-specifier[opt] /// base-type-specifier /// attribute-specifier-seq[opt] access-specifier 'virtual'[opt] /// base-type-specifier BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { … } /// getAccessSpecifierIfPresent - Determine whether the next token is /// a C++ access-specifier. /// /// access-specifier: [C++ class.derived] /// 'private' /// 'protected' /// 'public' AccessSpecifier Parser::getAccessSpecifierIfPresent() const { … } /// If the given declarator has any parts for which parsing has to be /// delayed, e.g., default arguments or an exception-specification, create a /// late-parsed method declaration record to handle the parsing at the end of /// the class definition. void Parser::HandleMemberFunctionDeclDelays(Declarator &DeclaratorInfo, Decl *ThisDecl) { … } /// isCXX11VirtSpecifier - Determine whether the given token is a C++11 /// virt-specifier. /// /// virt-specifier: /// override /// final /// __final VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const { … } /// ParseOptionalCXX11VirtSpecifierSeq - Parse a virt-specifier-seq. /// /// virt-specifier-seq: /// virt-specifier /// virt-specifier-seq virt-specifier void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, bool IsInterface, SourceLocation FriendLoc) { … } /// isCXX11FinalKeyword - Determine whether the next token is a C++11 /// 'final' or Microsoft 'sealed' contextual keyword. bool Parser::isCXX11FinalKeyword() const { … } /// isClassCompatibleKeyword - Determine whether the next token is a C++11 /// 'final' or Microsoft 'sealed' or 'abstract' contextual keywords. bool Parser::isClassCompatibleKeyword() const { … } /// Parse a C++ member-declarator up to, but not including, the optional /// brace-or-equal-initializer or pure-specifier. bool Parser::ParseCXXMemberDeclaratorBeforeInitializer( Declarator &DeclaratorInfo, VirtSpecifiers &VS, ExprResult &BitfieldSize, LateParsedAttrList &LateParsedAttrs) { … } /// Look for declaration specifiers possibly occurring after C++11 /// virt-specifier-seq and diagnose them. void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq( Declarator &D, VirtSpecifiers &VS) { … } /// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration. /// /// member-declaration: /// decl-specifier-seq[opt] member-declarator-list[opt] ';' /// function-definition ';'[opt] /// [C++26] friend-type-declaration /// ::[opt] nested-name-specifier template[opt] unqualified-id ';'[TODO] /// using-declaration [TODO] /// [C++0x] static_assert-declaration /// template-declaration /// [GNU] '__extension__' member-declaration /// /// member-declarator-list: /// member-declarator /// member-declarator-list ',' member-declarator /// /// member-declarator: /// declarator virt-specifier-seq[opt] pure-specifier[opt] /// [C++2a] declarator requires-clause /// declarator constant-initializer[opt] /// [C++11] declarator brace-or-equal-initializer[opt] /// identifier[opt] ':' constant-expression /// /// virt-specifier-seq: /// virt-specifier /// virt-specifier-seq virt-specifier /// /// virt-specifier: /// override /// final /// [MS] sealed /// /// pure-specifier: /// '= 0' /// /// constant-initializer: /// '=' constant-expression /// /// friend-type-declaration: /// 'friend' friend-type-specifier-list ; /// /// friend-type-specifier-list: /// friend-type-specifier ...[opt] /// friend-type-specifier-list , friend-type-specifier ...[opt] /// /// friend-type-specifier: /// simple-type-specifier /// elaborated-type-specifier /// typename-specifier /// Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration( AccessSpecifier AS, ParsedAttributes &AccessAttrs, ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject *TemplateDiags) { … } /// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer. /// Also detect and reject any attempted defaulted/deleted function definition. /// The location of the '=', if any, will be placed in EqualLoc. /// /// This does not check for a pure-specifier; that's handled elsewhere. /// /// brace-or-equal-initializer: /// '=' initializer-expression /// braced-init-list /// /// initializer-clause: /// assignment-expression /// braced-init-list /// /// defaulted/deleted function-definition: /// '=' 'default' /// '=' 'delete' /// /// Prior to C++0x, the assignment-expression in an initializer-clause must /// be a constant-expression. ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, SourceLocation &EqualLoc) { … } void Parser::SkipCXXMemberSpecification(SourceLocation RecordLoc, SourceLocation AttrFixitLoc, unsigned TagType, Decl *TagDecl) { … } Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas( AccessSpecifier &AS, ParsedAttributes &AccessAttrs, DeclSpec::TST TagType, Decl *TagDecl) { … } /// ParseCXXMemberSpecification - Parse the class definition. /// /// member-specification: /// member-declaration member-specification[opt] /// access-specifier ':' member-specification[opt] /// void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, SourceLocation AttrFixitLoc, ParsedAttributes &Attrs, unsigned TagType, Decl *TagDecl) { … } void Parser::DiagnoseUnexpectedNamespace(NamedDecl *D) { … } /// ParseConstructorInitializer - Parse a C++ constructor initializer, /// which explicitly initializes the members or base classes of a /// class (C++ [class.base.init]). For example, the three initializers /// after the ':' in the Derived constructor below: /// /// @code /// class Base { }; /// class Derived : Base { /// int x; /// float f; /// public: /// Derived(float f) : Base(), x(17), f(f) { } /// }; /// @endcode /// /// [C++] ctor-initializer: /// ':' mem-initializer-list /// /// [C++] mem-initializer-list: /// mem-initializer ...[opt] /// mem-initializer ...[opt] , mem-initializer-list void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { … } /// ParseMemInitializer - Parse a C++ member initializer, which is /// part of a constructor initializer that explicitly initializes one /// member or base class (C++ [class.base.init]). See /// ParseConstructorInitializer for an example. /// /// [C++] mem-initializer: /// mem-initializer-id '(' expression-list[opt] ')' /// [C++0x] mem-initializer-id braced-init-list /// /// [C++] mem-initializer-id: /// '::'[opt] nested-name-specifier[opt] class-name /// identifier MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { … } /// Parse a C++ exception-specification if present (C++0x [except.spec]). /// /// exception-specification: /// dynamic-exception-specification /// noexcept-specification /// /// noexcept-specification: /// 'noexcept' /// 'noexcept' '(' constant-expression ')' ExceptionSpecificationType Parser::tryParseExceptionSpecification( bool Delayed, SourceRange &SpecificationRange, SmallVectorImpl<ParsedType> &DynamicExceptions, SmallVectorImpl<SourceRange> &DynamicExceptionRanges, ExprResult &NoexceptExpr, CachedTokens *&ExceptionSpecTokens) { … } static void diagnoseDynamicExceptionSpecification(Parser &P, SourceRange Range, bool IsNoexcept) { … } /// ParseDynamicExceptionSpecification - Parse a C++ /// dynamic-exception-specification (C++ [except.spec]). /// /// dynamic-exception-specification: /// 'throw' '(' type-id-list [opt] ')' /// [MS] 'throw' '(' '...' ')' /// /// type-id-list: /// type-id ... [opt] /// type-id-list ',' type-id ... [opt] /// ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( SourceRange &SpecificationRange, SmallVectorImpl<ParsedType> &Exceptions, SmallVectorImpl<SourceRange> &Ranges) { … } /// ParseTrailingReturnType - Parse a trailing return type on a new-style /// function declaration. TypeResult Parser::ParseTrailingReturnType(SourceRange &Range, bool MayBeFollowedByDirectInit) { … } /// Parse a requires-clause as part of a function declaration. void Parser::ParseTrailingRequiresClause(Declarator &D) { … } /// We have just started parsing the definition of a new class, /// so push that class onto our stack of classes that is currently /// being parsed. Sema::ParsingClassState Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass, bool IsInterface) { … } /// Deallocate the given parsed class and all of its nested /// classes. void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) { … } /// Pop the top class of the stack of classes that are /// currently being parsed. /// /// This routine should be called when we have finished parsing the /// definition of a class, but have not yet popped the Scope /// associated with the class's definition. void Parser::PopParsingClass(Sema::ParsingClassState state) { … } /// Try to parse an 'identifier' which appears within an attribute-token. /// /// \return the parsed identifier on success, and 0 if the next token is not an /// attribute-token. /// /// C++11 [dcl.attr.grammar]p3: /// If a keyword or an alternative token that satisfies the syntactic /// requirements of an identifier is contained in an attribute-token, /// it is considered an identifier. IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier( SourceLocation &Loc, SemaCodeCompletion::AttributeCompletion Completion, const IdentifierInfo *Scope) { … } void Parser::ParseOpenMPAttributeArgs(const IdentifierInfo *AttrName, CachedTokens &OpenMPTokens) { … } static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName, IdentifierInfo *ScopeName) { … } /// Parse the argument to C++23's [[assume()]] attribute. bool Parser::ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs, IdentifierInfo *AttrName, SourceLocation AttrNameLoc, SourceLocation *EndLoc, ParsedAttr::Form Form) { … } /// ParseCXX11AttributeArgs -- Parse a C++11 attribute-argument-clause. /// /// [C++11] attribute-argument-clause: /// '(' balanced-token-seq ')' /// /// [C++11] balanced-token-seq: /// balanced-token /// balanced-token-seq balanced-token /// /// [C++11] balanced-token: /// '(' balanced-token-seq ')' /// '[' balanced-token-seq ']' /// '{' balanced-token-seq '}' /// any token but '(', ')', '[', ']', '{', or '}' bool Parser::ParseCXX11AttributeArgs( IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, CachedTokens &OpenMPTokens) { … } /// Parse a C++11 or C23 attribute-specifier. /// /// [C++11] attribute-specifier: /// '[' '[' attribute-list ']' ']' /// alignment-specifier /// /// [C++11] attribute-list: /// attribute[opt] /// attribute-list ',' attribute[opt] /// attribute '...' /// attribute-list ',' attribute '...' /// /// [C++11] attribute: /// attribute-token attribute-argument-clause[opt] /// /// [C++11] attribute-token: /// identifier /// attribute-scoped-token /// /// [C++11] attribute-scoped-token: /// attribute-namespace '::' identifier /// /// [C++11] attribute-namespace: /// identifier void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, CachedTokens &OpenMPTokens, SourceLocation *EndLoc) { … } /// ParseCXX11Attributes - Parse a C++11 or C23 attribute-specifier-seq. /// /// attribute-specifier-seq: /// attribute-specifier-seq[opt] attribute-specifier void Parser::ParseCXX11Attributes(ParsedAttributes &Attrs) { … } void Parser::DiagnoseAndSkipCXX11Attributes() { … } SourceLocation Parser::SkipCXX11Attributes() { … } /// Parse uuid() attribute when it appears in a [] Microsoft attribute. void Parser::ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs) { … } /// ParseMicrosoftAttributes - Parse Microsoft attributes [Attr] /// /// [MS] ms-attribute: /// '[' token-seq ']' /// /// [MS] ms-attribute-seq: /// ms-attribute[opt] /// ms-attribute ms-attribute-seq void Parser::ParseMicrosoftAttributes(ParsedAttributes &Attrs) { … } void Parser::ParseMicrosoftIfExistsClassDeclaration( DeclSpec::TST TagType, ParsedAttributes &AccessAttrs, AccessSpecifier &CurAS) { … }