//===--- ParseDecl.cpp - 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 Declaration portions of the Parser interfaces. // //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/PrettyDeclStackTrace.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/AttributeCommonInfo.h" #include "clang/Basic/Attributes.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TokenKinds.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaCodeCompletion.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/SemaObjC.h" #include "clang/Sema/SemaOpenMP.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include <optional> usingnamespaceclang; //===----------------------------------------------------------------------===// // C99 6.7: Declarations. //===----------------------------------------------------------------------===// /// ParseTypeName /// type-name: [C99 6.7.6] /// specifier-qualifier-list abstract-declarator[opt] /// /// Called type-id in C++. TypeResult Parser::ParseTypeName(SourceRange *Range, DeclaratorContext Context, AccessSpecifier AS, Decl **OwnedType, ParsedAttributes *Attrs) { … } /// Normalizes an attribute name by dropping prefixed and suffixed __. static StringRef normalizeAttrName(StringRef Name) { … } /// returns true iff attribute is annotated with `LateAttrParseExperimentalExt` /// in `Attr.td`. static bool IsAttributeLateParsedExperimentalExt(const IdentifierInfo &II) { … } /// returns true iff attribute is annotated with `LateAttrParseStandard` in /// `Attr.td`. static bool IsAttributeLateParsedStandard(const IdentifierInfo &II) { … } /// Check if the a start and end source location expand to the same macro. static bool FindLocsWithCommonFileID(Preprocessor &PP, SourceLocation StartLoc, SourceLocation EndLoc) { … } void Parser::ParseAttributes(unsigned WhichAttrKinds, ParsedAttributes &Attrs, LateParsedAttrList *LateAttrs) { … } /// ParseSingleGNUAttribute - Parse a single GNU attribute. /// /// [GNU] attrib: /// empty /// attrib-name /// attrib-name '(' identifier ')' /// attrib-name '(' identifier ',' nonempty-expr-list ')' /// attrib-name '(' argument-expression-list [C99 6.5.2] ')' /// /// [GNU] attrib-name: /// identifier /// typespec /// typequal /// storageclass bool Parser::ParseSingleGNUAttribute(ParsedAttributes &Attrs, SourceLocation &EndLoc, LateParsedAttrList *LateAttrs, Declarator *D) { … } /// ParseGNUAttributes - Parse a non-empty attributes list. /// /// [GNU] attributes: /// attribute /// attributes attribute /// /// [GNU] attribute: /// '__attribute__' '(' '(' attribute-list ')' ')' /// /// [GNU] attribute-list: /// attrib /// attribute_list ',' attrib /// /// [GNU] attrib: /// empty /// attrib-name /// attrib-name '(' identifier ')' /// attrib-name '(' identifier ',' nonempty-expr-list ')' /// attrib-name '(' argument-expression-list [C99 6.5.2] ')' /// /// [GNU] attrib-name: /// identifier /// typespec /// typequal /// storageclass /// /// Whether an attribute takes an 'identifier' is determined by the /// attrib-name. GCC's behavior here is not worth imitating: /// /// * In C mode, if the attribute argument list starts with an identifier /// followed by a ',' or an ')', and the identifier doesn't resolve to /// a type, it is parsed as an identifier. If the attribute actually /// wanted an expression, it's out of luck (but it turns out that no /// attributes work that way, because C constant expressions are very /// limited). /// * In C++ mode, if the attribute argument list starts with an identifier, /// and the attribute *wants* an identifier, it is parsed as an identifier. /// At block scope, any additional tokens between the identifier and the /// ',' or ')' are ignored, otherwise they produce a parse error. /// /// We follow the C++ model, but don't allow junk after the identifier. void Parser::ParseGNUAttributes(ParsedAttributes &Attrs, LateParsedAttrList *LateAttrs, Declarator *D) { … } /// Determine whether the given attribute has an identifier argument. static bool attributeHasIdentifierArg(const llvm::Triple &T, const IdentifierInfo &II, ParsedAttr::Syntax Syntax, IdentifierInfo *ScopeName) { … } /// Determine whether the given attribute has string arguments. static ParsedAttributeArgumentsProperties attributeStringLiteralListArg(const llvm::Triple &T, const IdentifierInfo &II, ParsedAttr::Syntax Syntax, IdentifierInfo *ScopeName) { … } /// Determine whether the given attribute has a variadic identifier argument. static bool attributeHasVariadicIdentifierArg(const IdentifierInfo &II, ParsedAttr::Syntax Syntax, IdentifierInfo *ScopeName) { … } /// Determine whether the given attribute treats kw_this as an identifier. static bool attributeTreatsKeywordThisAsIdentifier(const IdentifierInfo &II, ParsedAttr::Syntax Syntax, IdentifierInfo *ScopeName) { … } /// Determine if an attribute accepts parameter packs. static bool attributeAcceptsExprPack(const IdentifierInfo &II, ParsedAttr::Syntax Syntax, IdentifierInfo *ScopeName) { … } /// Determine whether the given attribute parses a type argument. static bool attributeIsTypeArgAttr(const IdentifierInfo &II, ParsedAttr::Syntax Syntax, IdentifierInfo *ScopeName) { … } /// Determine whether the given attribute takes a strict identifier argument. static bool attributeHasStrictIdentifierArgs(const IdentifierInfo &II, ParsedAttr::Syntax Syntax, IdentifierInfo *ScopeName) { … } /// Determine whether the given attribute requires parsing its arguments /// in an unevaluated context or not. static bool attributeParsedArgsUnevaluated(const IdentifierInfo &II, ParsedAttr::Syntax Syntax, IdentifierInfo *ScopeName) { … } IdentifierLoc *Parser::ParseIdentifierLoc() { … } void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form) { … } ExprResult Parser::ParseUnevaluatedStringInAttribute(const IdentifierInfo &AttrName) { … } bool Parser::ParseAttributeArgumentList( const IdentifierInfo &AttrName, SmallVectorImpl<Expr *> &Exprs, ParsedAttributeArgumentsProperties ArgsProperties) { … } unsigned Parser::ParseAttributeArgsCommon( IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form) { … } /// Parse the arguments to a parameterized GNU attribute or /// a C++11 attribute in "gnu" namespace. void Parser::ParseGNUAttributeArgs( IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form, Declarator *D) { … } unsigned Parser::ParseClangAttributeArgs( IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form) { … } bool Parser::ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs) { … } /// [MS] decl-specifier: /// __declspec ( extended-decl-modifier-seq ) /// /// [MS] extended-decl-modifier-seq: /// extended-decl-modifier[opt] /// extended-decl-modifier extended-decl-modifier-seq void Parser::ParseMicrosoftDeclSpecs(ParsedAttributes &Attrs) { … } void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { … } void Parser::ParseWebAssemblyFuncrefTypeAttribute(ParsedAttributes &attrs) { … } void Parser::DiagnoseAndSkipExtendedMicrosoftTypeAttributes() { … } SourceLocation Parser::SkipExtendedMicrosoftTypeAttributes() { … } void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { … } void Parser::ParseOpenCLKernelAttributes(ParsedAttributes &attrs) { … } void Parser::ParseCUDAFunctionAttributes(ParsedAttributes &attrs) { … } void Parser::ParseOpenCLQualifiers(ParsedAttributes &Attrs) { … } bool Parser::isHLSLQualifier(const Token &Tok) const { … } void Parser::ParseHLSLQualifiers(ParsedAttributes &Attrs) { … } void Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) { … } static bool VersionNumberSeparator(const char Separator) { … } /// Parse a version number. /// /// version: /// simple-integer /// simple-integer '.' simple-integer /// simple-integer '_' simple-integer /// simple-integer '.' simple-integer '.' simple-integer /// simple-integer '_' simple-integer '_' simple-integer VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { … } /// Parse the contents of the "availability" attribute. /// /// availability-attribute: /// 'availability' '(' platform ',' opt-strict version-arg-list, /// opt-replacement, opt-message')' /// /// platform: /// identifier /// /// opt-strict: /// 'strict' ',' /// /// version-arg-list: /// version-arg /// version-arg ',' version-arg-list /// /// version-arg: /// 'introduced' '=' version /// 'deprecated' '=' version /// 'obsoleted' = version /// 'unavailable' /// opt-replacement: /// 'replacement' '=' <string> /// opt-message: /// 'message' '=' <string> void Parser::ParseAvailabilityAttribute( IdentifierInfo &Availability, SourceLocation AvailabilityLoc, ParsedAttributes &attrs, SourceLocation *endLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form) { … } /// Parse the contents of the "external_source_symbol" attribute. /// /// external-source-symbol-attribute: /// 'external_source_symbol' '(' keyword-arg-list ')' /// /// keyword-arg-list: /// keyword-arg /// keyword-arg ',' keyword-arg-list /// /// keyword-arg: /// 'language' '=' <string> /// 'defined_in' '=' <string> /// 'USR' '=' <string> /// 'generated_declaration' void Parser::ParseExternalSourceSymbolAttribute( IdentifierInfo &ExternalSourceSymbol, SourceLocation Loc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form) { … } /// Parse the contents of the "objc_bridge_related" attribute. /// objc_bridge_related '(' related_class ',' opt-class_method ',' opt-instance_method ')' /// related_class: /// Identifier /// /// opt-class_method: /// Identifier: | <empty> /// /// opt-instance_method: /// Identifier | <empty> /// void Parser::ParseObjCBridgeRelatedAttribute( IdentifierInfo &ObjCBridgeRelated, SourceLocation ObjCBridgeRelatedLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form) { … } void Parser::ParseSwiftNewTypeAttribute( IdentifierInfo &AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form) { … } void Parser::ParseTypeTagForDatatypeAttribute( IdentifierInfo &AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form) { … } /// DiagnoseProhibitedCXX11Attribute - We have found the opening square brackets /// of a C++11 attribute-specifier in a location where an attribute is not /// permitted. By C++11 [dcl.attr.grammar]p6, this is ill-formed. Diagnose this /// situation. /// /// \return \c true if we skipped an attribute-like chunk of tokens, \c false if /// this doesn't appear to actually be an attribute-specifier, and the caller /// should try to parse it. bool Parser::DiagnoseProhibitedCXX11Attribute() { … } /// We have found the opening square brackets of a C++11 /// attribute-specifier in a location where an attribute is not permitted, but /// we know where the attributes ought to be written. Parse them anyway, and /// provide a fixit moving them to the right place. void Parser::DiagnoseMisplacedCXX11Attribute(ParsedAttributes &Attrs, SourceLocation CorrectLocation) { … } void Parser::DiagnoseProhibitedAttributes( const ParsedAttributesView &Attrs, const SourceLocation CorrectLocation) { … } void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned AttrDiagID, unsigned KeywordDiagID, bool DiagnoseEmptyAttrs, bool WarnOnUnknownAttrs) { … } void Parser::DiagnoseCXX11AttributeExtension(ParsedAttributes &Attrs) { … } // Usually, `__attribute__((attrib)) class Foo {} var` means that attribute // applies to var, not the type Foo. // As an exception to the rule, __declspec(align(...)) before the // class-key affects the type instead of the variable. // Also, Microsoft-style [attributes] seem to affect the type instead of the // variable. // This function moves attributes that should apply to the type off DS to Attrs. void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributes &Attrs, DeclSpec &DS, TagUseKind TUK) { … } /// ParseDeclaration - Parse a full 'declaration', which consists of /// declaration-specifiers, some number of declarators, and a semicolon. /// 'Context' should be a DeclaratorContext value. This returns the /// location of the semicolon in DeclEnd. /// /// declaration: [C99 6.7] /// block-declaration -> /// simple-declaration /// others [FIXME] /// [C++] template-declaration /// [C++] namespace-definition /// [C++] using-directive /// [C++] using-declaration /// [C++11/C11] static_assert-declaration /// others... [FIXME] /// Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &DeclAttrs, ParsedAttributes &DeclSpecAttrs, SourceLocation *DeclSpecStart) { … } /// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl] /// declaration-specifiers init-declarator-list[opt] ';' /// [C++11] attribute-specifier-seq decl-specifier-seq[opt] /// init-declarator-list ';' ///[C90/C++]init-declarator-list ';' [TODO] /// [OMP] threadprivate-directive /// [OMP] allocate-directive [TODO] /// /// for-range-declaration: [C++11 6.5p1: stmt.ranged] /// attribute-specifier-seq[opt] type-specifier-seq declarator /// /// If RequireSemi is false, this does not check for a ';' at the end of the /// declaration. If it is true, it checks for and eats it. /// /// If FRI is non-null, we might be parsing a for-range-declaration instead /// of a simple-declaration. If we find that we are, we also parse the /// for-range-initializer, and place it here. /// /// DeclSpecStart is used when decl-specifiers are parsed before parsing /// the Declaration. The SourceLocation for this Decl is set to /// DeclSpecStart if DeclSpecStart is non-null. Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration( DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &DeclAttrs, ParsedAttributes &DeclSpecAttrs, bool RequireSemi, ForRangeInit *FRI, SourceLocation *DeclSpecStart) { … } /// Returns true if this might be the start of a declarator, or a common typo /// for a declarator. bool Parser::MightBeDeclarator(DeclaratorContext Context) { … } /// Skip until we reach something which seems like a sensible place to pick /// up parsing after a malformed declaration. This will sometimes stop sooner /// than SkipUntil(tok::r_brace) would, but will never stop later. void Parser::SkipMalformedDecl() { … } /// ParseDeclGroup - Having concluded that this is either a function /// definition or a group of object declarations, actually parse the /// result. Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context, ParsedAttributes &Attrs, ParsedTemplateInfo &TemplateInfo, SourceLocation *DeclEnd, ForRangeInit *FRI) { … } /// Parse an optional simple-asm-expr and attributes, and attach them to a /// declarator. Returns true on an error. bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) { … } /// Parse 'declaration' after parsing 'declaration-specifiers /// declarator'. This method parses the remainder of the declaration /// (including any attributes or initializer, among other things) and /// finalizes the declaration. /// /// init-declarator: [C99 6.7] /// declarator /// declarator '=' initializer /// [GNU] declarator simple-asm-expr[opt] attributes[opt] /// [GNU] declarator simple-asm-expr[opt] attributes[opt] '=' initializer /// [C++] declarator initializer[opt] /// /// [C++] initializer: /// [C++] '=' initializer-clause /// [C++] '(' expression-list ')' /// [C++0x] '=' 'default' [TODO] /// [C++0x] '=' 'delete' /// [C++0x] braced-init-list /// /// According to the standard grammar, =default and =delete are function /// definitions, but that definitely doesn't fit with the parser here. /// Decl *Parser::ParseDeclarationAfterDeclarator( Declarator &D, const ParsedTemplateInfo &TemplateInfo) { … } Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) { … } /// ParseSpecifierQualifierList /// specifier-qualifier-list: /// type-specifier specifier-qualifier-list[opt] /// type-qualifier specifier-qualifier-list[opt] /// [GNU] attributes specifier-qualifier-list[opt] /// void Parser::ParseSpecifierQualifierList( DeclSpec &DS, ImplicitTypenameContext AllowImplicitTypename, AccessSpecifier AS, DeclSpecContext DSC) { … } /// isValidAfterIdentifierInDeclaratorAfterDeclSpec - Return true if the /// specified token is valid after the identifier in a declarator which /// immediately follows the declspec. For example, these things are valid: /// /// int x [ 4]; // direct-declarator /// int x ( int y); // direct-declarator /// int(int x ) // direct-declarator /// int x ; // simple-declaration /// int x = 17; // init-declarator-list /// int x , y; // init-declarator-list /// int x __asm__ ("foo"); // init-declarator-list /// int x : 4; // struct-declarator /// int x { 5}; // C++'0x unified initializers /// /// This is not, because 'x' does not immediately follow the declspec (though /// ')' happens to be valid anyway). /// int (x) /// static bool isValidAfterIdentifierInDeclarator(const Token &T) { … } /// ParseImplicitInt - This method is called when we have an non-typename /// identifier in a declspec (which normally terminates the decl spec) when /// the declspec has no type specifier. In this case, the declspec is either /// malformed or is "implicit int" (in K&R and C89). /// /// This method handles diagnosing this prettily and returns false if the /// declspec is done being processed. If it recovers and thinks there may be /// other pieces of declspec after it, it returns true. /// bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSC, ParsedAttributes &Attrs) { … } /// Determine the declaration specifier context from the declarator /// context. /// /// \param Context the declarator context, which is one of the /// DeclaratorContext enumerator values. Parser::DeclSpecContext Parser::getDeclSpecContextFromDeclaratorContext(DeclaratorContext Context) { … } /// ParseAlignArgument - Parse the argument to an alignment-specifier. /// /// [C11] type-id /// [C11] constant-expression /// [C++0x] type-id ...[opt] /// [C++0x] assignment-expression ...[opt] ExprResult Parser::ParseAlignArgument(StringRef KWName, SourceLocation Start, SourceLocation &EllipsisLoc, bool &IsType, ParsedType &TypeResult) { … } /// ParseAlignmentSpecifier - Parse an alignment-specifier, and add the /// attribute to Attrs. /// /// alignment-specifier: /// [C11] '_Alignas' '(' type-id ')' /// [C11] '_Alignas' '(' constant-expression ')' /// [C++11] 'alignas' '(' type-id ...[opt] ')' /// [C++11] 'alignas' '(' assignment-expression ...[opt] ')' void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation *EndLoc) { … } void Parser::DistributeCLateParsedAttrs(Decl *Dcl, LateParsedAttrList *LateAttrs) { … } /// Bounds attributes (e.g., counted_by): /// AttrName '(' expression ')' void Parser::ParseBoundsAttribute(IdentifierInfo &AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form) { … } ExprResult Parser::ParseExtIntegerArgument() { … } /// Determine whether we're looking at something that might be a declarator /// in a simple-declaration. If it can't possibly be a declarator, maybe /// diagnose a missing semicolon after a prior tag definition in the decl /// specifier. /// /// \return \c true if an error occurred and this can't be any kind of /// declaration. bool Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, DeclSpecContext DSContext, LateParsedAttrList *LateAttrs) { … } /// ParseDeclarationSpecifiers /// declaration-specifiers: [C99 6.7] /// storage-class-specifier declaration-specifiers[opt] /// type-specifier declaration-specifiers[opt] /// [C99] function-specifier declaration-specifiers[opt] /// [C11] alignment-specifier declaration-specifiers[opt] /// [GNU] attributes declaration-specifiers[opt] /// [Clang] '__module_private__' declaration-specifiers[opt] /// [ObjC1] '__kindof' declaration-specifiers[opt] /// /// storage-class-specifier: [C99 6.7.1] /// 'typedef' /// 'extern' /// 'static' /// 'auto' /// 'register' /// [C++] 'mutable' /// [C++11] 'thread_local' /// [C11] '_Thread_local' /// [GNU] '__thread' /// function-specifier: [C99 6.7.4] /// [C99] 'inline' /// [C++] 'virtual' /// [C++] 'explicit' /// [OpenCL] '__kernel' /// 'friend': [C++ dcl.friend] /// 'constexpr': [C++0x dcl.constexpr] void Parser::ParseDeclarationSpecifiers( DeclSpec &DS, ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSContext, LateParsedAttrList *LateAttrs, ImplicitTypenameContext AllowImplicitTypename) { … } static void DiagnoseCountAttributedTypeInUnnamedAnon(ParsingDeclSpec &DS, Parser &P) { … } /// ParseStructDeclaration - Parse a struct declaration without the terminating /// semicolon. /// /// Note that a struct declaration refers to a declaration in a struct, /// not to the declaration of a struct. /// /// struct-declaration: /// [C23] attributes-specifier-seq[opt] /// specifier-qualifier-list struct-declarator-list /// [GNU] __extension__ struct-declaration /// [GNU] specifier-qualifier-list /// struct-declarator-list: /// struct-declarator /// struct-declarator-list ',' struct-declarator /// [GNU] struct-declarator-list ',' attributes[opt] struct-declarator /// struct-declarator: /// declarator /// [GNU] declarator attributes[opt] /// declarator[opt] ':' constant-expression /// [GNU] declarator[opt] ':' constant-expression attributes[opt] /// void Parser::ParseStructDeclaration( ParsingDeclSpec &DS, llvm::function_ref<Decl *(ParsingFieldDeclarator &)> FieldsCallback, LateParsedAttrList *LateFieldAttrs) { … } // TODO: All callers of this function should be moved to // `Parser::ParseLexedAttributeList`. void Parser::ParseLexedCAttributeList(LateParsedAttrList &LAs, bool EnterScope, ParsedAttributes *OutAttrs) { … } /// Finish parsing an attribute for which parsing was delayed. /// This will be called at the end of parsing a class declaration /// for each LateParsedAttribute. We consume the saved tokens and /// create an attribute with the arguments filled in. We add this /// to the Attribute list for the decl. void Parser::ParseLexedCAttribute(LateParsedAttribute &LA, bool EnterScope, ParsedAttributes *OutAttrs) { … } /// ParseStructUnionBody /// struct-contents: /// struct-declaration-list /// [EXT] empty /// [GNU] "struct-declaration-list" without terminating ';' /// struct-declaration-list: /// struct-declaration /// struct-declaration-list struct-declaration /// [OBC] '@' 'defs' '(' class-name ')' /// void Parser::ParseStructUnionBody(SourceLocation RecordLoc, DeclSpec::TST TagType, RecordDecl *TagDecl) { … } /// ParseEnumSpecifier /// enum-specifier: [C99 6.7.2.2] /// 'enum' identifier[opt] '{' enumerator-list '}' ///[C99/C++]'enum' identifier[opt] '{' enumerator-list ',' '}' /// [GNU] 'enum' attributes[opt] identifier[opt] '{' enumerator-list ',' [opt] /// '}' attributes[opt] /// [MS] 'enum' __declspec[opt] identifier[opt] '{' enumerator-list ',' [opt] /// '}' /// 'enum' identifier /// [GNU] 'enum' attributes[opt] identifier /// /// [C++11] enum-head '{' enumerator-list[opt] '}' /// [C++11] enum-head '{' enumerator-list ',' '}' /// /// enum-head: [C++11] /// enum-key attribute-specifier-seq[opt] identifier[opt] enum-base[opt] /// enum-key attribute-specifier-seq[opt] nested-name-specifier /// identifier enum-base[opt] /// /// enum-key: [C++11] /// 'enum' /// 'enum' 'class' /// 'enum' 'struct' /// /// enum-base: [C++11] /// ':' type-specifier-seq /// /// [C++] elaborated-type-specifier: /// [C++] 'enum' nested-name-specifier[opt] identifier /// void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSC) { … } /// ParseEnumBody - Parse a {} enclosed enumerator-list. /// enumerator-list: /// enumerator /// enumerator-list ',' enumerator /// enumerator: /// enumeration-constant attributes[opt] /// enumeration-constant attributes[opt] '=' constant-expression /// enumeration-constant: /// identifier /// void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { … } /// isKnownToBeTypeSpecifier - Return true if we know that the specified token /// is definitely a type-specifier. Return false if it isn't part of a type /// specifier or if we're not sure. bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { … } /// isTypeSpecifierQualifier - Return true if the current token could be the /// start of a specifier-qualifier-list. bool Parser::isTypeSpecifierQualifier() { … } Parser::DeclGroupPtrTy Parser::ParseTopLevelStmtDecl() { … } /// isDeclarationSpecifier() - Return true if the current token is part of a /// declaration specifier. /// /// \param AllowImplicitTypename whether this is a context where T::type [T /// dependent] can appear. /// \param DisambiguatingWithExpression True to indicate that the purpose of /// this check is to disambiguate between an expression and a declaration. bool Parser::isDeclarationSpecifier( ImplicitTypenameContext AllowImplicitTypename, bool DisambiguatingWithExpression) { … } bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide, DeclSpec::FriendSpecified IsFriend, const ParsedTemplateInfo *TemplateInfo) { … } /// ParseTypeQualifierListOpt /// type-qualifier-list: [C99 6.7.5] /// type-qualifier /// [vendor] attributes /// [ only if AttrReqs & AR_VendorAttributesParsed ] /// type-qualifier-list type-qualifier /// [vendor] type-qualifier-list attributes /// [ only if AttrReqs & AR_VendorAttributesParsed ] /// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq /// [ only if AttReqs & AR_CXX11AttributesParsed ] /// Note: vendor can be GNU, MS, etc and can be explicitly controlled via /// AttrRequirements bitmask values. void Parser::ParseTypeQualifierListOpt( DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed, bool IdentifierRequired, std::optional<llvm::function_ref<void()>> CodeCompletionHandler) { … } /// ParseDeclarator - Parse and verify a newly-initialized declarator. void Parser::ParseDeclarator(Declarator &D) { … } static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang, DeclaratorContext TheContext) { … } // Indicates whether the given declarator is a pipe declarator. static bool isPipeDeclarator(const Declarator &D) { … } /// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator /// is parsed by the function passed to it. Pass null, and the direct-declarator /// isn't parsed at all, making this function effectively parse the C++ /// ptr-operator production. /// /// If the grammar of this construct is extended, matching changes must also be /// made to TryParseDeclarator and MightBeDeclarator, and possibly to /// isConstructorDeclarator. /// /// declarator: [C99 6.7.5] [C++ 8p4, dcl.decl] /// [C] pointer[opt] direct-declarator /// [C++] direct-declarator /// [C++] ptr-operator declarator /// /// pointer: [C99 6.7.5] /// '*' type-qualifier-list[opt] /// '*' type-qualifier-list[opt] pointer /// /// ptr-operator: /// '*' cv-qualifier-seq[opt] /// '&' /// [C++0x] '&&' /// [GNU] '&' restrict[opt] attributes[opt] /// [GNU?] '&&' restrict[opt] attributes[opt] /// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] void Parser::ParseDeclaratorInternal(Declarator &D, DirectDeclParseFunction DirectDeclParser) { … } // When correcting from misplaced brackets before the identifier, the location // is saved inside the declarator so that other diagnostic messages can use // them. This extracts and returns that location, or returns the provided // location if a stored location does not exist. static SourceLocation getMissingDeclaratorIdLoc(Declarator &D, SourceLocation Loc) { … } /// ParseDirectDeclarator /// direct-declarator: [C99 6.7.5] /// [C99] identifier /// '(' declarator ')' /// [GNU] '(' attributes declarator ')' /// [C90] direct-declarator '[' constant-expression[opt] ']' /// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']' /// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']' /// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' /// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' /// [C++11] direct-declarator '[' constant-expression[opt] ']' /// attribute-specifier-seq[opt] /// direct-declarator '(' parameter-type-list ')' /// direct-declarator '(' identifier-list[opt] ')' /// [GNU] direct-declarator '(' parameter-forward-declarations /// parameter-type-list[opt] ')' /// [C++] direct-declarator '(' parameter-declaration-clause ')' /// cv-qualifier-seq[opt] exception-specification[opt] /// [C++11] direct-declarator '(' parameter-declaration-clause ')' /// attribute-specifier-seq[opt] cv-qualifier-seq[opt] /// ref-qualifier[opt] exception-specification[opt] /// [C++] declarator-id /// [C++11] declarator-id attribute-specifier-seq[opt] /// /// declarator-id: [C++ 8] /// '...'[opt] id-expression /// '::'[opt] nested-name-specifier[opt] type-name /// /// id-expression: [C++ 5.1] /// unqualified-id /// qualified-id /// /// unqualified-id: [C++ 5.1] /// identifier /// operator-function-id /// conversion-function-id /// '~' class-name /// template-id /// /// C++17 adds the following, which we also handle here: /// /// simple-declaration: /// <decl-spec> '[' identifier-list ']' brace-or-equal-initializer ';' /// /// Note, any additional constructs added here may need corresponding changes /// in isConstructorDeclarator. void Parser::ParseDirectDeclarator(Declarator &D) { … } void Parser::ParseDecompositionDeclarator(Declarator &D) { … } /// ParseParenDeclarator - We parsed the declarator D up to a paren. This is /// only called before the identifier, so these are most likely just grouping /// parens for precedence. If we find that these are actually function /// parameter parens in an abstract-declarator, we call ParseFunctionDeclarator. /// /// direct-declarator: /// '(' declarator ')' /// [GNU] '(' attributes declarator ')' /// direct-declarator '(' parameter-type-list ')' /// direct-declarator '(' identifier-list[opt] ')' /// [GNU] direct-declarator '(' parameter-forward-declarations /// parameter-type-list[opt] ')' /// void Parser::ParseParenDeclarator(Declarator &D) { … } void Parser::InitCXXThisScopeForDeclaratorIfRelevant( const Declarator &D, const DeclSpec &DS, std::optional<Sema::CXXThisScopeRAII> &ThisScope) { … } /// ParseFunctionDeclarator - We are after the identifier and have parsed the /// declarator D up to a paren, which indicates that we are parsing function /// arguments. /// /// If FirstArgAttrs is non-null, then the caller parsed those attributes /// immediately after the open paren - they will be applied to the DeclSpec /// of the first parameter. /// /// If RequiresArg is true, then the first argument of the function is required /// to be present and required to not be an identifier list. /// /// For C++, after the parameter-list, it also parses the cv-qualifier-seq[opt], /// (C++11) ref-qualifier[opt], exception-specification[opt], /// (C++11) attribute-specifier-seq[opt], (C++11) trailing-return-type[opt] and /// (C++2a) the trailing requires-clause. /// /// [C++11] exception-specification: /// dynamic-exception-specification /// noexcept-specification /// void Parser::ParseFunctionDeclarator(Declarator &D, ParsedAttributes &FirstArgAttrs, BalancedDelimiterTracker &Tracker, bool IsAmbiguous, bool RequiresArg) { … } /// ParseRefQualifier - Parses a member function ref-qualifier. Returns /// true if a ref-qualifier is found. bool Parser::ParseRefQualifier(bool &RefQualifierIsLValueRef, SourceLocation &RefQualifierLoc) { … } /// isFunctionDeclaratorIdentifierList - This parameter list may have an /// identifier list form for a K&R-style function: void foo(a,b,c) /// /// Note that identifier-lists are only allowed for normal declarators, not for /// abstract-declarators. bool Parser::isFunctionDeclaratorIdentifierList() { … } /// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator /// we found a K&R-style identifier list instead of a typed parameter list. /// /// After returning, ParamInfo will hold the parsed parameters. /// /// identifier-list: [C99 6.7.5] /// identifier /// identifier-list ',' identifier /// void Parser::ParseFunctionDeclaratorIdentifierList( Declarator &D, SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo) { … } /// ParseParameterDeclarationClause - Parse a (possibly empty) parameter-list /// after the opening parenthesis. This function will not parse a K&R-style /// identifier list. /// /// DeclContext is the context of the declarator being parsed. If FirstArgAttrs /// is non-null, then the caller parsed those attributes immediately after the /// open paren - they will be applied to the DeclSpec of the first parameter. /// /// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will /// be the location of the ellipsis, if any was parsed. /// /// parameter-type-list: [C99 6.7.5] /// parameter-list /// parameter-list ',' '...' /// [C++] parameter-list '...' /// /// parameter-list: [C99 6.7.5] /// parameter-declaration /// parameter-list ',' parameter-declaration /// /// parameter-declaration: [C99 6.7.5] /// declaration-specifiers declarator /// [C++] declaration-specifiers declarator '=' assignment-expression /// [C++11] initializer-clause /// [GNU] declaration-specifiers declarator attributes /// declaration-specifiers abstract-declarator[opt] /// [C++] declaration-specifiers abstract-declarator[opt] /// '=' assignment-expression /// [GNU] declaration-specifiers abstract-declarator[opt] attributes /// [C++11] attribute-specifier-seq parameter-declaration /// [C++2b] attribute-specifier-seq 'this' parameter-declaration /// void Parser::ParseParameterDeclarationClause( DeclaratorContext DeclaratorCtx, ParsedAttributes &FirstArgAttrs, SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo, SourceLocation &EllipsisLoc, bool IsACXXFunctionDeclaration) { … } /// [C90] direct-declarator '[' constant-expression[opt] ']' /// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']' /// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']' /// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' /// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' /// [C++11] direct-declarator '[' constant-expression[opt] ']' /// attribute-specifier-seq[opt] void Parser::ParseBracketDeclarator(Declarator &D) { … } /// Diagnose brackets before an identifier. void Parser::ParseMisplacedBracketDeclarator(Declarator &D) { … } /// [GNU] typeof-specifier: /// typeof ( expressions ) /// typeof ( type-name ) /// [GNU/C++] typeof unary-expression /// [C23] typeof-specifier: /// typeof '(' typeof-specifier-argument ')' /// typeof_unqual '(' typeof-specifier-argument ')' /// /// typeof-specifier-argument: /// expression /// type-name /// void Parser::ParseTypeofSpecifier(DeclSpec &DS) { … } /// [C11] atomic-specifier: /// _Atomic ( type-name ) /// void Parser::ParseAtomicSpecifier(DeclSpec &DS) { … } /// TryAltiVecVectorTokenOutOfLine - Out of line body that should only be called /// from TryAltiVecVectorToken. bool Parser::TryAltiVecVectorTokenOutOfLine() { … } bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, bool &isInvalid) { … } TypeResult Parser::ParseTypeFromString(StringRef TypeStr, StringRef Context, SourceLocation IncludeLoc) { … } void Parser::DiagnoseBitIntUse(const Token &Tok) { … }