diff options
author | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 13:58:24 +0300 |
---|---|---|
committer | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 14:11:53 +0300 |
commit | 11a895b7e15d1c5a1f52706396b82e3f9db953cb (patch) | |
tree | fabc6d883b0f946151f61ae7865cee9f529a1fdd /contrib/libs/clang16/include/clang/Sema | |
parent | 9685917341315774aad5733b1793b1e533a88bbb (diff) | |
download | ydb-11a895b7e15d1c5a1f52706396b82e3f9db953cb.tar.gz |
Export clang-format16 via ydblib project
6e6be3a95868fde888d801b7590af4044049563f
Diffstat (limited to 'contrib/libs/clang16/include/clang/Sema')
34 files changed, 29534 insertions, 0 deletions
diff --git a/contrib/libs/clang16/include/clang/Sema/AnalysisBasedWarnings.h b/contrib/libs/clang16/include/clang/Sema/AnalysisBasedWarnings.h new file mode 100644 index 0000000000..6e21df3702 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/AnalysisBasedWarnings.h @@ -0,0 +1,117 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//=- AnalysisBasedWarnings.h - Sema warnings based on libAnalysis -*- 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 defines AnalysisBasedWarnings, a worker object used by Sema +// that issues warnings based on dataflow-analysis. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H +#define LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H + +#include "llvm/ADT/DenseMap.h" +#include <memory> + +namespace clang { + +class Decl; +class FunctionDecl; +class QualType; +class Sema; +namespace sema { + class FunctionScopeInfo; +} + +namespace sema { + +class AnalysisBasedWarnings { +public: + class Policy { + friend class AnalysisBasedWarnings; + // The warnings to run. + unsigned enableCheckFallThrough : 1; + unsigned enableCheckUnreachable : 1; + unsigned enableThreadSafetyAnalysis : 1; + unsigned enableConsumedAnalysis : 1; + public: + Policy(); + void disableCheckFallThrough() { enableCheckFallThrough = 0; } + }; + +private: + Sema &S; + Policy DefaultPolicy; + + class InterProceduralData; + std::unique_ptr<InterProceduralData> IPData; + + enum VisitFlag { NotVisited = 0, Visited = 1, Pending = 2 }; + llvm::DenseMap<const FunctionDecl*, VisitFlag> VisitedFD; + + /// \name Statistics + /// @{ + + /// Number of function CFGs built and analyzed. + unsigned NumFunctionsAnalyzed; + + /// Number of functions for which the CFG could not be successfully + /// built. + unsigned NumFunctionsWithBadCFGs; + + /// Total number of blocks across all CFGs. + unsigned NumCFGBlocks; + + /// Largest number of CFG blocks for a single function analyzed. + unsigned MaxCFGBlocksPerFunction; + + /// Total number of CFGs with variables analyzed for uninitialized + /// uses. + unsigned NumUninitAnalysisFunctions; + + /// Total number of variables analyzed for uninitialized uses. + unsigned NumUninitAnalysisVariables; + + /// Max number of variables analyzed for uninitialized uses in a single + /// function. + unsigned MaxUninitAnalysisVariablesPerFunction; + + /// Total number of block visits during uninitialized use analysis. + unsigned NumUninitAnalysisBlockVisits; + + /// Max number of block visits during uninitialized use analysis of + /// a single function. + unsigned MaxUninitAnalysisBlockVisitsPerFunction; + + /// @} + +public: + AnalysisBasedWarnings(Sema &s); + ~AnalysisBasedWarnings(); + + void IssueWarnings(Policy P, FunctionScopeInfo *fscope, + const Decl *D, QualType BlockType); + + Policy getDefaultPolicy() { return DefaultPolicy; } + + void PrintStats() const; +}; + +} // namespace sema +} // namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/CXXFieldCollector.h b/contrib/libs/clang16/include/clang/Sema/CXXFieldCollector.h new file mode 100644 index 0000000000..cba83ff996 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/CXXFieldCollector.h @@ -0,0 +1,90 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- CXXFieldCollector.h - Utility class for C++ class semantic analysis ===// +// +// 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 provides CXXFieldCollector that is used during parsing & semantic +// analysis of C++ classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H +#define LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class FieldDecl; + +/// CXXFieldCollector - Used to keep track of CXXFieldDecls during parsing of +/// C++ classes. +class CXXFieldCollector { + /// Fields - Contains all FieldDecls collected during parsing of a C++ + /// class. When a nested class is entered, its fields are appended to the + /// fields of its parent class, when it is exited its fields are removed. + SmallVector<FieldDecl*, 32> Fields; + + /// FieldCount - Each entry represents the number of fields collected during + /// the parsing of a C++ class. When a nested class is entered, a new field + /// count is pushed, when it is exited, the field count is popped. + SmallVector<size_t, 4> FieldCount; + + // Example: + // + // class C { + // int x,y; + // class NC { + // int q; + // // At this point, Fields contains [x,y,q] decls and FieldCount contains + // // [2,1]. + // }; + // int z; + // // At this point, Fields contains [x,y,z] decls and FieldCount contains + // // [3]. + // }; + +public: + /// StartClass - Called by Sema::ActOnStartCXXClassDef. + void StartClass() { FieldCount.push_back(0); } + + /// Add - Called by Sema::ActOnCXXMemberDeclarator. + void Add(FieldDecl *D) { + Fields.push_back(D); + ++FieldCount.back(); + } + + /// getCurNumField - The number of fields added to the currently parsed class. + size_t getCurNumFields() const { + assert(!FieldCount.empty() && "no currently-parsed class"); + return FieldCount.back(); + } + + /// getCurFields - Pointer to array of fields added to the currently parsed + /// class. + FieldDecl **getCurFields() { return &*(Fields.end() - getCurNumFields()); } + + /// FinishClass - Called by Sema::ActOnFinishCXXClassDef. + void FinishClass() { + Fields.resize(Fields.size() - getCurNumFields()); + FieldCount.pop_back(); + } +}; + +} // end namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/CleanupInfo.h b/contrib/libs/clang16/include/clang/Sema/CleanupInfo.h new file mode 100644 index 0000000000..fc9ac9c517 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/CleanupInfo.h @@ -0,0 +1,57 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- CleanupInfo.cpp - Cleanup Control in Sema ------------------------===// +// +// 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 a set of operations on whether generating an +// ExprWithCleanups in a full expression. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_CLEANUPINFO_H +#define LLVM_CLANG_SEMA_CLEANUPINFO_H + +namespace clang { + +class CleanupInfo { + bool ExprNeedsCleanups = false; + bool CleanupsHaveSideEffects = false; + +public: + bool exprNeedsCleanups() const { return ExprNeedsCleanups; } + + bool cleanupsHaveSideEffects() const { return CleanupsHaveSideEffects; } + + void setExprNeedsCleanups(bool SideEffects) { + ExprNeedsCleanups = true; + CleanupsHaveSideEffects |= SideEffects; + } + + void reset() { + ExprNeedsCleanups = false; + CleanupsHaveSideEffects = false; + } + + void mergeFrom(CleanupInfo Rhs) { + ExprNeedsCleanups |= Rhs.ExprNeedsCleanups; + CleanupsHaveSideEffects |= Rhs.CleanupsHaveSideEffects; + } +}; + +} // end namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/CodeCompleteConsumer.h b/contrib/libs/clang16/include/clang/Sema/CodeCompleteConsumer.h new file mode 100644 index 0000000000..737c7cb07f --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/CodeCompleteConsumer.h @@ -0,0 +1,1299 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- CodeCompleteConsumer.h - Code Completion Interface -------*- 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 defines the CodeCompleteConsumer class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H +#define LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H + +#include "clang-c/Index.h" +#include "clang/AST/Type.h" +#include "clang/Basic/LLVM.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Sema/CodeCompleteOptions.h" +#include "clang/Sema/DeclSpec.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/type_traits.h" +#include <cassert> +#include <memory> +#include <optional> +#include <string> +#include <utility> + +namespace clang { + +class ASTContext; +class Decl; +class DeclContext; +class FunctionDecl; +class FunctionTemplateDecl; +class IdentifierInfo; +class LangOptions; +class NamedDecl; +class NestedNameSpecifier; +class Preprocessor; +class RawComment; +class Sema; +class UsingShadowDecl; + +/// Default priority values for code-completion results based +/// on their kind. +enum { + /// Priority for the next initialization in a constructor initializer + /// list. + CCP_NextInitializer = 7, + + /// Priority for an enumeration constant inside a switch whose + /// condition is of the enumeration type. + CCP_EnumInCase = 7, + + /// Priority for a send-to-super completion. + CCP_SuperCompletion = 20, + + /// Priority for a declaration that is in the local scope. + CCP_LocalDeclaration = 34, + + /// Priority for a member declaration found from the current + /// method or member function. + CCP_MemberDeclaration = 35, + + /// Priority for a language keyword (that isn't any of the other + /// categories). + CCP_Keyword = 40, + + /// Priority for a code pattern. + CCP_CodePattern = 40, + + /// Priority for a non-type declaration. + CCP_Declaration = 50, + + /// Priority for a type. + CCP_Type = CCP_Declaration, + + /// Priority for a constant value (e.g., enumerator). + CCP_Constant = 65, + + /// Priority for a preprocessor macro. + CCP_Macro = 70, + + /// Priority for a nested-name-specifier. + CCP_NestedNameSpecifier = 75, + + /// Priority for a result that isn't likely to be what the user wants, + /// but is included for completeness. + CCP_Unlikely = 80, + + /// Priority for the Objective-C "_cmd" implicit parameter. + CCP_ObjC_cmd = CCP_Unlikely +}; + +/// Priority value deltas that are added to code-completion results +/// based on the context of the result. +enum { + /// The result is in a base class. + CCD_InBaseClass = 2, + + /// The result is a C++ non-static member function whose qualifiers + /// exactly match the object type on which the member function can be called. + CCD_ObjectQualifierMatch = -1, + + /// The selector of the given message exactly matches the selector + /// of the current method, which might imply that some kind of delegation + /// is occurring. + CCD_SelectorMatch = -3, + + /// Adjustment to the "bool" type in Objective-C, where the typedef + /// "BOOL" is preferred. + CCD_bool_in_ObjC = 1, + + /// Adjustment for KVC code pattern priorities when it doesn't look + /// like the + CCD_ProbablyNotObjCCollection = 15, + + /// An Objective-C method being used as a property. + CCD_MethodAsProperty = 2, + + /// An Objective-C block property completed as a setter with a + /// block placeholder. + CCD_BlockPropertySetter = 3 +}; + +/// Priority value factors by which we will divide or multiply the +/// priority of a code-completion result. +enum { + /// Divide by this factor when a code-completion result's type exactly + /// matches the type we expect. + CCF_ExactTypeMatch = 4, + + /// Divide by this factor when a code-completion result's type is + /// similar to the type we expect (e.g., both arithmetic types, both + /// Objective-C object pointer types). + CCF_SimilarTypeMatch = 2 +}; + +/// A simplified classification of types used when determining +/// "similar" types for code completion. +enum SimplifiedTypeClass { + STC_Arithmetic, + STC_Array, + STC_Block, + STC_Function, + STC_ObjectiveC, + STC_Other, + STC_Pointer, + STC_Record, + STC_Void +}; + +/// Determine the simplified type class of the given canonical type. +SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T); + +/// Determine the type that this declaration will have if it is used +/// as a type or in an expression. +QualType getDeclUsageType(ASTContext &C, const NamedDecl *ND); + +/// Determine the priority to be given to a macro code completion result +/// with the given name. +/// +/// \param MacroName The name of the macro. +/// +/// \param LangOpts Options describing the current language dialect. +/// +/// \param PreferredTypeIsPointer Whether the preferred type for the context +/// of this macro is a pointer type. +unsigned getMacroUsagePriority(StringRef MacroName, + const LangOptions &LangOpts, + bool PreferredTypeIsPointer = false); + +/// Determine the libclang cursor kind associated with the given +/// declaration. +CXCursorKind getCursorKindForDecl(const Decl *D); + +/// The context in which code completion occurred, so that the +/// code-completion consumer can process the results accordingly. +class CodeCompletionContext { +public: + enum Kind { + /// An unspecified code-completion context. + CCC_Other, + + /// An unspecified code-completion context where we should also add + /// macro completions. + CCC_OtherWithMacros, + + /// Code completion occurred within a "top-level" completion context, + /// e.g., at namespace or global scope. + CCC_TopLevel, + + /// Code completion occurred within an Objective-C interface, + /// protocol, or category interface. + CCC_ObjCInterface, + + /// Code completion occurred within an Objective-C implementation + /// or category implementation. + CCC_ObjCImplementation, + + /// Code completion occurred within the instance variable list of + /// an Objective-C interface, implementation, or category implementation. + CCC_ObjCIvarList, + + /// Code completion occurred within a class, struct, or union. + CCC_ClassStructUnion, + + /// Code completion occurred where a statement (or declaration) is + /// expected in a function, method, or block. + CCC_Statement, + + /// Code completion occurred where an expression is expected. + CCC_Expression, + + /// Code completion occurred where an Objective-C message receiver + /// is expected. + CCC_ObjCMessageReceiver, + + /// Code completion occurred on the right-hand side of a member + /// access expression using the dot operator. + /// + /// The results of this completion are the members of the type being + /// accessed. The type itself is available via + /// \c CodeCompletionContext::getType(). + CCC_DotMemberAccess, + + /// Code completion occurred on the right-hand side of a member + /// access expression using the arrow operator. + /// + /// The results of this completion are the members of the type being + /// accessed. The type itself is available via + /// \c CodeCompletionContext::getType(). + CCC_ArrowMemberAccess, + + /// Code completion occurred on the right-hand side of an Objective-C + /// property access expression. + /// + /// The results of this completion are the members of the type being + /// accessed. The type itself is available via + /// \c CodeCompletionContext::getType(). + CCC_ObjCPropertyAccess, + + /// Code completion occurred after the "enum" keyword, to indicate + /// an enumeration name. + CCC_EnumTag, + + /// Code completion occurred after the "union" keyword, to indicate + /// a union name. + CCC_UnionTag, + + /// Code completion occurred after the "struct" or "class" keyword, + /// to indicate a struct or class name. + CCC_ClassOrStructTag, + + /// Code completion occurred where a protocol name is expected. + CCC_ObjCProtocolName, + + /// Code completion occurred where a namespace or namespace alias + /// is expected. + CCC_Namespace, + + /// Code completion occurred where a type name is expected. + CCC_Type, + + /// Code completion occurred where a new name is expected. + CCC_NewName, + + /// Code completion occurred where both a new name and an existing symbol is + /// permissible. + CCC_SymbolOrNewName, + + /// Code completion occurred where an existing name(such as type, function + /// or variable) is expected. + CCC_Symbol, + + /// Code completion occurred where an macro is being defined. + CCC_MacroName, + + /// Code completion occurred where a macro name is expected + /// (without any arguments, in the case of a function-like macro). + CCC_MacroNameUse, + + /// Code completion occurred within a preprocessor expression. + CCC_PreprocessorExpression, + + /// Code completion occurred where a preprocessor directive is + /// expected. + CCC_PreprocessorDirective, + + /// Code completion occurred in a context where natural language is + /// expected, e.g., a comment or string literal. + /// + /// This context usually implies that no completions should be added, + /// unless they come from an appropriate natural-language dictionary. + CCC_NaturalLanguage, + + /// Code completion for a selector, as in an \@selector expression. + CCC_SelectorName, + + /// Code completion within a type-qualifier list. + CCC_TypeQualifiers, + + /// Code completion in a parenthesized expression, which means that + /// we may also have types here in C and Objective-C (as well as in C++). + CCC_ParenthesizedExpression, + + /// Code completion where an Objective-C instance message is + /// expected. + CCC_ObjCInstanceMessage, + + /// Code completion where an Objective-C class message is expected. + CCC_ObjCClassMessage, + + /// Code completion where the name of an Objective-C class is + /// expected. + CCC_ObjCInterfaceName, + + /// Code completion where an Objective-C category name is expected. + CCC_ObjCCategoryName, + + /// Code completion inside the filename part of a #include directive. + CCC_IncludedFile, + + /// Code completion of an attribute name. + CCC_Attribute, + + /// An unknown context, in which we are recovering from a parsing + /// error and don't know which completions we should give. + CCC_Recovery + }; + + using VisitedContextSet = llvm::SmallPtrSet<DeclContext *, 8>; + +private: + Kind CCKind; + + /// Indicates whether we are completing a name of a using declaration, e.g. + /// using ^; + /// using a::^; + bool IsUsingDeclaration; + + /// The type that would prefer to see at this point (e.g., the type + /// of an initializer or function parameter). + QualType PreferredType; + + /// The type of the base object in a member access expression. + QualType BaseType; + + /// The identifiers for Objective-C selector parts. + ArrayRef<IdentifierInfo *> SelIdents; + + /// The scope specifier that comes before the completion token e.g. + /// "a::b::" + std::optional<CXXScopeSpec> ScopeSpecifier; + + /// A set of declaration contexts visited by Sema when doing lookup for + /// code completion. + VisitedContextSet VisitedContexts; + +public: + /// Construct a new code-completion context of the given kind. + CodeCompletionContext(Kind CCKind) + : CCKind(CCKind), IsUsingDeclaration(false), SelIdents(std::nullopt) {} + + /// Construct a new code-completion context of the given kind. + CodeCompletionContext(Kind CCKind, QualType T, + ArrayRef<IdentifierInfo *> SelIdents = std::nullopt) + : CCKind(CCKind), IsUsingDeclaration(false), SelIdents(SelIdents) { + if (CCKind == CCC_DotMemberAccess || CCKind == CCC_ArrowMemberAccess || + CCKind == CCC_ObjCPropertyAccess || CCKind == CCC_ObjCClassMessage || + CCKind == CCC_ObjCInstanceMessage) + BaseType = T; + else + PreferredType = T; + } + + bool isUsingDeclaration() const { return IsUsingDeclaration; } + void setIsUsingDeclaration(bool V) { IsUsingDeclaration = V; } + + /// Retrieve the kind of code-completion context. + Kind getKind() const { return CCKind; } + + /// Retrieve the type that this expression would prefer to have, e.g., + /// if the expression is a variable initializer or a function argument, the + /// type of the corresponding variable or function parameter. + QualType getPreferredType() const { return PreferredType; } + void setPreferredType(QualType T) { PreferredType = T; } + + /// Retrieve the type of the base object in a member-access + /// expression. + QualType getBaseType() const { return BaseType; } + + /// Retrieve the Objective-C selector identifiers. + ArrayRef<IdentifierInfo *> getSelIdents() const { return SelIdents; } + + /// Determines whether we want C++ constructors as results within this + /// context. + bool wantConstructorResults() const; + + /// Sets the scope specifier that comes before the completion token. + /// This is expected to be set in code completions on qualfied specifiers + /// (e.g. "a::b::"). + void setCXXScopeSpecifier(CXXScopeSpec SS) { + this->ScopeSpecifier = std::move(SS); + } + + /// Adds a visited context. + void addVisitedContext(DeclContext *Ctx) { + VisitedContexts.insert(Ctx); + } + + /// Retrieves all visited contexts. + const VisitedContextSet &getVisitedContexts() const { + return VisitedContexts; + } + + std::optional<const CXXScopeSpec *> getCXXScopeSpecifier() { + if (ScopeSpecifier) + return &*ScopeSpecifier; + return std::nullopt; + } +}; + +/// Get string representation of \p Kind, useful for debugging. +llvm::StringRef getCompletionKindString(CodeCompletionContext::Kind Kind); + +/// A "string" used to describe how code completion can +/// be performed for an entity. +/// +/// A code completion string typically shows how a particular entity can be +/// used. For example, the code completion string for a function would show +/// the syntax to call it, including the parentheses, placeholders for the +/// arguments, etc. +class CodeCompletionString { +public: + /// The different kinds of "chunks" that can occur within a code + /// completion string. + enum ChunkKind { + /// The piece of text that the user is expected to type to + /// match the code-completion string, typically a keyword or the name of a + /// declarator or macro. + CK_TypedText, + + /// A piece of text that should be placed in the buffer, e.g., + /// parentheses or a comma in a function call. + CK_Text, + + /// A code completion string that is entirely optional. For example, + /// an optional code completion string that describes the default arguments + /// in a function call. + CK_Optional, + + /// A string that acts as a placeholder for, e.g., a function + /// call argument. + CK_Placeholder, + + /// A piece of text that describes something about the result but + /// should not be inserted into the buffer. + CK_Informative, + /// A piece of text that describes the type of an entity or, for + /// functions and methods, the return type. + CK_ResultType, + + /// A piece of text that describes the parameter that corresponds + /// to the code-completion location within a function call, message send, + /// macro invocation, etc. + CK_CurrentParameter, + + /// A left parenthesis ('('). + CK_LeftParen, + + /// A right parenthesis (')'). + CK_RightParen, + + /// A left bracket ('['). + CK_LeftBracket, + + /// A right bracket (']'). + CK_RightBracket, + + /// A left brace ('{'). + CK_LeftBrace, + + /// A right brace ('}'). + CK_RightBrace, + + /// A left angle bracket ('<'). + CK_LeftAngle, + + /// A right angle bracket ('>'). + CK_RightAngle, + + /// A comma separator (','). + CK_Comma, + + /// A colon (':'). + CK_Colon, + + /// A semicolon (';'). + CK_SemiColon, + + /// An '=' sign. + CK_Equal, + + /// Horizontal whitespace (' '). + CK_HorizontalSpace, + + /// Vertical whitespace ('\\n' or '\\r\\n', depending on the + /// platform). + CK_VerticalSpace + }; + + /// One piece of the code completion string. + struct Chunk { + /// The kind of data stored in this piece of the code completion + /// string. + ChunkKind Kind = CK_Text; + + union { + /// The text string associated with a CK_Text, CK_Placeholder, + /// CK_Informative, or CK_Comma chunk. + /// The string is owned by the chunk and will be deallocated + /// (with delete[]) when the chunk is destroyed. + const char *Text; + + /// The code completion string associated with a CK_Optional chunk. + /// The optional code completion string is owned by the chunk, and will + /// be deallocated (with delete) when the chunk is destroyed. + CodeCompletionString *Optional; + }; + + Chunk() : Text(nullptr) {} + + explicit Chunk(ChunkKind Kind, const char *Text = ""); + + /// Create a new text chunk. + static Chunk CreateText(const char *Text); + + /// Create a new optional chunk. + static Chunk CreateOptional(CodeCompletionString *Optional); + + /// Create a new placeholder chunk. + static Chunk CreatePlaceholder(const char *Placeholder); + + /// Create a new informative chunk. + static Chunk CreateInformative(const char *Informative); + + /// Create a new result type chunk. + static Chunk CreateResultType(const char *ResultType); + + /// Create a new current-parameter chunk. + static Chunk CreateCurrentParameter(const char *CurrentParameter); + }; + +private: + friend class CodeCompletionBuilder; + friend class CodeCompletionResult; + + /// The number of chunks stored in this string. + unsigned NumChunks : 16; + + /// The number of annotations for this code-completion result. + unsigned NumAnnotations : 16; + + /// The priority of this code-completion string. + unsigned Priority : 16; + + /// The availability of this code-completion result. + unsigned Availability : 2; + + /// The name of the parent context. + StringRef ParentName; + + /// A brief documentation comment attached to the declaration of + /// entity being completed by this result. + const char *BriefComment; + + CodeCompletionString(const Chunk *Chunks, unsigned NumChunks, + unsigned Priority, CXAvailabilityKind Availability, + const char **Annotations, unsigned NumAnnotations, + StringRef ParentName, + const char *BriefComment); + ~CodeCompletionString() = default; + +public: + CodeCompletionString(const CodeCompletionString &) = delete; + CodeCompletionString &operator=(const CodeCompletionString &) = delete; + + using iterator = const Chunk *; + + iterator begin() const { return reinterpret_cast<const Chunk *>(this + 1); } + iterator end() const { return begin() + NumChunks; } + bool empty() const { return NumChunks == 0; } + unsigned size() const { return NumChunks; } + + const Chunk &operator[](unsigned I) const { + assert(I < size() && "Chunk index out-of-range"); + return begin()[I]; + } + + /// Returns the text in the first TypedText chunk. + const char *getTypedText() const; + + /// Returns the combined text from all TypedText chunks. + std::string getAllTypedText() const; + + /// Retrieve the priority of this code completion result. + unsigned getPriority() const { return Priority; } + + /// Retrieve the availability of this code completion result. + unsigned getAvailability() const { return Availability; } + + /// Retrieve the number of annotations for this code completion result. + unsigned getAnnotationCount() const; + + /// Retrieve the annotation string specified by \c AnnotationNr. + const char *getAnnotation(unsigned AnnotationNr) const; + + /// Retrieve the name of the parent context. + StringRef getParentContextName() const { + return ParentName; + } + + const char *getBriefComment() const { + return BriefComment; + } + + /// Retrieve a string representation of the code completion string, + /// which is mainly useful for debugging. + std::string getAsString() const; +}; + +/// An allocator used specifically for the purpose of code completion. +class CodeCompletionAllocator : public llvm::BumpPtrAllocator { +public: + /// Copy the given string into this allocator. + const char *CopyString(const Twine &String); +}; + +/// Allocator for a cached set of global code completions. +class GlobalCodeCompletionAllocator : public CodeCompletionAllocator {}; + +class CodeCompletionTUInfo { + llvm::DenseMap<const DeclContext *, StringRef> ParentNames; + std::shared_ptr<GlobalCodeCompletionAllocator> AllocatorRef; + +public: + explicit CodeCompletionTUInfo( + std::shared_ptr<GlobalCodeCompletionAllocator> Allocator) + : AllocatorRef(std::move(Allocator)) {} + + std::shared_ptr<GlobalCodeCompletionAllocator> getAllocatorRef() const { + return AllocatorRef; + } + + CodeCompletionAllocator &getAllocator() const { + assert(AllocatorRef); + return *AllocatorRef; + } + + StringRef getParentName(const DeclContext *DC); +}; + +} // namespace clang + +namespace clang { + +/// A builder class used to construct new code-completion strings. +class CodeCompletionBuilder { +public: + using Chunk = CodeCompletionString::Chunk; + +private: + CodeCompletionAllocator &Allocator; + CodeCompletionTUInfo &CCTUInfo; + unsigned Priority = 0; + CXAvailabilityKind Availability = CXAvailability_Available; + StringRef ParentName; + const char *BriefComment = nullptr; + + /// The chunks stored in this string. + SmallVector<Chunk, 4> Chunks; + + SmallVector<const char *, 2> Annotations; + +public: + CodeCompletionBuilder(CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo) + : Allocator(Allocator), CCTUInfo(CCTUInfo) {} + + CodeCompletionBuilder(CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo, + unsigned Priority, CXAvailabilityKind Availability) + : Allocator(Allocator), CCTUInfo(CCTUInfo), Priority(Priority), + Availability(Availability) {} + + /// Retrieve the allocator into which the code completion + /// strings should be allocated. + CodeCompletionAllocator &getAllocator() const { return Allocator; } + + CodeCompletionTUInfo &getCodeCompletionTUInfo() const { return CCTUInfo; } + + /// Take the resulting completion string. + /// + /// This operation can only be performed once. + CodeCompletionString *TakeString(); + + /// Add a new typed-text chunk. + void AddTypedTextChunk(const char *Text); + + /// Add a new text chunk. + void AddTextChunk(const char *Text); + + /// Add a new optional chunk. + void AddOptionalChunk(CodeCompletionString *Optional); + + /// Add a new placeholder chunk. + void AddPlaceholderChunk(const char *Placeholder); + + /// Add a new informative chunk. + void AddInformativeChunk(const char *Text); + + /// Add a new result-type chunk. + void AddResultTypeChunk(const char *ResultType); + + /// Add a new current-parameter chunk. + void AddCurrentParameterChunk(const char *CurrentParameter); + + /// Add a new chunk. + void AddChunk(CodeCompletionString::ChunkKind CK, const char *Text = ""); + + void AddAnnotation(const char *A) { Annotations.push_back(A); } + + /// Add the parent context information to this code completion. + void addParentContext(const DeclContext *DC); + + const char *getBriefComment() const { return BriefComment; } + void addBriefComment(StringRef Comment); + + StringRef getParentName() const { return ParentName; } +}; + +/// Captures a result of code completion. +class CodeCompletionResult { +public: + /// Describes the kind of result generated. + enum ResultKind { + /// Refers to a declaration. + RK_Declaration = 0, + + /// Refers to a keyword or symbol. + RK_Keyword, + + /// Refers to a macro. + RK_Macro, + + /// Refers to a precomputed pattern. + RK_Pattern + }; + + /// When Kind == RK_Declaration or RK_Pattern, the declaration we are + /// referring to. In the latter case, the declaration might be NULL. + const NamedDecl *Declaration = nullptr; + + union { + /// When Kind == RK_Keyword, the string representing the keyword + /// or symbol's spelling. + const char *Keyword; + + /// When Kind == RK_Pattern, the code-completion string that + /// describes the completion text to insert. + CodeCompletionString *Pattern; + + /// When Kind == RK_Macro, the identifier that refers to a macro. + const IdentifierInfo *Macro; + }; + + /// The priority of this particular code-completion result. + unsigned Priority; + + /// Specifies which parameter (of a function, Objective-C method, + /// macro, etc.) we should start with when formatting the result. + unsigned StartParameter = 0; + + /// The kind of result stored here. + ResultKind Kind; + + /// The cursor kind that describes this result. + CXCursorKind CursorKind; + + /// The availability of this result. + CXAvailabilityKind Availability = CXAvailability_Available; + + /// Fix-its that *must* be applied before inserting the text for the + /// corresponding completion. + /// + /// By default, CodeCompletionBuilder only returns completions with empty + /// fix-its. Extra completions with non-empty fix-its should be explicitly + /// requested by setting CompletionOptions::IncludeFixIts. + /// + /// For the clients to be able to compute position of the cursor after + /// applying fix-its, the following conditions are guaranteed to hold for + /// RemoveRange of the stored fix-its: + /// - Ranges in the fix-its are guaranteed to never contain the completion + /// point (or identifier under completion point, if any) inside them, except + /// at the start or at the end of the range. + /// - If a fix-it range starts or ends with completion point (or starts or + /// ends after the identifier under completion point), it will contain at + /// least one character. It allows to unambiguously recompute completion + /// point after applying the fix-it. + /// + /// The intuition is that provided fix-its change code around the identifier + /// we complete, but are not allowed to touch the identifier itself or the + /// completion point. One example of completions with corrections are the ones + /// replacing '.' with '->' and vice versa: + /// + /// std::unique_ptr<std::vector<int>> vec_ptr; + /// In 'vec_ptr.^', one of the completions is 'push_back', it requires + /// replacing '.' with '->'. + /// In 'vec_ptr->^', one of the completions is 'release', it requires + /// replacing '->' with '.'. + std::vector<FixItHint> FixIts; + + /// Whether this result is hidden by another name. + bool Hidden : 1; + + /// Whether this is a class member from base class. + bool InBaseClass : 1; + + /// Whether this result was found via lookup into a base class. + bool QualifierIsInformative : 1; + + /// Whether this declaration is the beginning of a + /// nested-name-specifier and, therefore, should be followed by '::'. + bool StartsNestedNameSpecifier : 1; + + /// Whether all parameters (of a function, Objective-C + /// method, etc.) should be considered "informative". + bool AllParametersAreInformative : 1; + + /// Whether we're completing a declaration of the given entity, + /// rather than a use of that entity. + bool DeclaringEntity : 1; + + /// When completing a function, whether it can be a call. This will usually be + /// true, but we have some heuristics, e.g. when a pointer to a non-static + /// member function is completed outside of that class' scope, it can never + /// be a call. + bool FunctionCanBeCall : 1; + + /// If the result should have a nested-name-specifier, this is it. + /// When \c QualifierIsInformative, the nested-name-specifier is + /// informative rather than required. + NestedNameSpecifier *Qualifier = nullptr; + + /// If this Decl was unshadowed by using declaration, this can store a + /// pointer to the UsingShadowDecl which was used in the unshadowing process. + /// This information can be used to uprank CodeCompletionResults / which have + /// corresponding `using decl::qualified::name;` nearby. + const UsingShadowDecl *ShadowDecl = nullptr; + + /// If the result is RK_Macro, this can store the information about the macro + /// definition. This should be set in most cases but can be missing when + /// the macro has been undefined. + const MacroInfo *MacroDefInfo = nullptr; + + /// Build a result that refers to a declaration. + CodeCompletionResult(const NamedDecl *Declaration, unsigned Priority, + NestedNameSpecifier *Qualifier = nullptr, + bool QualifierIsInformative = false, + bool Accessible = true, + std::vector<FixItHint> FixIts = std::vector<FixItHint>()) + : Declaration(Declaration), Priority(Priority), Kind(RK_Declaration), + FixIts(std::move(FixIts)), Hidden(false), InBaseClass(false), + QualifierIsInformative(QualifierIsInformative), + StartsNestedNameSpecifier(false), AllParametersAreInformative(false), + DeclaringEntity(false), FunctionCanBeCall(true), Qualifier(Qualifier) { + // FIXME: Add assert to check FixIts range requirements. + computeCursorKindAndAvailability(Accessible); + } + + /// Build a result that refers to a keyword or symbol. + CodeCompletionResult(const char *Keyword, unsigned Priority = CCP_Keyword) + : Keyword(Keyword), Priority(Priority), Kind(RK_Keyword), + CursorKind(CXCursor_NotImplemented), Hidden(false), InBaseClass(false), + QualifierIsInformative(false), StartsNestedNameSpecifier(false), + AllParametersAreInformative(false), DeclaringEntity(false), + FunctionCanBeCall(true) {} + + /// Build a result that refers to a macro. + CodeCompletionResult(const IdentifierInfo *Macro, + const MacroInfo *MI = nullptr, + unsigned Priority = CCP_Macro) + : Macro(Macro), Priority(Priority), Kind(RK_Macro), + CursorKind(CXCursor_MacroDefinition), Hidden(false), InBaseClass(false), + QualifierIsInformative(false), StartsNestedNameSpecifier(false), + AllParametersAreInformative(false), DeclaringEntity(false), + FunctionCanBeCall(true), MacroDefInfo(MI) {} + + /// Build a result that refers to a pattern. + CodeCompletionResult( + CodeCompletionString *Pattern, unsigned Priority = CCP_CodePattern, + CXCursorKind CursorKind = CXCursor_NotImplemented, + CXAvailabilityKind Availability = CXAvailability_Available, + const NamedDecl *D = nullptr) + : Declaration(D), Pattern(Pattern), Priority(Priority), Kind(RK_Pattern), + CursorKind(CursorKind), Availability(Availability), Hidden(false), + InBaseClass(false), QualifierIsInformative(false), + StartsNestedNameSpecifier(false), AllParametersAreInformative(false), + DeclaringEntity(false), FunctionCanBeCall(true) {} + + /// Build a result that refers to a pattern with an associated + /// declaration. + CodeCompletionResult(CodeCompletionString *Pattern, const NamedDecl *D, + unsigned Priority) + : Declaration(D), Pattern(Pattern), Priority(Priority), Kind(RK_Pattern), + Hidden(false), InBaseClass(false), QualifierIsInformative(false), + StartsNestedNameSpecifier(false), AllParametersAreInformative(false), + DeclaringEntity(false), FunctionCanBeCall(true) { + computeCursorKindAndAvailability(); + } + + /// Retrieve the declaration stored in this result. This might be nullptr if + /// Kind is RK_Pattern. + const NamedDecl *getDeclaration() const { + assert(((Kind == RK_Declaration) || (Kind == RK_Pattern)) && + "Not a declaration or pattern result"); + return Declaration; + } + + /// Retrieve the keyword stored in this result. + const char *getKeyword() const { + assert(Kind == RK_Keyword && "Not a keyword result"); + return Keyword; + } + + /// Create a new code-completion string that describes how to insert + /// this result into a program. + /// + /// \param S The semantic analysis that created the result. + /// + /// \param Allocator The allocator that will be used to allocate the + /// string itself. + CodeCompletionString *CreateCodeCompletionString(Sema &S, + const CodeCompletionContext &CCContext, + CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo, + bool IncludeBriefComments); + CodeCompletionString *CreateCodeCompletionString(ASTContext &Ctx, + Preprocessor &PP, + const CodeCompletionContext &CCContext, + CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo, + bool IncludeBriefComments); + /// Creates a new code-completion string for the macro result. Similar to the + /// above overloads, except this only requires preprocessor information. + /// The result kind must be `RK_Macro`. + CodeCompletionString * + CreateCodeCompletionStringForMacro(Preprocessor &PP, + CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo); + + CodeCompletionString *createCodeCompletionStringForDecl( + Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result, + bool IncludeBriefComments, const CodeCompletionContext &CCContext, + PrintingPolicy &Policy); + + CodeCompletionString *createCodeCompletionStringForOverride( + Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result, + bool IncludeBriefComments, const CodeCompletionContext &CCContext, + PrintingPolicy &Policy); + + /// Retrieve the name that should be used to order a result. + /// + /// If the name needs to be constructed as a string, that string will be + /// saved into Saved and the returned StringRef will refer to it. + StringRef getOrderedName(std::string &Saved) const; + +private: + void computeCursorKindAndAvailability(bool Accessible = true); +}; + +bool operator<(const CodeCompletionResult &X, const CodeCompletionResult &Y); + +inline bool operator>(const CodeCompletionResult &X, + const CodeCompletionResult &Y) { + return Y < X; +} + +inline bool operator<=(const CodeCompletionResult &X, + const CodeCompletionResult &Y) { + return !(Y < X); +} + +inline bool operator>=(const CodeCompletionResult &X, + const CodeCompletionResult &Y) { + return !(X < Y); +} + +/// Abstract interface for a consumer of code-completion +/// information. +class CodeCompleteConsumer { +protected: + const CodeCompleteOptions CodeCompleteOpts; + +public: + class OverloadCandidate { + public: + /// Describes the type of overload candidate. + enum CandidateKind { + /// The candidate is a function declaration. + CK_Function, + + /// The candidate is a function template, arguments are being completed. + CK_FunctionTemplate, + + /// The "candidate" is actually a variable, expression, or block + /// for which we only have a function prototype. + CK_FunctionType, + + /// The candidate is a variable or expression of function type + /// for which we have the location of the prototype declaration. + CK_FunctionProtoTypeLoc, + + /// The candidate is a template, template arguments are being completed. + CK_Template, + + /// The candidate is aggregate initialization of a record type. + CK_Aggregate, + }; + + private: + /// The kind of overload candidate. + CandidateKind Kind; + + union { + /// The function overload candidate, available when + /// Kind == CK_Function. + FunctionDecl *Function; + + /// The function template overload candidate, available when + /// Kind == CK_FunctionTemplate. + FunctionTemplateDecl *FunctionTemplate; + + /// The function type that describes the entity being called, + /// when Kind == CK_FunctionType. + const FunctionType *Type; + + /// The location of the function prototype that describes the entity being + /// called, when Kind == CK_FunctionProtoTypeLoc. + FunctionProtoTypeLoc ProtoTypeLoc; + + /// The template overload candidate, available when + /// Kind == CK_Template. + const TemplateDecl *Template; + + /// The class being aggregate-initialized, + /// when Kind == CK_Aggregate + const RecordDecl *AggregateType; + }; + + public: + OverloadCandidate(FunctionDecl *Function) + : Kind(CK_Function), Function(Function) { + assert(Function != nullptr); + } + + OverloadCandidate(FunctionTemplateDecl *FunctionTemplateDecl) + : Kind(CK_FunctionTemplate), FunctionTemplate(FunctionTemplateDecl) { + assert(FunctionTemplateDecl != nullptr); + } + + OverloadCandidate(const FunctionType *Type) + : Kind(CK_FunctionType), Type(Type) { + assert(Type != nullptr); + } + + OverloadCandidate(FunctionProtoTypeLoc Prototype) + : Kind(CK_FunctionProtoTypeLoc), ProtoTypeLoc(Prototype) { + assert(!Prototype.isNull()); + } + + OverloadCandidate(const RecordDecl *Aggregate) + : Kind(CK_Aggregate), AggregateType(Aggregate) { + assert(Aggregate != nullptr); + } + + OverloadCandidate(const TemplateDecl *Template) + : Kind(CK_Template), Template(Template) {} + + /// Determine the kind of overload candidate. + CandidateKind getKind() const { return Kind; } + + /// Retrieve the function overload candidate or the templated + /// function declaration for a function template. + FunctionDecl *getFunction() const; + + /// Retrieve the function template overload candidate. + FunctionTemplateDecl *getFunctionTemplate() const { + assert(getKind() == CK_FunctionTemplate && "Not a function template"); + return FunctionTemplate; + } + + /// Retrieve the function type of the entity, regardless of how the + /// function is stored. + const FunctionType *getFunctionType() const; + + /// Retrieve the function ProtoTypeLoc candidate. + /// This can be called for any Kind, but returns null for kinds + /// other than CK_FunctionProtoTypeLoc. + const FunctionProtoTypeLoc getFunctionProtoTypeLoc() const; + + const TemplateDecl *getTemplate() const { + assert(getKind() == CK_Template && "Not a template"); + return Template; + } + + /// Retrieve the aggregate type being initialized. + const RecordDecl *getAggregate() const { + assert(getKind() == CK_Aggregate); + return AggregateType; + } + + /// Get the number of parameters in this signature. + unsigned getNumParams() const; + + /// Get the type of the Nth parameter. + /// Returns null if the type is unknown or N is out of range. + QualType getParamType(unsigned N) const; + + /// Get the declaration of the Nth parameter. + /// Returns null if the decl is unknown or N is out of range. + const NamedDecl *getParamDecl(unsigned N) const; + + /// Create a new code-completion string that describes the function + /// signature of this overload candidate. + CodeCompletionString * + CreateSignatureString(unsigned CurrentArg, Sema &S, + CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo, + bool IncludeBriefComments, bool Braced) const; + }; + + CodeCompleteConsumer(const CodeCompleteOptions &CodeCompleteOpts) + : CodeCompleteOpts(CodeCompleteOpts) {} + + /// Whether the code-completion consumer wants to see macros. + bool includeMacros() const { + return CodeCompleteOpts.IncludeMacros; + } + + /// Whether the code-completion consumer wants to see code patterns. + bool includeCodePatterns() const { + return CodeCompleteOpts.IncludeCodePatterns; + } + + /// Whether to include global (top-level) declaration results. + bool includeGlobals() const { return CodeCompleteOpts.IncludeGlobals; } + + /// Whether to include declarations in namespace contexts (including + /// the global namespace). If this is false, `includeGlobals()` will be + /// ignored. + bool includeNamespaceLevelDecls() const { + return CodeCompleteOpts.IncludeNamespaceLevelDecls; + } + + /// Whether to include brief documentation comments within the set of + /// code completions returned. + bool includeBriefComments() const { + return CodeCompleteOpts.IncludeBriefComments; + } + + /// Whether to include completion items with small fix-its, e.g. change + /// '.' to '->' on member access, etc. + bool includeFixIts() const { return CodeCompleteOpts.IncludeFixIts; } + + /// Hint whether to load data from the external AST in order to provide + /// full results. If false, declarations from the preamble may be omitted. + bool loadExternal() const { + return CodeCompleteOpts.LoadExternal; + } + + /// Deregisters and destroys this code-completion consumer. + virtual ~CodeCompleteConsumer(); + + /// \name Code-completion filtering + /// Check if the result should be filtered out. + virtual bool isResultFilteredOut(StringRef Filter, + CodeCompletionResult Results) { + return false; + } + + /// \name Code-completion callbacks + //@{ + /// Process the finalized code-completion results. + virtual void ProcessCodeCompleteResults(Sema &S, + CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults) {} + + /// \param S the semantic-analyzer object for which code-completion is being + /// done. + /// + /// \param CurrentArg the index of the current argument. + /// + /// \param Candidates an array of overload candidates. + /// + /// \param NumCandidates the number of overload candidates + /// + /// \param OpenParLoc location of the opening parenthesis of the argument + /// list. + virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates, + SourceLocation OpenParLoc, + bool Braced) {} + //@} + + /// Retrieve the allocator that will be used to allocate + /// code completion strings. + virtual CodeCompletionAllocator &getAllocator() = 0; + + virtual CodeCompletionTUInfo &getCodeCompletionTUInfo() = 0; +}; + +/// Get the documentation comment used to produce +/// CodeCompletionString::BriefComment for RK_Declaration. +const RawComment *getCompletionComment(const ASTContext &Ctx, + const NamedDecl *Decl); + +/// Get the documentation comment used to produce +/// CodeCompletionString::BriefComment for RK_Pattern. +const RawComment *getPatternCompletionComment(const ASTContext &Ctx, + const NamedDecl *Decl); + +/// Get the documentation comment used to produce +/// CodeCompletionString::BriefComment for OverloadCandidate. +const RawComment * +getParameterComment(const ASTContext &Ctx, + const CodeCompleteConsumer::OverloadCandidate &Result, + unsigned ArgIndex); + +/// A simple code-completion consumer that prints the results it +/// receives in a simple format. +class PrintingCodeCompleteConsumer : public CodeCompleteConsumer { + /// The raw output stream. + raw_ostream &OS; + + CodeCompletionTUInfo CCTUInfo; + +public: + /// Create a new printing code-completion consumer that prints its + /// results to the given raw output stream. + PrintingCodeCompleteConsumer(const CodeCompleteOptions &CodeCompleteOpts, + raw_ostream &OS) + : CodeCompleteConsumer(CodeCompleteOpts), OS(OS), + CCTUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {} + + /// Prints the finalized code-completion results. + void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults) override; + + void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates, + SourceLocation OpenParLoc, + bool Braced) override; + + bool isResultFilteredOut(StringRef Filter, CodeCompletionResult Results) override; + + CodeCompletionAllocator &getAllocator() override { + return CCTUInfo.getAllocator(); + } + + CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; } +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/CodeCompleteOptions.h b/contrib/libs/clang16/include/clang/Sema/CodeCompleteOptions.h new file mode 100644 index 0000000000..121f586a81 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/CodeCompleteOptions.h @@ -0,0 +1,66 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===---- CodeCompleteOptions.h - Code Completion Options -------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_CODECOMPLETEOPTIONS_H +#define LLVM_CLANG_SEMA_CODECOMPLETEOPTIONS_H + +namespace clang { + +/// Options controlling the behavior of code completion. +class CodeCompleteOptions { +public: + /// Show macros in code completion results. + unsigned IncludeMacros : 1; + + /// Show code patterns in code completion results. + unsigned IncludeCodePatterns : 1; + + /// Show top-level decls in code completion results. + unsigned IncludeGlobals : 1; + + /// Show decls in namespace (including the global namespace) in code + /// completion results. If this is 0, `IncludeGlobals` will be ignored. + /// + /// Currently, this only works when completing qualified IDs (i.e. + /// `Sema::CodeCompleteQualifiedId`). + /// FIXME: consider supporting more completion cases with this option. + unsigned IncludeNamespaceLevelDecls : 1; + + /// Show brief documentation comments in code completion results. + unsigned IncludeBriefComments : 1; + + /// Hint whether to load data from the external AST to provide full results. + /// If false, namespace-level declarations and macros from the preamble may be + /// omitted. + unsigned LoadExternal : 1; + + /// Include results after corrections (small fix-its), e.g. change '.' to '->' + /// on member access, etc. + unsigned IncludeFixIts : 1; + + CodeCompleteOptions() + : IncludeMacros(0), IncludeCodePatterns(0), IncludeGlobals(1), + IncludeNamespaceLevelDecls(1), IncludeBriefComments(0), + LoadExternal(1), IncludeFixIts(0) {} +}; + +} // namespace clang + +#endif + + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/DeclSpec.h b/contrib/libs/clang16/include/clang/Sema/DeclSpec.h new file mode 100644 index 0000000000..6bc95d8a48 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/DeclSpec.h @@ -0,0 +1,2820 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- DeclSpec.h - Parsed declaration specifiers -------------*- 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file defines the classes used to store parsed information about +/// declaration-specifiers and declarators. +/// +/// \verbatim +/// static const int volatile x, *y, *(*(*z)[10])(const void *x); +/// ------------------------- - -- --------------------------- +/// declaration-specifiers \ | / +/// declarators +/// \endverbatim +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_DECLSPEC_H +#define LLVM_CLANG_SEMA_DECLSPEC_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjCCommon.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/Lambda.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Lex/Token.h" +#include "clang/Sema/Ownership.h" +#include "clang/Sema/ParsedAttr.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { + class ASTContext; + class CXXRecordDecl; + class TypeLoc; + class LangOptions; + class IdentifierInfo; + class NamespaceAliasDecl; + class NamespaceDecl; + class ObjCDeclSpec; + class Sema; + class Declarator; + struct TemplateIdAnnotation; + +/// Represents a C++ nested-name-specifier or a global scope specifier. +/// +/// These can be in 3 states: +/// 1) Not present, identified by isEmpty() +/// 2) Present, identified by isNotEmpty() +/// 2.a) Valid, identified by isValid() +/// 2.b) Invalid, identified by isInvalid(). +/// +/// isSet() is deprecated because it mostly corresponded to "valid" but was +/// often used as if it meant "present". +/// +/// The actual scope is described by getScopeRep(). +class CXXScopeSpec { + SourceRange Range; + NestedNameSpecifierLocBuilder Builder; + +public: + SourceRange getRange() const { return Range; } + void setRange(SourceRange R) { Range = R; } + void setBeginLoc(SourceLocation Loc) { Range.setBegin(Loc); } + void setEndLoc(SourceLocation Loc) { Range.setEnd(Loc); } + SourceLocation getBeginLoc() const { return Range.getBegin(); } + SourceLocation getEndLoc() const { return Range.getEnd(); } + + /// Retrieve the representation of the nested-name-specifier. + NestedNameSpecifier *getScopeRep() const { + return Builder.getRepresentation(); + } + + /// Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'type::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param TemplateKWLoc The location of the 'template' keyword, if present. + /// + /// \param TL The TypeLoc that describes the type preceding the '::'. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL, + SourceLocation ColonColonLoc); + + /// Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'identifier::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Identifier The identifier. + /// + /// \param IdentifierLoc The location of the identifier. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, IdentifierInfo *Identifier, + SourceLocation IdentifierLoc, SourceLocation ColonColonLoc); + + /// Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'namespace::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Namespace The namespace. + /// + /// \param NamespaceLoc The location of the namespace name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, NamespaceDecl *Namespace, + SourceLocation NamespaceLoc, SourceLocation ColonColonLoc); + + /// Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'namespace-alias::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Alias The namespace alias. + /// + /// \param AliasLoc The location of the namespace alias + /// name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, NamespaceAliasDecl *Alias, + SourceLocation AliasLoc, SourceLocation ColonColonLoc); + + /// Turn this (empty) nested-name-specifier into the global + /// nested-name-specifier '::'. + void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); + + /// Turns this (empty) nested-name-specifier into '__super' + /// nested-name-specifier. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param RD The declaration of the class in which nested-name-specifier + /// appeared. + /// + /// \param SuperLoc The location of the '__super' keyword. + /// name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void MakeSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, SourceLocation ColonColonLoc); + + /// Make a new nested-name-specifier from incomplete source-location + /// information. + /// + /// FIXME: This routine should be used very, very rarely, in cases where we + /// need to synthesize a nested-name-specifier. Most code should instead use + /// \c Adopt() with a proper \c NestedNameSpecifierLoc. + void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, + SourceRange R); + + /// Adopt an existing nested-name-specifier (with source-range + /// information). + void Adopt(NestedNameSpecifierLoc Other); + + /// Retrieve a nested-name-specifier with location information, copied + /// into the given AST context. + /// + /// \param Context The context into which this nested-name-specifier will be + /// copied. + NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; + + /// Retrieve the location of the name in the last qualifier + /// in this nested name specifier. + /// + /// For example, the location of \c bar + /// in + /// \verbatim + /// \::foo::bar<0>:: + /// ^~~ + /// \endverbatim + SourceLocation getLastQualifierNameLoc() const; + + /// No scope specifier. + bool isEmpty() const { return Range.isInvalid() && getScopeRep() == nullptr; } + /// A scope specifier is present, but may be valid or invalid. + bool isNotEmpty() const { return !isEmpty(); } + + /// An error occurred during parsing of the scope specifier. + bool isInvalid() const { return Range.isValid() && getScopeRep() == nullptr; } + /// A scope specifier is present, and it refers to a real scope. + bool isValid() const { return getScopeRep() != nullptr; } + + /// Indicate that this nested-name-specifier is invalid. + void SetInvalid(SourceRange R) { + assert(R.isValid() && "Must have a valid source range"); + if (Range.getBegin().isInvalid()) + Range.setBegin(R.getBegin()); + Range.setEnd(R.getEnd()); + Builder.Clear(); + } + + /// Deprecated. Some call sites intend isNotEmpty() while others intend + /// isValid(). + bool isSet() const { return getScopeRep() != nullptr; } + + void clear() { + Range = SourceRange(); + Builder.Clear(); + } + + /// Retrieve the data associated with the source-location information. + char *location_data() const { return Builder.getBuffer().first; } + + /// Retrieve the size of the data associated with source-location + /// information. + unsigned location_size() const { return Builder.getBuffer().second; } +}; + +/// Captures information about "declaration specifiers". +/// +/// "Declaration specifiers" encompasses storage-class-specifiers, +/// type-specifiers, type-qualifiers, and function-specifiers. +class DeclSpec { +public: + /// storage-class-specifier + /// \note The order of these enumerators is important for diagnostics. + enum SCS { + SCS_unspecified = 0, + SCS_typedef, + SCS_extern, + SCS_static, + SCS_auto, + SCS_register, + SCS_private_extern, + SCS_mutable + }; + + // Import thread storage class specifier enumeration and constants. + // These can be combined with SCS_extern and SCS_static. + typedef ThreadStorageClassSpecifier TSCS; + static const TSCS TSCS_unspecified = clang::TSCS_unspecified; + static const TSCS TSCS___thread = clang::TSCS___thread; + static const TSCS TSCS_thread_local = clang::TSCS_thread_local; + static const TSCS TSCS__Thread_local = clang::TSCS__Thread_local; + + enum TSC { + TSC_unspecified, + TSC_imaginary, + TSC_complex + }; + + // Import type specifier type enumeration and constants. + typedef TypeSpecifierType TST; + static const TST TST_unspecified = clang::TST_unspecified; + static const TST TST_void = clang::TST_void; + static const TST TST_char = clang::TST_char; + static const TST TST_wchar = clang::TST_wchar; + static const TST TST_char8 = clang::TST_char8; + static const TST TST_char16 = clang::TST_char16; + static const TST TST_char32 = clang::TST_char32; + static const TST TST_int = clang::TST_int; + static const TST TST_int128 = clang::TST_int128; + static const TST TST_bitint = clang::TST_bitint; + static const TST TST_half = clang::TST_half; + static const TST TST_BFloat16 = clang::TST_BFloat16; + static const TST TST_float = clang::TST_float; + static const TST TST_double = clang::TST_double; + static const TST TST_float16 = clang::TST_Float16; + static const TST TST_accum = clang::TST_Accum; + static const TST TST_fract = clang::TST_Fract; + static const TST TST_float128 = clang::TST_float128; + static const TST TST_ibm128 = clang::TST_ibm128; + static const TST TST_bool = clang::TST_bool; + static const TST TST_decimal32 = clang::TST_decimal32; + static const TST TST_decimal64 = clang::TST_decimal64; + static const TST TST_decimal128 = clang::TST_decimal128; + static const TST TST_enum = clang::TST_enum; + static const TST TST_union = clang::TST_union; + static const TST TST_struct = clang::TST_struct; + static const TST TST_interface = clang::TST_interface; + static const TST TST_class = clang::TST_class; + static const TST TST_typename = clang::TST_typename; + static const TST TST_typeofType = clang::TST_typeofType; + static const TST TST_typeofExpr = clang::TST_typeofExpr; + static const TST TST_typeof_unqualType = clang::TST_typeof_unqualType; + static const TST TST_typeof_unqualExpr = clang::TST_typeof_unqualExpr; + static const TST TST_decltype = clang::TST_decltype; + static const TST TST_decltype_auto = clang::TST_decltype_auto; +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \ + static const TST TST_##Trait = clang::TST_##Trait; +#include "clang/Basic/TransformTypeTraits.def" + static const TST TST_auto = clang::TST_auto; + static const TST TST_auto_type = clang::TST_auto_type; + static const TST TST_unknown_anytype = clang::TST_unknown_anytype; + static const TST TST_atomic = clang::TST_atomic; +#define GENERIC_IMAGE_TYPE(ImgType, Id) \ + static const TST TST_##ImgType##_t = clang::TST_##ImgType##_t; +#include "clang/Basic/OpenCLImageTypes.def" + static const TST TST_error = clang::TST_error; + + // type-qualifiers + enum TQ { // NOTE: These flags must be kept in sync with Qualifiers::TQ. + TQ_unspecified = 0, + TQ_const = 1, + TQ_restrict = 2, + TQ_volatile = 4, + TQ_unaligned = 8, + // This has no corresponding Qualifiers::TQ value, because it's not treated + // as a qualifier in our type system. + TQ_atomic = 16 + }; + + /// ParsedSpecifiers - Flags to query which specifiers were applied. This is + /// returned by getParsedSpecifiers. + enum ParsedSpecifiers { + PQ_None = 0, + PQ_StorageClassSpecifier = 1, + PQ_TypeSpecifier = 2, + PQ_TypeQualifier = 4, + PQ_FunctionSpecifier = 8 + // FIXME: Attributes should be included here. + }; + + enum FriendSpecified : bool { + No, + Yes, + }; + +private: + // storage-class-specifier + /*SCS*/unsigned StorageClassSpec : 3; + /*TSCS*/unsigned ThreadStorageClassSpec : 2; + unsigned SCS_extern_in_linkage_spec : 1; + + // type-specifier + /*TypeSpecifierWidth*/ unsigned TypeSpecWidth : 2; + /*TSC*/unsigned TypeSpecComplex : 2; + /*TSS*/unsigned TypeSpecSign : 2; + /*TST*/unsigned TypeSpecType : 7; + unsigned TypeAltiVecVector : 1; + unsigned TypeAltiVecPixel : 1; + unsigned TypeAltiVecBool : 1; + unsigned TypeSpecOwned : 1; + unsigned TypeSpecPipe : 1; + unsigned TypeSpecSat : 1; + unsigned ConstrainedAuto : 1; + + // type-qualifiers + unsigned TypeQualifiers : 5; // Bitwise OR of TQ. + + // function-specifier + unsigned FS_inline_specified : 1; + unsigned FS_forceinline_specified: 1; + unsigned FS_virtual_specified : 1; + unsigned FS_noreturn_specified : 1; + + // friend-specifier + unsigned Friend_specified : 1; + + // constexpr-specifier + unsigned ConstexprSpecifier : 2; + + union { + UnionParsedType TypeRep; + Decl *DeclRep; + Expr *ExprRep; + TemplateIdAnnotation *TemplateIdRep; + }; + + /// ExplicitSpecifier - Store information about explicit spicifer. + ExplicitSpecifier FS_explicit_specifier; + + // attributes. + ParsedAttributes Attrs; + + // Scope specifier for the type spec, if applicable. + CXXScopeSpec TypeScope; + + // SourceLocation info. These are null if the item wasn't specified or if + // the setting was synthesized. + SourceRange Range; + + SourceLocation StorageClassSpecLoc, ThreadStorageClassSpecLoc; + SourceRange TSWRange; + SourceLocation TSCLoc, TSSLoc, TSTLoc, AltiVecLoc, TSSatLoc; + /// TSTNameLoc - If TypeSpecType is any of class, enum, struct, union, + /// typename, then this is the location of the named type (if present); + /// otherwise, it is the same as TSTLoc. Hence, the pair TSTLoc and + /// TSTNameLoc provides source range info for tag types. + SourceLocation TSTNameLoc; + SourceRange TypeofParensRange; + SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc, + TQ_unalignedLoc; + SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc; + SourceLocation FS_explicitCloseParenLoc; + SourceLocation FS_forceinlineLoc; + SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc; + SourceLocation TQ_pipeLoc; + + WrittenBuiltinSpecs writtenBS; + void SaveWrittenBuiltinSpecs(); + + ObjCDeclSpec *ObjCQualifiers; + + static bool isTypeRep(TST T) { + return T == TST_atomic || T == TST_typename || T == TST_typeofType || + T == TST_typeof_unqualType || isTransformTypeTrait(T); + } + static bool isExprRep(TST T) { + return T == TST_typeofExpr || T == TST_typeof_unqualExpr || + T == TST_decltype || T == TST_bitint; + } + static bool isTemplateIdRep(TST T) { + return (T == TST_auto || T == TST_decltype_auto); + } + + DeclSpec(const DeclSpec &) = delete; + void operator=(const DeclSpec &) = delete; +public: + static bool isDeclRep(TST T) { + return (T == TST_enum || T == TST_struct || + T == TST_interface || T == TST_union || + T == TST_class); + } + static bool isTransformTypeTrait(TST T) { + constexpr std::array<TST, 16> Traits = { +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) TST_##Trait, +#include "clang/Basic/TransformTypeTraits.def" + }; + + return T >= Traits.front() && T <= Traits.back(); + } + + DeclSpec(AttributeFactory &attrFactory) + : StorageClassSpec(SCS_unspecified), + ThreadStorageClassSpec(TSCS_unspecified), + SCS_extern_in_linkage_spec(false), + TypeSpecWidth(static_cast<unsigned>(TypeSpecifierWidth::Unspecified)), + TypeSpecComplex(TSC_unspecified), + TypeSpecSign(static_cast<unsigned>(TypeSpecifierSign::Unspecified)), + TypeSpecType(TST_unspecified), TypeAltiVecVector(false), + TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false), + TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false), + TypeQualifiers(TQ_unspecified), FS_inline_specified(false), + FS_forceinline_specified(false), FS_virtual_specified(false), + FS_noreturn_specified(false), Friend_specified(false), + ConstexprSpecifier( + static_cast<unsigned>(ConstexprSpecKind::Unspecified)), + Attrs(attrFactory), writtenBS(), ObjCQualifiers(nullptr) {} + + // storage-class-specifier + SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; } + TSCS getThreadStorageClassSpec() const { + return (TSCS)ThreadStorageClassSpec; + } + bool isExternInLinkageSpec() const { return SCS_extern_in_linkage_spec; } + void setExternInLinkageSpec(bool Value) { + SCS_extern_in_linkage_spec = Value; + } + + SourceLocation getStorageClassSpecLoc() const { return StorageClassSpecLoc; } + SourceLocation getThreadStorageClassSpecLoc() const { + return ThreadStorageClassSpecLoc; + } + + void ClearStorageClassSpecs() { + StorageClassSpec = DeclSpec::SCS_unspecified; + ThreadStorageClassSpec = DeclSpec::TSCS_unspecified; + SCS_extern_in_linkage_spec = false; + StorageClassSpecLoc = SourceLocation(); + ThreadStorageClassSpecLoc = SourceLocation(); + } + + void ClearTypeSpecType() { + TypeSpecType = DeclSpec::TST_unspecified; + TypeSpecOwned = false; + TSTLoc = SourceLocation(); + } + + // type-specifier + TypeSpecifierWidth getTypeSpecWidth() const { + return static_cast<TypeSpecifierWidth>(TypeSpecWidth); + } + TSC getTypeSpecComplex() const { return (TSC)TypeSpecComplex; } + TypeSpecifierSign getTypeSpecSign() const { + return static_cast<TypeSpecifierSign>(TypeSpecSign); + } + TST getTypeSpecType() const { return (TST)TypeSpecType; } + bool isTypeAltiVecVector() const { return TypeAltiVecVector; } + bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; } + bool isTypeAltiVecBool() const { return TypeAltiVecBool; } + bool isTypeSpecOwned() const { return TypeSpecOwned; } + bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); } + bool isTypeSpecPipe() const { return TypeSpecPipe; } + bool isTypeSpecSat() const { return TypeSpecSat; } + bool isConstrainedAuto() const { return ConstrainedAuto; } + + ParsedType getRepAsType() const { + assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type"); + return TypeRep; + } + Decl *getRepAsDecl() const { + assert(isDeclRep((TST) TypeSpecType) && "DeclSpec does not store a decl"); + return DeclRep; + } + Expr *getRepAsExpr() const { + assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr"); + return ExprRep; + } + TemplateIdAnnotation *getRepAsTemplateId() const { + assert(isTemplateIdRep((TST) TypeSpecType) && + "DeclSpec does not store a template id"); + return TemplateIdRep; + } + CXXScopeSpec &getTypeSpecScope() { return TypeScope; } + const CXXScopeSpec &getTypeSpecScope() const { return TypeScope; } + + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } + + SourceLocation getTypeSpecWidthLoc() const { return TSWRange.getBegin(); } + SourceRange getTypeSpecWidthRange() const { return TSWRange; } + SourceLocation getTypeSpecComplexLoc() const { return TSCLoc; } + SourceLocation getTypeSpecSignLoc() const { return TSSLoc; } + SourceLocation getTypeSpecTypeLoc() const { return TSTLoc; } + SourceLocation getAltiVecLoc() const { return AltiVecLoc; } + SourceLocation getTypeSpecSatLoc() const { return TSSatLoc; } + + SourceLocation getTypeSpecTypeNameLoc() const { + assert(isDeclRep((TST)TypeSpecType) || isTypeRep((TST)TypeSpecType) || + isExprRep((TST)TypeSpecType)); + return TSTNameLoc; + } + + SourceRange getTypeofParensRange() const { return TypeofParensRange; } + void setTypeArgumentRange(SourceRange range) { TypeofParensRange = range; } + + bool hasAutoTypeSpec() const { + return (TypeSpecType == TST_auto || TypeSpecType == TST_auto_type || + TypeSpecType == TST_decltype_auto); + } + + bool hasTagDefinition() const; + + /// Turn a type-specifier-type into a string like "_Bool" or "union". + static const char *getSpecifierName(DeclSpec::TST T, + const PrintingPolicy &Policy); + static const char *getSpecifierName(DeclSpec::TQ Q); + static const char *getSpecifierName(TypeSpecifierSign S); + static const char *getSpecifierName(DeclSpec::TSC C); + static const char *getSpecifierName(TypeSpecifierWidth W); + static const char *getSpecifierName(DeclSpec::SCS S); + static const char *getSpecifierName(DeclSpec::TSCS S); + static const char *getSpecifierName(ConstexprSpecKind C); + + // type-qualifiers + + /// getTypeQualifiers - Return a set of TQs. + unsigned getTypeQualifiers() const { return TypeQualifiers; } + SourceLocation getConstSpecLoc() const { return TQ_constLoc; } + SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; } + SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; } + SourceLocation getAtomicSpecLoc() const { return TQ_atomicLoc; } + SourceLocation getUnalignedSpecLoc() const { return TQ_unalignedLoc; } + SourceLocation getPipeLoc() const { return TQ_pipeLoc; } + + /// Clear out all of the type qualifiers. + void ClearTypeQualifiers() { + TypeQualifiers = 0; + TQ_constLoc = SourceLocation(); + TQ_restrictLoc = SourceLocation(); + TQ_volatileLoc = SourceLocation(); + TQ_atomicLoc = SourceLocation(); + TQ_unalignedLoc = SourceLocation(); + TQ_pipeLoc = SourceLocation(); + } + + // function-specifier + bool isInlineSpecified() const { + return FS_inline_specified | FS_forceinline_specified; + } + SourceLocation getInlineSpecLoc() const { + return FS_inline_specified ? FS_inlineLoc : FS_forceinlineLoc; + } + + ExplicitSpecifier getExplicitSpecifier() const { + return FS_explicit_specifier; + } + + bool isVirtualSpecified() const { return FS_virtual_specified; } + SourceLocation getVirtualSpecLoc() const { return FS_virtualLoc; } + + bool hasExplicitSpecifier() const { + return FS_explicit_specifier.isSpecified(); + } + SourceLocation getExplicitSpecLoc() const { return FS_explicitLoc; } + SourceRange getExplicitSpecRange() const { + return FS_explicit_specifier.getExpr() + ? SourceRange(FS_explicitLoc, FS_explicitCloseParenLoc) + : SourceRange(FS_explicitLoc); + } + + bool isNoreturnSpecified() const { return FS_noreturn_specified; } + SourceLocation getNoreturnSpecLoc() const { return FS_noreturnLoc; } + + void ClearFunctionSpecs() { + FS_inline_specified = false; + FS_inlineLoc = SourceLocation(); + FS_forceinline_specified = false; + FS_forceinlineLoc = SourceLocation(); + FS_virtual_specified = false; + FS_virtualLoc = SourceLocation(); + FS_explicit_specifier = ExplicitSpecifier(); + FS_explicitLoc = SourceLocation(); + FS_explicitCloseParenLoc = SourceLocation(); + FS_noreturn_specified = false; + FS_noreturnLoc = SourceLocation(); + } + + /// This method calls the passed in handler on each CVRU qual being + /// set. + /// Handle - a handler to be invoked. + void forEachCVRUQualifier( + llvm::function_ref<void(TQ, StringRef, SourceLocation)> Handle); + + /// This method calls the passed in handler on each qual being + /// set. + /// Handle - a handler to be invoked. + void forEachQualifier( + llvm::function_ref<void(TQ, StringRef, SourceLocation)> Handle); + + /// Return true if any type-specifier has been found. + bool hasTypeSpecifier() const { + return getTypeSpecType() != DeclSpec::TST_unspecified || + getTypeSpecWidth() != TypeSpecifierWidth::Unspecified || + getTypeSpecComplex() != DeclSpec::TSC_unspecified || + getTypeSpecSign() != TypeSpecifierSign::Unspecified; + } + + /// Return a bitmask of which flavors of specifiers this + /// DeclSpec includes. + unsigned getParsedSpecifiers() const; + + /// isEmpty - Return true if this declaration specifier is completely empty: + /// no tokens were parsed in the production of it. + bool isEmpty() const { + return getParsedSpecifiers() == DeclSpec::PQ_None; + } + + void SetRangeStart(SourceLocation Loc) { Range.setBegin(Loc); } + void SetRangeEnd(SourceLocation Loc) { Range.setEnd(Loc); } + + /// These methods set the specified attribute of the DeclSpec and + /// return false if there was no error. If an error occurs (for + /// example, if we tried to set "auto" on a spec with "extern" + /// already set), they return true and set PrevSpec and DiagID + /// such that + /// Diag(Loc, DiagID) << PrevSpec; + /// will yield a useful result. + /// + /// TODO: use a more general approach that still allows these + /// diagnostics to be ignored when desired. + bool SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy); + bool SetStorageClassSpecThread(TSCS TSC, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID); + bool SetTypeSpecWidth(TypeSpecifierWidth W, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy); + bool SetTypeSpecComplex(TSC C, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetTypeSpecSign(TypeSpecifierSign S, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, const PrintingPolicy &Policy); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, ParsedType Rep, + const PrintingPolicy &Policy); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, TypeResult Rep, + const PrintingPolicy &Policy) { + if (Rep.isInvalid()) + return SetTypeSpecError(); + return SetTypeSpecType(T, Loc, PrevSpec, DiagID, Rep.get(), Policy); + } + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, Decl *Rep, bool Owned, + const PrintingPolicy &Policy); + bool SetTypeSpecType(TST T, SourceLocation TagKwLoc, + SourceLocation TagNameLoc, const char *&PrevSpec, + unsigned &DiagID, ParsedType Rep, + const PrintingPolicy &Policy); + bool SetTypeSpecType(TST T, SourceLocation TagKwLoc, + SourceLocation TagNameLoc, const char *&PrevSpec, + unsigned &DiagID, Decl *Rep, bool Owned, + const PrintingPolicy &Policy); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, TemplateIdAnnotation *Rep, + const PrintingPolicy &Policy); + + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, Expr *Rep, + const PrintingPolicy &policy); + bool SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy); + bool SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy); + bool SetTypeAltiVecBool(bool isAltiVecBool, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy); + bool SetTypePipe(bool isPipe, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy); + bool SetBitIntType(SourceLocation KWLoc, Expr *BitWidth, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy); + bool SetTypeSpecSat(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetTypeSpecError(); + void UpdateDeclRep(Decl *Rep) { + assert(isDeclRep((TST) TypeSpecType)); + DeclRep = Rep; + } + void UpdateTypeRep(ParsedType Rep) { + assert(isTypeRep((TST) TypeSpecType)); + TypeRep = Rep; + } + void UpdateExprRep(Expr *Rep) { + assert(isExprRep((TST) TypeSpecType)); + ExprRep = Rep; + } + + bool SetTypeQual(TQ T, SourceLocation Loc); + + bool SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, const LangOptions &Lang); + + bool setFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool setFunctionSpecForceInline(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool setFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool setFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, ExplicitSpecifier ExplicitSpec, + SourceLocation CloseParenLoc); + bool setFunctionSpecNoreturn(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + + bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetConstexprSpec(ConstexprSpecKind ConstexprKind, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID); + + FriendSpecified isFriendSpecified() const { + return static_cast<FriendSpecified>(Friend_specified); + } + + SourceLocation getFriendSpecLoc() const { return FriendLoc; } + + bool isModulePrivateSpecified() const { return ModulePrivateLoc.isValid(); } + SourceLocation getModulePrivateSpecLoc() const { return ModulePrivateLoc; } + + ConstexprSpecKind getConstexprSpecifier() const { + return ConstexprSpecKind(ConstexprSpecifier); + } + + SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; } + bool hasConstexprSpecifier() const { + return getConstexprSpecifier() != ConstexprSpecKind::Unspecified; + } + + void ClearConstexprSpec() { + ConstexprSpecifier = static_cast<unsigned>(ConstexprSpecKind::Unspecified); + ConstexprLoc = SourceLocation(); + } + + AttributePool &getAttributePool() const { + return Attrs.getPool(); + } + + /// Concatenates two attribute lists. + /// + /// The GCC attribute syntax allows for the following: + /// + /// \code + /// short __attribute__(( unused, deprecated )) + /// int __attribute__(( may_alias, aligned(16) )) var; + /// \endcode + /// + /// This declares 4 attributes using 2 lists. The following syntax is + /// also allowed and equivalent to the previous declaration. + /// + /// \code + /// short __attribute__((unused)) __attribute__((deprecated)) + /// int __attribute__((may_alias)) __attribute__((aligned(16))) var; + /// \endcode + /// + void addAttributes(const ParsedAttributesView &AL) { + Attrs.addAll(AL.begin(), AL.end()); + } + + bool hasAttributes() const { return !Attrs.empty(); } + + ParsedAttributes &getAttributes() { return Attrs; } + const ParsedAttributes &getAttributes() const { return Attrs; } + + void takeAttributesFrom(ParsedAttributes &attrs) { + Attrs.takeAllFrom(attrs); + } + + /// Finish - This does final analysis of the declspec, issuing diagnostics for + /// things like "_Imaginary" (lacking an FP type). After calling this method, + /// DeclSpec is guaranteed self-consistent, even if an error occurred. + void Finish(Sema &S, const PrintingPolicy &Policy); + + const WrittenBuiltinSpecs& getWrittenBuiltinSpecs() const { + return writtenBS; + } + + ObjCDeclSpec *getObjCQualifiers() const { return ObjCQualifiers; } + void setObjCQualifiers(ObjCDeclSpec *quals) { ObjCQualifiers = quals; } + + /// Checks if this DeclSpec can stand alone, without a Declarator. + /// + /// Only tag declspecs can stand alone. + bool isMissingDeclaratorOk(); +}; + +/// Captures information about "declaration specifiers" specific to +/// Objective-C. +class ObjCDeclSpec { +public: + /// ObjCDeclQualifier - Qualifier used on types in method + /// declarations. Not all combinations are sensible. Parameters + /// can be one of { in, out, inout } with one of { bycopy, byref }. + /// Returns can either be { oneway } or not. + /// + /// This should be kept in sync with Decl::ObjCDeclQualifier. + enum ObjCDeclQualifier { + DQ_None = 0x0, + DQ_In = 0x1, + DQ_Inout = 0x2, + DQ_Out = 0x4, + DQ_Bycopy = 0x8, + DQ_Byref = 0x10, + DQ_Oneway = 0x20, + DQ_CSNullability = 0x40 + }; + + ObjCDeclSpec() + : objcDeclQualifier(DQ_None), + PropertyAttributes(ObjCPropertyAttribute::kind_noattr), Nullability(0), + GetterName(nullptr), SetterName(nullptr) {} + + ObjCDeclQualifier getObjCDeclQualifier() const { + return (ObjCDeclQualifier)objcDeclQualifier; + } + void setObjCDeclQualifier(ObjCDeclQualifier DQVal) { + objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier | DQVal); + } + void clearObjCDeclQualifier(ObjCDeclQualifier DQVal) { + objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier & ~DQVal); + } + + ObjCPropertyAttribute::Kind getPropertyAttributes() const { + return ObjCPropertyAttribute::Kind(PropertyAttributes); + } + void setPropertyAttributes(ObjCPropertyAttribute::Kind PRVal) { + PropertyAttributes = + (ObjCPropertyAttribute::Kind)(PropertyAttributes | PRVal); + } + + NullabilityKind getNullability() const { + assert( + ((getObjCDeclQualifier() & DQ_CSNullability) || + (getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)) && + "Objective-C declspec doesn't have nullability"); + return static_cast<NullabilityKind>(Nullability); + } + + SourceLocation getNullabilityLoc() const { + assert( + ((getObjCDeclQualifier() & DQ_CSNullability) || + (getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)) && + "Objective-C declspec doesn't have nullability"); + return NullabilityLoc; + } + + void setNullability(SourceLocation loc, NullabilityKind kind) { + assert( + ((getObjCDeclQualifier() & DQ_CSNullability) || + (getPropertyAttributes() & ObjCPropertyAttribute::kind_nullability)) && + "Set the nullability declspec or property attribute first"); + Nullability = static_cast<unsigned>(kind); + NullabilityLoc = loc; + } + + const IdentifierInfo *getGetterName() const { return GetterName; } + IdentifierInfo *getGetterName() { return GetterName; } + SourceLocation getGetterNameLoc() const { return GetterNameLoc; } + void setGetterName(IdentifierInfo *name, SourceLocation loc) { + GetterName = name; + GetterNameLoc = loc; + } + + const IdentifierInfo *getSetterName() const { return SetterName; } + IdentifierInfo *getSetterName() { return SetterName; } + SourceLocation getSetterNameLoc() const { return SetterNameLoc; } + void setSetterName(IdentifierInfo *name, SourceLocation loc) { + SetterName = name; + SetterNameLoc = loc; + } + +private: + // FIXME: These two are unrelated and mutually exclusive. So perhaps + // we can put them in a union to reflect their mutual exclusivity + // (space saving is negligible). + unsigned objcDeclQualifier : 7; + + // NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttribute::Kind + unsigned PropertyAttributes : NumObjCPropertyAttrsBits; + + unsigned Nullability : 2; + + SourceLocation NullabilityLoc; + + IdentifierInfo *GetterName; // getter name or NULL if no getter + IdentifierInfo *SetterName; // setter name or NULL if no setter + SourceLocation GetterNameLoc; // location of the getter attribute's value + SourceLocation SetterNameLoc; // location of the setter attribute's value + +}; + +/// Describes the kind of unqualified-id parsed. +enum class UnqualifiedIdKind { + /// An identifier. + IK_Identifier, + /// An overloaded operator name, e.g., operator+. + IK_OperatorFunctionId, + /// A conversion function name, e.g., operator int. + IK_ConversionFunctionId, + /// A user-defined literal name, e.g., operator "" _i. + IK_LiteralOperatorId, + /// A constructor name. + IK_ConstructorName, + /// A constructor named via a template-id. + IK_ConstructorTemplateId, + /// A destructor name. + IK_DestructorName, + /// A template-id, e.g., f<int>. + IK_TemplateId, + /// An implicit 'self' parameter + IK_ImplicitSelfParam, + /// A deduction-guide name (a template-name) + IK_DeductionGuideName +}; + +/// Represents a C++ unqualified-id that has been parsed. +class UnqualifiedId { +private: + UnqualifiedId(const UnqualifiedId &Other) = delete; + const UnqualifiedId &operator=(const UnqualifiedId &) = delete; + + /// Describes the kind of unqualified-id parsed. + UnqualifiedIdKind Kind; + +public: + struct OFI { + /// The kind of overloaded operator. + OverloadedOperatorKind Operator; + + /// The source locations of the individual tokens that name + /// the operator, e.g., the "new", "[", and "]" tokens in + /// operator new []. + /// + /// Different operators have different numbers of tokens in their name, + /// up to three. Any remaining source locations in this array will be + /// set to an invalid value for operators with fewer than three tokens. + SourceLocation SymbolLocations[3]; + }; + + /// Anonymous union that holds extra data associated with the + /// parsed unqualified-id. + union { + /// When Kind == IK_Identifier, the parsed identifier, or when + /// Kind == IK_UserLiteralId, the identifier suffix. + IdentifierInfo *Identifier; + + /// When Kind == IK_OperatorFunctionId, the overloaded operator + /// that we parsed. + struct OFI OperatorFunctionId; + + /// When Kind == IK_ConversionFunctionId, the type that the + /// conversion function names. + UnionParsedType ConversionFunctionId; + + /// When Kind == IK_ConstructorName, the class-name of the type + /// whose constructor is being referenced. + UnionParsedType ConstructorName; + + /// When Kind == IK_DestructorName, the type referred to by the + /// class-name. + UnionParsedType DestructorName; + + /// When Kind == IK_DeductionGuideName, the parsed template-name. + UnionParsedTemplateTy TemplateName; + + /// When Kind == IK_TemplateId or IK_ConstructorTemplateId, + /// the template-id annotation that contains the template name and + /// template arguments. + TemplateIdAnnotation *TemplateId; + }; + + /// The location of the first token that describes this unqualified-id, + /// which will be the location of the identifier, "operator" keyword, + /// tilde (for a destructor), or the template name of a template-id. + SourceLocation StartLocation; + + /// The location of the last token that describes this unqualified-id. + SourceLocation EndLocation; + + UnqualifiedId() + : Kind(UnqualifiedIdKind::IK_Identifier), Identifier(nullptr) {} + + /// Clear out this unqualified-id, setting it to default (invalid) + /// state. + void clear() { + Kind = UnqualifiedIdKind::IK_Identifier; + Identifier = nullptr; + StartLocation = SourceLocation(); + EndLocation = SourceLocation(); + } + + /// Determine whether this unqualified-id refers to a valid name. + bool isValid() const { return StartLocation.isValid(); } + + /// Determine whether this unqualified-id refers to an invalid name. + bool isInvalid() const { return !isValid(); } + + /// Determine what kind of name we have. + UnqualifiedIdKind getKind() const { return Kind; } + + /// Specify that this unqualified-id was parsed as an identifier. + /// + /// \param Id the parsed identifier. + /// \param IdLoc the location of the parsed identifier. + void setIdentifier(const IdentifierInfo *Id, SourceLocation IdLoc) { + Kind = UnqualifiedIdKind::IK_Identifier; + Identifier = const_cast<IdentifierInfo *>(Id); + StartLocation = EndLocation = IdLoc; + } + + /// Specify that this unqualified-id was parsed as an + /// operator-function-id. + /// + /// \param OperatorLoc the location of the 'operator' keyword. + /// + /// \param Op the overloaded operator. + /// + /// \param SymbolLocations the locations of the individual operator symbols + /// in the operator. + void setOperatorFunctionId(SourceLocation OperatorLoc, + OverloadedOperatorKind Op, + SourceLocation SymbolLocations[3]); + + /// Specify that this unqualified-id was parsed as a + /// conversion-function-id. + /// + /// \param OperatorLoc the location of the 'operator' keyword. + /// + /// \param Ty the type to which this conversion function is converting. + /// + /// \param EndLoc the location of the last token that makes up the type name. + void setConversionFunctionId(SourceLocation OperatorLoc, + ParsedType Ty, + SourceLocation EndLoc) { + Kind = UnqualifiedIdKind::IK_ConversionFunctionId; + StartLocation = OperatorLoc; + EndLocation = EndLoc; + ConversionFunctionId = Ty; + } + + /// Specific that this unqualified-id was parsed as a + /// literal-operator-id. + /// + /// \param Id the parsed identifier. + /// + /// \param OpLoc the location of the 'operator' keyword. + /// + /// \param IdLoc the location of the identifier. + void setLiteralOperatorId(const IdentifierInfo *Id, SourceLocation OpLoc, + SourceLocation IdLoc) { + Kind = UnqualifiedIdKind::IK_LiteralOperatorId; + Identifier = const_cast<IdentifierInfo *>(Id); + StartLocation = OpLoc; + EndLocation = IdLoc; + } + + /// Specify that this unqualified-id was parsed as a constructor name. + /// + /// \param ClassType the class type referred to by the constructor name. + /// + /// \param ClassNameLoc the location of the class name. + /// + /// \param EndLoc the location of the last token that makes up the type name. + void setConstructorName(ParsedType ClassType, + SourceLocation ClassNameLoc, + SourceLocation EndLoc) { + Kind = UnqualifiedIdKind::IK_ConstructorName; + StartLocation = ClassNameLoc; + EndLocation = EndLoc; + ConstructorName = ClassType; + } + + /// Specify that this unqualified-id was parsed as a + /// template-id that names a constructor. + /// + /// \param TemplateId the template-id annotation that describes the parsed + /// template-id. This UnqualifiedId instance will take ownership of the + /// \p TemplateId and will free it on destruction. + void setConstructorTemplateId(TemplateIdAnnotation *TemplateId); + + /// Specify that this unqualified-id was parsed as a destructor name. + /// + /// \param TildeLoc the location of the '~' that introduces the destructor + /// name. + /// + /// \param ClassType the name of the class referred to by the destructor name. + void setDestructorName(SourceLocation TildeLoc, + ParsedType ClassType, + SourceLocation EndLoc) { + Kind = UnqualifiedIdKind::IK_DestructorName; + StartLocation = TildeLoc; + EndLocation = EndLoc; + DestructorName = ClassType; + } + + /// Specify that this unqualified-id was parsed as a template-id. + /// + /// \param TemplateId the template-id annotation that describes the parsed + /// template-id. This UnqualifiedId instance will take ownership of the + /// \p TemplateId and will free it on destruction. + void setTemplateId(TemplateIdAnnotation *TemplateId); + + /// Specify that this unqualified-id was parsed as a template-name for + /// a deduction-guide. + /// + /// \param Template The parsed template-name. + /// \param TemplateLoc The location of the parsed template-name. + void setDeductionGuideName(ParsedTemplateTy Template, + SourceLocation TemplateLoc) { + Kind = UnqualifiedIdKind::IK_DeductionGuideName; + TemplateName = Template; + StartLocation = EndLocation = TemplateLoc; + } + + /// Specify that this unqualified-id is an implicit 'self' + /// parameter. + /// + /// \param Id the identifier. + void setImplicitSelfParam(const IdentifierInfo *Id) { + Kind = UnqualifiedIdKind::IK_ImplicitSelfParam; + Identifier = const_cast<IdentifierInfo *>(Id); + StartLocation = EndLocation = SourceLocation(); + } + + /// Return the source range that covers this unqualified-id. + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(StartLocation, EndLocation); + } + SourceLocation getBeginLoc() const LLVM_READONLY { return StartLocation; } + SourceLocation getEndLoc() const LLVM_READONLY { return EndLocation; } +}; + +/// A set of tokens that has been cached for later parsing. +typedef SmallVector<Token, 4> CachedTokens; + +/// One instance of this struct is used for each type in a +/// declarator that is parsed. +/// +/// This is intended to be a small value object. +struct DeclaratorChunk { + DeclaratorChunk() {}; + + enum { + Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren, Pipe + } Kind; + + /// Loc - The place where this type was defined. + SourceLocation Loc; + /// EndLoc - If valid, the place where this chunck ends. + SourceLocation EndLoc; + + SourceRange getSourceRange() const { + if (EndLoc.isInvalid()) + return SourceRange(Loc, Loc); + return SourceRange(Loc, EndLoc); + } + + ParsedAttributesView AttrList; + + struct PointerTypeInfo { + /// The type qualifiers: const/volatile/restrict/unaligned/atomic. + unsigned TypeQuals : 5; + + /// The location of the const-qualifier, if any. + SourceLocation ConstQualLoc; + + /// The location of the volatile-qualifier, if any. + SourceLocation VolatileQualLoc; + + /// The location of the restrict-qualifier, if any. + SourceLocation RestrictQualLoc; + + /// The location of the _Atomic-qualifier, if any. + SourceLocation AtomicQualLoc; + + /// The location of the __unaligned-qualifier, if any. + SourceLocation UnalignedQualLoc; + + void destroy() { + } + }; + + struct ReferenceTypeInfo { + /// The type qualifier: restrict. [GNU] C++ extension + bool HasRestrict : 1; + /// True if this is an lvalue reference, false if it's an rvalue reference. + bool LValueRef : 1; + void destroy() { + } + }; + + struct ArrayTypeInfo { + /// The type qualifiers for the array: + /// const/volatile/restrict/__unaligned/_Atomic. + unsigned TypeQuals : 5; + + /// True if this dimension included the 'static' keyword. + unsigned hasStatic : 1; + + /// True if this dimension was [*]. In this case, NumElts is null. + unsigned isStar : 1; + + /// This is the size of the array, or null if [] or [*] was specified. + /// Since the parser is multi-purpose, and we don't want to impose a root + /// expression class on all clients, NumElts is untyped. + Expr *NumElts; + + void destroy() {} + }; + + /// ParamInfo - An array of paraminfo objects is allocated whenever a function + /// declarator is parsed. There are two interesting styles of parameters + /// here: + /// K&R-style identifier lists and parameter type lists. K&R-style identifier + /// lists will have information about the identifier, but no type information. + /// Parameter type lists will have type info (if the actions module provides + /// it), but may have null identifier info: e.g. for 'void foo(int X, int)'. + struct ParamInfo { + IdentifierInfo *Ident; + SourceLocation IdentLoc; + Decl *Param; + + /// DefaultArgTokens - When the parameter's default argument + /// cannot be parsed immediately (because it occurs within the + /// declaration of a member function), it will be stored here as a + /// sequence of tokens to be parsed once the class definition is + /// complete. Non-NULL indicates that there is a default argument. + std::unique_ptr<CachedTokens> DefaultArgTokens; + + ParamInfo() = default; + ParamInfo(IdentifierInfo *ident, SourceLocation iloc, + Decl *param, + std::unique_ptr<CachedTokens> DefArgTokens = nullptr) + : Ident(ident), IdentLoc(iloc), Param(param), + DefaultArgTokens(std::move(DefArgTokens)) {} + }; + + struct TypeAndRange { + ParsedType Ty; + SourceRange Range; + }; + + struct FunctionTypeInfo { + /// hasPrototype - This is true if the function had at least one typed + /// parameter. If the function is () or (a,b,c), then it has no prototype, + /// and is treated as a K&R-style function. + unsigned hasPrototype : 1; + + /// isVariadic - If this function has a prototype, and if that + /// proto ends with ',...)', this is true. When true, EllipsisLoc + /// contains the location of the ellipsis. + unsigned isVariadic : 1; + + /// Can this declaration be a constructor-style initializer? + unsigned isAmbiguous : 1; + + /// Whether the ref-qualifier (if any) is an lvalue reference. + /// Otherwise, it's an rvalue reference. + unsigned RefQualifierIsLValueRef : 1; + + /// ExceptionSpecType - An ExceptionSpecificationType value. + unsigned ExceptionSpecType : 4; + + /// DeleteParams - If this is true, we need to delete[] Params. + unsigned DeleteParams : 1; + + /// HasTrailingReturnType - If this is true, a trailing return type was + /// specified. + unsigned HasTrailingReturnType : 1; + + /// The location of the left parenthesis in the source. + SourceLocation LParenLoc; + + /// When isVariadic is true, the location of the ellipsis in the source. + SourceLocation EllipsisLoc; + + /// The location of the right parenthesis in the source. + SourceLocation RParenLoc; + + /// NumParams - This is the number of formal parameters specified by the + /// declarator. + unsigned NumParams; + + /// NumExceptionsOrDecls - This is the number of types in the + /// dynamic-exception-decl, if the function has one. In C, this is the + /// number of declarations in the function prototype. + unsigned NumExceptionsOrDecls; + + /// The location of the ref-qualifier, if any. + /// + /// If this is an invalid location, there is no ref-qualifier. + SourceLocation RefQualifierLoc; + + /// The location of the 'mutable' qualifer in a lambda-declarator, if + /// any. + SourceLocation MutableLoc; + + /// The beginning location of the exception specification, if any. + SourceLocation ExceptionSpecLocBeg; + + /// The end location of the exception specification, if any. + SourceLocation ExceptionSpecLocEnd; + + /// Params - This is a pointer to a new[]'d array of ParamInfo objects that + /// describe the parameters specified by this function declarator. null if + /// there are no parameters specified. + ParamInfo *Params; + + /// DeclSpec for the function with the qualifier related info. + DeclSpec *MethodQualifiers; + + /// AttributeFactory for the MethodQualifiers. + AttributeFactory *QualAttrFactory; + + union { + /// Pointer to a new[]'d array of TypeAndRange objects that + /// contain the types in the function's dynamic exception specification + /// and their locations, if there is one. + TypeAndRange *Exceptions; + + /// Pointer to the expression in the noexcept-specifier of this + /// function, if it has one. + Expr *NoexceptExpr; + + /// Pointer to the cached tokens for an exception-specification + /// that has not yet been parsed. + CachedTokens *ExceptionSpecTokens; + + /// Pointer to a new[]'d array of declarations that need to be available + /// for lookup inside the function body, if one exists. Does not exist in + /// C++. + NamedDecl **DeclsInPrototype; + }; + + /// If HasTrailingReturnType is true, this is the trailing return + /// type specified. + UnionParsedType TrailingReturnType; + + /// If HasTrailingReturnType is true, this is the location of the trailing + /// return type. + SourceLocation TrailingReturnTypeLoc; + + /// Reset the parameter list to having zero parameters. + /// + /// This is used in various places for error recovery. + void freeParams() { + for (unsigned I = 0; I < NumParams; ++I) + Params[I].DefaultArgTokens.reset(); + if (DeleteParams) { + delete[] Params; + DeleteParams = false; + } + NumParams = 0; + } + + void destroy() { + freeParams(); + delete QualAttrFactory; + delete MethodQualifiers; + switch (getExceptionSpecType()) { + default: + break; + case EST_Dynamic: + delete[] Exceptions; + break; + case EST_Unparsed: + delete ExceptionSpecTokens; + break; + case EST_None: + if (NumExceptionsOrDecls != 0) + delete[] DeclsInPrototype; + break; + } + } + + DeclSpec &getOrCreateMethodQualifiers() { + if (!MethodQualifiers) { + QualAttrFactory = new AttributeFactory(); + MethodQualifiers = new DeclSpec(*QualAttrFactory); + } + return *MethodQualifiers; + } + + /// isKNRPrototype - Return true if this is a K&R style identifier list, + /// like "void foo(a,b,c)". In a function definition, this will be followed + /// by the parameter type definitions. + bool isKNRPrototype() const { return !hasPrototype && NumParams != 0; } + + SourceLocation getLParenLoc() const { return LParenLoc; } + + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceLocation getExceptionSpecLocBeg() const { + return ExceptionSpecLocBeg; + } + + SourceLocation getExceptionSpecLocEnd() const { + return ExceptionSpecLocEnd; + } + + SourceRange getExceptionSpecRange() const { + return SourceRange(getExceptionSpecLocBeg(), getExceptionSpecLocEnd()); + } + + /// Retrieve the location of the ref-qualifier, if any. + SourceLocation getRefQualifierLoc() const { return RefQualifierLoc; } + + /// Retrieve the location of the 'const' qualifier. + SourceLocation getConstQualifierLoc() const { + assert(MethodQualifiers); + return MethodQualifiers->getConstSpecLoc(); + } + + /// Retrieve the location of the 'volatile' qualifier. + SourceLocation getVolatileQualifierLoc() const { + assert(MethodQualifiers); + return MethodQualifiers->getVolatileSpecLoc(); + } + + /// Retrieve the location of the 'restrict' qualifier. + SourceLocation getRestrictQualifierLoc() const { + assert(MethodQualifiers); + return MethodQualifiers->getRestrictSpecLoc(); + } + + /// Retrieve the location of the 'mutable' qualifier, if any. + SourceLocation getMutableLoc() const { return MutableLoc; } + + /// Determine whether this function declaration contains a + /// ref-qualifier. + bool hasRefQualifier() const { return getRefQualifierLoc().isValid(); } + + /// Determine whether this lambda-declarator contains a 'mutable' + /// qualifier. + bool hasMutableQualifier() const { return getMutableLoc().isValid(); } + + /// Determine whether this method has qualifiers. + bool hasMethodTypeQualifiers() const { + return MethodQualifiers && (MethodQualifiers->getTypeQualifiers() || + MethodQualifiers->getAttributes().size()); + } + + /// Get the type of exception specification this function has. + ExceptionSpecificationType getExceptionSpecType() const { + return static_cast<ExceptionSpecificationType>(ExceptionSpecType); + } + + /// Get the number of dynamic exception specifications. + unsigned getNumExceptions() const { + assert(ExceptionSpecType != EST_None); + return NumExceptionsOrDecls; + } + + /// Get the non-parameter decls defined within this function + /// prototype. Typically these are tag declarations. + ArrayRef<NamedDecl *> getDeclsInPrototype() const { + assert(ExceptionSpecType == EST_None); + return llvm::ArrayRef(DeclsInPrototype, NumExceptionsOrDecls); + } + + /// Determine whether this function declarator had a + /// trailing-return-type. + bool hasTrailingReturnType() const { return HasTrailingReturnType; } + + /// Get the trailing-return-type for this function declarator. + ParsedType getTrailingReturnType() const { + assert(HasTrailingReturnType); + return TrailingReturnType; + } + + /// Get the trailing-return-type location for this function declarator. + SourceLocation getTrailingReturnTypeLoc() const { + assert(HasTrailingReturnType); + return TrailingReturnTypeLoc; + } + }; + + struct BlockPointerTypeInfo { + /// For now, sema will catch these as invalid. + /// The type qualifiers: const/volatile/restrict/__unaligned/_Atomic. + unsigned TypeQuals : 5; + + void destroy() { + } + }; + + struct MemberPointerTypeInfo { + /// The type qualifiers: const/volatile/restrict/__unaligned/_Atomic. + unsigned TypeQuals : 5; + /// Location of the '*' token. + SourceLocation StarLoc; + // CXXScopeSpec has a constructor, so it can't be a direct member. + // So we need some pointer-aligned storage and a bit of trickery. + alignas(CXXScopeSpec) char ScopeMem[sizeof(CXXScopeSpec)]; + CXXScopeSpec &Scope() { + return *reinterpret_cast<CXXScopeSpec *>(ScopeMem); + } + const CXXScopeSpec &Scope() const { + return *reinterpret_cast<const CXXScopeSpec *>(ScopeMem); + } + void destroy() { + Scope().~CXXScopeSpec(); + } + }; + + struct PipeTypeInfo { + /// The access writes. + unsigned AccessWrites : 3; + + void destroy() {} + }; + + union { + PointerTypeInfo Ptr; + ReferenceTypeInfo Ref; + ArrayTypeInfo Arr; + FunctionTypeInfo Fun; + BlockPointerTypeInfo Cls; + MemberPointerTypeInfo Mem; + PipeTypeInfo PipeInfo; + }; + + void destroy() { + switch (Kind) { + case DeclaratorChunk::Function: return Fun.destroy(); + case DeclaratorChunk::Pointer: return Ptr.destroy(); + case DeclaratorChunk::BlockPointer: return Cls.destroy(); + case DeclaratorChunk::Reference: return Ref.destroy(); + case DeclaratorChunk::Array: return Arr.destroy(); + case DeclaratorChunk::MemberPointer: return Mem.destroy(); + case DeclaratorChunk::Paren: return; + case DeclaratorChunk::Pipe: return PipeInfo.destroy(); + } + } + + /// If there are attributes applied to this declaratorchunk, return + /// them. + const ParsedAttributesView &getAttrs() const { return AttrList; } + ParsedAttributesView &getAttrs() { return AttrList; } + + /// Return a DeclaratorChunk for a pointer. + static DeclaratorChunk getPointer(unsigned TypeQuals, SourceLocation Loc, + SourceLocation ConstQualLoc, + SourceLocation VolatileQualLoc, + SourceLocation RestrictQualLoc, + SourceLocation AtomicQualLoc, + SourceLocation UnalignedQualLoc) { + DeclaratorChunk I; + I.Kind = Pointer; + I.Loc = Loc; + new (&I.Ptr) PointerTypeInfo; + I.Ptr.TypeQuals = TypeQuals; + I.Ptr.ConstQualLoc = ConstQualLoc; + I.Ptr.VolatileQualLoc = VolatileQualLoc; + I.Ptr.RestrictQualLoc = RestrictQualLoc; + I.Ptr.AtomicQualLoc = AtomicQualLoc; + I.Ptr.UnalignedQualLoc = UnalignedQualLoc; + return I; + } + + /// Return a DeclaratorChunk for a reference. + static DeclaratorChunk getReference(unsigned TypeQuals, SourceLocation Loc, + bool lvalue) { + DeclaratorChunk I; + I.Kind = Reference; + I.Loc = Loc; + I.Ref.HasRestrict = (TypeQuals & DeclSpec::TQ_restrict) != 0; + I.Ref.LValueRef = lvalue; + return I; + } + + /// Return a DeclaratorChunk for an array. + static DeclaratorChunk getArray(unsigned TypeQuals, + bool isStatic, bool isStar, Expr *NumElts, + SourceLocation LBLoc, SourceLocation RBLoc) { + DeclaratorChunk I; + I.Kind = Array; + I.Loc = LBLoc; + I.EndLoc = RBLoc; + I.Arr.TypeQuals = TypeQuals; + I.Arr.hasStatic = isStatic; + I.Arr.isStar = isStar; + I.Arr.NumElts = NumElts; + return I; + } + + /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. + /// "TheDeclarator" is the declarator that this will be added to. + static DeclaratorChunk getFunction(bool HasProto, + bool IsAmbiguous, + SourceLocation LParenLoc, + ParamInfo *Params, unsigned NumParams, + SourceLocation EllipsisLoc, + SourceLocation RParenLoc, + bool RefQualifierIsLvalueRef, + SourceLocation RefQualifierLoc, + SourceLocation MutableLoc, + ExceptionSpecificationType ESpecType, + SourceRange ESpecRange, + ParsedType *Exceptions, + SourceRange *ExceptionRanges, + unsigned NumExceptions, + Expr *NoexceptExpr, + CachedTokens *ExceptionSpecTokens, + ArrayRef<NamedDecl *> DeclsInPrototype, + SourceLocation LocalRangeBegin, + SourceLocation LocalRangeEnd, + Declarator &TheDeclarator, + TypeResult TrailingReturnType = + TypeResult(), + SourceLocation TrailingReturnTypeLoc = + SourceLocation(), + DeclSpec *MethodQualifiers = nullptr); + + /// Return a DeclaratorChunk for a block. + static DeclaratorChunk getBlockPointer(unsigned TypeQuals, + SourceLocation Loc) { + DeclaratorChunk I; + I.Kind = BlockPointer; + I.Loc = Loc; + I.Cls.TypeQuals = TypeQuals; + return I; + } + + /// Return a DeclaratorChunk for a block. + static DeclaratorChunk getPipe(unsigned TypeQuals, + SourceLocation Loc) { + DeclaratorChunk I; + I.Kind = Pipe; + I.Loc = Loc; + I.Cls.TypeQuals = TypeQuals; + return I; + } + + static DeclaratorChunk getMemberPointer(const CXXScopeSpec &SS, + unsigned TypeQuals, + SourceLocation StarLoc, + SourceLocation EndLoc) { + DeclaratorChunk I; + I.Kind = MemberPointer; + I.Loc = SS.getBeginLoc(); + I.EndLoc = EndLoc; + new (&I.Mem) MemberPointerTypeInfo; + I.Mem.StarLoc = StarLoc; + I.Mem.TypeQuals = TypeQuals; + new (I.Mem.ScopeMem) CXXScopeSpec(SS); + return I; + } + + /// Return a DeclaratorChunk for a paren. + static DeclaratorChunk getParen(SourceLocation LParenLoc, + SourceLocation RParenLoc) { + DeclaratorChunk I; + I.Kind = Paren; + I.Loc = LParenLoc; + I.EndLoc = RParenLoc; + return I; + } + + bool isParen() const { + return Kind == Paren; + } +}; + +/// A parsed C++17 decomposition declarator of the form +/// '[' identifier-list ']' +class DecompositionDeclarator { +public: + struct Binding { + IdentifierInfo *Name; + SourceLocation NameLoc; + }; + +private: + /// The locations of the '[' and ']' tokens. + SourceLocation LSquareLoc, RSquareLoc; + + /// The bindings. + Binding *Bindings; + unsigned NumBindings : 31; + unsigned DeleteBindings : 1; + + friend class Declarator; + +public: + DecompositionDeclarator() + : Bindings(nullptr), NumBindings(0), DeleteBindings(false) {} + DecompositionDeclarator(const DecompositionDeclarator &G) = delete; + DecompositionDeclarator &operator=(const DecompositionDeclarator &G) = delete; + ~DecompositionDeclarator() { + if (DeleteBindings) + delete[] Bindings; + } + + void clear() { + LSquareLoc = RSquareLoc = SourceLocation(); + if (DeleteBindings) + delete[] Bindings; + Bindings = nullptr; + NumBindings = 0; + DeleteBindings = false; + } + + ArrayRef<Binding> bindings() const { + return llvm::ArrayRef(Bindings, NumBindings); + } + + bool isSet() const { return LSquareLoc.isValid(); } + + SourceLocation getLSquareLoc() const { return LSquareLoc; } + SourceLocation getRSquareLoc() const { return RSquareLoc; } + SourceRange getSourceRange() const { + return SourceRange(LSquareLoc, RSquareLoc); + } +}; + +/// Described the kind of function definition (if any) provided for +/// a function. +enum class FunctionDefinitionKind { + Declaration, + Definition, + Defaulted, + Deleted +}; + +enum class DeclaratorContext { + File, // File scope declaration. + Prototype, // Within a function prototype. + ObjCResult, // An ObjC method result type. + ObjCParameter, // An ObjC method parameter type. + KNRTypeList, // K&R type definition list for formals. + TypeName, // Abstract declarator for types. + FunctionalCast, // Type in a C++ functional cast expression. + Member, // Struct/Union field. + Block, // Declaration within a block in a function. + ForInit, // Declaration within first part of a for loop. + SelectionInit, // Declaration within optional init stmt of if/switch. + Condition, // Condition declaration in a C++ if/switch/while/for. + TemplateParam, // Within a template parameter list. + CXXNew, // C++ new-expression. + CXXCatch, // C++ catch exception-declaration + ObjCCatch, // Objective-C catch exception-declaration + BlockLiteral, // Block literal declarator. + LambdaExpr, // Lambda-expression declarator. + LambdaExprParameter, // Lambda-expression parameter declarator. + ConversionId, // C++ conversion-type-id. + TrailingReturn, // C++11 trailing-type-specifier. + TrailingReturnVar, // C++11 trailing-type-specifier for variable. + TemplateArg, // Any template argument (in template argument list). + TemplateTypeArg, // Template type argument (in default argument). + AliasDecl, // C++11 alias-declaration. + AliasTemplate, // C++11 alias-declaration template. + RequiresExpr, // C++2a requires-expression. + Association // C11 _Generic selection expression association. +}; + +// Describes whether the current context is a context where an implicit +// typename is allowed (C++2a [temp.res]p5]). +enum class ImplicitTypenameContext { + No, + Yes, +}; + +/// Information about one declarator, including the parsed type +/// information and the identifier. +/// +/// When the declarator is fully formed, this is turned into the appropriate +/// Decl object. +/// +/// Declarators come in two types: normal declarators and abstract declarators. +/// Abstract declarators are used when parsing types, and don't have an +/// identifier. Normal declarators do have ID's. +/// +/// Instances of this class should be a transient object that lives on the +/// stack, not objects that are allocated in large quantities on the heap. +class Declarator { + +private: + const DeclSpec &DS; + CXXScopeSpec SS; + UnqualifiedId Name; + SourceRange Range; + + /// Where we are parsing this declarator. + DeclaratorContext Context; + + /// The C++17 structured binding, if any. This is an alternative to a Name. + DecompositionDeclarator BindingGroup; + + /// DeclTypeInfo - This holds each type that the declarator includes as it is + /// parsed. This is pushed from the identifier out, which means that element + /// #0 will be the most closely bound to the identifier, and + /// DeclTypeInfo.back() will be the least closely bound. + SmallVector<DeclaratorChunk, 8> DeclTypeInfo; + + /// InvalidType - Set by Sema::GetTypeForDeclarator(). + unsigned InvalidType : 1; + + /// GroupingParens - Set by Parser::ParseParenDeclarator(). + unsigned GroupingParens : 1; + + /// FunctionDefinition - Is this Declarator for a function or member + /// definition and, if so, what kind? + /// + /// Actually a FunctionDefinitionKind. + unsigned FunctionDefinition : 2; + + /// Is this Declarator a redeclaration? + unsigned Redeclaration : 1; + + /// true if the declaration is preceded by \c __extension__. + unsigned Extension : 1; + + /// Indicates whether this is an Objective-C instance variable. + unsigned ObjCIvar : 1; + + /// Indicates whether this is an Objective-C 'weak' property. + unsigned ObjCWeakProperty : 1; + + /// Indicates whether the InlineParams / InlineBindings storage has been used. + unsigned InlineStorageUsed : 1; + + /// Indicates whether this declarator has an initializer. + unsigned HasInitializer : 1; + + /// Attributes attached to the declarator. + ParsedAttributes Attrs; + + /// Attributes attached to the declaration. See also documentation for the + /// corresponding constructor parameter. + const ParsedAttributesView &DeclarationAttrs; + + /// The asm label, if specified. + Expr *AsmLabel; + + /// \brief The constraint-expression specified by the trailing + /// requires-clause, or null if no such clause was specified. + Expr *TrailingRequiresClause; + + /// If this declarator declares a template, its template parameter lists. + ArrayRef<TemplateParameterList *> TemplateParameterLists; + + /// If the declarator declares an abbreviated function template, the innermost + /// template parameter list containing the invented and explicit template + /// parameters (if any). + TemplateParameterList *InventedTemplateParameterList; + +#ifndef _MSC_VER + union { +#endif + /// InlineParams - This is a local array used for the first function decl + /// chunk to avoid going to the heap for the common case when we have one + /// function chunk in the declarator. + DeclaratorChunk::ParamInfo InlineParams[16]; + DecompositionDeclarator::Binding InlineBindings[16]; +#ifndef _MSC_VER + }; +#endif + + /// If this is the second or subsequent declarator in this declaration, + /// the location of the comma before this declarator. + SourceLocation CommaLoc; + + /// If provided, the source location of the ellipsis used to describe + /// this declarator as a parameter pack. + SourceLocation EllipsisLoc; + + friend struct DeclaratorChunk; + +public: + /// `DS` and `DeclarationAttrs` must outlive the `Declarator`. In particular, + /// take care not to pass temporary objects for these parameters. + /// + /// `DeclarationAttrs` contains [[]] attributes from the + /// attribute-specifier-seq at the beginning of a declaration, which appertain + /// to the declared entity itself. Attributes with other syntax (e.g. GNU) + /// should not be placed in this attribute list; if they occur at the + /// beginning of a declaration, they apply to the `DeclSpec` and should be + /// attached to that instead. + /// + /// Here is an example of an attribute associated with a declaration: + /// + /// [[deprecated]] int x, y; + /// + /// This attribute appertains to all of the entities declared in the + /// declaration, i.e. `x` and `y` in this case. + Declarator(const DeclSpec &DS, const ParsedAttributesView &DeclarationAttrs, + DeclaratorContext C) + : DS(DS), Range(DS.getSourceRange()), Context(C), + InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error), + GroupingParens(false), FunctionDefinition(static_cast<unsigned>( + FunctionDefinitionKind::Declaration)), + Redeclaration(false), Extension(false), ObjCIvar(false), + ObjCWeakProperty(false), InlineStorageUsed(false), + HasInitializer(false), Attrs(DS.getAttributePool().getFactory()), + DeclarationAttrs(DeclarationAttrs), AsmLabel(nullptr), + TrailingRequiresClause(nullptr), + InventedTemplateParameterList(nullptr) { + assert(llvm::all_of(DeclarationAttrs, + [](const ParsedAttr &AL) { + return AL.isStandardAttributeSyntax(); + }) && + "DeclarationAttrs may only contain [[]] attributes"); + } + + ~Declarator() { + clear(); + } + /// getDeclSpec - Return the declaration-specifier that this declarator was + /// declared with. + const DeclSpec &getDeclSpec() const { return DS; } + + /// getMutableDeclSpec - Return a non-const version of the DeclSpec. This + /// should be used with extreme care: declspecs can often be shared between + /// multiple declarators, so mutating the DeclSpec affects all of the + /// Declarators. This should only be done when the declspec is known to not + /// be shared or when in error recovery etc. + DeclSpec &getMutableDeclSpec() { return const_cast<DeclSpec &>(DS); } + + AttributePool &getAttributePool() const { + return Attrs.getPool(); + } + + /// getCXXScopeSpec - Return the C++ scope specifier (global scope or + /// nested-name-specifier) that is part of the declarator-id. + const CXXScopeSpec &getCXXScopeSpec() const { return SS; } + CXXScopeSpec &getCXXScopeSpec() { return SS; } + + /// Retrieve the name specified by this declarator. + UnqualifiedId &getName() { return Name; } + + const DecompositionDeclarator &getDecompositionDeclarator() const { + return BindingGroup; + } + + DeclaratorContext getContext() const { return Context; } + + bool isPrototypeContext() const { + return (Context == DeclaratorContext::Prototype || + Context == DeclaratorContext::ObjCParameter || + Context == DeclaratorContext::ObjCResult || + Context == DeclaratorContext::LambdaExprParameter); + } + + /// Get the source range that spans this declarator. + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } + + void SetSourceRange(SourceRange R) { Range = R; } + /// SetRangeBegin - Set the start of the source range to Loc, unless it's + /// invalid. + void SetRangeBegin(SourceLocation Loc) { + if (!Loc.isInvalid()) + Range.setBegin(Loc); + } + /// SetRangeEnd - Set the end of the source range to Loc, unless it's invalid. + void SetRangeEnd(SourceLocation Loc) { + if (!Loc.isInvalid()) + Range.setEnd(Loc); + } + /// ExtendWithDeclSpec - Extend the declarator source range to include the + /// given declspec, unless its location is invalid. Adopts the range start if + /// the current range start is invalid. + void ExtendWithDeclSpec(const DeclSpec &DS) { + SourceRange SR = DS.getSourceRange(); + if (Range.getBegin().isInvalid()) + Range.setBegin(SR.getBegin()); + if (!SR.getEnd().isInvalid()) + Range.setEnd(SR.getEnd()); + } + + /// Reset the contents of this Declarator. + void clear() { + SS.clear(); + Name.clear(); + Range = DS.getSourceRange(); + BindingGroup.clear(); + + for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i) + DeclTypeInfo[i].destroy(); + DeclTypeInfo.clear(); + Attrs.clear(); + AsmLabel = nullptr; + InlineStorageUsed = false; + HasInitializer = false; + ObjCIvar = false; + ObjCWeakProperty = false; + CommaLoc = SourceLocation(); + EllipsisLoc = SourceLocation(); + } + + /// mayOmitIdentifier - Return true if the identifier is either optional or + /// not allowed. This is true for typenames, prototypes, and template + /// parameter lists. + bool mayOmitIdentifier() const { + switch (Context) { + case DeclaratorContext::File: + case DeclaratorContext::KNRTypeList: + case DeclaratorContext::Member: + case DeclaratorContext::Block: + case DeclaratorContext::ForInit: + case DeclaratorContext::SelectionInit: + case DeclaratorContext::Condition: + return false; + + case DeclaratorContext::TypeName: + case DeclaratorContext::FunctionalCast: + case DeclaratorContext::AliasDecl: + case DeclaratorContext::AliasTemplate: + case DeclaratorContext::Prototype: + case DeclaratorContext::LambdaExprParameter: + case DeclaratorContext::ObjCParameter: + case DeclaratorContext::ObjCResult: + case DeclaratorContext::TemplateParam: + case DeclaratorContext::CXXNew: + case DeclaratorContext::CXXCatch: + case DeclaratorContext::ObjCCatch: + case DeclaratorContext::BlockLiteral: + case DeclaratorContext::LambdaExpr: + case DeclaratorContext::ConversionId: + case DeclaratorContext::TemplateArg: + case DeclaratorContext::TemplateTypeArg: + case DeclaratorContext::TrailingReturn: + case DeclaratorContext::TrailingReturnVar: + case DeclaratorContext::RequiresExpr: + case DeclaratorContext::Association: + return true; + } + llvm_unreachable("unknown context kind!"); + } + + /// mayHaveIdentifier - Return true if the identifier is either optional or + /// required. This is true for normal declarators and prototypes, but not + /// typenames. + bool mayHaveIdentifier() const { + switch (Context) { + case DeclaratorContext::File: + case DeclaratorContext::KNRTypeList: + case DeclaratorContext::Member: + case DeclaratorContext::Block: + case DeclaratorContext::ForInit: + case DeclaratorContext::SelectionInit: + case DeclaratorContext::Condition: + case DeclaratorContext::Prototype: + case DeclaratorContext::LambdaExprParameter: + case DeclaratorContext::TemplateParam: + case DeclaratorContext::CXXCatch: + case DeclaratorContext::ObjCCatch: + case DeclaratorContext::RequiresExpr: + return true; + + case DeclaratorContext::TypeName: + case DeclaratorContext::FunctionalCast: + case DeclaratorContext::CXXNew: + case DeclaratorContext::AliasDecl: + case DeclaratorContext::AliasTemplate: + case DeclaratorContext::ObjCParameter: + case DeclaratorContext::ObjCResult: + case DeclaratorContext::BlockLiteral: + case DeclaratorContext::LambdaExpr: + case DeclaratorContext::ConversionId: + case DeclaratorContext::TemplateArg: + case DeclaratorContext::TemplateTypeArg: + case DeclaratorContext::TrailingReturn: + case DeclaratorContext::TrailingReturnVar: + case DeclaratorContext::Association: + return false; + } + llvm_unreachable("unknown context kind!"); + } + + /// Return true if the context permits a C++17 decomposition declarator. + bool mayHaveDecompositionDeclarator() const { + switch (Context) { + case DeclaratorContext::File: + // FIXME: It's not clear that the proposal meant to allow file-scope + // structured bindings, but it does. + case DeclaratorContext::Block: + case DeclaratorContext::ForInit: + case DeclaratorContext::SelectionInit: + case DeclaratorContext::Condition: + return true; + + case DeclaratorContext::Member: + case DeclaratorContext::Prototype: + case DeclaratorContext::TemplateParam: + case DeclaratorContext::RequiresExpr: + // Maybe one day... + return false; + + // These contexts don't allow any kind of non-abstract declarator. + case DeclaratorContext::KNRTypeList: + case DeclaratorContext::TypeName: + case DeclaratorContext::FunctionalCast: + case DeclaratorContext::AliasDecl: + case DeclaratorContext::AliasTemplate: + case DeclaratorContext::LambdaExprParameter: + case DeclaratorContext::ObjCParameter: + case DeclaratorContext::ObjCResult: + case DeclaratorContext::CXXNew: + case DeclaratorContext::CXXCatch: + case DeclaratorContext::ObjCCatch: + case DeclaratorContext::BlockLiteral: + case DeclaratorContext::LambdaExpr: + case DeclaratorContext::ConversionId: + case DeclaratorContext::TemplateArg: + case DeclaratorContext::TemplateTypeArg: + case DeclaratorContext::TrailingReturn: + case DeclaratorContext::TrailingReturnVar: + case DeclaratorContext::Association: + return false; + } + llvm_unreachable("unknown context kind!"); + } + + /// mayBeFollowedByCXXDirectInit - Return true if the declarator can be + /// followed by a C++ direct initializer, e.g. "int x(1);". + bool mayBeFollowedByCXXDirectInit() const { + if (hasGroupingParens()) return false; + + if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) + return false; + + if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern && + Context != DeclaratorContext::File) + return false; + + // Special names can't have direct initializers. + if (Name.getKind() != UnqualifiedIdKind::IK_Identifier) + return false; + + switch (Context) { + case DeclaratorContext::File: + case DeclaratorContext::Block: + case DeclaratorContext::ForInit: + case DeclaratorContext::SelectionInit: + case DeclaratorContext::TrailingReturnVar: + return true; + + case DeclaratorContext::Condition: + // This may not be followed by a direct initializer, but it can't be a + // function declaration either, and we'd prefer to perform a tentative + // parse in order to produce the right diagnostic. + return true; + + case DeclaratorContext::KNRTypeList: + case DeclaratorContext::Member: + case DeclaratorContext::Prototype: + case DeclaratorContext::LambdaExprParameter: + case DeclaratorContext::ObjCParameter: + case DeclaratorContext::ObjCResult: + case DeclaratorContext::TemplateParam: + case DeclaratorContext::CXXCatch: + case DeclaratorContext::ObjCCatch: + case DeclaratorContext::TypeName: + case DeclaratorContext::FunctionalCast: // FIXME + case DeclaratorContext::CXXNew: + case DeclaratorContext::AliasDecl: + case DeclaratorContext::AliasTemplate: + case DeclaratorContext::BlockLiteral: + case DeclaratorContext::LambdaExpr: + case DeclaratorContext::ConversionId: + case DeclaratorContext::TemplateArg: + case DeclaratorContext::TemplateTypeArg: + case DeclaratorContext::TrailingReturn: + case DeclaratorContext::RequiresExpr: + case DeclaratorContext::Association: + return false; + } + llvm_unreachable("unknown context kind!"); + } + + /// isPastIdentifier - Return true if we have parsed beyond the point where + /// the name would appear. (This may happen even if we haven't actually parsed + /// a name, perhaps because this context doesn't require one.) + bool isPastIdentifier() const { return Name.isValid(); } + + /// hasName - Whether this declarator has a name, which might be an + /// identifier (accessible via getIdentifier()) or some kind of + /// special C++ name (constructor, destructor, etc.), or a structured + /// binding (which is not exactly a name, but occupies the same position). + bool hasName() const { + return Name.getKind() != UnqualifiedIdKind::IK_Identifier || + Name.Identifier || isDecompositionDeclarator(); + } + + /// Return whether this declarator is a decomposition declarator. + bool isDecompositionDeclarator() const { + return BindingGroup.isSet(); + } + + IdentifierInfo *getIdentifier() const { + if (Name.getKind() == UnqualifiedIdKind::IK_Identifier) + return Name.Identifier; + + return nullptr; + } + SourceLocation getIdentifierLoc() const { return Name.StartLocation; } + + /// Set the name of this declarator to be the given identifier. + void SetIdentifier(IdentifierInfo *Id, SourceLocation IdLoc) { + Name.setIdentifier(Id, IdLoc); + } + + /// Set the decomposition bindings for this declarator. + void + setDecompositionBindings(SourceLocation LSquareLoc, + ArrayRef<DecompositionDeclarator::Binding> Bindings, + SourceLocation RSquareLoc); + + /// AddTypeInfo - Add a chunk to this declarator. Also extend the range to + /// EndLoc, which should be the last token of the chunk. + /// This function takes attrs by R-Value reference because it takes ownership + /// of those attributes from the parameter. + void AddTypeInfo(const DeclaratorChunk &TI, ParsedAttributes &&attrs, + SourceLocation EndLoc) { + DeclTypeInfo.push_back(TI); + DeclTypeInfo.back().getAttrs().addAll(attrs.begin(), attrs.end()); + getAttributePool().takeAllFrom(attrs.getPool()); + + if (!EndLoc.isInvalid()) + SetRangeEnd(EndLoc); + } + + /// AddTypeInfo - Add a chunk to this declarator. Also extend the range to + /// EndLoc, which should be the last token of the chunk. + void AddTypeInfo(const DeclaratorChunk &TI, SourceLocation EndLoc) { + DeclTypeInfo.push_back(TI); + + if (!EndLoc.isInvalid()) + SetRangeEnd(EndLoc); + } + + /// Add a new innermost chunk to this declarator. + void AddInnermostTypeInfo(const DeclaratorChunk &TI) { + DeclTypeInfo.insert(DeclTypeInfo.begin(), TI); + } + + /// Return the number of types applied to this declarator. + unsigned getNumTypeObjects() const { return DeclTypeInfo.size(); } + + /// Return the specified TypeInfo from this declarator. TypeInfo #0 is + /// closest to the identifier. + const DeclaratorChunk &getTypeObject(unsigned i) const { + assert(i < DeclTypeInfo.size() && "Invalid type chunk"); + return DeclTypeInfo[i]; + } + DeclaratorChunk &getTypeObject(unsigned i) { + assert(i < DeclTypeInfo.size() && "Invalid type chunk"); + return DeclTypeInfo[i]; + } + + typedef SmallVectorImpl<DeclaratorChunk>::const_iterator type_object_iterator; + typedef llvm::iterator_range<type_object_iterator> type_object_range; + + /// Returns the range of type objects, from the identifier outwards. + type_object_range type_objects() const { + return type_object_range(DeclTypeInfo.begin(), DeclTypeInfo.end()); + } + + void DropFirstTypeObject() { + assert(!DeclTypeInfo.empty() && "No type chunks to drop."); + DeclTypeInfo.front().destroy(); + DeclTypeInfo.erase(DeclTypeInfo.begin()); + } + + /// Return the innermost (closest to the declarator) chunk of this + /// declarator that is not a parens chunk, or null if there are no + /// non-parens chunks. + const DeclaratorChunk *getInnermostNonParenChunk() const { + for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) { + if (!DeclTypeInfo[i].isParen()) + return &DeclTypeInfo[i]; + } + return nullptr; + } + + /// Return the outermost (furthest from the declarator) chunk of + /// this declarator that is not a parens chunk, or null if there are + /// no non-parens chunks. + const DeclaratorChunk *getOutermostNonParenChunk() const { + for (unsigned i = DeclTypeInfo.size(), i_end = 0; i != i_end; --i) { + if (!DeclTypeInfo[i-1].isParen()) + return &DeclTypeInfo[i-1]; + } + return nullptr; + } + + /// isArrayOfUnknownBound - This method returns true if the declarator + /// is a declarator for an array of unknown bound (looking through + /// parentheses). + bool isArrayOfUnknownBound() const { + const DeclaratorChunk *chunk = getInnermostNonParenChunk(); + return (chunk && chunk->Kind == DeclaratorChunk::Array && + !chunk->Arr.NumElts); + } + + /// isFunctionDeclarator - This method returns true if the declarator + /// is a function declarator (looking through parentheses). + /// If true is returned, then the reference type parameter idx is + /// assigned with the index of the declaration chunk. + bool isFunctionDeclarator(unsigned& idx) const { + for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) { + switch (DeclTypeInfo[i].Kind) { + case DeclaratorChunk::Function: + idx = i; + return true; + case DeclaratorChunk::Paren: + continue; + case DeclaratorChunk::Pointer: + case DeclaratorChunk::Reference: + case DeclaratorChunk::Array: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: + return false; + } + llvm_unreachable("Invalid type chunk"); + } + return false; + } + + /// isFunctionDeclarator - Once this declarator is fully parsed and formed, + /// this method returns true if the identifier is a function declarator + /// (looking through parentheses). + bool isFunctionDeclarator() const { + unsigned index; + return isFunctionDeclarator(index); + } + + /// getFunctionTypeInfo - Retrieves the function type info object + /// (looking through parentheses). + DeclaratorChunk::FunctionTypeInfo &getFunctionTypeInfo() { + assert(isFunctionDeclarator() && "Not a function declarator!"); + unsigned index = 0; + isFunctionDeclarator(index); + return DeclTypeInfo[index].Fun; + } + + /// getFunctionTypeInfo - Retrieves the function type info object + /// (looking through parentheses). + const DeclaratorChunk::FunctionTypeInfo &getFunctionTypeInfo() const { + return const_cast<Declarator*>(this)->getFunctionTypeInfo(); + } + + /// Determine whether the declaration that will be produced from + /// this declaration will be a function. + /// + /// A declaration can declare a function even if the declarator itself + /// isn't a function declarator, if the type specifier refers to a function + /// type. This routine checks for both cases. + bool isDeclarationOfFunction() const; + + /// Return true if this declaration appears in a context where a + /// function declarator would be a function declaration. + bool isFunctionDeclarationContext() const { + if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) + return false; + + switch (Context) { + case DeclaratorContext::File: + case DeclaratorContext::Member: + case DeclaratorContext::Block: + case DeclaratorContext::ForInit: + case DeclaratorContext::SelectionInit: + return true; + + case DeclaratorContext::Condition: + case DeclaratorContext::KNRTypeList: + case DeclaratorContext::TypeName: + case DeclaratorContext::FunctionalCast: + case DeclaratorContext::AliasDecl: + case DeclaratorContext::AliasTemplate: + case DeclaratorContext::Prototype: + case DeclaratorContext::LambdaExprParameter: + case DeclaratorContext::ObjCParameter: + case DeclaratorContext::ObjCResult: + case DeclaratorContext::TemplateParam: + case DeclaratorContext::CXXNew: + case DeclaratorContext::CXXCatch: + case DeclaratorContext::ObjCCatch: + case DeclaratorContext::BlockLiteral: + case DeclaratorContext::LambdaExpr: + case DeclaratorContext::ConversionId: + case DeclaratorContext::TemplateArg: + case DeclaratorContext::TemplateTypeArg: + case DeclaratorContext::TrailingReturn: + case DeclaratorContext::TrailingReturnVar: + case DeclaratorContext::RequiresExpr: + case DeclaratorContext::Association: + return false; + } + llvm_unreachable("unknown context kind!"); + } + + /// Determine whether this declaration appears in a context where an + /// expression could appear. + bool isExpressionContext() const { + switch (Context) { + case DeclaratorContext::File: + case DeclaratorContext::KNRTypeList: + case DeclaratorContext::Member: + + // FIXME: sizeof(...) permits an expression. + case DeclaratorContext::TypeName: + + case DeclaratorContext::FunctionalCast: + case DeclaratorContext::AliasDecl: + case DeclaratorContext::AliasTemplate: + case DeclaratorContext::Prototype: + case DeclaratorContext::LambdaExprParameter: + case DeclaratorContext::ObjCParameter: + case DeclaratorContext::ObjCResult: + case DeclaratorContext::TemplateParam: + case DeclaratorContext::CXXNew: + case DeclaratorContext::CXXCatch: + case DeclaratorContext::ObjCCatch: + case DeclaratorContext::BlockLiteral: + case DeclaratorContext::LambdaExpr: + case DeclaratorContext::ConversionId: + case DeclaratorContext::TrailingReturn: + case DeclaratorContext::TrailingReturnVar: + case DeclaratorContext::TemplateTypeArg: + case DeclaratorContext::RequiresExpr: + case DeclaratorContext::Association: + return false; + + case DeclaratorContext::Block: + case DeclaratorContext::ForInit: + case DeclaratorContext::SelectionInit: + case DeclaratorContext::Condition: + case DeclaratorContext::TemplateArg: + return true; + } + + llvm_unreachable("unknown context kind!"); + } + + /// Return true if a function declarator at this position would be a + /// function declaration. + bool isFunctionDeclaratorAFunctionDeclaration() const { + if (!isFunctionDeclarationContext()) + return false; + + for (unsigned I = 0, N = getNumTypeObjects(); I != N; ++I) + if (getTypeObject(I).Kind != DeclaratorChunk::Paren) + return false; + + return true; + } + + /// Determine whether a trailing return type was written (at any + /// level) within this declarator. + bool hasTrailingReturnType() const { + for (const auto &Chunk : type_objects()) + if (Chunk.Kind == DeclaratorChunk::Function && + Chunk.Fun.hasTrailingReturnType()) + return true; + return false; + } + /// Get the trailing return type appearing (at any level) within this + /// declarator. + ParsedType getTrailingReturnType() const { + for (const auto &Chunk : type_objects()) + if (Chunk.Kind == DeclaratorChunk::Function && + Chunk.Fun.hasTrailingReturnType()) + return Chunk.Fun.getTrailingReturnType(); + return ParsedType(); + } + + /// \brief Sets a trailing requires clause for this declarator. + void setTrailingRequiresClause(Expr *TRC) { + TrailingRequiresClause = TRC; + + SetRangeEnd(TRC->getEndLoc()); + } + + /// \brief Sets a trailing requires clause for this declarator. + Expr *getTrailingRequiresClause() { + return TrailingRequiresClause; + } + + /// \brief Determine whether a trailing requires clause was written in this + /// declarator. + bool hasTrailingRequiresClause() const { + return TrailingRequiresClause != nullptr; + } + + /// Sets the template parameter lists that preceded the declarator. + void setTemplateParameterLists(ArrayRef<TemplateParameterList *> TPLs) { + TemplateParameterLists = TPLs; + } + + /// The template parameter lists that preceded the declarator. + ArrayRef<TemplateParameterList *> getTemplateParameterLists() const { + return TemplateParameterLists; + } + + /// Sets the template parameter list generated from the explicit template + /// parameters along with any invented template parameters from + /// placeholder-typed parameters. + void setInventedTemplateParameterList(TemplateParameterList *Invented) { + InventedTemplateParameterList = Invented; + } + + /// The template parameter list generated from the explicit template + /// parameters along with any invented template parameters from + /// placeholder-typed parameters, if there were any such parameters. + TemplateParameterList * getInventedTemplateParameterList() const { + return InventedTemplateParameterList; + } + + /// takeAttributes - Takes attributes from the given parsed-attributes + /// set and add them to this declarator. + /// + /// These examples both add 3 attributes to "var": + /// short int var __attribute__((aligned(16),common,deprecated)); + /// short int x, __attribute__((aligned(16)) var + /// __attribute__((common,deprecated)); + /// + /// Also extends the range of the declarator. + void takeAttributes(ParsedAttributes &attrs) { + Attrs.takeAllFrom(attrs); + + if (attrs.Range.getEnd().isValid()) + SetRangeEnd(attrs.Range.getEnd()); + } + + const ParsedAttributes &getAttributes() const { return Attrs; } + ParsedAttributes &getAttributes() { return Attrs; } + + const ParsedAttributesView &getDeclarationAttributes() const { + return DeclarationAttrs; + } + + /// hasAttributes - do we contain any attributes? + bool hasAttributes() const { + if (!getAttributes().empty() || !getDeclarationAttributes().empty() || + getDeclSpec().hasAttributes()) + return true; + for (unsigned i = 0, e = getNumTypeObjects(); i != e; ++i) + if (!getTypeObject(i).getAttrs().empty()) + return true; + return false; + } + + /// Return a source range list of C++11 attributes associated + /// with the declarator. + void getCXX11AttributeRanges(SmallVectorImpl<SourceRange> &Ranges) { + for (const ParsedAttr &AL : Attrs) + if (AL.isCXX11Attribute()) + Ranges.push_back(AL.getRange()); + } + + void setAsmLabel(Expr *E) { AsmLabel = E; } + Expr *getAsmLabel() const { return AsmLabel; } + + void setExtension(bool Val = true) { Extension = Val; } + bool getExtension() const { return Extension; } + + void setObjCIvar(bool Val = true) { ObjCIvar = Val; } + bool isObjCIvar() const { return ObjCIvar; } + + void setObjCWeakProperty(bool Val = true) { ObjCWeakProperty = Val; } + bool isObjCWeakProperty() const { return ObjCWeakProperty; } + + void setInvalidType(bool Val = true) { InvalidType = Val; } + bool isInvalidType() const { + return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error; + } + + void setGroupingParens(bool flag) { GroupingParens = flag; } + bool hasGroupingParens() const { return GroupingParens; } + + bool isFirstDeclarator() const { return !CommaLoc.isValid(); } + SourceLocation getCommaLoc() const { return CommaLoc; } + void setCommaLoc(SourceLocation CL) { CommaLoc = CL; } + + bool hasEllipsis() const { return EllipsisLoc.isValid(); } + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + void setEllipsisLoc(SourceLocation EL) { EllipsisLoc = EL; } + + void setFunctionDefinitionKind(FunctionDefinitionKind Val) { + FunctionDefinition = static_cast<unsigned>(Val); + } + + bool isFunctionDefinition() const { + return getFunctionDefinitionKind() != FunctionDefinitionKind::Declaration; + } + + FunctionDefinitionKind getFunctionDefinitionKind() const { + return (FunctionDefinitionKind)FunctionDefinition; + } + + void setHasInitializer(bool Val = true) { HasInitializer = Val; } + bool hasInitializer() const { return HasInitializer; } + + /// Returns true if this declares a real member and not a friend. + bool isFirstDeclarationOfMember() { + return getContext() == DeclaratorContext::Member && + !getDeclSpec().isFriendSpecified(); + } + + /// Returns true if this declares a static member. This cannot be called on a + /// declarator outside of a MemberContext because we won't know until + /// redeclaration time if the decl is static. + bool isStaticMember(); + + /// Returns true if this declares a constructor or a destructor. + bool isCtorOrDtor(); + + void setRedeclaration(bool Val) { Redeclaration = Val; } + bool isRedeclaration() const { return Redeclaration; } +}; + +/// This little struct is used to capture information about +/// structure field declarators, which is basically just a bitfield size. +struct FieldDeclarator { + Declarator D; + Expr *BitfieldSize; + explicit FieldDeclarator(const DeclSpec &DS, + const ParsedAttributes &DeclarationAttrs) + : D(DS, DeclarationAttrs, DeclaratorContext::Member), + BitfieldSize(nullptr) {} +}; + +/// Represents a C++11 virt-specifier-seq. +class VirtSpecifiers { +public: + enum Specifier { + VS_None = 0, + VS_Override = 1, + VS_Final = 2, + VS_Sealed = 4, + // Represents the __final keyword, which is legal for gcc in pre-C++11 mode. + VS_GNU_Final = 8, + VS_Abstract = 16 + }; + + VirtSpecifiers() : Specifiers(0), LastSpecifier(VS_None) { } + + bool SetSpecifier(Specifier VS, SourceLocation Loc, + const char *&PrevSpec); + + bool isUnset() const { return Specifiers == 0; } + + bool isOverrideSpecified() const { return Specifiers & VS_Override; } + SourceLocation getOverrideLoc() const { return VS_overrideLoc; } + + bool isFinalSpecified() const { return Specifiers & (VS_Final | VS_Sealed | VS_GNU_Final); } + bool isFinalSpelledSealed() const { return Specifiers & VS_Sealed; } + SourceLocation getFinalLoc() const { return VS_finalLoc; } + SourceLocation getAbstractLoc() const { return VS_abstractLoc; } + + void clear() { Specifiers = 0; } + + static const char *getSpecifierName(Specifier VS); + + SourceLocation getFirstLocation() const { return FirstLocation; } + SourceLocation getLastLocation() const { return LastLocation; } + Specifier getLastSpecifier() const { return LastSpecifier; } + +private: + unsigned Specifiers; + Specifier LastSpecifier; + + SourceLocation VS_overrideLoc, VS_finalLoc, VS_abstractLoc; + SourceLocation FirstLocation; + SourceLocation LastLocation; +}; + +enum class LambdaCaptureInitKind { + NoInit, //!< [a] + CopyInit, //!< [a = b], [a = {b}] + DirectInit, //!< [a(b)] + ListInit //!< [a{b}] +}; + +/// Represents a complete lambda introducer. +struct LambdaIntroducer { + /// An individual capture in a lambda introducer. + struct LambdaCapture { + LambdaCaptureKind Kind; + SourceLocation Loc; + IdentifierInfo *Id; + SourceLocation EllipsisLoc; + LambdaCaptureInitKind InitKind; + ExprResult Init; + ParsedType InitCaptureType; + SourceRange ExplicitRange; + + LambdaCapture(LambdaCaptureKind Kind, SourceLocation Loc, + IdentifierInfo *Id, SourceLocation EllipsisLoc, + LambdaCaptureInitKind InitKind, ExprResult Init, + ParsedType InitCaptureType, + SourceRange ExplicitRange) + : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc), + InitKind(InitKind), Init(Init), InitCaptureType(InitCaptureType), + ExplicitRange(ExplicitRange) {} + }; + + SourceRange Range; + SourceLocation DefaultLoc; + LambdaCaptureDefault Default; + SmallVector<LambdaCapture, 4> Captures; + + LambdaIntroducer() + : Default(LCD_None) {} + + bool hasLambdaCapture() const { + return Captures.size() > 0 || Default != LCD_None; + } + + /// Append a capture in a lambda introducer. + void addCapture(LambdaCaptureKind Kind, + SourceLocation Loc, + IdentifierInfo* Id, + SourceLocation EllipsisLoc, + LambdaCaptureInitKind InitKind, + ExprResult Init, + ParsedType InitCaptureType, + SourceRange ExplicitRange) { + Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc, InitKind, Init, + InitCaptureType, ExplicitRange)); + } +}; + +struct InventedTemplateParameterInfo { + /// The number of parameters in the template parameter list that were + /// explicitly specified by the user, as opposed to being invented by use + /// of an auto parameter. + unsigned NumExplicitTemplateParams = 0; + + /// If this is a generic lambda or abbreviated function template, use this + /// as the depth of each 'auto' parameter, during initial AST construction. + unsigned AutoTemplateParameterDepth = 0; + + /// Store the list of the template parameters for a generic lambda or an + /// abbreviated function template. + /// If this is a generic lambda or abbreviated function template, this holds + /// the explicit template parameters followed by the auto parameters + /// converted into TemplateTypeParmDecls. + /// It can be used to construct the generic lambda or abbreviated template's + /// template parameter list during initial AST construction. + SmallVector<NamedDecl*, 4> TemplateParams; +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_DECLSPEC_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/DelayedDiagnostic.h b/contrib/libs/clang16/include/clang/Sema/DelayedDiagnostic.h new file mode 100644 index 0000000000..dd6b1ca0fd --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/DelayedDiagnostic.h @@ -0,0 +1,343 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- DelayedDiagnostic.h - Delayed declarator diagnostics -----*- 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 +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the classes clang::DelayedDiagnostic and +/// clang::AccessedEntity. +/// +/// DelayedDiangostic is used to record diagnostics that are being +/// conditionally produced during declarator parsing. Certain kinds of +/// diagnostics -- notably deprecation and access control -- are suppressed +/// based on semantic properties of the parsed declaration that aren't known +/// until it is fully parsed. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H +#define LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H + +#include "clang/AST/DeclAccessPair.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include <cassert> +#include <cstddef> +#include <utility> + +namespace clang { + +class ObjCInterfaceDecl; +class ObjCPropertyDecl; + +namespace sema { + +/// A declaration being accessed, together with information about how +/// it was accessed. +class AccessedEntity { +public: + /// A member declaration found through lookup. The target is the + /// member. + enum MemberNonce { Member }; + + /// A hierarchy (base-to-derived or derived-to-base) conversion. + /// The target is the base class. + enum BaseNonce { Base }; + + AccessedEntity(PartialDiagnostic::DiagStorageAllocator &Allocator, + MemberNonce _, CXXRecordDecl *NamingClass, + DeclAccessPair FoundDecl, QualType BaseObjectType) + : Access(FoundDecl.getAccess()), IsMember(true), + Target(FoundDecl.getDecl()), NamingClass(NamingClass), + BaseObjectType(BaseObjectType), Diag(0, Allocator) {} + + AccessedEntity(PartialDiagnostic::DiagStorageAllocator &Allocator, + BaseNonce _, CXXRecordDecl *BaseClass, + CXXRecordDecl *DerivedClass, AccessSpecifier Access) + : Access(Access), IsMember(false), Target(BaseClass), + NamingClass(DerivedClass), Diag(0, Allocator) {} + + bool isMemberAccess() const { return IsMember; } + + bool isQuiet() const { return Diag.getDiagID() == 0; } + + AccessSpecifier getAccess() const { return AccessSpecifier(Access); } + + // These apply to member decls... + NamedDecl *getTargetDecl() const { return Target; } + CXXRecordDecl *getNamingClass() const { return NamingClass; } + + // ...and these apply to hierarchy conversions. + CXXRecordDecl *getBaseClass() const { + assert(!IsMember); return cast<CXXRecordDecl>(Target); + } + CXXRecordDecl *getDerivedClass() const { return NamingClass; } + + /// Retrieves the base object type, important when accessing + /// an instance member. + QualType getBaseObjectType() const { return BaseObjectType; } + + /// Sets a diagnostic to be performed. The diagnostic is given + /// four (additional) arguments: + /// %0 - 0 if the entity was private, 1 if protected + /// %1 - the DeclarationName of the entity + /// %2 - the TypeDecl type of the naming class + /// %3 - the TypeDecl type of the declaring class + void setDiag(const PartialDiagnostic &PDiag) { + assert(isQuiet() && "partial diagnostic already defined"); + Diag = PDiag; + } + PartialDiagnostic &setDiag(unsigned DiagID) { + assert(isQuiet() && "partial diagnostic already defined"); + assert(DiagID && "creating null diagnostic"); + Diag.Reset(DiagID); + return Diag; + } + const PartialDiagnostic &getDiag() const { + return Diag; + } + +private: + unsigned Access : 2; + unsigned IsMember : 1; + NamedDecl *Target; + CXXRecordDecl *NamingClass; + QualType BaseObjectType; + PartialDiagnostic Diag; +}; + +/// A diagnostic message which has been conditionally emitted pending +/// the complete parsing of the current declaration. +class DelayedDiagnostic { +public: + enum DDKind : unsigned char { Availability, Access, ForbiddenType }; + + DDKind Kind; + bool Triggered; + + SourceLocation Loc; + + void Destroy(); + + static DelayedDiagnostic makeAvailability(AvailabilityResult AR, + ArrayRef<SourceLocation> Locs, + const NamedDecl *ReferringDecl, + const NamedDecl *OffendingDecl, + const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty, + StringRef Msg, + bool ObjCPropertyAccess); + + static DelayedDiagnostic makeAccess(SourceLocation Loc, + const AccessedEntity &Entity) { + DelayedDiagnostic DD; + DD.Kind = Access; + DD.Triggered = false; + DD.Loc = Loc; + new (&DD.getAccessData()) AccessedEntity(Entity); + return DD; + } + + static DelayedDiagnostic makeForbiddenType(SourceLocation loc, + unsigned diagnostic, + QualType type, + unsigned argument) { + DelayedDiagnostic DD; + DD.Kind = ForbiddenType; + DD.Triggered = false; + DD.Loc = loc; + DD.ForbiddenTypeData.Diagnostic = diagnostic; + DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr(); + DD.ForbiddenTypeData.Argument = argument; + return DD; + } + + AccessedEntity &getAccessData() { + assert(Kind == Access && "Not an access diagnostic."); + return *reinterpret_cast<AccessedEntity*>(AccessData); + } + const AccessedEntity &getAccessData() const { + assert(Kind == Access && "Not an access diagnostic."); + return *reinterpret_cast<const AccessedEntity*>(AccessData); + } + + const NamedDecl *getAvailabilityReferringDecl() const { + assert(Kind == Availability && "Not an availability diagnostic."); + return AvailabilityData.ReferringDecl; + } + + const NamedDecl *getAvailabilityOffendingDecl() const { + return AvailabilityData.OffendingDecl; + } + + StringRef getAvailabilityMessage() const { + assert(Kind == Availability && "Not an availability diagnostic."); + return StringRef(AvailabilityData.Message, AvailabilityData.MessageLen); + } + + ArrayRef<SourceLocation> getAvailabilitySelectorLocs() const { + assert(Kind == Availability && "Not an availability diagnostic."); + return llvm::ArrayRef(AvailabilityData.SelectorLocs, + AvailabilityData.NumSelectorLocs); + } + + AvailabilityResult getAvailabilityResult() const { + assert(Kind == Availability && "Not an availability diagnostic."); + return AvailabilityData.AR; + } + + /// The diagnostic ID to emit. Used like so: + /// Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) + /// << diag.getForbiddenTypeOperand() + /// << diag.getForbiddenTypeArgument(); + unsigned getForbiddenTypeDiagnostic() const { + assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); + return ForbiddenTypeData.Diagnostic; + } + + unsigned getForbiddenTypeArgument() const { + assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); + return ForbiddenTypeData.Argument; + } + + QualType getForbiddenTypeOperand() const { + assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); + return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType); + } + + const ObjCInterfaceDecl *getUnknownObjCClass() const { + return AvailabilityData.UnknownObjCClass; + } + + const ObjCPropertyDecl *getObjCProperty() const { + return AvailabilityData.ObjCProperty; + } + + bool getObjCPropertyAccess() const { + return AvailabilityData.ObjCPropertyAccess; + } + +private: + struct AD { + const NamedDecl *ReferringDecl; + const NamedDecl *OffendingDecl; + const ObjCInterfaceDecl *UnknownObjCClass; + const ObjCPropertyDecl *ObjCProperty; + const char *Message; + size_t MessageLen; + SourceLocation *SelectorLocs; + size_t NumSelectorLocs; + AvailabilityResult AR; + bool ObjCPropertyAccess; + }; + + struct FTD { + unsigned Diagnostic; + unsigned Argument; + void *OperandType; + }; + + union { + struct AD AvailabilityData; + struct FTD ForbiddenTypeData; + + /// Access control. + char AccessData[sizeof(AccessedEntity)]; + }; +}; + +/// A collection of diagnostics which were delayed. +class DelayedDiagnosticPool { + const DelayedDiagnosticPool *Parent; + SmallVector<DelayedDiagnostic, 4> Diagnostics; + +public: + DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {} + + DelayedDiagnosticPool(const DelayedDiagnosticPool &) = delete; + DelayedDiagnosticPool &operator=(const DelayedDiagnosticPool &) = delete; + + DelayedDiagnosticPool(DelayedDiagnosticPool &&Other) + : Parent(Other.Parent), Diagnostics(std::move(Other.Diagnostics)) { + Other.Diagnostics.clear(); + } + + DelayedDiagnosticPool &operator=(DelayedDiagnosticPool &&Other) { + Parent = Other.Parent; + Diagnostics = std::move(Other.Diagnostics); + Other.Diagnostics.clear(); + return *this; + } + + ~DelayedDiagnosticPool() { + for (SmallVectorImpl<DelayedDiagnostic>::iterator + i = Diagnostics.begin(), e = Diagnostics.end(); i != e; ++i) + i->Destroy(); + } + + const DelayedDiagnosticPool *getParent() const { return Parent; } + + /// Does this pool, or any of its ancestors, contain any diagnostics? + bool empty() const { + return (Diagnostics.empty() && (!Parent || Parent->empty())); + } + + /// Add a diagnostic to this pool. + void add(const DelayedDiagnostic &diag) { + Diagnostics.push_back(diag); + } + + /// Steal the diagnostics from the given pool. + void steal(DelayedDiagnosticPool &pool) { + if (pool.Diagnostics.empty()) return; + + if (Diagnostics.empty()) { + Diagnostics = std::move(pool.Diagnostics); + } else { + Diagnostics.append(pool.pool_begin(), pool.pool_end()); + } + pool.Diagnostics.clear(); + } + + using pool_iterator = SmallVectorImpl<DelayedDiagnostic>::const_iterator; + + pool_iterator pool_begin() const { return Diagnostics.begin(); } + pool_iterator pool_end() const { return Diagnostics.end(); } + bool pool_empty() const { return Diagnostics.empty(); } +}; + +} // namespace clang + +/// Add a diagnostic to the current delay pool. +inline void Sema::DelayedDiagnostics::add(const sema::DelayedDiagnostic &diag) { + assert(shouldDelayDiagnostics() && "trying to delay without pool"); + CurPool->add(diag); +} + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/Designator.h b/contrib/libs/clang16/include/clang/Sema/Designator.h new file mode 100644 index 0000000000..b449537566 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/Designator.h @@ -0,0 +1,225 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- Designator.h - Initialization Designator ---------------*- 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 defines interfaces used to represent designators (a la +// C99 designated initializers) during parsing. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_DESIGNATOR_H +#define LLVM_CLANG_SEMA_DESIGNATOR_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +class Expr; +class IdentifierInfo; +class Sema; + +/// Designator - A designator in a C99 designated initializer. +/// +/// This class is a discriminated union which holds the various +/// different sorts of designators possible. A Designation is an array of +/// these. An example of a designator are things like this: +/// [8] .field [47] // C99 designation: 3 designators +/// [8 ... 47] field: // GNU extensions: 2 designators +/// These occur in initializers, e.g.: +/// int a[10] = {2, 4, [8]=9, 10}; +/// +class Designator { +public: + enum DesignatorKind { + FieldDesignator, ArrayDesignator, ArrayRangeDesignator + }; +private: + Designator() {}; + + DesignatorKind Kind; + + struct FieldDesignatorInfo { + const IdentifierInfo *II; + SourceLocation DotLoc; + SourceLocation NameLoc; + }; + struct ArrayDesignatorInfo { + Expr *Index; + SourceLocation LBracketLoc; + mutable SourceLocation RBracketLoc; + }; + struct ArrayRangeDesignatorInfo { + Expr *Start, *End; + SourceLocation LBracketLoc, EllipsisLoc; + mutable SourceLocation RBracketLoc; + }; + + union { + FieldDesignatorInfo FieldInfo; + ArrayDesignatorInfo ArrayInfo; + ArrayRangeDesignatorInfo ArrayRangeInfo; + }; + +public: + + DesignatorKind getKind() const { return Kind; } + bool isFieldDesignator() const { return Kind == FieldDesignator; } + bool isArrayDesignator() const { return Kind == ArrayDesignator; } + bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; } + + const IdentifierInfo *getField() const { + assert(isFieldDesignator() && "Invalid accessor"); + return FieldInfo.II; + } + + SourceLocation getDotLoc() const { + assert(isFieldDesignator() && "Invalid accessor"); + return FieldInfo.DotLoc; + } + + SourceLocation getFieldLoc() const { + assert(isFieldDesignator() && "Invalid accessor"); + return FieldInfo.NameLoc; + } + + Expr *getArrayIndex() const { + assert(isArrayDesignator() && "Invalid accessor"); + return ArrayInfo.Index; + } + + Expr *getArrayRangeStart() const { + assert(isArrayRangeDesignator() && "Invalid accessor"); + return ArrayRangeInfo.Start; + } + Expr *getArrayRangeEnd() const { + assert(isArrayRangeDesignator() && "Invalid accessor"); + return ArrayRangeInfo.End; + } + + SourceLocation getLBracketLoc() const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && + "Invalid accessor"); + if (isArrayDesignator()) + return ArrayInfo.LBracketLoc; + else + return ArrayRangeInfo.LBracketLoc; + } + + SourceLocation getRBracketLoc() const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && + "Invalid accessor"); + if (isArrayDesignator()) + return ArrayInfo.RBracketLoc; + else + return ArrayRangeInfo.RBracketLoc; + } + + SourceLocation getEllipsisLoc() const { + assert(isArrayRangeDesignator() && "Invalid accessor"); + return ArrayRangeInfo.EllipsisLoc; + } + + static Designator getField(const IdentifierInfo *II, SourceLocation DotLoc, + SourceLocation NameLoc) { + Designator D; + D.Kind = FieldDesignator; + new (&D.FieldInfo) FieldDesignatorInfo; + D.FieldInfo.II = II; + D.FieldInfo.DotLoc = DotLoc; + D.FieldInfo.NameLoc = NameLoc; + return D; + } + + static Designator getArray(Expr *Index, + SourceLocation LBracketLoc) { + Designator D; + D.Kind = ArrayDesignator; + new (&D.ArrayInfo) ArrayDesignatorInfo; + D.ArrayInfo.Index = Index; + D.ArrayInfo.LBracketLoc = LBracketLoc; + D.ArrayInfo.RBracketLoc = SourceLocation(); + return D; + } + + static Designator getArrayRange(Expr *Start, + Expr *End, + SourceLocation LBracketLoc, + SourceLocation EllipsisLoc) { + Designator D; + D.Kind = ArrayRangeDesignator; + new (&D.ArrayRangeInfo) ArrayRangeDesignatorInfo; + D.ArrayRangeInfo.Start = Start; + D.ArrayRangeInfo.End = End; + D.ArrayRangeInfo.LBracketLoc = LBracketLoc; + D.ArrayRangeInfo.EllipsisLoc = EllipsisLoc; + D.ArrayRangeInfo.RBracketLoc = SourceLocation(); + return D; + } + + void setRBracketLoc(SourceLocation RBracketLoc) const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && + "Invalid accessor"); + if (isArrayDesignator()) + ArrayInfo.RBracketLoc = RBracketLoc; + else + ArrayRangeInfo.RBracketLoc = RBracketLoc; + } + + /// ClearExprs - Null out any expression references, which prevents + /// them from being 'delete'd later. + void ClearExprs(Sema &Actions) {} + + /// FreeExprs - Release any unclaimed memory for the expressions in + /// this designator. + void FreeExprs(Sema &Actions) {} +}; + + +/// Designation - Represent a full designation, which is a sequence of +/// designators. This class is mostly a helper for InitListDesignations. +class Designation { + /// Designators - The actual designators for this initializer. + SmallVector<Designator, 2> Designators; + +public: + /// AddDesignator - Add a designator to the end of this list. + void AddDesignator(Designator D) { + Designators.push_back(D); + } + + bool empty() const { return Designators.empty(); } + + unsigned getNumDesignators() const { return Designators.size(); } + const Designator &getDesignator(unsigned Idx) const { + assert(Idx < Designators.size()); + return Designators[Idx]; + } + + /// ClearExprs - Null out any expression references, which prevents them from + /// being 'delete'd later. + void ClearExprs(Sema &Actions) {} + + /// FreeExprs - Release any unclaimed memory for the expressions in this + /// designation. + void FreeExprs(Sema &Actions) {} +}; + +} // end namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/ExternalSemaSource.h b/contrib/libs/clang16/include/clang/Sema/ExternalSemaSource.h new file mode 100644 index 0000000000..795f336a6d --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/ExternalSemaSource.h @@ -0,0 +1,255 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- ExternalSemaSource.h - External Sema Interface ---------*- 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 defines the ExternalSemaSource interface. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_EXTERNALSEMASOURCE_H +#define LLVM_CLANG_SEMA_EXTERNALSEMASOURCE_H + +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/Type.h" +#include "clang/Sema/TypoCorrection.h" +#include "clang/Sema/Weak.h" +#include "llvm/ADT/MapVector.h" +#include <utility> + +namespace llvm { +template <class T, unsigned n> class SmallSetVector; +} + +namespace clang { + +class CXXConstructorDecl; +class CXXRecordDecl; +class DeclaratorDecl; +class LookupResult; +class Scope; +class Sema; +class TypedefNameDecl; +class ValueDecl; +class VarDecl; +struct LateParsedTemplate; + +/// A simple structure that captures a vtable use for the purposes of +/// the \c ExternalSemaSource. +struct ExternalVTableUse { + CXXRecordDecl *Record; + SourceLocation Location; + bool DefinitionRequired; +}; + +/// An abstract interface that should be implemented by +/// external AST sources that also provide information for semantic +/// analysis. +class ExternalSemaSource : public ExternalASTSource { + /// LLVM-style RTTI. + static char ID; + +public: + ExternalSemaSource() = default; + + ~ExternalSemaSource() override; + + /// Initialize the semantic source with the Sema instance + /// being used to perform semantic analysis on the abstract syntax + /// tree. + virtual void InitializeSema(Sema &S) {} + + /// Inform the semantic consumer that Sema is no longer available. + virtual void ForgetSema() {} + + /// Load the contents of the global method pool for a given + /// selector. + virtual void ReadMethodPool(Selector Sel); + + /// Load the contents of the global method pool for a given + /// selector if necessary. + virtual void updateOutOfDateSelector(Selector Sel); + + /// Load the set of namespaces that are known to the external source, + /// which will be used during typo correction. + virtual void ReadKnownNamespaces( + SmallVectorImpl<NamespaceDecl *> &Namespaces); + + /// Load the set of used but not defined functions or variables with + /// internal linkage, or used but not defined internal functions. + virtual void + ReadUndefinedButUsed(llvm::MapVector<NamedDecl *, SourceLocation> &Undefined); + + virtual void ReadMismatchingDeleteExpressions(llvm::MapVector< + FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> &); + + /// Do last resort, unqualified lookup on a LookupResult that + /// Sema cannot find. + /// + /// \param R a LookupResult that is being recovered. + /// + /// \param S the Scope of the identifier occurrence. + /// + /// \return true to tell Sema to recover using the LookupResult. + virtual bool LookupUnqualified(LookupResult &R, Scope *S) { return false; } + + /// Read the set of tentative definitions known to the external Sema + /// source. + /// + /// The external source should append its own tentative definitions to the + /// given vector of tentative definitions. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadTentativeDefinitions( + SmallVectorImpl<VarDecl *> &TentativeDefs) {} + + /// Read the set of unused file-scope declarations known to the + /// external Sema source. + /// + /// The external source should append its own unused, filed-scope to the + /// given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadUnusedFileScopedDecls( + SmallVectorImpl<const DeclaratorDecl *> &Decls) {} + + /// Read the set of delegating constructors known to the + /// external Sema source. + /// + /// The external source should append its own delegating constructors to the + /// given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadDelegatingConstructors( + SmallVectorImpl<CXXConstructorDecl *> &Decls) {} + + /// Read the set of ext_vector type declarations known to the + /// external Sema source. + /// + /// The external source should append its own ext_vector type declarations to + /// the given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) {} + + /// Read the set of potentially unused typedefs known to the source. + /// + /// The external source should append its own potentially unused local + /// typedefs to the given vector of declarations. Note that this routine may + /// be invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadUnusedLocalTypedefNameCandidates( + llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) {} + + /// Read the set of referenced selectors known to the + /// external Sema source. + /// + /// The external source should append its own referenced selectors to the + /// given vector of selectors. Note that this routine + /// may be invoked multiple times; the external source should take care not + /// to introduce the same selectors repeatedly. + virtual void ReadReferencedSelectors( + SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) {} + + /// Read the set of weak, undeclared identifiers known to the + /// external Sema source. + /// + /// The external source should append its own weak, undeclared identifiers to + /// the given vector. Note that this routine may be invoked multiple times; + /// the external source should take care not to introduce the same identifiers + /// repeatedly. + virtual void ReadWeakUndeclaredIdentifiers( + SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WI) {} + + /// Read the set of used vtables known to the external Sema source. + /// + /// The external source should append its own used vtables to the given + /// vector. Note that this routine may be invoked multiple times; the external + /// source should take care not to introduce the same vtables repeatedly. + virtual void ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) {} + + /// Read the set of pending instantiations known to the external + /// Sema source. + /// + /// The external source should append its own pending instantiations to the + /// given vector. Note that this routine may be invoked multiple times; the + /// external source should take care not to introduce the same instantiations + /// repeatedly. + virtual void ReadPendingInstantiations( + SmallVectorImpl<std::pair<ValueDecl *, + SourceLocation> > &Pending) {} + + /// Read the set of late parsed template functions for this source. + /// + /// The external source should insert its own late parsed template functions + /// into the map. Note that this routine may be invoked multiple times; the + /// external source should take care not to introduce the same map entries + /// repeatedly. + virtual void ReadLateParsedTemplates( + llvm::MapVector<const FunctionDecl *, std::unique_ptr<LateParsedTemplate>> + &LPTMap) {} + + /// Read the set of decls to be checked for deferred diags. + /// + /// The external source should append its own potentially emitted function + /// and variable decls which may cause deferred diags. Note that this routine + /// may be invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void + ReadDeclsToCheckForDeferredDiags(llvm::SmallSetVector<Decl *, 4> &Decls) {} + + /// \copydoc Sema::CorrectTypo + /// \note LookupKind must correspond to a valid Sema::LookupNameKind + /// + /// ExternalSemaSource::CorrectTypo is always given the first chance to + /// correct a typo (really, to offer suggestions to repair a failed lookup). + /// It will even be called when SpellChecking is turned off or after a + /// fatal error has already been detected. + virtual TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, + int LookupKind, Scope *S, CXXScopeSpec *SS, + CorrectionCandidateCallback &CCC, + DeclContext *MemberContext, + bool EnteringContext, + const ObjCObjectPointerType *OPT) { + return TypoCorrection(); + } + + /// Produces a diagnostic note if the external source contains a + /// complete definition for \p T. + /// + /// \param Loc the location at which a complete type was required but not + /// provided + /// + /// \param T the \c QualType that should have been complete at \p Loc + /// + /// \return true if a diagnostic was produced, false otherwise. + virtual bool MaybeDiagnoseMissingCompleteType(SourceLocation Loc, + QualType T) { + return false; + } + + /// LLVM-style RTTI. + /// \{ + bool isA(const void *ClassID) const override { + return ClassID == &ID || ExternalASTSource::isA(ClassID); + } + static bool classof(const ExternalASTSource *S) { return S->isA(&ID); } + /// \} +}; + +} // end namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/HLSLExternalSemaSource.h b/contrib/libs/clang16/include/clang/Sema/HLSLExternalSemaSource.h new file mode 100644 index 0000000000..85e29b8849 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/HLSLExternalSemaSource.h @@ -0,0 +1,66 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- HLSLExternalSemaSource.h - HLSL Sema Source ------------*- 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 defines the HLSLExternalSemaSource interface. +// +//===----------------------------------------------------------------------===// +#ifndef CLANG_SEMA_HLSLEXTERNALSEMASOURCE_H +#define CLANG_SEMA_HLSLEXTERNALSEMASOURCE_H + +#include "llvm/ADT/DenseMap.h" + +#include "clang/Sema/ExternalSemaSource.h" + +namespace clang { +class NamespaceDecl; +class Sema; + +class HLSLExternalSemaSource : public ExternalSemaSource { + Sema *SemaPtr = nullptr; + NamespaceDecl *HLSLNamespace = nullptr; + CXXRecordDecl *ResourceDecl; + + using CompletionFunction = std::function<void(CXXRecordDecl *)>; + llvm::DenseMap<CXXRecordDecl *, CompletionFunction> Completions; + + void defineHLSLVectorAlias(); + void defineTrivialHLSLTypes(); + void forwardDeclareHLSLTypes(); + + void completeBufferType(CXXRecordDecl *Record); + +public: + ~HLSLExternalSemaSource() override; + + /// Initialize the semantic source with the Sema instance + /// being used to perform semantic analysis on the abstract syntax + /// tree. + void InitializeSema(Sema &S) override; + + /// Inform the semantic consumer that Sema is no longer available. + void ForgetSema() override { SemaPtr = nullptr; } + + using ExternalASTSource::CompleteType; + /// Complete an incomplete HLSL builtin type + void CompleteType(TagDecl *Tag) override; +}; + +} // namespace clang + +#endif // CLANG_SEMA_HLSLEXTERNALSEMASOURCE_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/IdentifierResolver.h b/contrib/libs/clang16/include/clang/Sema/IdentifierResolver.h new file mode 100644 index 0000000000..d20f645f4c --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/IdentifierResolver.h @@ -0,0 +1,216 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- IdentifierResolver.h - Lexical Scope Name lookup ---------*- 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 defines the IdentifierResolver class, which is used for lexical +// scoped lookup, based on declaration names. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_IDENTIFIERRESOLVER_H +#define LLVM_CLANG_SEMA_IDENTIFIERRESOLVER_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <iterator> + +namespace clang { + +class Decl; +class DeclarationName; +class DeclContext; +class IdentifierInfo; +class LangOptions; +class NamedDecl; +class Preprocessor; +class Scope; + +/// IdentifierResolver - Keeps track of shadowed decls on enclosing +/// scopes. It manages the shadowing chains of declaration names and +/// implements efficient decl lookup based on a declaration name. +class IdentifierResolver { + /// IdDeclInfo - Keeps track of information about decls associated + /// to a particular declaration name. IdDeclInfos are lazily + /// constructed and assigned to a declaration name the first time a + /// decl with that declaration name is shadowed in some scope. + class IdDeclInfo { + public: + using DeclsTy = SmallVector<NamedDecl *, 2>; + + DeclsTy::iterator decls_begin() { return Decls.begin(); } + DeclsTy::iterator decls_end() { return Decls.end(); } + + void AddDecl(NamedDecl *D) { Decls.push_back(D); } + + /// RemoveDecl - Remove the decl from the scope chain. + /// The decl must already be part of the decl chain. + void RemoveDecl(NamedDecl *D); + + /// Insert the given declaration at the given position in the list. + void InsertDecl(DeclsTy::iterator Pos, NamedDecl *D) { + Decls.insert(Pos, D); + } + + private: + DeclsTy Decls; + }; + +public: + /// iterator - Iterate over the decls of a specified declaration name. + /// It will walk or not the parent declaration contexts depending on how + /// it was instantiated. + class iterator { + public: + friend class IdentifierResolver; + + using value_type = NamedDecl *; + using reference = NamedDecl *; + using pointer = NamedDecl *; + using iterator_category = std::input_iterator_tag; + using difference_type = std::ptrdiff_t; + + /// Ptr - There are 2 forms that 'Ptr' represents: + /// 1) A single NamedDecl. (Ptr & 0x1 == 0) + /// 2) A IdDeclInfo::DeclsTy::iterator that traverses only the decls of the + /// same declaration context. (Ptr & 0x1 == 0x1) + uintptr_t Ptr = 0; + using BaseIter = IdDeclInfo::DeclsTy::iterator; + + /// A single NamedDecl. (Ptr & 0x1 == 0) + iterator(NamedDecl *D) { + Ptr = reinterpret_cast<uintptr_t>(D); + assert((Ptr & 0x1) == 0 && "Invalid Ptr!"); + } + + /// A IdDeclInfo::DeclsTy::iterator that walks or not the parent declaration + /// contexts depending on 'LookInParentCtx'. + iterator(BaseIter I) { + Ptr = reinterpret_cast<uintptr_t>(I) | 0x1; + } + + bool isIterator() const { return (Ptr & 0x1); } + + BaseIter getIterator() const { + assert(isIterator() && "Ptr not an iterator!"); + return reinterpret_cast<BaseIter>(Ptr & ~0x1); + } + + void incrementSlowCase(); + + public: + iterator() = default; + + NamedDecl *operator*() const { + if (isIterator()) + return *getIterator(); + else + return reinterpret_cast<NamedDecl*>(Ptr); + } + + bool operator==(const iterator &RHS) const { + return Ptr == RHS.Ptr; + } + bool operator!=(const iterator &RHS) const { + return Ptr != RHS.Ptr; + } + + // Preincrement. + iterator& operator++() { + if (!isIterator()) // common case. + Ptr = 0; + else + incrementSlowCase(); + return *this; + } + }; + + explicit IdentifierResolver(Preprocessor &PP); + ~IdentifierResolver(); + + /// begin - Returns an iterator for decls with the name 'Name'. + iterator begin(DeclarationName Name); + + /// end - Returns an iterator that has 'finished'. + iterator end() { + return iterator(); + } + + /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true + /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns + /// true if 'D' belongs to the given declaration context. + /// + /// \param AllowInlineNamespace If \c true, we are checking whether a prior + /// declaration is in scope in a declaration that requires a prior + /// declaration (because it is either explicitly qualified or is a + /// template instantiation or specialization). In this case, a + /// declaration is in scope if it's in the inline namespace set of the + /// context. + bool isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S = nullptr, + bool AllowInlineNamespace = false) const; + + /// AddDecl - Link the decl to its shadowed decl chain. + void AddDecl(NamedDecl *D); + + /// RemoveDecl - Unlink the decl from its shadowed decl chain. + /// The decl must already be part of the decl chain. + void RemoveDecl(NamedDecl *D); + + /// Insert the given declaration after the given iterator + /// position. + void InsertDeclAfter(iterator Pos, NamedDecl *D); + + /// Try to add the given declaration to the top level scope, if it + /// (or a redeclaration of it) hasn't already been added. + /// + /// \param D The externally-produced declaration to add. + /// + /// \param Name The name of the externally-produced declaration. + /// + /// \returns true if the declaration was added, false otherwise. + bool tryAddTopLevelDecl(NamedDecl *D, DeclarationName Name); + +private: + const LangOptions &LangOpt; + Preprocessor &PP; + + class IdDeclInfoMap; + IdDeclInfoMap *IdDeclInfos; + + void updatingIdentifier(IdentifierInfo &II); + void readingIdentifier(IdentifierInfo &II); + + /// FETokenInfo contains a Decl pointer if lower bit == 0. + static inline bool isDeclPtr(void *Ptr) { + return (reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 0; + } + + /// FETokenInfo contains a IdDeclInfo pointer if lower bit == 1. + static inline IdDeclInfo *toIdDeclInfo(void *Ptr) { + assert((reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 1 + && "Ptr not a IdDeclInfo* !"); + return reinterpret_cast<IdDeclInfo*>( + reinterpret_cast<uintptr_t>(Ptr) & ~0x1); + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_IDENTIFIERRESOLVER_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/Initialization.h b/contrib/libs/clang16/include/clang/Sema/Initialization.h new file mode 100644 index 0000000000..ba0d6542b3 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/Initialization.h @@ -0,0 +1,1433 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- Initialization.h - Semantic Analysis for Initializers ----*- 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 provides supporting data types for initialization of objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_INITIALIZATION_H +#define LLVM_CLANG_SEMA_INITIALIZATION_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclAccessPair.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Sema/Overload.h" +#include "clang/Sema/Ownership.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" +#include <cassert> +#include <cstdint> +#include <string> + +namespace clang { + +class CXXBaseSpecifier; +class CXXConstructorDecl; +class ObjCMethodDecl; +class Sema; + +/// Describes an entity that is being initialized. +class alignas(8) InitializedEntity { +public: + /// Specifies the kind of entity being initialized. + enum EntityKind { + /// The entity being initialized is a variable. + EK_Variable, + + /// The entity being initialized is a function parameter. + EK_Parameter, + + /// The entity being initialized is a non-type template parameter. + EK_TemplateParameter, + + /// The entity being initialized is the result of a function call. + EK_Result, + + /// The entity being initialized is the result of a statement expression. + EK_StmtExprResult, + + /// The entity being initialized is an exception object that + /// is being thrown. + EK_Exception, + + /// The entity being initialized is a non-static data member + /// subobject. + EK_Member, + + /// The entity being initialized is an element of an array. + EK_ArrayElement, + + /// The entity being initialized is an object (or array of + /// objects) allocated via new. + EK_New, + + /// The entity being initialized is a temporary object. + EK_Temporary, + + /// The entity being initialized is a base member subobject. + EK_Base, + + /// The initialization is being done by a delegating constructor. + EK_Delegating, + + /// The entity being initialized is an element of a vector. + /// or vector. + EK_VectorElement, + + /// The entity being initialized is a field of block descriptor for + /// the copied-in c++ object. + EK_BlockElement, + + /// The entity being initialized is a field of block descriptor for the + /// copied-in lambda object that's used in the lambda to block conversion. + EK_LambdaToBlockConversionBlockElement, + + /// The entity being initialized is the real or imaginary part of a + /// complex number. + EK_ComplexElement, + + /// The entity being initialized is the field that captures a + /// variable in a lambda. + EK_LambdaCapture, + + /// The entity being initialized is the initializer for a compound + /// literal. + EK_CompoundLiteralInit, + + /// The entity being implicitly initialized back to the formal + /// result type. + EK_RelatedResult, + + /// The entity being initialized is a function parameter; function + /// is member of group of audited CF APIs. + EK_Parameter_CF_Audited, + + /// The entity being initialized is a structured binding of a + /// decomposition declaration. + EK_Binding, + + // Note: err_init_conversion_failed in DiagnosticSemaKinds.td uses this + // enum as an index for its first %select. When modifying this list, + // that diagnostic text needs to be updated as well. + }; + +private: + /// The kind of entity being initialized. + EntityKind Kind; + + /// If non-NULL, the parent entity in which this + /// initialization occurs. + const InitializedEntity *Parent = nullptr; + + /// The type of the object or reference being initialized. + QualType Type; + + /// The mangling number for the next reference temporary to be created. + mutable unsigned ManglingNumber = 0; + + struct LN { + /// When Kind == EK_Result, EK_Exception, EK_New, the + /// location of the 'return', 'throw', or 'new' keyword, + /// respectively. When Kind == EK_Temporary, the location where + /// the temporary is being created. + SourceLocation Location; + + /// Whether the entity being initialized may end up using the + /// named return value optimization (NRVO). + bool NRVO; + }; + + struct VD { + /// The VarDecl, FieldDecl, or BindingDecl being initialized. + ValueDecl *VariableOrMember; + + /// When Kind == EK_Member, whether this is an implicit member + /// initialization in a copy or move constructor. These can perform array + /// copies. + bool IsImplicitFieldInit; + + /// When Kind == EK_Member, whether this is the initial initialization + /// check for a default member initializer. + bool IsDefaultMemberInit; + }; + + struct C { + /// The name of the variable being captured by an EK_LambdaCapture. + IdentifierInfo *VarID; + + /// The source location at which the capture occurs. + SourceLocation Location; + }; + + union { + /// When Kind == EK_Variable, EK_Member, EK_Binding, or + /// EK_TemplateParameter, the variable, binding, or template parameter. + VD Variable; + + /// When Kind == EK_RelatedResult, the ObjectiveC method where + /// result type was implicitly changed to accommodate ARC semantics. + ObjCMethodDecl *MethodDecl; + + /// When Kind == EK_Parameter, the ParmVarDecl, with the + /// integer indicating whether the parameter is "consumed". + llvm::PointerIntPair<ParmVarDecl *, 1> Parameter; + + /// When Kind == EK_Temporary or EK_CompoundLiteralInit, the type + /// source information for the temporary. + TypeSourceInfo *TypeInfo; + + struct LN LocAndNRVO; + + /// When Kind == EK_Base, the base specifier that provides the + /// base class. The integer specifies whether the base is an inherited + /// virtual base. + llvm::PointerIntPair<const CXXBaseSpecifier *, 1> Base; + + /// When Kind == EK_ArrayElement, EK_VectorElement, or + /// EK_ComplexElement, the index of the array or vector element being + /// initialized. + unsigned Index; + + struct C Capture; + }; + + InitializedEntity() {}; + + /// Create the initialization entity for a variable. + InitializedEntity(VarDecl *Var, EntityKind EK = EK_Variable) + : Kind(EK), Type(Var->getType()), Variable{Var, false, false} {} + + /// Create the initialization entity for the result of a + /// function, throwing an object, performing an explicit cast, or + /// initializing a parameter for which there is no declaration. + InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type, + bool NRVO = false) + : Kind(Kind), Type(Type) { + new (&LocAndNRVO) LN; + LocAndNRVO.Location = Loc; + LocAndNRVO.NRVO = NRVO; + } + + /// Create the initialization entity for a member subobject. + InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent, + bool Implicit, bool DefaultMemberInit) + : Kind(EK_Member), Parent(Parent), Type(Member->getType()), + Variable{Member, Implicit, DefaultMemberInit} {} + + /// Create the initialization entity for an array element. + InitializedEntity(ASTContext &Context, unsigned Index, + const InitializedEntity &Parent); + + /// Create the initialization entity for a lambda capture. + InitializedEntity(IdentifierInfo *VarID, QualType FieldType, SourceLocation Loc) + : Kind(EK_LambdaCapture), Type(FieldType) { + new (&Capture) C; + Capture.VarID = VarID; + Capture.Location = Loc; + } + +public: + /// Create the initialization entity for a variable. + static InitializedEntity InitializeVariable(VarDecl *Var) { + return InitializedEntity(Var); + } + + /// Create the initialization entity for a parameter. + static InitializedEntity InitializeParameter(ASTContext &Context, + ParmVarDecl *Parm) { + return InitializeParameter(Context, Parm, Parm->getType()); + } + + /// Create the initialization entity for a parameter, but use + /// another type. + static InitializedEntity + InitializeParameter(ASTContext &Context, ParmVarDecl *Parm, QualType Type) { + bool Consumed = (Context.getLangOpts().ObjCAutoRefCount && + Parm->hasAttr<NSConsumedAttr>()); + + InitializedEntity Entity; + Entity.Kind = EK_Parameter; + Entity.Type = + Context.getVariableArrayDecayedType(Type.getUnqualifiedType()); + Entity.Parent = nullptr; + Entity.Parameter = {Parm, Consumed}; + return Entity; + } + + /// Create the initialization entity for a parameter that is + /// only known by its type. + static InitializedEntity InitializeParameter(ASTContext &Context, + QualType Type, + bool Consumed) { + InitializedEntity Entity; + Entity.Kind = EK_Parameter; + Entity.Type = Context.getVariableArrayDecayedType(Type); + Entity.Parent = nullptr; + Entity.Parameter = {nullptr, Consumed}; + return Entity; + } + + /// Create the initialization entity for a template parameter. + static InitializedEntity + InitializeTemplateParameter(QualType T, NonTypeTemplateParmDecl *Param) { + InitializedEntity Entity; + Entity.Kind = EK_TemplateParameter; + Entity.Type = T; + Entity.Parent = nullptr; + Entity.Variable = {Param, false, false}; + return Entity; + } + + /// Create the initialization entity for the result of a function. + static InitializedEntity InitializeResult(SourceLocation ReturnLoc, + QualType Type) { + return InitializedEntity(EK_Result, ReturnLoc, Type); + } + + static InitializedEntity InitializeStmtExprResult(SourceLocation ReturnLoc, + QualType Type) { + return InitializedEntity(EK_StmtExprResult, ReturnLoc, Type); + } + + static InitializedEntity InitializeBlock(SourceLocation BlockVarLoc, + QualType Type) { + return InitializedEntity(EK_BlockElement, BlockVarLoc, Type); + } + + static InitializedEntity InitializeLambdaToBlock(SourceLocation BlockVarLoc, + QualType Type) { + return InitializedEntity(EK_LambdaToBlockConversionBlockElement, + BlockVarLoc, Type); + } + + /// Create the initialization entity for an exception object. + static InitializedEntity InitializeException(SourceLocation ThrowLoc, + QualType Type) { + return InitializedEntity(EK_Exception, ThrowLoc, Type); + } + + /// Create the initialization entity for an object allocated via new. + static InitializedEntity InitializeNew(SourceLocation NewLoc, QualType Type) { + return InitializedEntity(EK_New, NewLoc, Type); + } + + /// Create the initialization entity for a temporary. + static InitializedEntity InitializeTemporary(QualType Type) { + return InitializeTemporary(nullptr, Type); + } + + /// Create the initialization entity for a temporary. + static InitializedEntity InitializeTemporary(ASTContext &Context, + TypeSourceInfo *TypeInfo) { + QualType Type = TypeInfo->getType(); + if (Context.getLangOpts().OpenCLCPlusPlus) { + assert(!Type.hasAddressSpace() && "Temporary already has address space!"); + Type = Context.getAddrSpaceQualType(Type, LangAS::opencl_private); + } + + return InitializeTemporary(TypeInfo, Type); + } + + /// Create the initialization entity for a temporary. + static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo, + QualType Type) { + InitializedEntity Result(EK_Temporary, SourceLocation(), Type); + Result.TypeInfo = TypeInfo; + return Result; + } + + /// Create the initialization entity for a related result. + static InitializedEntity InitializeRelatedResult(ObjCMethodDecl *MD, + QualType Type) { + InitializedEntity Result(EK_RelatedResult, SourceLocation(), Type); + Result.MethodDecl = MD; + return Result; + } + + /// Create the initialization entity for a base class subobject. + static InitializedEntity + InitializeBase(ASTContext &Context, const CXXBaseSpecifier *Base, + bool IsInheritedVirtualBase, + const InitializedEntity *Parent = nullptr); + + /// Create the initialization entity for a delegated constructor. + static InitializedEntity InitializeDelegation(QualType Type) { + return InitializedEntity(EK_Delegating, SourceLocation(), Type); + } + + /// Create the initialization entity for a member subobject. + static InitializedEntity + InitializeMember(FieldDecl *Member, + const InitializedEntity *Parent = nullptr, + bool Implicit = false) { + return InitializedEntity(Member, Parent, Implicit, false); + } + + /// Create the initialization entity for a member subobject. + static InitializedEntity + InitializeMember(IndirectFieldDecl *Member, + const InitializedEntity *Parent = nullptr, + bool Implicit = false) { + return InitializedEntity(Member->getAnonField(), Parent, Implicit, false); + } + + /// Create the initialization entity for a default member initializer. + static InitializedEntity + InitializeMemberFromDefaultMemberInitializer(FieldDecl *Member) { + return InitializedEntity(Member, nullptr, false, true); + } + + /// Create the initialization entity for an array element. + static InitializedEntity InitializeElement(ASTContext &Context, + unsigned Index, + const InitializedEntity &Parent) { + return InitializedEntity(Context, Index, Parent); + } + + /// Create the initialization entity for a structured binding. + static InitializedEntity InitializeBinding(VarDecl *Binding) { + return InitializedEntity(Binding, EK_Binding); + } + + /// Create the initialization entity for a lambda capture. + /// + /// \p VarID The name of the entity being captured, or nullptr for 'this'. + static InitializedEntity InitializeLambdaCapture(IdentifierInfo *VarID, + QualType FieldType, + SourceLocation Loc) { + return InitializedEntity(VarID, FieldType, Loc); + } + + /// Create the entity for a compound literal initializer. + static InitializedEntity InitializeCompoundLiteralInit(TypeSourceInfo *TSI) { + InitializedEntity Result(EK_CompoundLiteralInit, SourceLocation(), + TSI->getType()); + Result.TypeInfo = TSI; + return Result; + } + + /// Determine the kind of initialization. + EntityKind getKind() const { return Kind; } + + /// Retrieve the parent of the entity being initialized, when + /// the initialization itself is occurring within the context of a + /// larger initialization. + const InitializedEntity *getParent() const { return Parent; } + + /// Retrieve type being initialized. + QualType getType() const { return Type; } + + /// Retrieve complete type-source information for the object being + /// constructed, if known. + TypeSourceInfo *getTypeSourceInfo() const { + if (Kind == EK_Temporary || Kind == EK_CompoundLiteralInit) + return TypeInfo; + + return nullptr; + } + + /// Retrieve the name of the entity being initialized. + DeclarationName getName() const; + + /// Retrieve the variable, parameter, or field being + /// initialized. + ValueDecl *getDecl() const; + + /// Retrieve the ObjectiveC method being initialized. + ObjCMethodDecl *getMethodDecl() const { return MethodDecl; } + + /// Determine whether this initialization allows the named return + /// value optimization, which also applies to thrown objects. + bool allowsNRVO() const; + + bool isParameterKind() const { + return (getKind() == EK_Parameter || + getKind() == EK_Parameter_CF_Audited); + } + + bool isParamOrTemplateParamKind() const { + return isParameterKind() || getKind() == EK_TemplateParameter; + } + + /// Determine whether this initialization consumes the + /// parameter. + bool isParameterConsumed() const { + assert(isParameterKind() && "Not a parameter"); + return Parameter.getInt(); + } + + /// Retrieve the base specifier. + const CXXBaseSpecifier *getBaseSpecifier() const { + assert(getKind() == EK_Base && "Not a base specifier"); + return Base.getPointer(); + } + + /// Return whether the base is an inherited virtual base. + bool isInheritedVirtualBase() const { + assert(getKind() == EK_Base && "Not a base specifier"); + return Base.getInt(); + } + + /// Determine whether this is an array new with an unknown bound. + bool isVariableLengthArrayNew() const { + return getKind() == EK_New && isa_and_nonnull<IncompleteArrayType>( + getType()->getAsArrayTypeUnsafe()); + } + + /// Is this the implicit initialization of a member of a class from + /// a defaulted constructor? + bool isImplicitMemberInitializer() const { + return getKind() == EK_Member && Variable.IsImplicitFieldInit; + } + + /// Is this the default member initializer of a member (specified inside + /// the class definition)? + bool isDefaultMemberInitializer() const { + return getKind() == EK_Member && Variable.IsDefaultMemberInit; + } + + /// Determine the location of the 'return' keyword when initializing + /// the result of a function call. + SourceLocation getReturnLoc() const { + assert(getKind() == EK_Result && "No 'return' location!"); + return LocAndNRVO.Location; + } + + /// Determine the location of the 'throw' keyword when initializing + /// an exception object. + SourceLocation getThrowLoc() const { + assert(getKind() == EK_Exception && "No 'throw' location!"); + return LocAndNRVO.Location; + } + + /// If this is an array, vector, or complex number element, get the + /// element's index. + unsigned getElementIndex() const { + assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement || + getKind() == EK_ComplexElement); + return Index; + } + + /// If this is already the initializer for an array or vector + /// element, sets the element index. + void setElementIndex(unsigned Index) { + assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement || + getKind() == EK_ComplexElement); + this->Index = Index; + } + + /// For a lambda capture, return the capture's name. + StringRef getCapturedVarName() const { + assert(getKind() == EK_LambdaCapture && "Not a lambda capture!"); + return Capture.VarID ? Capture.VarID->getName() : "this"; + } + + /// Determine the location of the capture when initializing + /// field from a captured variable in a lambda. + SourceLocation getCaptureLoc() const { + assert(getKind() == EK_LambdaCapture && "Not a lambda capture!"); + return Capture.Location; + } + + void setParameterCFAudited() { + Kind = EK_Parameter_CF_Audited; + } + + unsigned allocateManglingNumber() const { return ++ManglingNumber; } + + /// Dump a representation of the initialized entity to standard error, + /// for debugging purposes. + void dump() const; + +private: + unsigned dumpImpl(raw_ostream &OS) const; +}; + +/// Describes the kind of initialization being performed, along with +/// location information for tokens related to the initialization (equal sign, +/// parentheses). +class InitializationKind { +public: + /// The kind of initialization being performed. + enum InitKind { + /// Direct initialization + IK_Direct, + + /// Direct list-initialization + IK_DirectList, + + /// Copy initialization + IK_Copy, + + /// Default initialization + IK_Default, + + /// Value initialization + IK_Value + }; + +private: + /// The context of the initialization. + enum InitContext { + /// Normal context + IC_Normal, + + /// Normal context, but allows explicit conversion functionss + IC_ExplicitConvs, + + /// Implicit context (value initialization) + IC_Implicit, + + /// Static cast context + IC_StaticCast, + + /// C-style cast context + IC_CStyleCast, + + /// Functional cast context + IC_FunctionalCast + }; + + /// The kind of initialization being performed. + InitKind Kind : 8; + + /// The context of the initialization. + InitContext Context : 8; + + /// The source locations involved in the initialization. + SourceLocation Locations[3]; + + InitializationKind(InitKind Kind, InitContext Context, SourceLocation Loc1, + SourceLocation Loc2, SourceLocation Loc3) + : Kind(Kind), Context(Context) { + Locations[0] = Loc1; + Locations[1] = Loc2; + Locations[2] = Loc3; + } + +public: + /// Create a direct initialization. + static InitializationKind CreateDirect(SourceLocation InitLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return InitializationKind(IK_Direct, IC_Normal, + InitLoc, LParenLoc, RParenLoc); + } + + static InitializationKind CreateDirectList(SourceLocation InitLoc) { + return InitializationKind(IK_DirectList, IC_Normal, InitLoc, InitLoc, + InitLoc); + } + + static InitializationKind CreateDirectList(SourceLocation InitLoc, + SourceLocation LBraceLoc, + SourceLocation RBraceLoc) { + return InitializationKind(IK_DirectList, IC_Normal, InitLoc, LBraceLoc, + RBraceLoc); + } + + /// Create a direct initialization due to a cast that isn't a C-style + /// or functional cast. + static InitializationKind CreateCast(SourceRange TypeRange) { + return InitializationKind(IK_Direct, IC_StaticCast, TypeRange.getBegin(), + TypeRange.getBegin(), TypeRange.getEnd()); + } + + /// Create a direct initialization for a C-style cast. + static InitializationKind CreateCStyleCast(SourceLocation StartLoc, + SourceRange TypeRange, + bool InitList) { + // C++ cast syntax doesn't permit init lists, but C compound literals are + // exactly that. + return InitializationKind(InitList ? IK_DirectList : IK_Direct, + IC_CStyleCast, StartLoc, TypeRange.getBegin(), + TypeRange.getEnd()); + } + + /// Create a direct initialization for a functional cast. + static InitializationKind CreateFunctionalCast(SourceRange TypeRange, + bool InitList) { + return InitializationKind(InitList ? IK_DirectList : IK_Direct, + IC_FunctionalCast, TypeRange.getBegin(), + TypeRange.getBegin(), TypeRange.getEnd()); + } + + /// Create a copy initialization. + static InitializationKind CreateCopy(SourceLocation InitLoc, + SourceLocation EqualLoc, + bool AllowExplicitConvs = false) { + return InitializationKind(IK_Copy, + AllowExplicitConvs? IC_ExplicitConvs : IC_Normal, + InitLoc, EqualLoc, EqualLoc); + } + + /// Create a default initialization. + static InitializationKind CreateDefault(SourceLocation InitLoc) { + return InitializationKind(IK_Default, IC_Normal, InitLoc, InitLoc, InitLoc); + } + + /// Create a value initialization. + static InitializationKind CreateValue(SourceLocation InitLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc, + bool isImplicit = false) { + return InitializationKind(IK_Value, isImplicit ? IC_Implicit : IC_Normal, + InitLoc, LParenLoc, RParenLoc); + } + + /// Create an initialization from an initializer (which, for direct + /// initialization from a parenthesized list, will be a ParenListExpr). + static InitializationKind CreateForInit(SourceLocation Loc, bool DirectInit, + Expr *Init) { + if (!Init) return CreateDefault(Loc); + if (!DirectInit) + return CreateCopy(Loc, Init->getBeginLoc()); + if (isa<InitListExpr>(Init)) + return CreateDirectList(Loc, Init->getBeginLoc(), Init->getEndLoc()); + return CreateDirect(Loc, Init->getBeginLoc(), Init->getEndLoc()); + } + + /// Determine the initialization kind. + InitKind getKind() const { + return Kind; + } + + /// Determine whether this initialization is an explicit cast. + bool isExplicitCast() const { + return Context >= IC_StaticCast; + } + + /// Determine whether this initialization is a static cast. + bool isStaticCast() const { return Context == IC_StaticCast; } + + /// Determine whether this initialization is a C-style cast. + bool isCStyleOrFunctionalCast() const { + return Context >= IC_CStyleCast; + } + + /// Determine whether this is a C-style cast. + bool isCStyleCast() const { + return Context == IC_CStyleCast; + } + + /// Determine whether this is a functional-style cast. + bool isFunctionalCast() const { + return Context == IC_FunctionalCast; + } + + /// Determine whether this initialization is an implicit + /// value-initialization, e.g., as occurs during aggregate + /// initialization. + bool isImplicitValueInit() const { return Context == IC_Implicit; } + + /// Retrieve the location at which initialization is occurring. + SourceLocation getLocation() const { return Locations[0]; } + + /// Retrieve the source range that covers the initialization. + SourceRange getRange() const { + return SourceRange(Locations[0], Locations[2]); + } + + /// Retrieve the location of the equal sign for copy initialization + /// (if present). + SourceLocation getEqualLoc() const { + assert(Kind == IK_Copy && "Only copy initialization has an '='"); + return Locations[1]; + } + + bool isCopyInit() const { return Kind == IK_Copy; } + + /// Retrieve whether this initialization allows the use of explicit + /// constructors. + bool AllowExplicit() const { return !isCopyInit(); } + + /// Retrieve whether this initialization allows the use of explicit + /// conversion functions when binding a reference. If the reference is the + /// first parameter in a copy or move constructor, such conversions are + /// permitted even though we are performing copy-initialization. + bool allowExplicitConversionFunctionsInRefBinding() const { + return !isCopyInit() || Context == IC_ExplicitConvs; + } + + /// Determine whether this initialization has a source range containing the + /// locations of open and closing parentheses or braces. + bool hasParenOrBraceRange() const { + return Kind == IK_Direct || Kind == IK_Value || Kind == IK_DirectList; + } + + /// Retrieve the source range containing the locations of the open + /// and closing parentheses or braces for value, direct, and direct list + /// initializations. + SourceRange getParenOrBraceRange() const { + assert(hasParenOrBraceRange() && "Only direct, value, and direct-list " + "initialization have parentheses or " + "braces"); + return SourceRange(Locations[1], Locations[2]); + } +}; + +/// Describes the sequence of initializations required to initialize +/// a given object or reference with a set of arguments. +class InitializationSequence { +public: + /// Describes the kind of initialization sequence computed. + enum SequenceKind { + /// A failed initialization sequence. The failure kind tells what + /// happened. + FailedSequence = 0, + + /// A dependent initialization, which could not be + /// type-checked due to the presence of dependent types or + /// dependently-typed expressions. + DependentSequence, + + /// A normal sequence. + NormalSequence + }; + + /// Describes the kind of a particular step in an initialization + /// sequence. + enum StepKind { + /// Resolve the address of an overloaded function to a specific + /// function declaration. + SK_ResolveAddressOfOverloadedFunction, + + /// Perform a derived-to-base cast, producing an rvalue. + SK_CastDerivedToBasePRValue, + + /// Perform a derived-to-base cast, producing an xvalue. + SK_CastDerivedToBaseXValue, + + /// Perform a derived-to-base cast, producing an lvalue. + SK_CastDerivedToBaseLValue, + + /// Reference binding to an lvalue. + SK_BindReference, + + /// Reference binding to a temporary. + SK_BindReferenceToTemporary, + + /// An optional copy of a temporary object to another + /// temporary object, which is permitted (but not required) by + /// C++98/03 but not C++0x. + SK_ExtraneousCopyToTemporary, + + /// Direct-initialization from a reference-related object in the + /// final stage of class copy-initialization. + SK_FinalCopy, + + /// Perform a user-defined conversion, either via a conversion + /// function or via a constructor. + SK_UserConversion, + + /// Perform a qualification conversion, producing a prvalue. + SK_QualificationConversionPRValue, + + /// Perform a qualification conversion, producing an xvalue. + SK_QualificationConversionXValue, + + /// Perform a qualification conversion, producing an lvalue. + SK_QualificationConversionLValue, + + /// Perform a function reference conversion, see [dcl.init.ref]p4. + SK_FunctionReferenceConversion, + + /// Perform a conversion adding _Atomic to a type. + SK_AtomicConversion, + + /// Perform an implicit conversion sequence. + SK_ConversionSequence, + + /// Perform an implicit conversion sequence without narrowing. + SK_ConversionSequenceNoNarrowing, + + /// Perform list-initialization without a constructor. + SK_ListInitialization, + + /// Unwrap the single-element initializer list for a reference. + SK_UnwrapInitList, + + /// Rewrap the single-element initializer list for a reference. + SK_RewrapInitList, + + /// Perform initialization via a constructor. + SK_ConstructorInitialization, + + /// Perform initialization via a constructor, taking arguments from + /// a single InitListExpr. + SK_ConstructorInitializationFromList, + + /// Zero-initialize the object + SK_ZeroInitialization, + + /// C assignment + SK_CAssignment, + + /// Initialization by string + SK_StringInit, + + /// An initialization that "converts" an Objective-C object + /// (not a point to an object) to another Objective-C object type. + SK_ObjCObjectConversion, + + /// Array indexing for initialization by elementwise copy. + SK_ArrayLoopIndex, + + /// Array initialization by elementwise copy. + SK_ArrayLoopInit, + + /// Array initialization (from an array rvalue). + SK_ArrayInit, + + /// Array initialization (from an array rvalue) as a GNU extension. + SK_GNUArrayInit, + + /// Array initialization from a parenthesized initializer list. + /// This is a GNU C++ extension. + SK_ParenthesizedArrayInit, + + /// Pass an object by indirect copy-and-restore. + SK_PassByIndirectCopyRestore, + + /// Pass an object by indirect restore. + SK_PassByIndirectRestore, + + /// Produce an Objective-C object pointer. + SK_ProduceObjCObject, + + /// Construct a std::initializer_list from an initializer list. + SK_StdInitializerList, + + /// Perform initialization via a constructor taking a single + /// std::initializer_list argument. + SK_StdInitializerListConstructorCall, + + /// Initialize an OpenCL sampler from an integer. + SK_OCLSamplerInit, + + /// Initialize an opaque OpenCL type (event_t, queue_t, etc.) with zero + SK_OCLZeroOpaqueType, + + /// Initialize an aggreagate with parenthesized list of values. + /// This is a C++20 feature. + SK_ParenthesizedListInit + }; + + /// A single step in the initialization sequence. + class Step { + public: + /// The kind of conversion or initialization step we are taking. + StepKind Kind; + + // The type that results from this initialization. + QualType Type; + + struct F { + bool HadMultipleCandidates; + FunctionDecl *Function; + DeclAccessPair FoundDecl; + }; + + union { + /// When Kind == SK_ResolvedOverloadedFunction or Kind == + /// SK_UserConversion, the function that the expression should be + /// resolved to or the conversion function to call, respectively. + /// When Kind == SK_ConstructorInitialization or SK_ListConstruction, + /// the constructor to be called. + /// + /// Always a FunctionDecl, plus a Boolean flag telling if it was + /// selected from an overloaded set having size greater than 1. + /// For conversion decls, the naming class is the source type. + /// For construct decls, the naming class is the target type. + struct F Function; + + /// When Kind = SK_ConversionSequence, the implicit conversion + /// sequence. + ImplicitConversionSequence *ICS; + + /// When Kind = SK_RewrapInitList, the syntactic form of the + /// wrapping list. + InitListExpr *WrappingSyntacticList; + }; + + void Destroy(); + }; + +private: + /// The kind of initialization sequence computed. + enum SequenceKind SequenceKind; + + /// Steps taken by this initialization. + SmallVector<Step, 4> Steps; + +public: + /// Describes why initialization failed. + enum FailureKind { + /// Too many initializers provided for a reference. + FK_TooManyInitsForReference, + + /// Reference initialized from a parenthesized initializer list. + FK_ParenthesizedListInitForReference, + + /// Array must be initialized with an initializer list. + FK_ArrayNeedsInitList, + + /// Array must be initialized with an initializer list or a + /// string literal. + FK_ArrayNeedsInitListOrStringLiteral, + + /// Array must be initialized with an initializer list or a + /// wide string literal. + FK_ArrayNeedsInitListOrWideStringLiteral, + + /// Initializing a wide char array with narrow string literal. + FK_NarrowStringIntoWideCharArray, + + /// Initializing char array with wide string literal. + FK_WideStringIntoCharArray, + + /// Initializing wide char array with incompatible wide string + /// literal. + FK_IncompatWideStringIntoWideChar, + + /// Initializing char8_t array with plain string literal. + FK_PlainStringIntoUTF8Char, + + /// Initializing char array with UTF-8 string literal. + FK_UTF8StringIntoPlainChar, + + /// Array type mismatch. + FK_ArrayTypeMismatch, + + /// Non-constant array initializer + FK_NonConstantArrayInit, + + /// Cannot resolve the address of an overloaded function. + FK_AddressOfOverloadFailed, + + /// Overloading due to reference initialization failed. + FK_ReferenceInitOverloadFailed, + + /// Non-const lvalue reference binding to a temporary. + FK_NonConstLValueReferenceBindingToTemporary, + + /// Non-const lvalue reference binding to a bit-field. + FK_NonConstLValueReferenceBindingToBitfield, + + /// Non-const lvalue reference binding to a vector element. + FK_NonConstLValueReferenceBindingToVectorElement, + + /// Non-const lvalue reference binding to a matrix element. + FK_NonConstLValueReferenceBindingToMatrixElement, + + /// Non-const lvalue reference binding to an lvalue of unrelated + /// type. + FK_NonConstLValueReferenceBindingToUnrelated, + + /// Rvalue reference binding to an lvalue. + FK_RValueReferenceBindingToLValue, + + /// Reference binding drops qualifiers. + FK_ReferenceInitDropsQualifiers, + + /// Reference with mismatching address space binding to temporary. + FK_ReferenceAddrspaceMismatchTemporary, + + /// Reference binding failed. + FK_ReferenceInitFailed, + + /// Implicit conversion failed. + FK_ConversionFailed, + + /// Implicit conversion failed. + FK_ConversionFromPropertyFailed, + + /// Too many initializers for scalar + FK_TooManyInitsForScalar, + + /// Scalar initialized from a parenthesized initializer list. + FK_ParenthesizedListInitForScalar, + + /// Reference initialization from an initializer list + FK_ReferenceBindingToInitList, + + /// Initialization of some unused destination type with an + /// initializer list. + FK_InitListBadDestinationType, + + /// Overloading for a user-defined conversion failed. + FK_UserConversionOverloadFailed, + + /// Overloading for initialization by constructor failed. + FK_ConstructorOverloadFailed, + + /// Overloading for list-initialization by constructor failed. + FK_ListConstructorOverloadFailed, + + /// Default-initialization of a 'const' object. + FK_DefaultInitOfConst, + + /// Initialization of an incomplete type. + FK_Incomplete, + + /// Variable-length array must not have an initializer. + FK_VariableLengthArrayHasInitializer, + + /// List initialization failed at some point. + FK_ListInitializationFailed, + + /// Initializer has a placeholder type which cannot be + /// resolved by initialization. + FK_PlaceholderType, + + /// Trying to take the address of a function that doesn't support + /// having its address taken. + FK_AddressOfUnaddressableFunction, + + /// List-copy-initialization chose an explicit constructor. + FK_ExplicitConstructor, + + /// Parenthesized list initialization failed at some point. + /// This is a C++20 feature. + FK_ParenthesizedListInitFailed, + }; + +private: + /// The reason why initialization failed. + FailureKind Failure; + + /// The failed result of overload resolution. + OverloadingResult FailedOverloadResult; + + /// The candidate set created when initialization failed. + OverloadCandidateSet FailedCandidateSet; + + /// The incomplete type that caused a failure. + QualType FailedIncompleteType; + + /// The fixit that needs to be applied to make this initialization + /// succeed. + std::string ZeroInitializationFixit; + SourceLocation ZeroInitializationFixitLoc; + +public: + /// Call for initializations are invalid but that would be valid + /// zero initialzations if Fixit was applied. + void SetZeroInitializationFixit(const std::string& Fixit, SourceLocation L) { + ZeroInitializationFixit = Fixit; + ZeroInitializationFixitLoc = L; + } + +private: + /// Prints a follow-up note that highlights the location of + /// the initialized entity, if it's remote. + void PrintInitLocationNote(Sema &S, const InitializedEntity &Entity); + +public: + /// Try to perform initialization of the given entity, creating a + /// record of the steps required to perform the initialization. + /// + /// The generated initialization sequence will either contain enough + /// information to diagnose + /// + /// \param S the semantic analysis object. + /// + /// \param Entity the entity being initialized. + /// + /// \param Kind the kind of initialization being performed. + /// + /// \param Args the argument(s) provided for initialization. + /// + /// \param TopLevelOfInitList true if we are initializing from an expression + /// at the top level inside an initializer list. This disallows + /// narrowing conversions in C++11 onwards. + /// \param TreatUnavailableAsInvalid true if we want to treat unavailable + /// as invalid. + InitializationSequence(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + MultiExprArg Args, + bool TopLevelOfInitList = false, + bool TreatUnavailableAsInvalid = true); + void InitializeFrom(Sema &S, const InitializedEntity &Entity, + const InitializationKind &Kind, MultiExprArg Args, + bool TopLevelOfInitList, bool TreatUnavailableAsInvalid); + + ~InitializationSequence(); + + /// Perform the actual initialization of the given entity based on + /// the computed initialization sequence. + /// + /// \param S the semantic analysis object. + /// + /// \param Entity the entity being initialized. + /// + /// \param Kind the kind of initialization being performed. + /// + /// \param Args the argument(s) provided for initialization, ownership of + /// which is transferred into the routine. + /// + /// \param ResultType if non-NULL, will be set to the type of the + /// initialized object, which is the type of the declaration in most + /// cases. However, when the initialized object is a variable of + /// incomplete array type and the initializer is an initializer + /// list, this type will be set to the completed array type. + /// + /// \returns an expression that performs the actual object initialization, if + /// the initialization is well-formed. Otherwise, emits diagnostics + /// and returns an invalid expression. + ExprResult Perform(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + MultiExprArg Args, + QualType *ResultType = nullptr); + + /// Diagnose an potentially-invalid initialization sequence. + /// + /// \returns true if the initialization sequence was ill-formed, + /// false otherwise. + bool Diagnose(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + ArrayRef<Expr *> Args); + + /// Determine the kind of initialization sequence computed. + enum SequenceKind getKind() const { return SequenceKind; } + + /// Set the kind of sequence computed. + void setSequenceKind(enum SequenceKind SK) { SequenceKind = SK; } + + /// Determine whether the initialization sequence is valid. + explicit operator bool() const { return !Failed(); } + + /// Determine whether the initialization sequence is invalid. + bool Failed() const { return SequenceKind == FailedSequence; } + + using step_iterator = SmallVectorImpl<Step>::const_iterator; + + step_iterator step_begin() const { return Steps.begin(); } + step_iterator step_end() const { return Steps.end(); } + + using step_range = llvm::iterator_range<step_iterator>; + + step_range steps() const { return {step_begin(), step_end()}; } + + /// Determine whether this initialization is a direct reference + /// binding (C++ [dcl.init.ref]). + bool isDirectReferenceBinding() const; + + /// Determine whether this initialization failed due to an ambiguity. + bool isAmbiguous() const; + + /// Determine whether this initialization is direct call to a + /// constructor. + bool isConstructorInitialization() const; + + /// Add a new step in the initialization that resolves the address + /// of an overloaded function to a specific function declaration. + /// + /// \param Function the function to which the overloaded function reference + /// resolves. + void AddAddressOverloadResolutionStep(FunctionDecl *Function, + DeclAccessPair Found, + bool HadMultipleCandidates); + + /// Add a new step in the initialization that performs a derived-to- + /// base cast. + /// + /// \param BaseType the base type to which we will be casting. + /// + /// \param Category Indicates whether the result will be treated as an + /// rvalue, an xvalue, or an lvalue. + void AddDerivedToBaseCastStep(QualType BaseType, + ExprValueKind Category); + + /// Add a new step binding a reference to an object. + /// + /// \param BindingTemporary True if we are binding a reference to a temporary + /// object (thereby extending its lifetime); false if we are binding to an + /// lvalue or an lvalue treated as an rvalue. + void AddReferenceBindingStep(QualType T, bool BindingTemporary); + + /// Add a new step that makes an extraneous copy of the input + /// to a temporary of the same class type. + /// + /// This extraneous copy only occurs during reference binding in + /// C++98/03, where we are permitted (but not required) to introduce + /// an extra copy. At a bare minimum, we must check that we could + /// call the copy constructor, and produce a diagnostic if the copy + /// constructor is inaccessible or no copy constructor matches. + // + /// \param T The type of the temporary being created. + void AddExtraneousCopyToTemporary(QualType T); + + /// Add a new step that makes a copy of the input to an object of + /// the given type, as the final step in class copy-initialization. + void AddFinalCopy(QualType T); + + /// Add a new step invoking a conversion function, which is either + /// a constructor or a conversion function. + void AddUserConversionStep(FunctionDecl *Function, + DeclAccessPair FoundDecl, + QualType T, + bool HadMultipleCandidates); + + /// Add a new step that performs a qualification conversion to the + /// given type. + void AddQualificationConversionStep(QualType Ty, + ExprValueKind Category); + + /// Add a new step that performs a function reference conversion to the + /// given type. + void AddFunctionReferenceConversionStep(QualType Ty); + + /// Add a new step that performs conversion from non-atomic to atomic + /// type. + void AddAtomicConversionStep(QualType Ty); + + /// Add a new step that applies an implicit conversion sequence. + void AddConversionSequenceStep(const ImplicitConversionSequence &ICS, + QualType T, bool TopLevelOfInitList = false); + + /// Add a list-initialization step. + void AddListInitializationStep(QualType T); + + /// Add a constructor-initialization step. + /// + /// \param FromInitList The constructor call is syntactically an initializer + /// list. + /// \param AsInitList The constructor is called as an init list constructor. + void AddConstructorInitializationStep(DeclAccessPair FoundDecl, + CXXConstructorDecl *Constructor, + QualType T, + bool HadMultipleCandidates, + bool FromInitList, bool AsInitList); + + /// Add a zero-initialization step. + void AddZeroInitializationStep(QualType T); + + /// Add a C assignment step. + // + // FIXME: It isn't clear whether this should ever be needed; + // ideally, we would handle everything needed in C in the common + // path. However, that isn't the case yet. + void AddCAssignmentStep(QualType T); + + /// Add a string init step. + void AddStringInitStep(QualType T); + + /// Add an Objective-C object conversion step, which is + /// always a no-op. + void AddObjCObjectConversionStep(QualType T); + + /// Add an array initialization loop step. + void AddArrayInitLoopStep(QualType T, QualType EltTy); + + /// Add an array initialization step. + void AddArrayInitStep(QualType T, bool IsGNUExtension); + + /// Add a parenthesized array initialization step. + void AddParenthesizedArrayInitStep(QualType T); + + /// Add a step to pass an object by indirect copy-restore. + void AddPassByIndirectCopyRestoreStep(QualType T, bool shouldCopy); + + /// Add a step to "produce" an Objective-C object (by + /// retaining it). + void AddProduceObjCObjectStep(QualType T); + + /// Add a step to construct a std::initializer_list object from an + /// initializer list. + void AddStdInitializerListConstructionStep(QualType T); + + /// Add a step to initialize an OpenCL sampler from an integer + /// constant. + void AddOCLSamplerInitStep(QualType T); + + /// Add a step to initialzie an OpenCL opaque type (event_t, queue_t, etc.) + /// from a zero constant. + void AddOCLZeroOpaqueTypeStep(QualType T); + + void AddParenthesizedListInitStep(QualType T); + + /// Add steps to unwrap a initializer list for a reference around a + /// single element and rewrap it at the end. + void RewrapReferenceInitList(QualType T, InitListExpr *Syntactic); + + /// Note that this initialization sequence failed. + void SetFailed(FailureKind Failure) { + SequenceKind = FailedSequence; + this->Failure = Failure; + assert((Failure != FK_Incomplete || !FailedIncompleteType.isNull()) && + "Incomplete type failure requires a type!"); + } + + /// Note that this initialization sequence failed due to failed + /// overload resolution. + void SetOverloadFailure(FailureKind Failure, OverloadingResult Result); + + /// Retrieve a reference to the candidate set when overload + /// resolution fails. + OverloadCandidateSet &getFailedCandidateSet() { + return FailedCandidateSet; + } + + /// Get the overloading result, for when the initialization + /// sequence failed due to a bad overload. + OverloadingResult getFailedOverloadResult() const { + return FailedOverloadResult; + } + + /// Note that this initialization sequence failed due to an + /// incomplete type. + void setIncompleteTypeFailure(QualType IncompleteType) { + FailedIncompleteType = IncompleteType; + SetFailed(FK_Incomplete); + } + + /// Determine why initialization failed. + FailureKind getFailureKind() const { + assert(Failed() && "Not an initialization failure!"); + return Failure; + } + + /// Dump a representation of this initialization sequence to + /// the given stream, for debugging purposes. + void dump(raw_ostream &OS) const; + + /// Dump a representation of this initialization sequence to + /// standard error, for debugging purposes. + void dump() const; +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_INITIALIZATION_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/Lookup.h b/contrib/libs/clang16/include/clang/Sema/Lookup.h new file mode 100644 index 0000000000..e3378daa0e --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/Lookup.h @@ -0,0 +1,863 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- Lookup.h - Classes for name lookup -----------------------*- 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 defines the LookupResult class, which is integral to +// Sema's name-lookup subsystem. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_LOOKUP_H +#define LLVM_CLANG_SEMA_LOOKUP_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Type.h" +#include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Casting.h" +#include <cassert> +#include <optional> +#include <utility> + +namespace clang { + +class CXXBasePaths; + +/// Represents the results of name lookup. +/// +/// An instance of the LookupResult class captures the results of a +/// single name lookup, which can return no result (nothing found), +/// a single declaration, a set of overloaded functions, or an +/// ambiguity. Use the getKind() method to determine which of these +/// results occurred for a given lookup. +class LookupResult { +public: + enum LookupResultKind { + /// No entity found met the criteria. + NotFound = 0, + + /// No entity found met the criteria within the current + /// instantiation,, but there were dependent base classes of the + /// current instantiation that could not be searched. + NotFoundInCurrentInstantiation, + + /// Name lookup found a single declaration that met the + /// criteria. getFoundDecl() will return this declaration. + Found, + + /// Name lookup found a set of overloaded functions that + /// met the criteria. + FoundOverloaded, + + /// Name lookup found an unresolvable value declaration + /// and cannot yet complete. This only happens in C++ dependent + /// contexts with dependent using declarations. + FoundUnresolvedValue, + + /// Name lookup results in an ambiguity; use + /// getAmbiguityKind to figure out what kind of ambiguity + /// we have. + Ambiguous + }; + + enum AmbiguityKind { + /// Name lookup results in an ambiguity because multiple + /// entities that meet the lookup criteria were found in + /// subobjects of different types. For example: + /// @code + /// struct A { void f(int); } + /// struct B { void f(double); } + /// struct C : A, B { }; + /// void test(C c) { + /// c.f(0); // error: A::f and B::f come from subobjects of different + /// // types. overload resolution is not performed. + /// } + /// @endcode + AmbiguousBaseSubobjectTypes, + + /// Name lookup results in an ambiguity because multiple + /// nonstatic entities that meet the lookup criteria were found + /// in different subobjects of the same type. For example: + /// @code + /// struct A { int x; }; + /// struct B : A { }; + /// struct C : A { }; + /// struct D : B, C { }; + /// int test(D d) { + /// return d.x; // error: 'x' is found in two A subobjects (of B and C) + /// } + /// @endcode + AmbiguousBaseSubobjects, + + /// Name lookup results in an ambiguity because multiple definitions + /// of entity that meet the lookup criteria were found in different + /// declaration contexts. + /// @code + /// namespace A { + /// int i; + /// namespace B { int i; } + /// int test() { + /// using namespace B; + /// return i; // error 'i' is found in namespace A and A::B + /// } + /// } + /// @endcode + AmbiguousReference, + + /// Name lookup results in an ambiguity because an entity with a + /// tag name was hidden by an entity with an ordinary name from + /// a different context. + /// @code + /// namespace A { struct Foo {}; } + /// namespace B { void Foo(); } + /// namespace C { + /// using namespace A; + /// using namespace B; + /// } + /// void test() { + /// C::Foo(); // error: tag 'A::Foo' is hidden by an object in a + /// // different namespace + /// } + /// @endcode + AmbiguousTagHiding + }; + + /// A little identifier for flagging temporary lookup results. + enum TemporaryToken { + Temporary + }; + + using iterator = UnresolvedSetImpl::iterator; + + LookupResult(Sema &SemaRef, const DeclarationNameInfo &NameInfo, + Sema::LookupNameKind LookupKind, + Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) + : SemaPtr(&SemaRef), NameInfo(NameInfo), LookupKind(LookupKind), + Redecl(Redecl != Sema::NotForRedeclaration), + ExternalRedecl(Redecl == Sema::ForExternalRedeclaration), + Diagnose(Redecl == Sema::NotForRedeclaration) { + configure(); + } + + // TODO: consider whether this constructor should be restricted to take + // as input a const IdentifierInfo* (instead of Name), + // forcing other cases towards the constructor taking a DNInfo. + LookupResult(Sema &SemaRef, DeclarationName Name, + SourceLocation NameLoc, Sema::LookupNameKind LookupKind, + Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) + : SemaPtr(&SemaRef), NameInfo(Name, NameLoc), LookupKind(LookupKind), + Redecl(Redecl != Sema::NotForRedeclaration), + ExternalRedecl(Redecl == Sema::ForExternalRedeclaration), + Diagnose(Redecl == Sema::NotForRedeclaration) { + configure(); + } + + /// Creates a temporary lookup result, initializing its core data + /// using the information from another result. Diagnostics are always + /// disabled. + LookupResult(TemporaryToken _, const LookupResult &Other) + : SemaPtr(Other.SemaPtr), NameInfo(Other.NameInfo), + LookupKind(Other.LookupKind), IDNS(Other.IDNS), Redecl(Other.Redecl), + ExternalRedecl(Other.ExternalRedecl), HideTags(Other.HideTags), + AllowHidden(Other.AllowHidden), + TemplateNameLookup(Other.TemplateNameLookup) {} + + // FIXME: Remove these deleted methods once the default build includes + // -Wdeprecated. + LookupResult(const LookupResult &) = delete; + LookupResult &operator=(const LookupResult &) = delete; + + LookupResult(LookupResult &&Other) + : ResultKind(std::move(Other.ResultKind)), + Ambiguity(std::move(Other.Ambiguity)), Decls(std::move(Other.Decls)), + Paths(std::move(Other.Paths)), + NamingClass(std::move(Other.NamingClass)), + BaseObjectType(std::move(Other.BaseObjectType)), + SemaPtr(std::move(Other.SemaPtr)), NameInfo(std::move(Other.NameInfo)), + NameContextRange(std::move(Other.NameContextRange)), + LookupKind(std::move(Other.LookupKind)), IDNS(std::move(Other.IDNS)), + Redecl(std::move(Other.Redecl)), + ExternalRedecl(std::move(Other.ExternalRedecl)), + HideTags(std::move(Other.HideTags)), + Diagnose(std::move(Other.Diagnose)), + AllowHidden(std::move(Other.AllowHidden)), + Shadowed(std::move(Other.Shadowed)), + TemplateNameLookup(std::move(Other.TemplateNameLookup)) { + Other.Paths = nullptr; + Other.Diagnose = false; + } + + LookupResult &operator=(LookupResult &&Other) { + ResultKind = std::move(Other.ResultKind); + Ambiguity = std::move(Other.Ambiguity); + Decls = std::move(Other.Decls); + Paths = std::move(Other.Paths); + NamingClass = std::move(Other.NamingClass); + BaseObjectType = std::move(Other.BaseObjectType); + SemaPtr = std::move(Other.SemaPtr); + NameInfo = std::move(Other.NameInfo); + NameContextRange = std::move(Other.NameContextRange); + LookupKind = std::move(Other.LookupKind); + IDNS = std::move(Other.IDNS); + Redecl = std::move(Other.Redecl); + ExternalRedecl = std::move(Other.ExternalRedecl); + HideTags = std::move(Other.HideTags); + Diagnose = std::move(Other.Diagnose); + AllowHidden = std::move(Other.AllowHidden); + Shadowed = std::move(Other.Shadowed); + TemplateNameLookup = std::move(Other.TemplateNameLookup); + Other.Paths = nullptr; + Other.Diagnose = false; + return *this; + } + + ~LookupResult() { + if (Diagnose) diagnose(); + if (Paths) deletePaths(Paths); + } + + /// Gets the name info to look up. + const DeclarationNameInfo &getLookupNameInfo() const { + return NameInfo; + } + + /// Sets the name info to look up. + void setLookupNameInfo(const DeclarationNameInfo &NameInfo) { + this->NameInfo = NameInfo; + } + + /// Gets the name to look up. + DeclarationName getLookupName() const { + return NameInfo.getName(); + } + + /// Sets the name to look up. + void setLookupName(DeclarationName Name) { + NameInfo.setName(Name); + } + + /// Gets the kind of lookup to perform. + Sema::LookupNameKind getLookupKind() const { + return LookupKind; + } + + /// True if this lookup is just looking for an existing declaration. + bool isForRedeclaration() const { + return Redecl; + } + + /// True if this lookup is just looking for an existing declaration to link + /// against a declaration with external linkage. + bool isForExternalRedeclaration() const { + return ExternalRedecl; + } + + Sema::RedeclarationKind redeclarationKind() const { + return ExternalRedecl ? Sema::ForExternalRedeclaration : + Redecl ? Sema::ForVisibleRedeclaration : Sema::NotForRedeclaration; + } + + /// Specify whether hidden declarations are visible, e.g., + /// for recovery reasons. + void setAllowHidden(bool AH) { + AllowHidden = AH; + } + + /// Determine whether this lookup is permitted to see hidden + /// declarations, such as those in modules that have not yet been imported. + bool isHiddenDeclarationVisible(NamedDecl *ND) const { + return AllowHidden || + (isForExternalRedeclaration() && ND->isExternallyDeclarable()); + } + + /// Sets whether tag declarations should be hidden by non-tag + /// declarations during resolution. The default is true. + void setHideTags(bool Hide) { + HideTags = Hide; + } + + /// Sets whether this is a template-name lookup. For template-name lookups, + /// injected-class-names are treated as naming a template rather than a + /// template specialization. + void setTemplateNameLookup(bool TemplateName) { + TemplateNameLookup = TemplateName; + } + + bool isTemplateNameLookup() const { return TemplateNameLookup; } + + bool isAmbiguous() const { + return getResultKind() == Ambiguous; + } + + /// Determines if this names a single result which is not an + /// unresolved value using decl. If so, it is safe to call + /// getFoundDecl(). + bool isSingleResult() const { + return getResultKind() == Found; + } + + /// Determines if the results are overloaded. + bool isOverloadedResult() const { + return getResultKind() == FoundOverloaded; + } + + bool isUnresolvableResult() const { + return getResultKind() == FoundUnresolvedValue; + } + + LookupResultKind getResultKind() const { + assert(checkDebugAssumptions()); + return ResultKind; + } + + AmbiguityKind getAmbiguityKind() const { + assert(isAmbiguous()); + return Ambiguity; + } + + const UnresolvedSetImpl &asUnresolvedSet() const { + return Decls; + } + + iterator begin() const { return iterator(Decls.begin()); } + iterator end() const { return iterator(Decls.end()); } + + /// Return true if no decls were found + bool empty() const { return Decls.empty(); } + + /// Return the base paths structure that's associated with + /// these results, or null if none is. + CXXBasePaths *getBasePaths() const { + return Paths; + } + + /// Determine whether the given declaration is visible to the + /// program. + static bool isVisible(Sema &SemaRef, NamedDecl *D); + + static bool isReachable(Sema &SemaRef, NamedDecl *D); + + static bool isAcceptable(Sema &SemaRef, NamedDecl *D, + Sema::AcceptableKind Kind) { + return Kind == Sema::AcceptableKind::Visible ? isVisible(SemaRef, D) + : isReachable(SemaRef, D); + } + + /// Determine whether this lookup is permitted to see the declaration. + /// Note that a reachable but not visible declaration inhabiting a namespace + /// is not allowed to be seen during name lookup. + /// + /// For example: + /// ``` + /// // m.cppm + /// export module m; + /// struct reachable { int v; } + /// export auto func() { return reachable{43}; } + /// // Use.cpp + /// import m; + /// auto Use() { + /// // Not valid. We couldn't see reachable here. + /// // So isAvailableForLookup would return false when we look + /// up 'reachable' here. + /// // return reachable(43).v; + /// // Valid. The field name 'v' is allowed during name lookup. + /// // So isAvailableForLookup would return true when we look up 'v' here. + /// return func().v; + /// } + /// ``` + static bool isAvailableForLookup(Sema &SemaRef, NamedDecl *ND); + + /// Retrieve the accepted (re)declaration of the given declaration, + /// if there is one. + NamedDecl *getAcceptableDecl(NamedDecl *D) const { + if (!D->isInIdentifierNamespace(IDNS)) + return nullptr; + + if (isAvailableForLookup(getSema(), D) || isHiddenDeclarationVisible(D)) + return D; + + return getAcceptableDeclSlow(D); + } + +private: + static bool isAcceptableSlow(Sema &SemaRef, NamedDecl *D, + Sema::AcceptableKind Kind); + static bool isReachableSlow(Sema &SemaRef, NamedDecl *D); + NamedDecl *getAcceptableDeclSlow(NamedDecl *D) const; + +public: + /// Returns the identifier namespace mask for this lookup. + unsigned getIdentifierNamespace() const { + return IDNS; + } + + /// Returns whether these results arose from performing a + /// lookup into a class. + bool isClassLookup() const { + return NamingClass != nullptr; + } + + /// Returns the 'naming class' for this lookup, i.e. the + /// class which was looked into to find these results. + /// + /// C++0x [class.access.base]p5: + /// The access to a member is affected by the class in which the + /// member is named. This naming class is the class in which the + /// member name was looked up and found. [Note: this class can be + /// explicit, e.g., when a qualified-id is used, or implicit, + /// e.g., when a class member access operator (5.2.5) is used + /// (including cases where an implicit "this->" is added). If both + /// a class member access operator and a qualified-id are used to + /// name the member (as in p->T::m), the class naming the member + /// is the class named by the nested-name-specifier of the + /// qualified-id (that is, T). -- end note ] + /// + /// This is set by the lookup routines when they find results in a class. + CXXRecordDecl *getNamingClass() const { + return NamingClass; + } + + /// Sets the 'naming class' for this lookup. + void setNamingClass(CXXRecordDecl *Record) { + NamingClass = Record; + } + + /// Returns the base object type associated with this lookup; + /// important for [class.protected]. Most lookups do not have an + /// associated base object. + QualType getBaseObjectType() const { + return BaseObjectType; + } + + /// Sets the base object type for this lookup. + void setBaseObjectType(QualType T) { + BaseObjectType = T; + } + + /// Add a declaration to these results with its natural access. + /// Does not test the acceptance criteria. + void addDecl(NamedDecl *D) { + addDecl(D, D->getAccess()); + } + + /// Add a declaration to these results with the given access. + /// Does not test the acceptance criteria. + void addDecl(NamedDecl *D, AccessSpecifier AS) { + Decls.addDecl(D, AS); + ResultKind = Found; + } + + /// Add all the declarations from another set of lookup + /// results. + void addAllDecls(const LookupResult &Other) { + Decls.append(Other.Decls.begin(), Other.Decls.end()); + ResultKind = Found; + } + + /// Determine whether no result was found because we could not + /// search into dependent base classes of the current instantiation. + bool wasNotFoundInCurrentInstantiation() const { + return ResultKind == NotFoundInCurrentInstantiation; + } + + /// Note that while no result was found in the current instantiation, + /// there were dependent base classes that could not be searched. + void setNotFoundInCurrentInstantiation() { + assert(ResultKind == NotFound && Decls.empty()); + ResultKind = NotFoundInCurrentInstantiation; + } + + /// Determine whether the lookup result was shadowed by some other + /// declaration that lookup ignored. + bool isShadowed() const { return Shadowed; } + + /// Note that we found and ignored a declaration while performing + /// lookup. + void setShadowed() { Shadowed = true; } + + /// Resolves the result kind of the lookup, possibly hiding + /// decls. + /// + /// This should be called in any environment where lookup might + /// generate multiple lookup results. + void resolveKind(); + + /// Re-resolves the result kind of the lookup after a set of + /// removals has been performed. + void resolveKindAfterFilter() { + if (Decls.empty()) { + if (ResultKind != NotFoundInCurrentInstantiation) + ResultKind = NotFound; + + if (Paths) { + deletePaths(Paths); + Paths = nullptr; + } + } else { + std::optional<AmbiguityKind> SavedAK; + bool WasAmbiguous = false; + if (ResultKind == Ambiguous) { + SavedAK = Ambiguity; + WasAmbiguous = true; + } + ResultKind = Found; + resolveKind(); + + // If we didn't make the lookup unambiguous, restore the old + // ambiguity kind. + if (ResultKind == Ambiguous) { + (void)WasAmbiguous; + assert(WasAmbiguous); + Ambiguity = *SavedAK; + } else if (Paths) { + deletePaths(Paths); + Paths = nullptr; + } + } + } + + template <class DeclClass> + DeclClass *getAsSingle() const { + if (getResultKind() != Found) return nullptr; + return dyn_cast<DeclClass>(getFoundDecl()); + } + + /// Fetch the unique decl found by this lookup. Asserts + /// that one was found. + /// + /// This is intended for users who have examined the result kind + /// and are certain that there is only one result. + NamedDecl *getFoundDecl() const { + assert(getResultKind() == Found + && "getFoundDecl called on non-unique result"); + return (*begin())->getUnderlyingDecl(); + } + + /// Fetches a representative decl. Useful for lazy diagnostics. + NamedDecl *getRepresentativeDecl() const { + assert(!Decls.empty() && "cannot get representative of empty set"); + return *begin(); + } + + /// Asks if the result is a single tag decl. + bool isSingleTagDecl() const { + return getResultKind() == Found && isa<TagDecl>(getFoundDecl()); + } + + /// Make these results show that the name was found in + /// base classes of different types. + /// + /// The given paths object is copied and invalidated. + void setAmbiguousBaseSubobjectTypes(CXXBasePaths &P); + + /// Make these results show that the name was found in + /// distinct base classes of the same type. + /// + /// The given paths object is copied and invalidated. + void setAmbiguousBaseSubobjects(CXXBasePaths &P); + + /// Make these results show that the name was found in + /// different contexts and a tag decl was hidden by an ordinary + /// decl in a different context. + void setAmbiguousQualifiedTagHiding() { + setAmbiguous(AmbiguousTagHiding); + } + + /// Clears out any current state. + LLVM_ATTRIBUTE_REINITIALIZES void clear() { + ResultKind = NotFound; + Decls.clear(); + if (Paths) deletePaths(Paths); + Paths = nullptr; + NamingClass = nullptr; + Shadowed = false; + } + + /// Clears out any current state and re-initializes for a + /// different kind of lookup. + void clear(Sema::LookupNameKind Kind) { + clear(); + LookupKind = Kind; + configure(); + } + + /// Change this lookup's redeclaration kind. + void setRedeclarationKind(Sema::RedeclarationKind RK) { + Redecl = (RK != Sema::NotForRedeclaration); + ExternalRedecl = (RK == Sema::ForExternalRedeclaration); + configure(); + } + + void dump(); + void print(raw_ostream &); + + /// Suppress the diagnostics that would normally fire because of this + /// lookup. This happens during (e.g.) redeclaration lookups. + void suppressDiagnostics() { + Diagnose = false; + } + + /// Determines whether this lookup is suppressing diagnostics. + bool isSuppressingDiagnostics() const { + return !Diagnose; + } + + /// Sets a 'context' source range. + void setContextRange(SourceRange SR) { + NameContextRange = SR; + } + + /// Gets the source range of the context of this name; for C++ + /// qualified lookups, this is the source range of the scope + /// specifier. + SourceRange getContextRange() const { + return NameContextRange; + } + + /// Gets the location of the identifier. This isn't always defined: + /// sometimes we're doing lookups on synthesized names. + SourceLocation getNameLoc() const { + return NameInfo.getLoc(); + } + + /// Get the Sema object that this lookup result is searching + /// with. + Sema &getSema() const { return *SemaPtr; } + + /// A class for iterating through a result set and possibly + /// filtering out results. The results returned are possibly + /// sugared. + class Filter { + friend class LookupResult; + + LookupResult &Results; + LookupResult::iterator I; + bool Changed = false; + bool CalledDone = false; + + Filter(LookupResult &Results) : Results(Results), I(Results.begin()) {} + + public: + Filter(Filter &&F) + : Results(F.Results), I(F.I), Changed(F.Changed), + CalledDone(F.CalledDone) { + F.CalledDone = true; + } + + ~Filter() { + assert(CalledDone && + "LookupResult::Filter destroyed without done() call"); + } + + bool hasNext() const { + return I != Results.end(); + } + + NamedDecl *next() { + assert(I != Results.end() && "next() called on empty filter"); + return *I++; + } + + /// Restart the iteration. + void restart() { + I = Results.begin(); + } + + /// Erase the last element returned from this iterator. + void erase() { + Results.Decls.erase(--I); + Changed = true; + } + + /// Replaces the current entry with the given one, preserving the + /// access bits. + void replace(NamedDecl *D) { + Results.Decls.replace(I-1, D); + Changed = true; + } + + /// Replaces the current entry with the given one. + void replace(NamedDecl *D, AccessSpecifier AS) { + Results.Decls.replace(I-1, D, AS); + Changed = true; + } + + void done() { + assert(!CalledDone && "done() called twice"); + CalledDone = true; + + if (Changed) + Results.resolveKindAfterFilter(); + } + }; + + /// Create a filter for this result set. + Filter makeFilter() { + return Filter(*this); + } + + void setFindLocalExtern(bool FindLocalExtern) { + if (FindLocalExtern) + IDNS |= Decl::IDNS_LocalExtern; + else + IDNS &= ~Decl::IDNS_LocalExtern; + } + +private: + void diagnose() { + if (isAmbiguous()) + getSema().DiagnoseAmbiguousLookup(*this); + else if (isClassLookup() && getSema().getLangOpts().AccessControl) + getSema().CheckLookupAccess(*this); + } + + void setAmbiguous(AmbiguityKind AK) { + ResultKind = Ambiguous; + Ambiguity = AK; + } + + void addDeclsFromBasePaths(const CXXBasePaths &P); + void configure(); + + bool checkDebugAssumptions() const; + + bool checkUnresolved() const { + for (iterator I = begin(), E = end(); I != E; ++I) + if (isa<UnresolvedUsingValueDecl>((*I)->getUnderlyingDecl())) + return true; + return false; + } + + static void deletePaths(CXXBasePaths *); + + // Results. + LookupResultKind ResultKind = NotFound; + // ill-defined unless ambiguous. Still need to be initialized it will be + // copied/moved. + AmbiguityKind Ambiguity = {}; + UnresolvedSet<8> Decls; + CXXBasePaths *Paths = nullptr; + CXXRecordDecl *NamingClass = nullptr; + QualType BaseObjectType; + + // Parameters. + Sema *SemaPtr; + DeclarationNameInfo NameInfo; + SourceRange NameContextRange; + Sema::LookupNameKind LookupKind; + unsigned IDNS = 0; // set by configure() + + bool Redecl; + bool ExternalRedecl; + + /// True if tag declarations should be hidden if non-tags + /// are present + bool HideTags = true; + + bool Diagnose = false; + + /// True if we should allow hidden declarations to be 'visible'. + bool AllowHidden = false; + + /// True if the found declarations were shadowed by some other + /// declaration that we skipped. This only happens when \c LookupKind + /// is \c LookupRedeclarationWithLinkage. + bool Shadowed = false; + + /// True if we're looking up a template-name. + bool TemplateNameLookup = false; +}; + +/// Consumes visible declarations found when searching for +/// all visible names within a given scope or context. +/// +/// This abstract class is meant to be subclassed by clients of \c +/// Sema::LookupVisibleDecls(), each of which should override the \c +/// FoundDecl() function to process declarations as they are found. +class VisibleDeclConsumer { +public: + /// Destroys the visible declaration consumer. + virtual ~VisibleDeclConsumer(); + + /// Determine whether hidden declarations (from unimported + /// modules) should be given to this consumer. By default, they + /// are not included. + virtual bool includeHiddenDecls() const; + + /// Invoked each time \p Sema::LookupVisibleDecls() finds a + /// declaration visible from the current scope or context. + /// + /// \param ND the declaration found. + /// + /// \param Hiding a declaration that hides the declaration \p ND, + /// or NULL if no such declaration exists. + /// + /// \param Ctx the original context from which the lookup started. + /// + /// \param InBaseClass whether this declaration was found in base + /// class of the context we searched. + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, + bool InBaseClass) = 0; + + /// Callback to inform the client that Sema entered into a new context + /// to find a visible declaration. + // + /// \param Ctx the context which Sema entered. + virtual void EnteredContext(DeclContext *Ctx) {} +}; + +/// A class for storing results from argument-dependent lookup. +class ADLResult { +private: + /// A map from canonical decls to the 'most recent' decl. + llvm::MapVector<NamedDecl*, NamedDecl*> Decls; + + struct select_second { + NamedDecl *operator()(std::pair<NamedDecl*, NamedDecl*> P) const { + return P.second; + } + }; + +public: + /// Adds a new ADL candidate to this map. + void insert(NamedDecl *D); + + /// Removes any data associated with a given decl. + void erase(NamedDecl *D) { + Decls.erase(cast<NamedDecl>(D->getCanonicalDecl())); + } + + using iterator = + llvm::mapped_iterator<decltype(Decls)::iterator, select_second>; + + iterator begin() { return iterator(Decls.begin(), select_second()); } + iterator end() { return iterator(Decls.end(), select_second()); } +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_LOOKUP_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/MultiplexExternalSemaSource.h b/contrib/libs/clang16/include/clang/Sema/MultiplexExternalSemaSource.h new file mode 100644 index 0000000000..80022b97e5 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/MultiplexExternalSemaSource.h @@ -0,0 +1,385 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- MultiplexExternalSemaSource.h - External Sema Interface-*- 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 defines ExternalSemaSource interface, dispatching to all clients +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_MULTIPLEXEXTERNALSEMASOURCE_H +#define LLVM_CLANG_SEMA_MULTIPLEXEXTERNALSEMASOURCE_H + +#include "clang/Sema/ExternalSemaSource.h" +#include "clang/Sema/Weak.h" +#include "llvm/ADT/SmallVector.h" +#include <utility> + +namespace clang { + + class CXXConstructorDecl; + class CXXRecordDecl; + class DeclaratorDecl; + struct ExternalVTableUse; + class LookupResult; + class NamespaceDecl; + class Scope; + class Sema; + class TypedefNameDecl; + class ValueDecl; + class VarDecl; + + +/// An abstract interface that should be implemented by +/// external AST sources that also provide information for semantic +/// analysis. +class MultiplexExternalSemaSource : public ExternalSemaSource { + /// LLVM-style RTTI. + static char ID; + +private: + SmallVector<ExternalSemaSource *, 2> Sources; + +public: + /// Constructs a new multiplexing external sema source and appends the + /// given element to it. + /// + ///\param[in] S1 - A non-null (old) ExternalSemaSource. + ///\param[in] S2 - A non-null (new) ExternalSemaSource. + /// + MultiplexExternalSemaSource(ExternalSemaSource *S1, ExternalSemaSource *S2); + + ~MultiplexExternalSemaSource() override; + + /// Appends new source to the source list. + /// + ///\param[in] Source - An ExternalSemaSource. + /// + void AddSource(ExternalSemaSource *Source); + + //===--------------------------------------------------------------------===// + // ExternalASTSource. + //===--------------------------------------------------------------------===// + + /// Resolve a declaration ID into a declaration, potentially + /// building a new declaration. + Decl *GetExternalDecl(uint32_t ID) override; + + /// Complete the redeclaration chain if it's been extended since the + /// previous generation of the AST source. + void CompleteRedeclChain(const Decl *D) override; + + /// Resolve a selector ID into a selector. + Selector GetExternalSelector(uint32_t ID) override; + + /// Returns the number of selectors known to the external AST + /// source. + uint32_t GetNumExternalSelectors() override; + + /// Resolve the offset of a statement in the decl stream into + /// a statement. + Stmt *GetExternalDeclStmt(uint64_t Offset) override; + + /// Resolve the offset of a set of C++ base specifiers in the decl + /// stream into an array of specifiers. + CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) override; + + /// Resolve a handle to a list of ctor initializers into the list of + /// initializers themselves. + CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override; + + ExtKind hasExternalDefinitions(const Decl *D) override; + + /// Find all declarations with the given name in the + /// given context. + bool FindExternalVisibleDeclsByName(const DeclContext *DC, + DeclarationName Name) override; + + /// Ensures that the table of all visible declarations inside this + /// context is up to date. + void completeVisibleDeclsMap(const DeclContext *DC) override; + + /// Finds all declarations lexically contained within the given + /// DeclContext, after applying an optional filter predicate. + /// + /// \param IsKindWeWant a predicate function that returns true if the passed + /// declaration kind is one we are looking for. + void + FindExternalLexicalDecls(const DeclContext *DC, + llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, + SmallVectorImpl<Decl *> &Result) override; + + /// Get the decls that are contained in a file in the Offset/Length + /// range. \p Length can be 0 to indicate a point at \p Offset instead of + /// a range. + void FindFileRegionDecls(FileID File, unsigned Offset,unsigned Length, + SmallVectorImpl<Decl *> &Decls) override; + + /// Gives the external AST source an opportunity to complete + /// an incomplete type. + void CompleteType(TagDecl *Tag) override; + + /// Gives the external AST source an opportunity to complete an + /// incomplete Objective-C class. + /// + /// This routine will only be invoked if the "externally completed" bit is + /// set on the ObjCInterfaceDecl via the function + /// \c ObjCInterfaceDecl::setExternallyCompleted(). + void CompleteType(ObjCInterfaceDecl *Class) override; + + /// Loads comment ranges. + void ReadComments() override; + + /// Notify ExternalASTSource that we started deserialization of + /// a decl or type so until FinishedDeserializing is called there may be + /// decls that are initializing. Must be paired with FinishedDeserializing. + void StartedDeserializing() override; + + /// Notify ExternalASTSource that we finished the deserialization of + /// a decl or type. Must be paired with StartedDeserializing. + void FinishedDeserializing() override; + + /// Function that will be invoked when we begin parsing a new + /// translation unit involving this external AST source. + void StartTranslationUnit(ASTConsumer *Consumer) override; + + /// Print any statistics that have been gathered regarding + /// the external AST source. + void PrintStats() override; + + /// Retrieve the module that corresponds to the given module ID. + Module *getModule(unsigned ID) override; + + /// Perform layout on the given record. + /// + /// This routine allows the external AST source to provide an specific + /// layout for a record, overriding the layout that would normally be + /// constructed. It is intended for clients who receive specific layout + /// details rather than source code (such as LLDB). The client is expected + /// to fill in the field offsets, base offsets, virtual base offsets, and + /// complete object size. + /// + /// \param Record The record whose layout is being requested. + /// + /// \param Size The final size of the record, in bits. + /// + /// \param Alignment The final alignment of the record, in bits. + /// + /// \param FieldOffsets The offset of each of the fields within the record, + /// expressed in bits. All of the fields must be provided with offsets. + /// + /// \param BaseOffsets The offset of each of the direct, non-virtual base + /// classes. If any bases are not given offsets, the bases will be laid + /// out according to the ABI. + /// + /// \param VirtualBaseOffsets The offset of each of the virtual base classes + /// (either direct or not). If any bases are not given offsets, the bases will + /// be laid out according to the ABI. + /// + /// \returns true if the record layout was provided, false otherwise. + bool + layoutRecordType(const RecordDecl *Record, + uint64_t &Size, uint64_t &Alignment, + llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets, + llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets, + llvm::DenseMap<const CXXRecordDecl *, + CharUnits> &VirtualBaseOffsets) override; + + /// Return the amount of memory used by memory buffers, breaking down + /// by heap-backed versus mmap'ed memory. + void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override; + + //===--------------------------------------------------------------------===// + // ExternalSemaSource. + //===--------------------------------------------------------------------===// + + /// Initialize the semantic source with the Sema instance + /// being used to perform semantic analysis on the abstract syntax + /// tree. + void InitializeSema(Sema &S) override; + + /// Inform the semantic consumer that Sema is no longer available. + void ForgetSema() override; + + /// Load the contents of the global method pool for a given + /// selector. + void ReadMethodPool(Selector Sel) override; + + /// Load the contents of the global method pool for a given + /// selector if necessary. + void updateOutOfDateSelector(Selector Sel) override; + + /// Load the set of namespaces that are known to the external source, + /// which will be used during typo correction. + void + ReadKnownNamespaces(SmallVectorImpl<NamespaceDecl*> &Namespaces) override; + + /// Load the set of used but not defined functions or variables with + /// internal linkage, or used but not defined inline functions. + void ReadUndefinedButUsed( + llvm::MapVector<NamedDecl *, SourceLocation> &Undefined) override; + + void ReadMismatchingDeleteExpressions(llvm::MapVector< + FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> & + Exprs) override; + + /// Do last resort, unqualified lookup on a LookupResult that + /// Sema cannot find. + /// + /// \param R a LookupResult that is being recovered. + /// + /// \param S the Scope of the identifier occurrence. + /// + /// \return true to tell Sema to recover using the LookupResult. + bool LookupUnqualified(LookupResult &R, Scope *S) override; + + /// Read the set of tentative definitions known to the external Sema + /// source. + /// + /// The external source should append its own tentative definitions to the + /// given vector of tentative definitions. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + void ReadTentativeDefinitions(SmallVectorImpl<VarDecl*> &Defs) override; + + /// Read the set of unused file-scope declarations known to the + /// external Sema source. + /// + /// The external source should append its own unused, filed-scope to the + /// given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + void ReadUnusedFileScopedDecls( + SmallVectorImpl<const DeclaratorDecl*> &Decls) override; + + /// Read the set of delegating constructors known to the + /// external Sema source. + /// + /// The external source should append its own delegating constructors to the + /// given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + void ReadDelegatingConstructors( + SmallVectorImpl<CXXConstructorDecl*> &Decls) override; + + /// Read the set of ext_vector type declarations known to the + /// external Sema source. + /// + /// The external source should append its own ext_vector type declarations to + /// the given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + void ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl*> &Decls) override; + + /// Read the set of potentially unused typedefs known to the source. + /// + /// The external source should append its own potentially unused local + /// typedefs to the given vector of declarations. Note that this routine may + /// be invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + void ReadUnusedLocalTypedefNameCandidates( + llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) override; + + /// Read the set of referenced selectors known to the + /// external Sema source. + /// + /// The external source should append its own referenced selectors to the + /// given vector of selectors. Note that this routine + /// may be invoked multiple times; the external source should take care not + /// to introduce the same selectors repeatedly. + void ReadReferencedSelectors(SmallVectorImpl<std::pair<Selector, + SourceLocation> > &Sels) override; + + /// Read the set of weak, undeclared identifiers known to the + /// external Sema source. + /// + /// The external source should append its own weak, undeclared identifiers to + /// the given vector. Note that this routine may be invoked multiple times; + /// the external source should take care not to introduce the same identifiers + /// repeatedly. + void ReadWeakUndeclaredIdentifiers( + SmallVectorImpl<std::pair<IdentifierInfo*, WeakInfo> > &WI) override; + + /// Read the set of used vtables known to the external Sema source. + /// + /// The external source should append its own used vtables to the given + /// vector. Note that this routine may be invoked multiple times; the external + /// source should take care not to introduce the same vtables repeatedly. + void ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) override; + + /// Read the set of pending instantiations known to the external + /// Sema source. + /// + /// The external source should append its own pending instantiations to the + /// given vector. Note that this routine may be invoked multiple times; the + /// external source should take care not to introduce the same instantiations + /// repeatedly. + void ReadPendingInstantiations( + SmallVectorImpl<std::pair<ValueDecl*, SourceLocation> >& Pending) override; + + /// Read the set of late parsed template functions for this source. + /// + /// The external source should insert its own late parsed template functions + /// into the map. Note that this routine may be invoked multiple times; the + /// external source should take care not to introduce the same map entries + /// repeatedly. + void ReadLateParsedTemplates( + llvm::MapVector<const FunctionDecl *, std::unique_ptr<LateParsedTemplate>> + &LPTMap) override; + + /// Read the set of decls to be checked for deferred diags. + /// + /// The external source should append its own potentially emitted function + /// and variable decls which may cause deferred diags. Note that this routine + /// may be invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + void ReadDeclsToCheckForDeferredDiags( + llvm::SmallSetVector<Decl *, 4> &Decls) override; + + /// \copydoc ExternalSemaSource::CorrectTypo + /// \note Returns the first nonempty correction. + TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, + int LookupKind, Scope *S, CXXScopeSpec *SS, + CorrectionCandidateCallback &CCC, + DeclContext *MemberContext, + bool EnteringContext, + const ObjCObjectPointerType *OPT) override; + + /// Produces a diagnostic note if one of the attached sources + /// contains a complete definition for \p T. Queries the sources in list + /// order until the first one claims that a diagnostic was produced. + /// + /// \param Loc the location at which a complete type was required but not + /// provided + /// + /// \param T the \c QualType that should have been complete at \p Loc + /// + /// \return true if a diagnostic was produced, false otherwise. + bool MaybeDiagnoseMissingCompleteType(SourceLocation Loc, + QualType T) override; + + /// LLVM-style RTTI. + /// \{ + bool isA(const void *ClassID) const override { + return ClassID == &ID || ExternalSemaSource::isA(ClassID); + } + static bool classof(const ExternalASTSource *S) { return S->isA(&ID); } + /// \} +}; + +} // end namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/ObjCMethodList.h b/contrib/libs/clang16/include/clang/Sema/ObjCMethodList.h new file mode 100644 index 0000000000..de81fae49a --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/ObjCMethodList.h @@ -0,0 +1,78 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- ObjCMethodList.h - A singly linked list of methods -----*- 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 defines ObjCMethodList, a singly-linked list of methods. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_OBJCMETHODLIST_H +#define LLVM_CLANG_SEMA_OBJCMETHODLIST_H + +#include "clang/AST/DeclObjC.h" +#include "llvm/ADT/PointerIntPair.h" + +namespace clang { + +class ObjCMethodDecl; + +/// a linked list of methods with the same selector name but different +/// signatures. +struct ObjCMethodList { + // NOTE: If you add any members to this struct, make sure to serialize them. + /// If there is more than one decl with this signature. + llvm::PointerIntPair<ObjCMethodDecl *, 1> MethodAndHasMoreThanOneDecl; + /// The next list object and 2 bits for extra info. + llvm::PointerIntPair<ObjCMethodList *, 2> NextAndExtraBits; + + ObjCMethodList() { } + ObjCMethodList(ObjCMethodDecl *M) + : MethodAndHasMoreThanOneDecl(M, 0) {} + ObjCMethodList(const ObjCMethodList &L) + : MethodAndHasMoreThanOneDecl(L.MethodAndHasMoreThanOneDecl), + NextAndExtraBits(L.NextAndExtraBits) {} + + ObjCMethodList &operator=(const ObjCMethodList &L) { + MethodAndHasMoreThanOneDecl = L.MethodAndHasMoreThanOneDecl; + NextAndExtraBits = L.NextAndExtraBits; + return *this; + } + + ObjCMethodList *getNext() const { return NextAndExtraBits.getPointer(); } + unsigned getBits() const { return NextAndExtraBits.getInt(); } + void setNext(ObjCMethodList *L) { NextAndExtraBits.setPointer(L); } + void setBits(unsigned B) { NextAndExtraBits.setInt(B); } + + ObjCMethodDecl *getMethod() const { + return MethodAndHasMoreThanOneDecl.getPointer(); + } + void setMethod(ObjCMethodDecl *M) { + return MethodAndHasMoreThanOneDecl.setPointer(M); + } + + bool hasMoreThanOneDecl() const { + return MethodAndHasMoreThanOneDecl.getInt(); + } + void setHasMoreThanOneDecl(bool B) { + return MethodAndHasMoreThanOneDecl.setInt(B); + } +}; + +} + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/Overload.h b/contrib/libs/clang16/include/clang/Sema/Overload.h new file mode 100644 index 0000000000..b84f66e8c8 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/Overload.h @@ -0,0 +1,1255 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- Overload.h - C++ Overloading -----------------------------*- 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 defines the data structures and types used in C++ +// overload resolution. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_OVERLOAD_H +#define LLVM_CLANG_SEMA_OVERLOAD_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclAccessPair.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/SemaFixItUtils.h" +#include "clang/Sema/TemplateDeduction.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/AlignOf.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <utility> + +namespace clang { + +class APValue; +class ASTContext; +class Sema; + + /// OverloadingResult - Capture the result of performing overload + /// resolution. + enum OverloadingResult { + /// Overload resolution succeeded. + OR_Success, + + /// No viable function found. + OR_No_Viable_Function, + + /// Ambiguous candidates found. + OR_Ambiguous, + + /// Succeeded, but refers to a deleted function. + OR_Deleted + }; + + enum OverloadCandidateDisplayKind { + /// Requests that all candidates be shown. Viable candidates will + /// be printed first. + OCD_AllCandidates, + + /// Requests that only viable candidates be shown. + OCD_ViableCandidates, + + /// Requests that only tied-for-best candidates be shown. + OCD_AmbiguousCandidates + }; + + /// The parameter ordering that will be used for the candidate. This is + /// used to represent C++20 binary operator rewrites that reverse the order + /// of the arguments. If the parameter ordering is Reversed, the Args list is + /// reversed (but obviously the ParamDecls for the function are not). + /// + /// After forming an OverloadCandidate with reversed parameters, the list + /// of conversions will (as always) be indexed by argument, so will be + /// in reverse parameter order. + enum class OverloadCandidateParamOrder : char { Normal, Reversed }; + + /// The kinds of rewrite we perform on overload candidates. Note that the + /// values here are chosen to serve as both bitflags and as a rank (lower + /// values are preferred by overload resolution). + enum OverloadCandidateRewriteKind : unsigned { + /// Candidate is not a rewritten candidate. + CRK_None = 0x0, + + /// Candidate is a rewritten candidate with a different operator name. + CRK_DifferentOperator = 0x1, + + /// Candidate is a rewritten candidate with a reversed order of parameters. + CRK_Reversed = 0x2, + }; + + /// ImplicitConversionKind - The kind of implicit conversion used to + /// convert an argument to a parameter's type. The enumerator values + /// match with the table titled 'Conversions' in [over.ics.scs] and are listed + /// such that better conversion kinds have smaller values. + enum ImplicitConversionKind { + /// Identity conversion (no conversion) + ICK_Identity = 0, + + /// Lvalue-to-rvalue conversion (C++ [conv.lval]) + ICK_Lvalue_To_Rvalue, + + /// Array-to-pointer conversion (C++ [conv.array]) + ICK_Array_To_Pointer, + + /// Function-to-pointer (C++ [conv.array]) + ICK_Function_To_Pointer, + + /// Function pointer conversion (C++17 [conv.fctptr]) + ICK_Function_Conversion, + + /// Qualification conversions (C++ [conv.qual]) + ICK_Qualification, + + /// Integral promotions (C++ [conv.prom]) + ICK_Integral_Promotion, + + /// Floating point promotions (C++ [conv.fpprom]) + ICK_Floating_Promotion, + + /// Complex promotions (Clang extension) + ICK_Complex_Promotion, + + /// Integral conversions (C++ [conv.integral]) + ICK_Integral_Conversion, + + /// Floating point conversions (C++ [conv.double] + ICK_Floating_Conversion, + + /// Complex conversions (C99 6.3.1.6) + ICK_Complex_Conversion, + + /// Floating-integral conversions (C++ [conv.fpint]) + ICK_Floating_Integral, + + /// Pointer conversions (C++ [conv.ptr]) + ICK_Pointer_Conversion, + + /// Pointer-to-member conversions (C++ [conv.mem]) + ICK_Pointer_Member, + + /// Boolean conversions (C++ [conv.bool]) + ICK_Boolean_Conversion, + + /// Conversions between compatible types in C99 + ICK_Compatible_Conversion, + + /// Derived-to-base (C++ [over.best.ics]) + ICK_Derived_To_Base, + + /// Vector conversions + ICK_Vector_Conversion, + + /// Arm SVE Vector conversions + ICK_SVE_Vector_Conversion, + + /// A vector splat from an arithmetic type + ICK_Vector_Splat, + + /// Complex-real conversions (C99 6.3.1.7) + ICK_Complex_Real, + + /// Block Pointer conversions + ICK_Block_Pointer_Conversion, + + /// Transparent Union Conversions + ICK_TransparentUnionConversion, + + /// Objective-C ARC writeback conversion + ICK_Writeback_Conversion, + + /// Zero constant to event (OpenCL1.2 6.12.10) + ICK_Zero_Event_Conversion, + + /// Zero constant to queue + ICK_Zero_Queue_Conversion, + + /// Conversions allowed in C, but not C++ + ICK_C_Only_Conversion, + + /// C-only conversion between pointers with incompatible types + ICK_Incompatible_Pointer_Conversion, + + /// The number of conversion kinds + ICK_Num_Conversion_Kinds, + }; + + /// ImplicitConversionRank - The rank of an implicit conversion + /// kind. The enumerator values match with Table 9 of (C++ + /// 13.3.3.1.1) and are listed such that better conversion ranks + /// have smaller values. + enum ImplicitConversionRank { + /// Exact Match + ICR_Exact_Match = 0, + + /// Promotion + ICR_Promotion, + + /// Conversion + ICR_Conversion, + + /// OpenCL Scalar Widening + ICR_OCL_Scalar_Widening, + + /// Complex <-> Real conversion + ICR_Complex_Real_Conversion, + + /// ObjC ARC writeback conversion + ICR_Writeback_Conversion, + + /// Conversion only allowed in the C standard (e.g. void* to char*). + ICR_C_Conversion, + + /// Conversion not allowed by the C standard, but that we accept as an + /// extension anyway. + ICR_C_Conversion_Extension + }; + + ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind); + + /// NarrowingKind - The kind of narrowing conversion being performed by a + /// standard conversion sequence according to C++11 [dcl.init.list]p7. + enum NarrowingKind { + /// Not a narrowing conversion. + NK_Not_Narrowing, + + /// A narrowing conversion by virtue of the source and destination types. + NK_Type_Narrowing, + + /// A narrowing conversion, because a constant expression got narrowed. + NK_Constant_Narrowing, + + /// A narrowing conversion, because a non-constant-expression variable might + /// have got narrowed. + NK_Variable_Narrowing, + + /// Cannot tell whether this is a narrowing conversion because the + /// expression is value-dependent. + NK_Dependent_Narrowing, + }; + + /// StandardConversionSequence - represents a standard conversion + /// sequence (C++ 13.3.3.1.1). A standard conversion sequence + /// contains between zero and three conversions. If a particular + /// conversion is not needed, it will be set to the identity conversion + /// (ICK_Identity). Note that the three conversions are + /// specified as separate members (rather than in an array) so that + /// we can keep the size of a standard conversion sequence to a + /// single word. + class StandardConversionSequence { + public: + /// First -- The first conversion can be an lvalue-to-rvalue + /// conversion, array-to-pointer conversion, or + /// function-to-pointer conversion. + ImplicitConversionKind First : 8; + + /// Second - The second conversion can be an integral promotion, + /// floating point promotion, integral conversion, floating point + /// conversion, floating-integral conversion, pointer conversion, + /// pointer-to-member conversion, or boolean conversion. + ImplicitConversionKind Second : 8; + + /// Third - The third conversion can be a qualification conversion + /// or a function conversion. + ImplicitConversionKind Third : 8; + + /// Whether this is the deprecated conversion of a + /// string literal to a pointer to non-const character data + /// (C++ 4.2p2). + unsigned DeprecatedStringLiteralToCharPtr : 1; + + /// Whether the qualification conversion involves a change in the + /// Objective-C lifetime (for automatic reference counting). + unsigned QualificationIncludesObjCLifetime : 1; + + /// IncompatibleObjC - Whether this is an Objective-C conversion + /// that we should warn about (if we actually use it). + unsigned IncompatibleObjC : 1; + + /// ReferenceBinding - True when this is a reference binding + /// (C++ [over.ics.ref]). + unsigned ReferenceBinding : 1; + + /// DirectBinding - True when this is a reference binding that is a + /// direct binding (C++ [dcl.init.ref]). + unsigned DirectBinding : 1; + + /// Whether this is an lvalue reference binding (otherwise, it's + /// an rvalue reference binding). + unsigned IsLvalueReference : 1; + + /// Whether we're binding to a function lvalue. + unsigned BindsToFunctionLvalue : 1; + + /// Whether we're binding to an rvalue. + unsigned BindsToRvalue : 1; + + /// Whether this binds an implicit object argument to a + /// non-static member function without a ref-qualifier. + unsigned BindsImplicitObjectArgumentWithoutRefQualifier : 1; + + /// Whether this binds a reference to an object with a different + /// Objective-C lifetime qualifier. + unsigned ObjCLifetimeConversionBinding : 1; + + /// FromType - The type that this conversion is converting + /// from. This is an opaque pointer that can be translated into a + /// QualType. + void *FromTypePtr; + + /// ToType - The types that this conversion is converting to in + /// each step. This is an opaque pointer that can be translated + /// into a QualType. + void *ToTypePtrs[3]; + + /// CopyConstructor - The copy constructor that is used to perform + /// this conversion, when the conversion is actually just the + /// initialization of an object via copy constructor. Such + /// conversions are either identity conversions or derived-to-base + /// conversions. + CXXConstructorDecl *CopyConstructor; + DeclAccessPair FoundCopyConstructor; + + void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } + + void setToType(unsigned Idx, QualType T) { + assert(Idx < 3 && "To type index is out of range"); + ToTypePtrs[Idx] = T.getAsOpaquePtr(); + } + + void setAllToTypes(QualType T) { + ToTypePtrs[0] = T.getAsOpaquePtr(); + ToTypePtrs[1] = ToTypePtrs[0]; + ToTypePtrs[2] = ToTypePtrs[0]; + } + + QualType getFromType() const { + return QualType::getFromOpaquePtr(FromTypePtr); + } + + QualType getToType(unsigned Idx) const { + assert(Idx < 3 && "To type index is out of range"); + return QualType::getFromOpaquePtr(ToTypePtrs[Idx]); + } + + void setAsIdentityConversion(); + + bool isIdentityConversion() const { + return Second == ICK_Identity && Third == ICK_Identity; + } + + ImplicitConversionRank getRank() const; + NarrowingKind + getNarrowingKind(ASTContext &Context, const Expr *Converted, + APValue &ConstantValue, QualType &ConstantType, + bool IgnoreFloatToIntegralConversion = false) const; + bool isPointerConversionToBool() const; + bool isPointerConversionToVoidPointer(ASTContext& Context) const; + void dump() const; + }; + + /// UserDefinedConversionSequence - Represents a user-defined + /// conversion sequence (C++ 13.3.3.1.2). + struct UserDefinedConversionSequence { + /// Represents the standard conversion that occurs before + /// the actual user-defined conversion. + /// + /// C++11 13.3.3.1.2p1: + /// If the user-defined conversion is specified by a constructor + /// (12.3.1), the initial standard conversion sequence converts + /// the source type to the type required by the argument of the + /// constructor. If the user-defined conversion is specified by + /// a conversion function (12.3.2), the initial standard + /// conversion sequence converts the source type to the implicit + /// object parameter of the conversion function. + StandardConversionSequence Before; + + /// EllipsisConversion - When this is true, it means user-defined + /// conversion sequence starts with a ... (ellipsis) conversion, instead of + /// a standard conversion. In this case, 'Before' field must be ignored. + // FIXME. I much rather put this as the first field. But there seems to be + // a gcc code gen. bug which causes a crash in a test. Putting it here seems + // to work around the crash. + bool EllipsisConversion : 1; + + /// HadMultipleCandidates - When this is true, it means that the + /// conversion function was resolved from an overloaded set having + /// size greater than 1. + bool HadMultipleCandidates : 1; + + /// After - Represents the standard conversion that occurs after + /// the actual user-defined conversion. + StandardConversionSequence After; + + /// ConversionFunction - The function that will perform the + /// user-defined conversion. Null if the conversion is an + /// aggregate initialization from an initializer list. + FunctionDecl* ConversionFunction; + + /// The declaration that we found via name lookup, which might be + /// the same as \c ConversionFunction or it might be a using declaration + /// that refers to \c ConversionFunction. + DeclAccessPair FoundConversionFunction; + + void dump() const; + }; + + /// Represents an ambiguous user-defined conversion sequence. + struct AmbiguousConversionSequence { + using ConversionSet = + SmallVector<std::pair<NamedDecl *, FunctionDecl *>, 4>; + + void *FromTypePtr; + void *ToTypePtr; + char Buffer[sizeof(ConversionSet)]; + + QualType getFromType() const { + return QualType::getFromOpaquePtr(FromTypePtr); + } + + QualType getToType() const { + return QualType::getFromOpaquePtr(ToTypePtr); + } + + void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); } + + ConversionSet &conversions() { + return *reinterpret_cast<ConversionSet*>(Buffer); + } + + const ConversionSet &conversions() const { + return *reinterpret_cast<const ConversionSet*>(Buffer); + } + + void addConversion(NamedDecl *Found, FunctionDecl *D) { + conversions().push_back(std::make_pair(Found, D)); + } + + using iterator = ConversionSet::iterator; + + iterator begin() { return conversions().begin(); } + iterator end() { return conversions().end(); } + + using const_iterator = ConversionSet::const_iterator; + + const_iterator begin() const { return conversions().begin(); } + const_iterator end() const { return conversions().end(); } + + void construct(); + void destruct(); + void copyFrom(const AmbiguousConversionSequence &); + }; + + /// BadConversionSequence - Records information about an invalid + /// conversion sequence. + struct BadConversionSequence { + enum FailureKind { + no_conversion, + unrelated_class, + bad_qualifiers, + lvalue_ref_to_rvalue, + rvalue_ref_to_lvalue, + too_few_initializers, + too_many_initializers, + }; + + // This can be null, e.g. for implicit object arguments. + Expr *FromExpr; + + FailureKind Kind; + + private: + // The type we're converting from (an opaque QualType). + void *FromTy; + + // The type we're converting to (an opaque QualType). + void *ToTy; + + public: + void init(FailureKind K, Expr *From, QualType To) { + init(K, From->getType(), To); + FromExpr = From; + } + + void init(FailureKind K, QualType From, QualType To) { + Kind = K; + FromExpr = nullptr; + setFromType(From); + setToType(To); + } + + QualType getFromType() const { return QualType::getFromOpaquePtr(FromTy); } + QualType getToType() const { return QualType::getFromOpaquePtr(ToTy); } + + void setFromExpr(Expr *E) { + FromExpr = E; + setFromType(E->getType()); + } + + void setFromType(QualType T) { FromTy = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTy = T.getAsOpaquePtr(); } + }; + + /// ImplicitConversionSequence - Represents an implicit conversion + /// sequence, which may be a standard conversion sequence + /// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2), + /// or an ellipsis conversion sequence (C++ 13.3.3.1.3). + class ImplicitConversionSequence { + public: + /// Kind - The kind of implicit conversion sequence. BadConversion + /// specifies that there is no conversion from the source type to + /// the target type. AmbiguousConversion represents the unique + /// ambiguous conversion (C++0x [over.best.ics]p10). + /// StaticObjectArgumentConversion represents the conversion rules for + /// the synthesized first argument of calls to static member functions + /// ([over.best.ics.general]p8). + enum Kind { + StandardConversion = 0, + StaticObjectArgumentConversion, + UserDefinedConversion, + AmbiguousConversion, + EllipsisConversion, + BadConversion + }; + + private: + enum { + Uninitialized = BadConversion + 1 + }; + + /// ConversionKind - The kind of implicit conversion sequence. + unsigned ConversionKind : 31; + + // Whether the initializer list was of an incomplete array. + unsigned InitializerListOfIncompleteArray : 1; + + /// When initializing an array or std::initializer_list from an + /// initializer-list, this is the array or std::initializer_list type being + /// initialized. The remainder of the conversion sequence, including ToType, + /// describe the worst conversion of an initializer to an element of the + /// array or std::initializer_list. (Note, 'worst' is not well defined.) + QualType InitializerListContainerType; + + void setKind(Kind K) { + destruct(); + ConversionKind = K; + } + + void destruct() { + if (ConversionKind == AmbiguousConversion) Ambiguous.destruct(); + } + + public: + union { + /// When ConversionKind == StandardConversion, provides the + /// details of the standard conversion sequence. + StandardConversionSequence Standard; + + /// When ConversionKind == UserDefinedConversion, provides the + /// details of the user-defined conversion sequence. + UserDefinedConversionSequence UserDefined; + + /// When ConversionKind == AmbiguousConversion, provides the + /// details of the ambiguous conversion. + AmbiguousConversionSequence Ambiguous; + + /// When ConversionKind == BadConversion, provides the details + /// of the bad conversion. + BadConversionSequence Bad; + }; + + ImplicitConversionSequence() + : ConversionKind(Uninitialized), + InitializerListOfIncompleteArray(false) { + Standard.setAsIdentityConversion(); + } + + ImplicitConversionSequence(const ImplicitConversionSequence &Other) + : ConversionKind(Other.ConversionKind), + InitializerListOfIncompleteArray( + Other.InitializerListOfIncompleteArray), + InitializerListContainerType(Other.InitializerListContainerType) { + switch (ConversionKind) { + case Uninitialized: break; + case StandardConversion: Standard = Other.Standard; break; + case StaticObjectArgumentConversion: + break; + case UserDefinedConversion: UserDefined = Other.UserDefined; break; + case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break; + case EllipsisConversion: break; + case BadConversion: Bad = Other.Bad; break; + } + } + + ImplicitConversionSequence & + operator=(const ImplicitConversionSequence &Other) { + destruct(); + new (this) ImplicitConversionSequence(Other); + return *this; + } + + ~ImplicitConversionSequence() { + destruct(); + } + + Kind getKind() const { + assert(isInitialized() && "querying uninitialized conversion"); + return Kind(ConversionKind); + } + + /// Return a ranking of the implicit conversion sequence + /// kind, where smaller ranks represent better conversion + /// sequences. + /// + /// In particular, this routine gives user-defined conversion + /// sequences and ambiguous conversion sequences the same rank, + /// per C++ [over.best.ics]p10. + unsigned getKindRank() const { + switch (getKind()) { + case StandardConversion: + case StaticObjectArgumentConversion: + return 0; + + case UserDefinedConversion: + case AmbiguousConversion: + return 1; + + case EllipsisConversion: + return 2; + + case BadConversion: + return 3; + } + + llvm_unreachable("Invalid ImplicitConversionSequence::Kind!"); + } + + bool isBad() const { return getKind() == BadConversion; } + bool isStandard() const { return getKind() == StandardConversion; } + bool isStaticObjectArgument() const { + return getKind() == StaticObjectArgumentConversion; + } + bool isEllipsis() const { return getKind() == EllipsisConversion; } + bool isAmbiguous() const { return getKind() == AmbiguousConversion; } + bool isUserDefined() const { return getKind() == UserDefinedConversion; } + bool isFailure() const { return isBad() || isAmbiguous(); } + + /// Determines whether this conversion sequence has been + /// initialized. Most operations should never need to query + /// uninitialized conversions and should assert as above. + bool isInitialized() const { return ConversionKind != Uninitialized; } + + /// Sets this sequence as a bad conversion for an explicit argument. + void setBad(BadConversionSequence::FailureKind Failure, + Expr *FromExpr, QualType ToType) { + setKind(BadConversion); + Bad.init(Failure, FromExpr, ToType); + } + + /// Sets this sequence as a bad conversion for an implicit argument. + void setBad(BadConversionSequence::FailureKind Failure, + QualType FromType, QualType ToType) { + setKind(BadConversion); + Bad.init(Failure, FromType, ToType); + } + + void setStandard() { setKind(StandardConversion); } + void setStaticObjectArgument() { setKind(StaticObjectArgumentConversion); } + void setEllipsis() { setKind(EllipsisConversion); } + void setUserDefined() { setKind(UserDefinedConversion); } + + void setAmbiguous() { + if (ConversionKind == AmbiguousConversion) return; + ConversionKind = AmbiguousConversion; + Ambiguous.construct(); + } + + void setAsIdentityConversion(QualType T) { + setStandard(); + Standard.setAsIdentityConversion(); + Standard.setFromType(T); + Standard.setAllToTypes(T); + } + + // True iff this is a conversion sequence from an initializer list to an + // array or std::initializer. + bool hasInitializerListContainerType() const { + return !InitializerListContainerType.isNull(); + } + void setInitializerListContainerType(QualType T, bool IA) { + InitializerListContainerType = T; + InitializerListOfIncompleteArray = IA; + } + bool isInitializerListOfIncompleteArray() const { + return InitializerListOfIncompleteArray; + } + QualType getInitializerListContainerType() const { + assert(hasInitializerListContainerType() && + "not initializer list container"); + return InitializerListContainerType; + } + + /// Form an "implicit" conversion sequence from nullptr_t to bool, for a + /// direct-initialization of a bool object from nullptr_t. + static ImplicitConversionSequence getNullptrToBool(QualType SourceType, + QualType DestType, + bool NeedLValToRVal) { + ImplicitConversionSequence ICS; + ICS.setStandard(); + ICS.Standard.setAsIdentityConversion(); + ICS.Standard.setFromType(SourceType); + if (NeedLValToRVal) + ICS.Standard.First = ICK_Lvalue_To_Rvalue; + ICS.Standard.setToType(0, SourceType); + ICS.Standard.Second = ICK_Boolean_Conversion; + ICS.Standard.setToType(1, DestType); + ICS.Standard.setToType(2, DestType); + return ICS; + } + + // The result of a comparison between implicit conversion + // sequences. Use Sema::CompareImplicitConversionSequences to + // actually perform the comparison. + enum CompareKind { + Better = -1, + Indistinguishable = 0, + Worse = 1 + }; + + void DiagnoseAmbiguousConversion(Sema &S, + SourceLocation CaretLoc, + const PartialDiagnostic &PDiag) const; + + void dump() const; + }; + + enum OverloadFailureKind { + ovl_fail_too_many_arguments, + ovl_fail_too_few_arguments, + ovl_fail_bad_conversion, + ovl_fail_bad_deduction, + + /// This conversion candidate was not considered because it + /// duplicates the work of a trivial or derived-to-base + /// conversion. + ovl_fail_trivial_conversion, + + /// This conversion candidate was not considered because it is + /// an illegal instantiation of a constructor temploid: it is + /// callable with one argument, we only have one argument, and + /// its first parameter type is exactly the type of the class. + /// + /// Defining such a constructor directly is illegal, and + /// template-argument deduction is supposed to ignore such + /// instantiations, but we can still get one with the right + /// kind of implicit instantiation. + ovl_fail_illegal_constructor, + + /// This conversion candidate is not viable because its result + /// type is not implicitly convertible to the desired type. + ovl_fail_bad_final_conversion, + + /// This conversion function template specialization candidate is not + /// viable because the final conversion was not an exact match. + ovl_fail_final_conversion_not_exact, + + /// (CUDA) This candidate was not viable because the callee + /// was not accessible from the caller's target (i.e. host->device, + /// global->host, device->host). + ovl_fail_bad_target, + + /// This candidate function was not viable because an enable_if + /// attribute disabled it. + ovl_fail_enable_if, + + /// This candidate constructor or conversion function is explicit but + /// the context doesn't permit explicit functions. + ovl_fail_explicit, + + /// This candidate was not viable because its address could not be taken. + ovl_fail_addr_not_available, + + /// This inherited constructor is not viable because it would slice the + /// argument. + ovl_fail_inhctor_slice, + + /// This candidate was not viable because it is a non-default multiversioned + /// function. + ovl_non_default_multiversion_function, + + /// This constructor/conversion candidate fail due to an address space + /// mismatch between the object being constructed and the overload + /// candidate. + ovl_fail_object_addrspace_mismatch, + + /// This candidate was not viable because its associated constraints were + /// not satisfied. + ovl_fail_constraints_not_satisfied, + + /// This candidate was not viable because it has internal linkage and is + /// from a different module unit than the use. + ovl_fail_module_mismatched, + }; + + /// A list of implicit conversion sequences for the arguments of an + /// OverloadCandidate. + using ConversionSequenceList = + llvm::MutableArrayRef<ImplicitConversionSequence>; + + /// OverloadCandidate - A single candidate in an overload set (C++ 13.3). + struct OverloadCandidate { + /// Function - The actual function that this candidate + /// represents. When NULL, this is a built-in candidate + /// (C++ [over.oper]) or a surrogate for a conversion to a + /// function pointer or reference (C++ [over.call.object]). + FunctionDecl *Function; + + /// FoundDecl - The original declaration that was looked up / + /// invented / otherwise found, together with its access. + /// Might be a UsingShadowDecl or a FunctionTemplateDecl. + DeclAccessPair FoundDecl; + + /// BuiltinParamTypes - Provides the parameter types of a built-in overload + /// candidate. Only valid when Function is NULL. + QualType BuiltinParamTypes[3]; + + /// Surrogate - The conversion function for which this candidate + /// is a surrogate, but only if IsSurrogate is true. + CXXConversionDecl *Surrogate; + + /// The conversion sequences used to convert the function arguments + /// to the function parameters. Note that these are indexed by argument, + /// so may not match the parameter order of Function. + ConversionSequenceList Conversions; + + /// The FixIt hints which can be used to fix the Bad candidate. + ConversionFixItGenerator Fix; + + /// Viable - True to indicate that this overload candidate is viable. + bool Viable : 1; + + /// Whether this candidate is the best viable function, or tied for being + /// the best viable function. + /// + /// For an ambiguous overload resolution, indicates whether this candidate + /// was part of the ambiguity kernel: the minimal non-empty set of viable + /// candidates such that all elements of the ambiguity kernel are better + /// than all viable candidates not in the ambiguity kernel. + bool Best : 1; + + /// IsSurrogate - True to indicate that this candidate is a + /// surrogate for a conversion to a function pointer or reference + /// (C++ [over.call.object]). + bool IsSurrogate : 1; + + /// IgnoreObjectArgument - True to indicate that the first + /// argument's conversion, which for this function represents the + /// implicit object argument, should be ignored. This will be true + /// when the candidate is a static member function (where the + /// implicit object argument is just a placeholder) or a + /// non-static member function when the call doesn't have an + /// object argument. + bool IgnoreObjectArgument : 1; + + /// True if the candidate was found using ADL. + CallExpr::ADLCallKind IsADLCandidate : 1; + + /// Whether this is a rewritten candidate, and if so, of what kind? + unsigned RewriteKind : 2; + + /// FailureKind - The reason why this candidate is not viable. + /// Actually an OverloadFailureKind. + unsigned char FailureKind; + + /// The number of call arguments that were explicitly provided, + /// to be used while performing partial ordering of function templates. + unsigned ExplicitCallArguments; + + union { + DeductionFailureInfo DeductionFailure; + + /// FinalConversion - For a conversion function (where Function is + /// a CXXConversionDecl), the standard conversion that occurs + /// after the call to the overload candidate to convert the result + /// of calling the conversion function to the required type. + StandardConversionSequence FinalConversion; + }; + + /// Get RewriteKind value in OverloadCandidateRewriteKind type (This + /// function is to workaround the spurious GCC bitfield enum warning) + OverloadCandidateRewriteKind getRewriteKind() const { + return static_cast<OverloadCandidateRewriteKind>(RewriteKind); + } + + bool isReversed() const { return getRewriteKind() & CRK_Reversed; } + + /// hasAmbiguousConversion - Returns whether this overload + /// candidate requires an ambiguous conversion or not. + bool hasAmbiguousConversion() const { + for (auto &C : Conversions) { + if (!C.isInitialized()) return false; + if (C.isAmbiguous()) return true; + } + return false; + } + + bool TryToFixBadConversion(unsigned Idx, Sema &S) { + bool CanFix = Fix.tryToFixConversion( + Conversions[Idx].Bad.FromExpr, + Conversions[Idx].Bad.getFromType(), + Conversions[Idx].Bad.getToType(), S); + + // If at least one conversion fails, the candidate cannot be fixed. + if (!CanFix) + Fix.clear(); + + return CanFix; + } + + unsigned getNumParams() const { + if (IsSurrogate) { + QualType STy = Surrogate->getConversionType(); + while (STy->isPointerType() || STy->isReferenceType()) + STy = STy->getPointeeType(); + return STy->castAs<FunctionProtoType>()->getNumParams(); + } + if (Function) + return Function->getNumParams(); + return ExplicitCallArguments; + } + + bool NotValidBecauseConstraintExprHasError() const; + + private: + friend class OverloadCandidateSet; + OverloadCandidate() + : IsSurrogate(false), IsADLCandidate(CallExpr::NotADL), RewriteKind(CRK_None) {} + }; + + /// OverloadCandidateSet - A set of overload candidates, used in C++ + /// overload resolution (C++ 13.3). + class OverloadCandidateSet { + public: + enum CandidateSetKind { + /// Normal lookup. + CSK_Normal, + + /// C++ [over.match.oper]: + /// Lookup of operator function candidates in a call using operator + /// syntax. Candidates that have no parameters of class type will be + /// skipped unless there is a parameter of (reference to) enum type and + /// the corresponding argument is of the same enum type. + CSK_Operator, + + /// C++ [over.match.copy]: + /// Copy-initialization of an object of class type by user-defined + /// conversion. + CSK_InitByUserDefinedConversion, + + /// C++ [over.match.ctor], [over.match.list] + /// Initialization of an object of class type by constructor, + /// using either a parenthesized or braced list of arguments. + CSK_InitByConstructor, + }; + + /// Information about operator rewrites to consider when adding operator + /// functions to a candidate set. + struct OperatorRewriteInfo { + OperatorRewriteInfo() + : OriginalOperator(OO_None), OpLoc(), AllowRewrittenCandidates(false) {} + OperatorRewriteInfo(OverloadedOperatorKind Op, SourceLocation OpLoc, + bool AllowRewritten) + : OriginalOperator(Op), OpLoc(OpLoc), + AllowRewrittenCandidates(AllowRewritten) {} + + /// The original operator as written in the source. + OverloadedOperatorKind OriginalOperator; + /// The source location of the operator. + SourceLocation OpLoc; + /// Whether we should include rewritten candidates in the overload set. + bool AllowRewrittenCandidates; + + /// Would use of this function result in a rewrite using a different + /// operator? + bool isRewrittenOperator(const FunctionDecl *FD) { + return OriginalOperator && + FD->getDeclName().getCXXOverloadedOperator() != OriginalOperator; + } + + bool isAcceptableCandidate(const FunctionDecl *FD) { + if (!OriginalOperator) + return true; + + // For an overloaded operator, we can have candidates with a different + // name in our unqualified lookup set. Make sure we only consider the + // ones we're supposed to. + OverloadedOperatorKind OO = + FD->getDeclName().getCXXOverloadedOperator(); + return OO && (OO == OriginalOperator || + (AllowRewrittenCandidates && + OO == getRewrittenOverloadedOperator(OriginalOperator))); + } + + /// Determine the kind of rewrite that should be performed for this + /// candidate. + OverloadCandidateRewriteKind + getRewriteKind(const FunctionDecl *FD, OverloadCandidateParamOrder PO) { + OverloadCandidateRewriteKind CRK = CRK_None; + if (isRewrittenOperator(FD)) + CRK = OverloadCandidateRewriteKind(CRK | CRK_DifferentOperator); + if (PO == OverloadCandidateParamOrder::Reversed) + CRK = OverloadCandidateRewriteKind(CRK | CRK_Reversed); + return CRK; + } + /// Determines whether this operator could be implemented by a function + /// with reversed parameter order. + bool isReversible() { + return AllowRewrittenCandidates && OriginalOperator && + (getRewrittenOverloadedOperator(OriginalOperator) != OO_None || + allowsReversed(OriginalOperator)); + } + + /// Determine whether reversing parameter order is allowed for operator + /// Op. + bool allowsReversed(OverloadedOperatorKind Op); + + /// Determine whether we should add a rewritten candidate for \p FD with + /// reversed parameter order. + /// \param OriginalArgs are the original non reversed arguments. + bool shouldAddReversed(Sema &S, ArrayRef<Expr *> OriginalArgs, + FunctionDecl *FD); + }; + + private: + SmallVector<OverloadCandidate, 16> Candidates; + llvm::SmallPtrSet<uintptr_t, 16> Functions; + + // Allocator for ConversionSequenceLists. We store the first few of these + // inline to avoid allocation for small sets. + llvm::BumpPtrAllocator SlabAllocator; + + SourceLocation Loc; + CandidateSetKind Kind; + OperatorRewriteInfo RewriteInfo; + + constexpr static unsigned NumInlineBytes = + 24 * sizeof(ImplicitConversionSequence); + unsigned NumInlineBytesUsed = 0; + alignas(void *) char InlineSpace[NumInlineBytes]; + + // Address space of the object being constructed. + LangAS DestAS = LangAS::Default; + + /// If we have space, allocates from inline storage. Otherwise, allocates + /// from the slab allocator. + /// FIXME: It would probably be nice to have a SmallBumpPtrAllocator + /// instead. + /// FIXME: Now that this only allocates ImplicitConversionSequences, do we + /// want to un-generalize this? + template <typename T> + T *slabAllocate(unsigned N) { + // It's simpler if this doesn't need to consider alignment. + static_assert(alignof(T) == alignof(void *), + "Only works for pointer-aligned types."); + static_assert(std::is_trivial<T>::value || + std::is_same<ImplicitConversionSequence, T>::value, + "Add destruction logic to OverloadCandidateSet::clear()."); + + unsigned NBytes = sizeof(T) * N; + if (NBytes > NumInlineBytes - NumInlineBytesUsed) + return SlabAllocator.Allocate<T>(N); + char *FreeSpaceStart = InlineSpace + NumInlineBytesUsed; + assert(uintptr_t(FreeSpaceStart) % alignof(void *) == 0 && + "Misaligned storage!"); + + NumInlineBytesUsed += NBytes; + return reinterpret_cast<T *>(FreeSpaceStart); + } + + void destroyCandidates(); + + public: + OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK, + OperatorRewriteInfo RewriteInfo = {}) + : Loc(Loc), Kind(CSK), RewriteInfo(RewriteInfo) {} + OverloadCandidateSet(const OverloadCandidateSet &) = delete; + OverloadCandidateSet &operator=(const OverloadCandidateSet &) = delete; + ~OverloadCandidateSet() { destroyCandidates(); } + + SourceLocation getLocation() const { return Loc; } + CandidateSetKind getKind() const { return Kind; } + OperatorRewriteInfo getRewriteInfo() const { return RewriteInfo; } + + /// Whether diagnostics should be deferred. + bool shouldDeferDiags(Sema &S, ArrayRef<Expr *> Args, SourceLocation OpLoc); + + /// Determine when this overload candidate will be new to the + /// overload set. + bool isNewCandidate(Decl *F, OverloadCandidateParamOrder PO = + OverloadCandidateParamOrder::Normal) { + uintptr_t Key = reinterpret_cast<uintptr_t>(F->getCanonicalDecl()); + Key |= static_cast<uintptr_t>(PO); + return Functions.insert(Key).second; + } + + /// Exclude a function from being considered by overload resolution. + void exclude(Decl *F) { + isNewCandidate(F, OverloadCandidateParamOrder::Normal); + isNewCandidate(F, OverloadCandidateParamOrder::Reversed); + } + + /// Clear out all of the candidates. + void clear(CandidateSetKind CSK); + + using iterator = SmallVectorImpl<OverloadCandidate>::iterator; + + iterator begin() { return Candidates.begin(); } + iterator end() { return Candidates.end(); } + + size_t size() const { return Candidates.size(); } + bool empty() const { return Candidates.empty(); } + + /// Allocate storage for conversion sequences for NumConversions + /// conversions. + ConversionSequenceList + allocateConversionSequences(unsigned NumConversions) { + ImplicitConversionSequence *Conversions = + slabAllocate<ImplicitConversionSequence>(NumConversions); + + // Construct the new objects. + for (unsigned I = 0; I != NumConversions; ++I) + new (&Conversions[I]) ImplicitConversionSequence(); + + return ConversionSequenceList(Conversions, NumConversions); + } + + /// Add a new candidate with NumConversions conversion sequence slots + /// to the overload set. + OverloadCandidate & + addCandidate(unsigned NumConversions = 0, + ConversionSequenceList Conversions = std::nullopt) { + assert((Conversions.empty() || Conversions.size() == NumConversions) && + "preallocated conversion sequence has wrong length"); + + Candidates.push_back(OverloadCandidate()); + OverloadCandidate &C = Candidates.back(); + C.Conversions = Conversions.empty() + ? allocateConversionSequences(NumConversions) + : Conversions; + return C; + } + + /// Find the best viable function on this overload set, if it exists. + OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc, + OverloadCandidateSet::iterator& Best); + + SmallVector<OverloadCandidate *, 32> CompleteCandidates( + Sema &S, OverloadCandidateDisplayKind OCD, ArrayRef<Expr *> Args, + SourceLocation OpLoc = SourceLocation(), + llvm::function_ref<bool(OverloadCandidate &)> Filter = + [](OverloadCandidate &) { return true; }); + + void NoteCandidates( + PartialDiagnosticAt PA, Sema &S, OverloadCandidateDisplayKind OCD, + ArrayRef<Expr *> Args, StringRef Opc = "", + SourceLocation Loc = SourceLocation(), + llvm::function_ref<bool(OverloadCandidate &)> Filter = + [](OverloadCandidate &) { return true; }); + + void NoteCandidates(Sema &S, ArrayRef<Expr *> Args, + ArrayRef<OverloadCandidate *> Cands, + StringRef Opc = "", + SourceLocation OpLoc = SourceLocation()); + + LangAS getDestAS() { return DestAS; } + + void setDestAS(LangAS AS) { + assert((Kind == CSK_InitByConstructor || + Kind == CSK_InitByUserDefinedConversion) && + "can't set the destination address space when not constructing an " + "object"); + DestAS = AS; + } + + }; + + bool isBetterOverloadCandidate(Sema &S, + const OverloadCandidate &Cand1, + const OverloadCandidate &Cand2, + SourceLocation Loc, + OverloadCandidateSet::CandidateSetKind Kind); + + struct ConstructorInfo { + DeclAccessPair FoundDecl; + CXXConstructorDecl *Constructor; + FunctionTemplateDecl *ConstructorTmpl; + + explicit operator bool() const { return Constructor; } + }; + + // FIXME: Add an AddOverloadCandidate / AddTemplateOverloadCandidate overload + // that takes one of these. + inline ConstructorInfo getConstructorInfo(NamedDecl *ND) { + if (isa<UsingDecl>(ND)) + return ConstructorInfo{}; + + // For constructors, the access check is performed against the underlying + // declaration, not the found declaration. + auto *D = ND->getUnderlyingDecl(); + ConstructorInfo Info = {DeclAccessPair::make(ND, D->getAccess()), nullptr, + nullptr}; + Info.ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D); + if (Info.ConstructorTmpl) + D = Info.ConstructorTmpl->getTemplatedDecl(); + Info.Constructor = dyn_cast<CXXConstructorDecl>(D); + return Info; + } + + // Returns false if signature help is relevant despite number of arguments + // exceeding parameters. Specifically, it returns false when + // PartialOverloading is true and one of the following: + // * Function is variadic + // * Function is template variadic + // * Function is an instantiation of template variadic function + // The last case may seem strange. The idea is that if we added one more + // argument, we'd end up with a function similar to Function. Since, in the + // context of signature help and/or code completion, we do not know what the + // type of the next argument (that the user is typing) will be, this is as + // good candidate as we can get, despite the fact that it takes one less + // parameter. + bool shouldEnforceArgLimit(bool PartialOverloading, FunctionDecl *Function); + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_OVERLOAD_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/Ownership.h b/contrib/libs/clang16/include/clang/Sema/Ownership.h new file mode 100644 index 0000000000..3c965bf853 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/Ownership.h @@ -0,0 +1,315 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- Ownership.h - Parser ownership helpers -------------------*- 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 contains classes for managing ownership of Stmt and Expr nodes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_OWNERSHIP_H +#define LLVM_CLANG_SEMA_OWNERSHIP_H + +#include "clang/AST/Expr.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include "llvm/Support/type_traits.h" +#include <cassert> +#include <cstddef> +#include <cstdint> + +//===----------------------------------------------------------------------===// +// OpaquePtr +//===----------------------------------------------------------------------===// + +namespace clang { + +class CXXBaseSpecifier; +class CXXCtorInitializer; +class Decl; +class Expr; +class ParsedTemplateArgument; +class QualType; +class Stmt; +class TemplateName; +class TemplateParameterList; + + /// Wrapper for void* pointer. + /// \tparam PtrTy Either a pointer type like 'T*' or a type that behaves like + /// a pointer. + /// + /// This is a very simple POD type that wraps a pointer that the Parser + /// doesn't know about but that Sema or another client does. The PtrTy + /// template argument is used to make sure that "Decl" pointers are not + /// compatible with "Type" pointers for example. + template <class PtrTy> + class OpaquePtr { + void *Ptr = nullptr; + + explicit OpaquePtr(void *Ptr) : Ptr(Ptr) {} + + using Traits = llvm::PointerLikeTypeTraits<PtrTy>; + + public: + OpaquePtr(std::nullptr_t = nullptr) {} + + static OpaquePtr make(PtrTy P) { OpaquePtr OP; OP.set(P); return OP; } + + /// Returns plain pointer to the entity pointed by this wrapper. + /// \tparam PointeeT Type of pointed entity. + /// + /// It is identical to getPtrAs<PointeeT*>. + template <typename PointeeT> PointeeT* getPtrTo() const { + return get(); + } + + /// Returns pointer converted to the specified type. + /// \tparam PtrT Result pointer type. There must be implicit conversion + /// from PtrTy to PtrT. + /// + /// In contrast to getPtrTo, this method allows the return type to be + /// a smart pointer. + template <typename PtrT> PtrT getPtrAs() const { + return get(); + } + + PtrTy get() const { + return Traits::getFromVoidPointer(Ptr); + } + + void set(PtrTy P) { + Ptr = Traits::getAsVoidPointer(P); + } + + explicit operator bool() const { return Ptr != nullptr; } + + void *getAsOpaquePtr() const { return Ptr; } + static OpaquePtr getFromOpaquePtr(void *P) { return OpaquePtr(P); } + }; + + /// UnionOpaquePtr - A version of OpaquePtr suitable for membership + /// in a union. + template <class T> struct UnionOpaquePtr { + void *Ptr; + + static UnionOpaquePtr make(OpaquePtr<T> P) { + UnionOpaquePtr OP = { P.getAsOpaquePtr() }; + return OP; + } + + OpaquePtr<T> get() const { return OpaquePtr<T>::getFromOpaquePtr(Ptr); } + operator OpaquePtr<T>() const { return get(); } + + UnionOpaquePtr &operator=(OpaquePtr<T> P) { + Ptr = P.getAsOpaquePtr(); + return *this; + } + }; + +} // namespace clang + +namespace llvm { + + template <class T> + struct PointerLikeTypeTraits<clang::OpaquePtr<T>> { + static constexpr int NumLowBitsAvailable = 0; + + static inline void *getAsVoidPointer(clang::OpaquePtr<T> P) { + // FIXME: Doesn't work? return P.getAs< void >(); + return P.getAsOpaquePtr(); + } + + static inline clang::OpaquePtr<T> getFromVoidPointer(void *P) { + return clang::OpaquePtr<T>::getFromOpaquePtr(P); + } + }; + +} // namespace llvm + +namespace clang { + + // Basic +class StreamingDiagnostic; + +// Determines whether the low bit of the result pointer for the +// given UID is always zero. If so, ActionResult will use that bit +// for it's "invalid" flag. +template <class Ptr> struct IsResultPtrLowBitFree { + static const bool value = false; + }; + + /// ActionResult - This structure is used while parsing/acting on + /// expressions, stmts, etc. It encapsulates both the object returned by + /// the action, plus a sense of whether or not it is valid. + /// When CompressInvalid is true, the "invalid" flag will be + /// stored in the low bit of the Val pointer. + template<class PtrTy, + bool CompressInvalid = IsResultPtrLowBitFree<PtrTy>::value> + class ActionResult { + PtrTy Val; + bool Invalid; + + public: + ActionResult(bool Invalid = false) : Val(PtrTy()), Invalid(Invalid) {} + ActionResult(PtrTy val) : Val(val), Invalid(false) {} + ActionResult(const DiagnosticBuilder &) : Val(PtrTy()), Invalid(true) {} + + // These two overloads prevent void* -> bool conversions. + ActionResult(const void *) = delete; + ActionResult(volatile void *) = delete; + + bool isInvalid() const { return Invalid; } + bool isUsable() const { return !Invalid && Val; } + bool isUnset() const { return !Invalid && !Val; } + + PtrTy get() const { return Val; } + template <typename T> T *getAs() { return static_cast<T*>(get()); } + + void set(PtrTy V) { Val = V; } + + const ActionResult &operator=(PtrTy RHS) { + Val = RHS; + Invalid = false; + return *this; + } + }; + + // This ActionResult partial specialization places the "invalid" + // flag into the low bit of the pointer. + template<typename PtrTy> + class ActionResult<PtrTy, true> { + // A pointer whose low bit is 1 if this result is invalid, 0 + // otherwise. + uintptr_t PtrWithInvalid; + + using PtrTraits = llvm::PointerLikeTypeTraits<PtrTy>; + + public: + ActionResult(bool Invalid = false) + : PtrWithInvalid(static_cast<uintptr_t>(Invalid)) {} + + ActionResult(PtrTy V) { + void *VP = PtrTraits::getAsVoidPointer(V); + PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); + assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); + } + + ActionResult(const DiagnosticBuilder &) : PtrWithInvalid(0x01) {} + + // These two overloads prevent void* -> bool conversions. + ActionResult(const void *) = delete; + ActionResult(volatile void *) = delete; + + bool isInvalid() const { return PtrWithInvalid & 0x01; } + bool isUsable() const { return PtrWithInvalid > 0x01; } + bool isUnset() const { return PtrWithInvalid == 0; } + + PtrTy get() const { + void *VP = reinterpret_cast<void *>(PtrWithInvalid & ~0x01); + return PtrTraits::getFromVoidPointer(VP); + } + + template <typename T> T *getAs() { return static_cast<T*>(get()); } + + void set(PtrTy V) { + void *VP = PtrTraits::getAsVoidPointer(V); + PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); + assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); + } + + const ActionResult &operator=(PtrTy RHS) { + void *VP = PtrTraits::getAsVoidPointer(RHS); + PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); + assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); + return *this; + } + + // For types where we can fit a flag in with the pointer, provide + // conversions to/from pointer type. + static ActionResult getFromOpaquePointer(void *P) { + ActionResult Result; + Result.PtrWithInvalid = (uintptr_t)P; + return Result; + } + void *getAsOpaquePointer() const { return (void*)PtrWithInvalid; } + }; + + /// An opaque type for threading parsed type information through the + /// parser. + using ParsedType = OpaquePtr<QualType>; + using UnionParsedType = UnionOpaquePtr<QualType>; + + // We can re-use the low bit of expression, statement, base, and + // member-initializer pointers for the "invalid" flag of + // ActionResult. + template<> struct IsResultPtrLowBitFree<Expr*> { + static const bool value = true; + }; + template<> struct IsResultPtrLowBitFree<Stmt*> { + static const bool value = true; + }; + template<> struct IsResultPtrLowBitFree<CXXBaseSpecifier*> { + static const bool value = true; + }; + template<> struct IsResultPtrLowBitFree<CXXCtorInitializer*> { + static const bool value = true; + }; + + using ExprResult = ActionResult<Expr *>; + using StmtResult = ActionResult<Stmt *>; + using TypeResult = ActionResult<ParsedType>; + using BaseResult = ActionResult<CXXBaseSpecifier *>; + using MemInitResult = ActionResult<CXXCtorInitializer *>; + + using DeclResult = ActionResult<Decl *>; + using ParsedTemplateTy = OpaquePtr<TemplateName>; + using UnionParsedTemplateTy = UnionOpaquePtr<TemplateName>; + + using MultiExprArg = MutableArrayRef<Expr *>; + using MultiStmtArg = MutableArrayRef<Stmt *>; + using ASTTemplateArgsPtr = MutableArrayRef<ParsedTemplateArgument>; + using MultiTypeArg = MutableArrayRef<ParsedType>; + using MultiTemplateParamsArg = MutableArrayRef<TemplateParameterList *>; + + inline ExprResult ExprError() { return ExprResult(true); } + inline StmtResult StmtError() { return StmtResult(true); } + inline TypeResult TypeError() { return TypeResult(true); } + + inline ExprResult ExprError(const StreamingDiagnostic &) { + return ExprError(); + } + inline StmtResult StmtError(const StreamingDiagnostic &) { + return StmtError(); + } + + inline ExprResult ExprEmpty() { return ExprResult(false); } + inline StmtResult StmtEmpty() { return StmtResult(false); } + + inline Expr *AssertSuccess(ExprResult R) { + assert(!R.isInvalid() && "operation was asserted to never fail!"); + return R.get(); + } + + inline Stmt *AssertSuccess(StmtResult R) { + assert(!R.isInvalid() && "operation was asserted to never fail!"); + return R.get(); + } + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_OWNERSHIP_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/ParsedAttr.h b/contrib/libs/clang16/include/clang/Sema/ParsedAttr.h new file mode 100644 index 0000000000..18392aee49 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/ParsedAttr.h @@ -0,0 +1,1220 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//======- ParsedAttr.h - Parsed attribute sets ------------------*- 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 defines the ParsedAttr class, which is used to collect +// parsed attributes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_PARSEDATTR_H +#define LLVM_CLANG_SEMA_PARSEDATTR_H + +#include "clang/Basic/AttrSubjectMatchRules.h" +#include "clang/Basic/AttributeCommonInfo.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/Ownership.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Registry.h" +#include "llvm/Support/VersionTuple.h" +#include <cassert> +#include <cstddef> +#include <cstring> +#include <utility> + +namespace clang { + +class ASTContext; +class Decl; +class Expr; +class IdentifierInfo; +class LangOptions; +class ParsedAttr; +class Sema; +class Stmt; +class TargetInfo; + +struct ParsedAttrInfo { + /// Corresponds to the Kind enum. + unsigned AttrKind : 16; + /// The number of required arguments of this attribute. + unsigned NumArgs : 4; + /// The number of optional arguments of this attributes. + unsigned OptArgs : 4; + /// The number of non-fake arguments specified in the attribute definition. + unsigned NumArgMembers : 4; + /// True if the parsing does not match the semantic content. + unsigned HasCustomParsing : 1; + // True if this attribute accepts expression parameter pack expansions. + unsigned AcceptsExprPack : 1; + /// True if this attribute is only available for certain targets. + unsigned IsTargetSpecific : 1; + /// True if this attribute applies to types. + unsigned IsType : 1; + /// True if this attribute applies to statements. + unsigned IsStmt : 1; + /// True if this attribute has any spellings that are known to gcc. + unsigned IsKnownToGCC : 1; + /// True if this attribute is supported by #pragma clang attribute. + unsigned IsSupportedByPragmaAttribute : 1; + /// The syntaxes supported by this attribute and how they're spelled. + struct Spelling { + AttributeCommonInfo::Syntax Syntax; + const char *NormalizedFullName; + }; + ArrayRef<Spelling> Spellings; + // The names of the known arguments of this attribute. + ArrayRef<const char *> ArgNames; + +protected: + constexpr ParsedAttrInfo(AttributeCommonInfo::Kind AttrKind = + AttributeCommonInfo::NoSemaHandlerAttribute) + : AttrKind(AttrKind), NumArgs(0), OptArgs(0), NumArgMembers(0), + HasCustomParsing(0), AcceptsExprPack(0), IsTargetSpecific(0), IsType(0), + IsStmt(0), IsKnownToGCC(0), IsSupportedByPragmaAttribute(0) {} + + constexpr ParsedAttrInfo(AttributeCommonInfo::Kind AttrKind, unsigned NumArgs, + unsigned OptArgs, unsigned NumArgMembers, + unsigned HasCustomParsing, unsigned AcceptsExprPack, + unsigned IsTargetSpecific, unsigned IsType, + unsigned IsStmt, unsigned IsKnownToGCC, + unsigned IsSupportedByPragmaAttribute, + ArrayRef<Spelling> Spellings, + ArrayRef<const char *> ArgNames) + : AttrKind(AttrKind), NumArgs(NumArgs), OptArgs(OptArgs), + NumArgMembers(NumArgMembers), HasCustomParsing(HasCustomParsing), + AcceptsExprPack(AcceptsExprPack), IsTargetSpecific(IsTargetSpecific), + IsType(IsType), IsStmt(IsStmt), IsKnownToGCC(IsKnownToGCC), + IsSupportedByPragmaAttribute(IsSupportedByPragmaAttribute), + Spellings(Spellings), ArgNames(ArgNames) {} + +public: + virtual ~ParsedAttrInfo() = default; + + /// Check if this attribute appertains to D, and issue a diagnostic if not. + virtual bool diagAppertainsToDecl(Sema &S, const ParsedAttr &Attr, + const Decl *D) const { + return true; + } + /// Check if this attribute appertains to St, and issue a diagnostic if not. + virtual bool diagAppertainsToStmt(Sema &S, const ParsedAttr &Attr, + const Stmt *St) const { + return true; + } + /// Check if the given attribute is mutually exclusive with other attributes + /// already applied to the given declaration. + virtual bool diagMutualExclusion(Sema &S, const ParsedAttr &A, + const Decl *D) const { + return true; + } + /// Check if this attribute is allowed by the language we are compiling. + virtual bool acceptsLangOpts(const LangOptions &LO) const { return true; } + + /// Check if this attribute is allowed when compiling for the given target. + virtual bool existsInTarget(const TargetInfo &Target) const { + return true; + } + /// Convert the spelling index of Attr to a semantic spelling enum value. + virtual unsigned + spellingIndexToSemanticSpelling(const ParsedAttr &Attr) const { + return UINT_MAX; + } + /// Returns true if the specified parameter index for this attribute in + /// Attr.td is an ExprArgument or VariadicExprArgument, or a subclass thereof; + /// returns false otherwise. + virtual bool isParamExpr(size_t N) const { return false; } + /// Populate Rules with the match rules of this attribute. + virtual void getPragmaAttributeMatchRules( + llvm::SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &Rules, + const LangOptions &LangOpts) const { + } + enum AttrHandling { + NotHandled, + AttributeApplied, + AttributeNotApplied + }; + /// If this ParsedAttrInfo knows how to handle this ParsedAttr applied to this + /// Decl then do so and return either AttributeApplied if it was applied or + /// AttributeNotApplied if it wasn't. Otherwise return NotHandled. + virtual AttrHandling handleDeclAttribute(Sema &S, Decl *D, + const ParsedAttr &Attr) const { + return NotHandled; + } + + static const ParsedAttrInfo &get(const AttributeCommonInfo &A); + static ArrayRef<const ParsedAttrInfo *> getAllBuiltin(); +}; + +typedef llvm::Registry<ParsedAttrInfo> ParsedAttrInfoRegistry; + +/// Represents information about a change in availability for +/// an entity, which is part of the encoding of the 'availability' +/// attribute. +struct AvailabilityChange { + /// The location of the keyword indicating the kind of change. + SourceLocation KeywordLoc; + + /// The version number at which the change occurred. + VersionTuple Version; + + /// The source range covering the version number. + SourceRange VersionRange; + + /// Determine whether this availability change is valid. + bool isValid() const { return !Version.empty(); } +}; + +namespace detail { +enum AvailabilitySlot { + IntroducedSlot, DeprecatedSlot, ObsoletedSlot, NumAvailabilitySlots +}; + +/// Describes the trailing object for Availability attribute in ParsedAttr. +struct AvailabilityData { + AvailabilityChange Changes[NumAvailabilitySlots]; + SourceLocation StrictLoc; + const Expr *Replacement; + + AvailabilityData(const AvailabilityChange &Introduced, + const AvailabilityChange &Deprecated, + const AvailabilityChange &Obsoleted, + SourceLocation Strict, const Expr *ReplaceExpr) + : StrictLoc(Strict), Replacement(ReplaceExpr) { + Changes[IntroducedSlot] = Introduced; + Changes[DeprecatedSlot] = Deprecated; + Changes[ObsoletedSlot] = Obsoleted; + } +}; + +struct TypeTagForDatatypeData { + ParsedType MatchingCType; + unsigned LayoutCompatible : 1; + unsigned MustBeNull : 1; +}; +struct PropertyData { + IdentifierInfo *GetterId, *SetterId; + + PropertyData(IdentifierInfo *getterId, IdentifierInfo *setterId) + : GetterId(getterId), SetterId(setterId) {} +}; + +} // namespace + +/// Wraps an identifier and optional source location for the identifier. +struct IdentifierLoc { + SourceLocation Loc; + IdentifierInfo *Ident; + + static IdentifierLoc *create(ASTContext &Ctx, SourceLocation Loc, + IdentifierInfo *Ident); +}; + +/// A union of the various pointer types that can be passed to an +/// ParsedAttr as an argument. +using ArgsUnion = llvm::PointerUnion<Expr *, IdentifierLoc *>; +using ArgsVector = llvm::SmallVector<ArgsUnion, 12U>; + +/// ParsedAttr - Represents a syntactic attribute. +/// +/// For a GNU attribute, there are four forms of this construct: +/// +/// 1: __attribute__(( const )). ParmName/Args/NumArgs will all be unused. +/// 2: __attribute__(( mode(byte) )). ParmName used, Args/NumArgs unused. +/// 3: __attribute__(( format(printf, 1, 2) )). ParmName/Args/NumArgs all used. +/// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used. +/// +class ParsedAttr final + : public AttributeCommonInfo, + private llvm::TrailingObjects< + ParsedAttr, ArgsUnion, detail::AvailabilityData, + detail::TypeTagForDatatypeData, ParsedType, detail::PropertyData> { + friend TrailingObjects; + + size_t numTrailingObjects(OverloadToken<ArgsUnion>) const { return NumArgs; } + size_t numTrailingObjects(OverloadToken<detail::AvailabilityData>) const { + return IsAvailability; + } + size_t + numTrailingObjects(OverloadToken<detail::TypeTagForDatatypeData>) const { + return IsTypeTagForDatatype; + } + size_t numTrailingObjects(OverloadToken<ParsedType>) const { + return HasParsedType; + } + size_t numTrailingObjects(OverloadToken<detail::PropertyData>) const { + return IsProperty; + } + +private: + IdentifierInfo *MacroII = nullptr; + SourceLocation MacroExpansionLoc; + SourceLocation EllipsisLoc; + + /// The number of expression arguments this attribute has. + /// The expressions themselves are stored after the object. + unsigned NumArgs : 16; + + /// True if already diagnosed as invalid. + mutable unsigned Invalid : 1; + + /// True if this attribute was used as a type attribute. + mutable unsigned UsedAsTypeAttr : 1; + + /// True if this has the extra information associated with an + /// availability attribute. + unsigned IsAvailability : 1; + + /// True if this has extra information associated with a + /// type_tag_for_datatype attribute. + unsigned IsTypeTagForDatatype : 1; + + /// True if this has extra information associated with a + /// Microsoft __delcspec(property) attribute. + unsigned IsProperty : 1; + + /// True if this has a ParsedType + unsigned HasParsedType : 1; + + /// True if the processing cache is valid. + mutable unsigned HasProcessingCache : 1; + + /// A cached value. + mutable unsigned ProcessingCache : 8; + + /// True if the attribute is specified using '#pragma clang attribute'. + mutable unsigned IsPragmaClangAttribute : 1; + + /// The location of the 'unavailable' keyword in an + /// availability attribute. + SourceLocation UnavailableLoc; + + const Expr *MessageExpr; + + const ParsedAttrInfo &Info; + + ArgsUnion *getArgsBuffer() { return getTrailingObjects<ArgsUnion>(); } + ArgsUnion const *getArgsBuffer() const { + return getTrailingObjects<ArgsUnion>(); + } + + detail::AvailabilityData *getAvailabilityData() { + return getTrailingObjects<detail::AvailabilityData>(); + } + const detail::AvailabilityData *getAvailabilityData() const { + return getTrailingObjects<detail::AvailabilityData>(); + } + +private: + friend class AttributeFactory; + friend class AttributePool; + + /// Constructor for attributes with expression arguments. + ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + ArgsUnion *args, unsigned numArgs, Syntax syntaxUsed, + SourceLocation ellipsisLoc) + : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, + syntaxUsed), + EllipsisLoc(ellipsisLoc), NumArgs(numArgs), Invalid(false), + UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false), + HasProcessingCache(false), IsPragmaClangAttribute(false), + Info(ParsedAttrInfo::get(*this)) { + if (numArgs) + memcpy(getArgsBuffer(), args, numArgs * sizeof(ArgsUnion)); + } + + /// Constructor for availability attributes. + ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Parm, const AvailabilityChange &introduced, + const AvailabilityChange &deprecated, + const AvailabilityChange &obsoleted, SourceLocation unavailable, + const Expr *messageExpr, Syntax syntaxUsed, SourceLocation strict, + const Expr *replacementExpr) + : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, + syntaxUsed), + NumArgs(1), Invalid(false), UsedAsTypeAttr(false), IsAvailability(true), + IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false), + HasProcessingCache(false), IsPragmaClangAttribute(false), + UnavailableLoc(unavailable), MessageExpr(messageExpr), + Info(ParsedAttrInfo::get(*this)) { + ArgsUnion PVal(Parm); + memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion)); + new (getAvailabilityData()) detail::AvailabilityData( + introduced, deprecated, obsoleted, strict, replacementExpr); + } + + /// Constructor for objc_bridge_related attributes. + ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Parm1, IdentifierLoc *Parm2, IdentifierLoc *Parm3, + Syntax syntaxUsed) + : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, + syntaxUsed), + NumArgs(3), Invalid(false), UsedAsTypeAttr(false), + IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false), + HasParsedType(false), HasProcessingCache(false), + IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) { + ArgsUnion *Args = getArgsBuffer(); + Args[0] = Parm1; + Args[1] = Parm2; + Args[2] = Parm3; + } + + /// Constructor for type_tag_for_datatype attribute. + ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *ArgKind, ParsedType matchingCType, + bool layoutCompatible, bool mustBeNull, Syntax syntaxUsed) + : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, + syntaxUsed), + NumArgs(1), Invalid(false), UsedAsTypeAttr(false), + IsAvailability(false), IsTypeTagForDatatype(true), IsProperty(false), + HasParsedType(false), HasProcessingCache(false), + IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) { + ArgsUnion PVal(ArgKind); + memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion)); + detail::TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot(); + new (&ExtraData.MatchingCType) ParsedType(matchingCType); + ExtraData.LayoutCompatible = layoutCompatible; + ExtraData.MustBeNull = mustBeNull; + } + + /// Constructor for attributes with a single type argument. + ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + ParsedType typeArg, Syntax syntaxUsed) + : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, + syntaxUsed), + NumArgs(0), Invalid(false), UsedAsTypeAttr(false), + IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false), + HasParsedType(true), HasProcessingCache(false), + IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) { + new (&getTypeBuffer()) ParsedType(typeArg); + } + + /// Constructor for microsoft __declspec(property) attribute. + ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *getterId, IdentifierInfo *setterId, + Syntax syntaxUsed) + : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, + syntaxUsed), + NumArgs(0), Invalid(false), UsedAsTypeAttr(false), + IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(true), + HasParsedType(false), HasProcessingCache(false), + IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) { + new (&getPropertyDataBuffer()) detail::PropertyData(getterId, setterId); + } + + /// Type tag information is stored immediately following the arguments, if + /// any, at the end of the object. They are mutually exclusive with + /// availability slots. + detail::TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() { + return *getTrailingObjects<detail::TypeTagForDatatypeData>(); + } + const detail::TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() const { + return *getTrailingObjects<detail::TypeTagForDatatypeData>(); + } + + /// The type buffer immediately follows the object and are mutually exclusive + /// with arguments. + ParsedType &getTypeBuffer() { return *getTrailingObjects<ParsedType>(); } + const ParsedType &getTypeBuffer() const { + return *getTrailingObjects<ParsedType>(); + } + + /// The property data immediately follows the object is mutually exclusive + /// with arguments. + detail::PropertyData &getPropertyDataBuffer() { + assert(IsProperty); + return *getTrailingObjects<detail::PropertyData>(); + } + const detail::PropertyData &getPropertyDataBuffer() const { + assert(IsProperty); + return *getTrailingObjects<detail::PropertyData>(); + } + + size_t allocated_size() const; + +public: + ParsedAttr(const ParsedAttr &) = delete; + ParsedAttr(ParsedAttr &&) = delete; + ParsedAttr &operator=(const ParsedAttr &) = delete; + ParsedAttr &operator=(ParsedAttr &&) = delete; + ~ParsedAttr() = delete; + + void operator delete(void *) = delete; + + bool hasParsedType() const { return HasParsedType; } + + /// Is this the Microsoft __declspec(property) attribute? + bool isDeclspecPropertyAttribute() const { + return IsProperty; + } + + bool isInvalid() const { return Invalid; } + void setInvalid(bool b = true) const { Invalid = b; } + + bool hasProcessingCache() const { return HasProcessingCache; } + + unsigned getProcessingCache() const { + assert(hasProcessingCache()); + return ProcessingCache; + } + + void setProcessingCache(unsigned value) const { + ProcessingCache = value; + HasProcessingCache = true; + } + + bool isUsedAsTypeAttr() const { return UsedAsTypeAttr; } + void setUsedAsTypeAttr(bool Used = true) { UsedAsTypeAttr = Used; } + + /// True if the attribute is specified using '#pragma clang attribute'. + bool isPragmaClangAttribute() const { return IsPragmaClangAttribute; } + + void setIsPragmaClangAttribute() { IsPragmaClangAttribute = true; } + + bool isPackExpansion() const { return EllipsisLoc.isValid(); } + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + + /// getNumArgs - Return the number of actual arguments to this attribute. + unsigned getNumArgs() const { return NumArgs; } + + /// getArg - Return the specified argument. + ArgsUnion getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return getArgsBuffer()[Arg]; + } + + bool isArgExpr(unsigned Arg) const { + return Arg < NumArgs && getArg(Arg).is<Expr*>(); + } + + Expr *getArgAsExpr(unsigned Arg) const { + return getArg(Arg).get<Expr*>(); + } + + bool isArgIdent(unsigned Arg) const { + return Arg < NumArgs && getArg(Arg).is<IdentifierLoc*>(); + } + + IdentifierLoc *getArgAsIdent(unsigned Arg) const { + return getArg(Arg).get<IdentifierLoc*>(); + } + + const AvailabilityChange &getAvailabilityIntroduced() const { + assert(getParsedKind() == AT_Availability && + "Not an availability attribute"); + return getAvailabilityData()->Changes[detail::IntroducedSlot]; + } + + const AvailabilityChange &getAvailabilityDeprecated() const { + assert(getParsedKind() == AT_Availability && + "Not an availability attribute"); + return getAvailabilityData()->Changes[detail::DeprecatedSlot]; + } + + const AvailabilityChange &getAvailabilityObsoleted() const { + assert(getParsedKind() == AT_Availability && + "Not an availability attribute"); + return getAvailabilityData()->Changes[detail::ObsoletedSlot]; + } + + SourceLocation getStrictLoc() const { + assert(getParsedKind() == AT_Availability && + "Not an availability attribute"); + return getAvailabilityData()->StrictLoc; + } + + SourceLocation getUnavailableLoc() const { + assert(getParsedKind() == AT_Availability && + "Not an availability attribute"); + return UnavailableLoc; + } + + const Expr * getMessageExpr() const { + assert(getParsedKind() == AT_Availability && + "Not an availability attribute"); + return MessageExpr; + } + + const Expr *getReplacementExpr() const { + assert(getParsedKind() == AT_Availability && + "Not an availability attribute"); + return getAvailabilityData()->Replacement; + } + + const ParsedType &getMatchingCType() const { + assert(getParsedKind() == AT_TypeTagForDatatype && + "Not a type_tag_for_datatype attribute"); + return getTypeTagForDatatypeDataSlot().MatchingCType; + } + + bool getLayoutCompatible() const { + assert(getParsedKind() == AT_TypeTagForDatatype && + "Not a type_tag_for_datatype attribute"); + return getTypeTagForDatatypeDataSlot().LayoutCompatible; + } + + bool getMustBeNull() const { + assert(getParsedKind() == AT_TypeTagForDatatype && + "Not a type_tag_for_datatype attribute"); + return getTypeTagForDatatypeDataSlot().MustBeNull; + } + + const ParsedType &getTypeArg() const { + assert(HasParsedType && "Not a type attribute"); + return getTypeBuffer(); + } + + IdentifierInfo *getPropertyDataGetter() const { + assert(isDeclspecPropertyAttribute() && + "Not a __delcspec(property) attribute"); + return getPropertyDataBuffer().GetterId; + } + + IdentifierInfo *getPropertyDataSetter() const { + assert(isDeclspecPropertyAttribute() && + "Not a __delcspec(property) attribute"); + return getPropertyDataBuffer().SetterId; + } + + /// Set the macro identifier info object that this parsed attribute was + /// declared in if it was declared in a macro. Also set the expansion location + /// of the macro. + void setMacroIdentifier(IdentifierInfo *MacroName, SourceLocation Loc) { + MacroII = MacroName; + MacroExpansionLoc = Loc; + } + + /// Returns true if this attribute was declared in a macro. + bool hasMacroIdentifier() const { return MacroII != nullptr; } + + /// Return the macro identifier if this attribute was declared in a macro. + /// nullptr is returned if it was not declared in a macro. + IdentifierInfo *getMacroIdentifier() const { return MacroII; } + + SourceLocation getMacroExpansionLoc() const { + assert(hasMacroIdentifier() && "Can only get the macro expansion location " + "if this attribute has a macro identifier."); + return MacroExpansionLoc; + } + + /// Check if the attribute has exactly as many args as Num. May output an + /// error. Returns false if a diagnostic is produced. + bool checkExactlyNumArgs(class Sema &S, unsigned Num) const; + /// Check if the attribute has at least as many args as Num. May output an + /// error. Returns false if a diagnostic is produced. + bool checkAtLeastNumArgs(class Sema &S, unsigned Num) const; + /// Check if the attribute has at most as many args as Num. May output an + /// error. Returns false if a diagnostic is produced. + bool checkAtMostNumArgs(class Sema &S, unsigned Num) const; + + bool isTargetSpecificAttr() const; + bool isTypeAttr() const; + bool isStmtAttr() const; + + bool hasCustomParsing() const; + bool acceptsExprPack() const; + bool isParamExpr(size_t N) const; + unsigned getMinArgs() const; + unsigned getMaxArgs() const; + unsigned getNumArgMembers() const; + bool hasVariadicArg() const; + void handleAttrWithDelayedArgs(Sema &S, Decl *D) const; + bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const; + bool diagnoseAppertainsTo(class Sema &S, const Stmt *St) const; + bool diagnoseMutualExclusion(class Sema &S, const Decl *D) const; + // This function stub exists for parity with the declaration checking code so + // that checkCommonAttributeFeatures() can work generically on declarations + // or statements. + bool diagnoseMutualExclusion(class Sema &S, const Stmt *St) const { + return true; + } + bool appliesToDecl(const Decl *D, attr::SubjectMatchRule MatchRule) const; + void getMatchRules(const LangOptions &LangOpts, + SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> + &MatchRules) const; + bool diagnoseLangOpts(class Sema &S) const; + bool existsInTarget(const TargetInfo &Target) const; + bool isKnownToGCC() const; + bool isSupportedByPragmaAttribute() const; + + /// Returns whether a [[]] attribute, if specified ahead of a declaration, + /// should be applied to the decl-specifier-seq instead (i.e. whether it + /// "slides" to the decl-specifier-seq). + /// + /// By the standard, attributes specified before the declaration always + /// appertain to the declaration, but historically we have allowed some of + /// these attributes to slide to the decl-specifier-seq, so we need to keep + /// supporting this behavior. + /// + /// This may only be called if isStandardAttributeSyntax() returns true. + bool slidesFromDeclToDeclSpecLegacyBehavior() const; + + /// If the parsed attribute has a semantic equivalent, and it would + /// have a semantic Spelling enumeration (due to having semantically-distinct + /// spelling variations), return the value of that semantic spelling. If the + /// parsed attribute does not have a semantic equivalent, or would not have + /// a Spelling enumeration, the value UINT_MAX is returned. + unsigned getSemanticSpelling() const; + + /// If this is an OpenCL address space attribute, returns its representation + /// in LangAS, otherwise returns default address space. + LangAS asOpenCLLangAS() const { + switch (getParsedKind()) { + case ParsedAttr::AT_OpenCLConstantAddressSpace: + return LangAS::opencl_constant; + case ParsedAttr::AT_OpenCLGlobalAddressSpace: + return LangAS::opencl_global; + case ParsedAttr::AT_OpenCLGlobalDeviceAddressSpace: + return LangAS::opencl_global_device; + case ParsedAttr::AT_OpenCLGlobalHostAddressSpace: + return LangAS::opencl_global_host; + case ParsedAttr::AT_OpenCLLocalAddressSpace: + return LangAS::opencl_local; + case ParsedAttr::AT_OpenCLPrivateAddressSpace: + return LangAS::opencl_private; + case ParsedAttr::AT_OpenCLGenericAddressSpace: + return LangAS::opencl_generic; + default: + return LangAS::Default; + } + } + + /// If this is an OpenCL address space attribute, returns its SYCL + /// representation in LangAS, otherwise returns default address space. + LangAS asSYCLLangAS() const { + switch (getKind()) { + case ParsedAttr::AT_OpenCLGlobalAddressSpace: + return LangAS::sycl_global; + case ParsedAttr::AT_OpenCLGlobalDeviceAddressSpace: + return LangAS::sycl_global_device; + case ParsedAttr::AT_OpenCLGlobalHostAddressSpace: + return LangAS::sycl_global_host; + case ParsedAttr::AT_OpenCLLocalAddressSpace: + return LangAS::sycl_local; + case ParsedAttr::AT_OpenCLPrivateAddressSpace: + return LangAS::sycl_private; + case ParsedAttr::AT_OpenCLGenericAddressSpace: + default: + return LangAS::Default; + } + } + + /// If this is an HLSL address space attribute, returns its representation + /// in LangAS, otherwise returns default address space. + LangAS asHLSLLangAS() const { + switch (getParsedKind()) { + case ParsedAttr::AT_HLSLGroupSharedAddressSpace: + return LangAS::hlsl_groupshared; + default: + return LangAS::Default; + } + } + + AttributeCommonInfo::Kind getKind() const { + return AttributeCommonInfo::Kind(Info.AttrKind); + } + const ParsedAttrInfo &getInfo() const { return Info; } +}; + +class AttributePool; +/// A factory, from which one makes pools, from which one creates +/// individual attributes which are deallocated with the pool. +/// +/// Note that it's tolerably cheap to create and destroy one of +/// these as long as you don't actually allocate anything in it. +class AttributeFactory { +public: + enum { + AvailabilityAllocSize = + ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, + detail::TypeTagForDatatypeData, ParsedType, + detail::PropertyData>(1, 1, 0, 0, 0), + TypeTagForDatatypeAllocSize = + ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, + detail::TypeTagForDatatypeData, ParsedType, + detail::PropertyData>(1, 0, 1, 0, 0), + PropertyAllocSize = + ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, + detail::TypeTagForDatatypeData, ParsedType, + detail::PropertyData>(0, 0, 0, 0, 1), + }; + +private: + enum { + /// The number of free lists we want to be sure to support + /// inline. This is just enough that availability attributes + /// don't surpass it. It's actually very unlikely we'll see an + /// attribute that needs more than that; on x86-64 you'd need 10 + /// expression arguments, and on i386 you'd need 19. + InlineFreeListsCapacity = + 1 + (AvailabilityAllocSize - sizeof(ParsedAttr)) / sizeof(void *) + }; + + llvm::BumpPtrAllocator Alloc; + + /// Free lists. The index is determined by the following formula: + /// (size - sizeof(ParsedAttr)) / sizeof(void*) + SmallVector<SmallVector<ParsedAttr *, 8>, InlineFreeListsCapacity> FreeLists; + + // The following are the private interface used by AttributePool. + friend class AttributePool; + + /// Allocate an attribute of the given size. + void *allocate(size_t size); + + void deallocate(ParsedAttr *AL); + + /// Reclaim all the attributes in the given pool chain, which is + /// non-empty. Note that the current implementation is safe + /// against reclaiming things which were not actually allocated + /// with the allocator, although of course it's important to make + /// sure that their allocator lives at least as long as this one. + void reclaimPool(AttributePool &head); + +public: + AttributeFactory(); + ~AttributeFactory(); +}; + +class AttributePool { + friend class AttributeFactory; + friend class ParsedAttributes; + AttributeFactory &Factory; + llvm::SmallVector<ParsedAttr *> Attrs; + + void *allocate(size_t size) { + return Factory.allocate(size); + } + + ParsedAttr *add(ParsedAttr *attr) { + Attrs.push_back(attr); + return attr; + } + + void remove(ParsedAttr *attr) { + assert(llvm::is_contained(Attrs, attr) && + "Can't take attribute from a pool that doesn't own it!"); + Attrs.erase(llvm::find(Attrs, attr)); + } + + void takePool(AttributePool &pool); + +public: + /// Create a new pool for a factory. + AttributePool(AttributeFactory &factory) : Factory(factory) {} + + AttributePool(const AttributePool &) = delete; + + ~AttributePool() { Factory.reclaimPool(*this); } + + /// Move the given pool's allocations to this pool. + AttributePool(AttributePool &&pool) = default; + + AttributeFactory &getFactory() const { return Factory; } + + void clear() { + Factory.reclaimPool(*this); + Attrs.clear(); + } + + /// Take the given pool's allocations and add them to this pool. + void takeAllFrom(AttributePool &pool) { + takePool(pool); + pool.Attrs.clear(); + } + + ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + ArgsUnion *args, unsigned numArgs, + ParsedAttr::Syntax syntax, + SourceLocation ellipsisLoc = SourceLocation()) { + size_t temp = + ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, + detail::TypeTagForDatatypeData, ParsedType, + detail::PropertyData>(numArgs, 0, 0, 0, 0); + (void)temp; + void *memory = allocate( + ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, + detail::TypeTagForDatatypeData, ParsedType, + detail::PropertyData>(numArgs, 0, 0, 0, + 0)); + return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, + args, numArgs, syntax, ellipsisLoc)); + } + + ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Param, const AvailabilityChange &introduced, + const AvailabilityChange &deprecated, + const AvailabilityChange &obsoleted, + SourceLocation unavailable, const Expr *MessageExpr, + ParsedAttr::Syntax syntax, SourceLocation strict, + const Expr *ReplacementExpr) { + void *memory = allocate(AttributeFactory::AvailabilityAllocSize); + return add(new (memory) ParsedAttr( + attrName, attrRange, scopeName, scopeLoc, Param, introduced, deprecated, + obsoleted, unavailable, MessageExpr, syntax, strict, ReplacementExpr)); + } + + ParsedAttr *create(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Param1, IdentifierLoc *Param2, + IdentifierLoc *Param3, ParsedAttr::Syntax syntax) { + void *memory = allocate( + ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, + detail::TypeTagForDatatypeData, ParsedType, + detail::PropertyData>(3, 0, 0, 0, 0)); + return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, + Param1, Param2, Param3, syntax)); + } + + ParsedAttr * + createTypeTagForDatatype(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *argumentKind, + ParsedType matchingCType, bool layoutCompatible, + bool mustBeNull, ParsedAttr::Syntax syntax) { + void *memory = allocate(AttributeFactory::TypeTagForDatatypeAllocSize); + return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, + argumentKind, matchingCType, + layoutCompatible, mustBeNull, syntax)); + } + + ParsedAttr *createTypeAttribute(IdentifierInfo *attrName, + SourceRange attrRange, + IdentifierInfo *scopeName, + SourceLocation scopeLoc, ParsedType typeArg, + ParsedAttr::Syntax syntaxUsed) { + void *memory = allocate( + ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, + detail::TypeTagForDatatypeData, ParsedType, + detail::PropertyData>(0, 0, 0, 1, 0)); + return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, + typeArg, syntaxUsed)); + } + + ParsedAttr * + createPropertyAttribute(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *getterId, IdentifierInfo *setterId, + ParsedAttr::Syntax syntaxUsed) { + void *memory = allocate(AttributeFactory::PropertyAllocSize); + return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, + getterId, setterId, syntaxUsed)); + } +}; + +class ParsedAttributesView { + using VecTy = llvm::SmallVector<ParsedAttr *>; + using SizeType = decltype(std::declval<VecTy>().size()); + +public: + SourceRange Range; + + static const ParsedAttributesView &none() { + static const ParsedAttributesView Attrs; + return Attrs; + } + + bool empty() const { return AttrList.empty(); } + SizeType size() const { return AttrList.size(); } + ParsedAttr &operator[](SizeType pos) { return *AttrList[pos]; } + const ParsedAttr &operator[](SizeType pos) const { return *AttrList[pos]; } + + void addAtEnd(ParsedAttr *newAttr) { + assert(newAttr); + AttrList.push_back(newAttr); + } + + void remove(ParsedAttr *ToBeRemoved) { + assert(is_contained(AttrList, ToBeRemoved) && + "Cannot remove attribute that isn't in the list"); + AttrList.erase(llvm::find(AttrList, ToBeRemoved)); + } + + void clearListOnly() { AttrList.clear(); } + + struct iterator : llvm::iterator_adaptor_base<iterator, VecTy::iterator, + std::random_access_iterator_tag, + ParsedAttr> { + iterator() : iterator_adaptor_base(nullptr) {} + iterator(VecTy::iterator I) : iterator_adaptor_base(I) {} + reference operator*() const { return **I; } + friend class ParsedAttributesView; + }; + struct const_iterator + : llvm::iterator_adaptor_base<const_iterator, VecTy::const_iterator, + std::random_access_iterator_tag, + ParsedAttr> { + const_iterator() : iterator_adaptor_base(nullptr) {} + const_iterator(VecTy::const_iterator I) : iterator_adaptor_base(I) {} + + reference operator*() const { return **I; } + friend class ParsedAttributesView; + }; + + void addAll(iterator B, iterator E) { + AttrList.insert(AttrList.begin(), B.I, E.I); + } + + void addAll(const_iterator B, const_iterator E) { + AttrList.insert(AttrList.begin(), B.I, E.I); + } + + void addAllAtEnd(iterator B, iterator E) { + AttrList.insert(AttrList.end(), B.I, E.I); + } + + void addAllAtEnd(const_iterator B, const_iterator E) { + AttrList.insert(AttrList.end(), B.I, E.I); + } + + iterator begin() { return iterator(AttrList.begin()); } + const_iterator begin() const { return const_iterator(AttrList.begin()); } + iterator end() { return iterator(AttrList.end()); } + const_iterator end() const { return const_iterator(AttrList.end()); } + + ParsedAttr &front() { + assert(!empty()); + return *AttrList.front(); + } + const ParsedAttr &front() const { + assert(!empty()); + return *AttrList.front(); + } + ParsedAttr &back() { + assert(!empty()); + return *AttrList.back(); + } + const ParsedAttr &back() const { + assert(!empty()); + return *AttrList.back(); + } + + bool hasAttribute(ParsedAttr::Kind K) const { + return llvm::any_of(AttrList, [K](const ParsedAttr *AL) { + return AL->getParsedKind() == K; + }); + } + +private: + VecTy AttrList; +}; + +/// ParsedAttributes - A collection of parsed attributes. Currently +/// we don't differentiate between the various attribute syntaxes, +/// which is basically silly. +/// +/// Right now this is a very lightweight container, but the expectation +/// is that this will become significantly more serious. +class ParsedAttributes : public ParsedAttributesView { +public: + ParsedAttributes(AttributeFactory &factory) : pool(factory) {} + ParsedAttributes(const ParsedAttributes &) = delete; + + AttributePool &getPool() const { return pool; } + + void takeAllFrom(ParsedAttributes &Other) { + assert(&Other != this && + "ParsedAttributes can't take attributes from itself"); + addAll(Other.begin(), Other.end()); + Other.clearListOnly(); + pool.takeAllFrom(Other.pool); + } + + void takeOneFrom(ParsedAttributes &Other, ParsedAttr *PA) { + assert(&Other != this && + "ParsedAttributes can't take attribute from itself"); + Other.getPool().remove(PA); + Other.remove(PA); + getPool().add(PA); + addAtEnd(PA); + } + + void clear() { + clearListOnly(); + pool.clear(); + Range = SourceRange(); + } + + /// Add attribute with expression arguments. + ParsedAttr *addNew(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + ArgsUnion *args, unsigned numArgs, + ParsedAttr::Syntax syntax, + SourceLocation ellipsisLoc = SourceLocation()) { + ParsedAttr *attr = pool.create(attrName, attrRange, scopeName, scopeLoc, + args, numArgs, syntax, ellipsisLoc); + addAtEnd(attr); + return attr; + } + + /// Add availability attribute. + ParsedAttr *addNew(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Param, const AvailabilityChange &introduced, + const AvailabilityChange &deprecated, + const AvailabilityChange &obsoleted, + SourceLocation unavailable, const Expr *MessageExpr, + ParsedAttr::Syntax syntax, SourceLocation strict, + const Expr *ReplacementExpr) { + ParsedAttr *attr = pool.create( + attrName, attrRange, scopeName, scopeLoc, Param, introduced, deprecated, + obsoleted, unavailable, MessageExpr, syntax, strict, ReplacementExpr); + addAtEnd(attr); + return attr; + } + + /// Add objc_bridge_related attribute. + ParsedAttr *addNew(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Param1, IdentifierLoc *Param2, + IdentifierLoc *Param3, ParsedAttr::Syntax syntax) { + ParsedAttr *attr = pool.create(attrName, attrRange, scopeName, scopeLoc, + Param1, Param2, Param3, syntax); + addAtEnd(attr); + return attr; + } + + /// Add type_tag_for_datatype attribute. + ParsedAttr * + addNewTypeTagForDatatype(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *argumentKind, + ParsedType matchingCType, bool layoutCompatible, + bool mustBeNull, ParsedAttr::Syntax syntax) { + ParsedAttr *attr = pool.createTypeTagForDatatype( + attrName, attrRange, scopeName, scopeLoc, argumentKind, matchingCType, + layoutCompatible, mustBeNull, syntax); + addAtEnd(attr); + return attr; + } + + /// Add an attribute with a single type argument. + ParsedAttr *addNewTypeAttr(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + ParsedType typeArg, + ParsedAttr::Syntax syntaxUsed) { + ParsedAttr *attr = pool.createTypeAttribute(attrName, attrRange, scopeName, + scopeLoc, typeArg, syntaxUsed); + addAtEnd(attr); + return attr; + } + + /// Add microsoft __delspec(property) attribute. + ParsedAttr * + addNewPropertyAttr(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *getterId, IdentifierInfo *setterId, + ParsedAttr::Syntax syntaxUsed) { + ParsedAttr *attr = + pool.createPropertyAttribute(attrName, attrRange, scopeName, scopeLoc, + getterId, setterId, syntaxUsed); + addAtEnd(attr); + return attr; + } + +private: + mutable AttributePool pool; +}; + +/// Consumes the attributes from `First` and `Second` and concatenates them into +/// `Result`. Sets `Result.Range` to the combined range of `First` and `Second`. +void takeAndConcatenateAttrs(ParsedAttributes &First, ParsedAttributes &Second, + ParsedAttributes &Result); + +/// These constants match the enumerated choices of +/// err_attribute_argument_n_type and err_attribute_argument_type. +enum AttributeArgumentNType { + AANT_ArgumentIntOrBool, + AANT_ArgumentIntegerConstant, + AANT_ArgumentString, + AANT_ArgumentIdentifier, + AANT_ArgumentConstantExpr, + AANT_ArgumentBuiltinFunction, +}; + +/// These constants match the enumerated choices of +/// warn_attribute_wrong_decl_type and err_attribute_wrong_decl_type. +enum AttributeDeclKind { + ExpectedFunction, + ExpectedUnion, + ExpectedVariableOrFunction, + ExpectedFunctionOrMethod, + ExpectedFunctionMethodOrBlock, + ExpectedFunctionMethodOrParameter, + ExpectedVariable, + ExpectedVariableOrField, + ExpectedVariableFieldOrTag, + ExpectedTypeOrNamespace, + ExpectedFunctionVariableOrClass, + ExpectedKernelFunction, + ExpectedFunctionWithProtoType, +}; + +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, + const ParsedAttr &At) { + DB.AddTaggedVal(reinterpret_cast<uint64_t>(At.getAttrName()), + DiagnosticsEngine::ak_identifierinfo); + return DB; +} + +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, + const ParsedAttr *At) { + DB.AddTaggedVal(reinterpret_cast<uint64_t>(At->getAttrName()), + DiagnosticsEngine::ak_identifierinfo); + return DB; +} + +/// AttributeCommonInfo has a non-explicit constructor which takes an +/// SourceRange as its only argument, this constructor has many uses so making +/// it explicit is hard. This constructor causes ambiguity with +/// DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, SourceRange R). +/// We use SFINAE to disable any conversion and remove any ambiguity. +template < + typename ACI, + std::enable_if_t<std::is_same<ACI, AttributeCommonInfo>::value, int> = 0> +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, + const ACI &CI) { + DB.AddTaggedVal(reinterpret_cast<uint64_t>(CI.getAttrName()), + DiagnosticsEngine::ak_identifierinfo); + return DB; +} + +template < + typename ACI, + std::enable_if_t<std::is_same<ACI, AttributeCommonInfo>::value, int> = 0> +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, + const ACI *CI) { + DB.AddTaggedVal(reinterpret_cast<uint64_t>(CI->getAttrName()), + DiagnosticsEngine::ak_identifierinfo); + return DB; +} + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_PARSEDATTR_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/ParsedTemplate.h b/contrib/libs/clang16/include/clang/Sema/ParsedTemplate.h new file mode 100644 index 0000000000..83faf47709 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/ParsedTemplate.h @@ -0,0 +1,273 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- ParsedTemplate.h - Template Parsing Data Types ---------*- 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 provides data structures that store the parsed representation of +// templates. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_PARSEDTEMPLATE_H +#define LLVM_CLANG_SEMA_PARSEDTEMPLATE_H + +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TemplateKinds.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Ownership.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> +#include <cstdlib> +#include <new> + +namespace clang { + /// Represents the parsed form of a C++ template argument. + class ParsedTemplateArgument { + public: + /// Describes the kind of template argument that was parsed. + enum KindType { + /// A template type parameter, stored as a type. + Type, + /// A non-type template parameter, stored as an expression. + NonType, + /// A template template argument, stored as a template name. + Template + }; + + /// Build an empty template argument. + /// + /// This template argument is invalid. + ParsedTemplateArgument() : Kind(Type), Arg(nullptr) { } + + /// Create a template type argument or non-type template argument. + /// + /// \param Arg the template type argument or non-type template argument. + /// \param Loc the location of the type. + ParsedTemplateArgument(KindType Kind, void *Arg, SourceLocation Loc) + : Kind(Kind), Arg(Arg), Loc(Loc) { } + + /// Create a template template argument. + /// + /// \param SS the C++ scope specifier that precedes the template name, if + /// any. + /// + /// \param Template the template to which this template template + /// argument refers. + /// + /// \param TemplateLoc the location of the template name. + ParsedTemplateArgument(const CXXScopeSpec &SS, + ParsedTemplateTy Template, + SourceLocation TemplateLoc) + : Kind(ParsedTemplateArgument::Template), + Arg(Template.getAsOpaquePtr()), SS(SS), Loc(TemplateLoc) {} + + /// Determine whether the given template argument is invalid. + bool isInvalid() const { return Arg == nullptr; } + + /// Determine what kind of template argument we have. + KindType getKind() const { return Kind; } + + /// Retrieve the template type argument's type. + ParsedType getAsType() const { + assert(Kind == Type && "Not a template type argument"); + return ParsedType::getFromOpaquePtr(Arg); + } + + /// Retrieve the non-type template argument's expression. + Expr *getAsExpr() const { + assert(Kind == NonType && "Not a non-type template argument"); + return static_cast<Expr*>(Arg); + } + + /// Retrieve the template template argument's template name. + ParsedTemplateTy getAsTemplate() const { + assert(Kind == Template && "Not a template template argument"); + return ParsedTemplateTy::getFromOpaquePtr(Arg); + } + + /// Retrieve the location of the template argument. + SourceLocation getLocation() const { return Loc; } + + /// Retrieve the nested-name-specifier that precedes the template + /// name in a template template argument. + const CXXScopeSpec &getScopeSpec() const { + assert(Kind == Template && + "Only template template arguments can have a scope specifier"); + return SS; + } + + /// Retrieve the location of the ellipsis that makes a template + /// template argument into a pack expansion. + SourceLocation getEllipsisLoc() const { + assert(Kind == Template && + "Only template template arguments can have an ellipsis"); + return EllipsisLoc; + } + + /// Retrieve a pack expansion of the given template template + /// argument. + /// + /// \param EllipsisLoc The location of the ellipsis. + ParsedTemplateArgument getTemplatePackExpansion( + SourceLocation EllipsisLoc) const; + + private: + KindType Kind; + + /// The actual template argument representation, which may be + /// an \c Sema::TypeTy* (for a type), an Expr* (for an + /// expression), or an Sema::TemplateTy (for a template). + void *Arg; + + /// The nested-name-specifier that can accompany a template template + /// argument. + CXXScopeSpec SS; + + /// the location of the template argument. + SourceLocation Loc; + + /// The ellipsis location that can accompany a template template + /// argument (turning it into a template template argument expansion). + SourceLocation EllipsisLoc; + }; + + /// Information about a template-id annotation + /// token. + /// + /// A template-id annotation token contains the template name, + /// template arguments, and the source locations for important + /// tokens. All of the information about template arguments is allocated + /// directly after this structure. + /// A template-id annotation token can also be generated by a type-constraint + /// construct with no explicit template arguments, e.g. "template<C T>" would + /// annotate C as a TemplateIdAnnotation with no template arguments (the angle + /// locations would be invalid in this case). + struct TemplateIdAnnotation final + : private llvm::TrailingObjects<TemplateIdAnnotation, + ParsedTemplateArgument> { + friend TrailingObjects; + /// TemplateKWLoc - The location of the template keyword. + /// For e.g. typename T::template Y<U> + SourceLocation TemplateKWLoc; + + /// TemplateNameLoc - The location of the template name within the + /// source. + SourceLocation TemplateNameLoc; + + /// FIXME: Temporarily stores the name of a specialization + IdentifierInfo *Name; + + /// FIXME: Temporarily stores the overloaded operator kind. + OverloadedOperatorKind Operator; + + /// The declaration of the template corresponding to the + /// template-name. + ParsedTemplateTy Template; + + /// The kind of template that Template refers to. If this is + /// TNK_Non_template, an error was encountered and diagnosed + /// when parsing or looking up the template name. + TemplateNameKind Kind; + + /// The location of the '<' before the template argument + /// list. + SourceLocation LAngleLoc; + + /// The location of the '>' after the template argument + /// list. + SourceLocation RAngleLoc; + + /// NumArgs - The number of template arguments. + unsigned NumArgs; + + /// Whether an error was encountered in the template arguments. + /// If so, NumArgs and the trailing arguments are best-effort. + bool ArgsInvalid; + + /// Retrieves a pointer to the template arguments + ParsedTemplateArgument *getTemplateArgs() { + return getTrailingObjects<ParsedTemplateArgument>(); + } + + /// Creates a new TemplateIdAnnotation with NumArgs arguments and + /// appends it to List. + static TemplateIdAnnotation * + Create(SourceLocation TemplateKWLoc, SourceLocation TemplateNameLoc, + IdentifierInfo *Name, OverloadedOperatorKind OperatorKind, + ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind, + SourceLocation LAngleLoc, SourceLocation RAngleLoc, + ArrayRef<ParsedTemplateArgument> TemplateArgs, bool ArgsInvalid, + SmallVectorImpl<TemplateIdAnnotation *> &CleanupList) { + TemplateIdAnnotation *TemplateId = new (llvm::safe_malloc( + totalSizeToAlloc<ParsedTemplateArgument>(TemplateArgs.size()))) + TemplateIdAnnotation(TemplateKWLoc, TemplateNameLoc, Name, + OperatorKind, OpaqueTemplateName, TemplateKind, + LAngleLoc, RAngleLoc, TemplateArgs, ArgsInvalid); + CleanupList.push_back(TemplateId); + return TemplateId; + } + + void Destroy() { + for (ParsedTemplateArgument &A : + llvm::make_range(getTemplateArgs(), getTemplateArgs() + NumArgs)) + A.~ParsedTemplateArgument(); + this->~TemplateIdAnnotation(); + free(this); + } + + /// Determine whether this might be a type template. + bool mightBeType() const { + return Kind == TNK_Non_template || + Kind == TNK_Type_template || + Kind == TNK_Dependent_template_name || + Kind == TNK_Undeclared_template; + } + + bool hasInvalidName() const { return Kind == TNK_Non_template; } + bool hasInvalidArgs() const { return ArgsInvalid; } + + bool isInvalid() const { return hasInvalidName() || hasInvalidArgs(); } + + private: + TemplateIdAnnotation(const TemplateIdAnnotation &) = delete; + + TemplateIdAnnotation(SourceLocation TemplateKWLoc, + SourceLocation TemplateNameLoc, IdentifierInfo *Name, + OverloadedOperatorKind OperatorKind, + ParsedTemplateTy OpaqueTemplateName, + TemplateNameKind TemplateKind, + SourceLocation LAngleLoc, SourceLocation RAngleLoc, + ArrayRef<ParsedTemplateArgument> TemplateArgs, + bool ArgsInvalid) noexcept + : TemplateKWLoc(TemplateKWLoc), TemplateNameLoc(TemplateNameLoc), + Name(Name), Operator(OperatorKind), Template(OpaqueTemplateName), + Kind(TemplateKind), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), + NumArgs(TemplateArgs.size()), ArgsInvalid(ArgsInvalid) { + + std::uninitialized_copy(TemplateArgs.begin(), TemplateArgs.end(), + getTemplateArgs()); + } + ~TemplateIdAnnotation() = default; + }; + + /// Retrieves the range of the given template parameter lists. + SourceRange getTemplateParamsRange(TemplateParameterList const *const *Params, + unsigned NumParams); +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_PARSEDTEMPLATE_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/RISCVIntrinsicManager.h b/contrib/libs/clang16/include/clang/Sema/RISCVIntrinsicManager.h new file mode 100644 index 0000000000..a5daf0737a --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/RISCVIntrinsicManager.h @@ -0,0 +1,46 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- RISCVIntrinsicManager.h - RISC-V Intrinsic Handler -------*- 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 defines the RISCVIntrinsicManager, which handles RISC-V vector +// intrinsic functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_RISCVINTRINSICMANAGER_H +#define LLVM_CLANG_SEMA_RISCVINTRINSICMANAGER_H + +namespace clang { +class LookupResult; +class IdentifierInfo; +class Preprocessor; + +namespace sema { +class RISCVIntrinsicManager { +public: + virtual ~RISCVIntrinsicManager() = default; + + // Create RISC-V intrinsic and insert into symbol table and return true if + // found, otherwise return false. + virtual bool CreateIntrinsicIfFound(LookupResult &LR, IdentifierInfo *II, + Preprocessor &PP) = 0; +}; +} // end namespace sema +} // end namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/Scope.h b/contrib/libs/clang16/include/clang/Sema/Scope.h new file mode 100644 index 0000000000..7873e593c3 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/Scope.h @@ -0,0 +1,581 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- Scope.h - Scope interface --------------------------------*- 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 defines the Scope interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SCOPE_H +#define LLVM_CLANG_SEMA_SCOPE_H + +#include "clang/AST/Decl.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator_range.h" +#include <cassert> +#include <optional> + +namespace llvm { + +class raw_ostream; + +} // namespace llvm + +namespace clang { + +class Decl; +class DeclContext; +class UsingDirectiveDecl; +class VarDecl; + +/// Scope - A scope is a transient data structure that is used while parsing the +/// program. It assists with resolving identifiers to the appropriate +/// declaration. +class Scope { +public: + /// ScopeFlags - These are bitfields that are or'd together when creating a + /// scope, which defines the sorts of things the scope contains. + enum ScopeFlags { + /// This indicates that the scope corresponds to a function, which + /// means that labels are set here. + FnScope = 0x01, + + /// This is a while, do, switch, for, etc that can have break + /// statements embedded into it. + BreakScope = 0x02, + + /// This is a while, do, for, which can have continue statements + /// embedded into it. + ContinueScope = 0x04, + + /// This is a scope that can contain a declaration. Some scopes + /// just contain loop constructs but don't contain decls. + DeclScope = 0x08, + + /// The controlling scope in a if/switch/while/for statement. + ControlScope = 0x10, + + /// The scope of a struct/union/class definition. + ClassScope = 0x20, + + /// This is a scope that corresponds to a block/closure object. + /// Blocks serve as top-level scopes for some objects like labels, they + /// also prevent things like break and continue. BlockScopes always have + /// the FnScope and DeclScope flags set as well. + BlockScope = 0x40, + + /// This is a scope that corresponds to the + /// template parameters of a C++ template. Template parameter + /// scope starts at the 'template' keyword and ends when the + /// template declaration ends. + TemplateParamScope = 0x80, + + /// This is a scope that corresponds to the + /// parameters within a function prototype. + FunctionPrototypeScope = 0x100, + + /// This is a scope that corresponds to the parameters within + /// a function prototype for a function declaration (as opposed to any + /// other kind of function declarator). Always has FunctionPrototypeScope + /// set as well. + FunctionDeclarationScope = 0x200, + + /// This is a scope that corresponds to the Objective-C + /// \@catch statement. + AtCatchScope = 0x400, + + /// This scope corresponds to an Objective-C method body. + /// It always has FnScope and DeclScope set as well. + ObjCMethodScope = 0x800, + + /// This is a scope that corresponds to a switch statement. + SwitchScope = 0x1000, + + /// This is the scope of a C++ try statement. + TryScope = 0x2000, + + /// This is the scope for a function-level C++ try or catch scope. + FnTryCatchScope = 0x4000, + + /// This is the scope of OpenMP executable directive. + OpenMPDirectiveScope = 0x8000, + + /// This is the scope of some OpenMP loop directive. + OpenMPLoopDirectiveScope = 0x10000, + + /// This is the scope of some OpenMP simd directive. + /// For example, it is used for 'omp simd', 'omp for simd'. + /// This flag is propagated to children scopes. + OpenMPSimdDirectiveScope = 0x20000, + + /// This scope corresponds to an enum. + EnumScope = 0x40000, + + /// This scope corresponds to an SEH try. + SEHTryScope = 0x80000, + + /// This scope corresponds to an SEH except. + SEHExceptScope = 0x100000, + + /// We are currently in the filter expression of an SEH except block. + SEHFilterScope = 0x200000, + + /// This is a compound statement scope. + CompoundStmtScope = 0x400000, + + /// We are between inheritance colon and the real class/struct definition + /// scope. + ClassInheritanceScope = 0x800000, + + /// This is the scope of a C++ catch statement. + CatchScope = 0x1000000, + + /// This is a scope in which a condition variable is currently being + /// parsed. If such a scope is a ContinueScope, it's invalid to jump to the + /// continue block from here. + ConditionVarScope = 0x2000000, + + /// This is a scope of some OpenMP directive with + /// order clause which specifies concurrent + OpenMPOrderClauseScope = 0x4000000, + }; + +private: + /// The parent scope for this scope. This is null for the translation-unit + /// scope. + Scope *AnyParent; + + /// Flags - This contains a set of ScopeFlags, which indicates how the scope + /// interrelates with other control flow statements. + unsigned Flags; + + /// Depth - This is the depth of this scope. The translation-unit scope has + /// depth 0. + unsigned short Depth; + + /// Declarations with static linkage are mangled with the number of + /// scopes seen as a component. + unsigned short MSLastManglingNumber; + + unsigned short MSCurManglingNumber; + + /// PrototypeDepth - This is the number of function prototype scopes + /// enclosing this scope, including this scope. + unsigned short PrototypeDepth; + + /// PrototypeIndex - This is the number of parameters currently + /// declared in this scope. + unsigned short PrototypeIndex; + + /// FnParent - If this scope has a parent scope that is a function body, this + /// pointer is non-null and points to it. This is used for label processing. + Scope *FnParent; + Scope *MSLastManglingParent; + + /// BreakParent/ContinueParent - This is a direct link to the innermost + /// BreakScope/ContinueScope which contains the contents of this scope + /// for control flow purposes (and might be this scope itself), or null + /// if there is no such scope. + Scope *BreakParent, *ContinueParent; + + /// BlockParent - This is a direct link to the immediately containing + /// BlockScope if this scope is not one, or null if there is none. + Scope *BlockParent; + + /// TemplateParamParent - This is a direct link to the + /// immediately containing template parameter scope. In the + /// case of nested templates, template parameter scopes can have + /// other template parameter scopes as parents. + Scope *TemplateParamParent; + + /// DeclsInScope - This keeps track of all declarations in this scope. When + /// the declaration is added to the scope, it is set as the current + /// declaration for the identifier in the IdentifierTable. When the scope is + /// popped, these declarations are removed from the IdentifierTable's notion + /// of current declaration. It is up to the current Action implementation to + /// implement these semantics. + using DeclSetTy = llvm::SmallPtrSet<Decl *, 32>; + DeclSetTy DeclsInScope; + + /// The DeclContext with which this scope is associated. For + /// example, the entity of a class scope is the class itself, the + /// entity of a function scope is a function, etc. + DeclContext *Entity; + + using UsingDirectivesTy = SmallVector<UsingDirectiveDecl *, 2>; + UsingDirectivesTy UsingDirectives; + + /// Used to determine if errors occurred in this scope. + DiagnosticErrorTrap ErrorTrap; + + /// A single NRVO candidate variable in this scope. + /// There are three possible values: + /// 1) pointer to VarDecl that denotes NRVO candidate itself. + /// 2) nullptr value means that NRVO is not allowed in this scope + /// (e.g. return a function parameter). + /// 3) std::nullopt value means that there is no NRVO candidate in this scope + /// (i.e. there are no return statements in this scope). + std::optional<VarDecl *> NRVO; + + /// Represents return slots for NRVO candidates in the current scope. + /// If a variable is present in this set, it means that a return slot is + /// available for this variable in the current scope. + llvm::SmallPtrSet<VarDecl *, 8> ReturnSlots; + + void setFlags(Scope *Parent, unsigned F); + +public: + Scope(Scope *Parent, unsigned ScopeFlags, DiagnosticsEngine &Diag) + : ErrorTrap(Diag) { + Init(Parent, ScopeFlags); + } + + /// getFlags - Return the flags for this scope. + unsigned getFlags() const { return Flags; } + + void setFlags(unsigned F) { setFlags(getParent(), F); } + + /// isBlockScope - Return true if this scope correspond to a closure. + bool isBlockScope() const { return Flags & BlockScope; } + + /// getParent - Return the scope that this is nested in. + const Scope *getParent() const { return AnyParent; } + Scope *getParent() { return AnyParent; } + + /// getFnParent - Return the closest scope that is a function body. + const Scope *getFnParent() const { return FnParent; } + Scope *getFnParent() { return FnParent; } + + const Scope *getMSLastManglingParent() const { + return MSLastManglingParent; + } + Scope *getMSLastManglingParent() { return MSLastManglingParent; } + + /// getContinueParent - Return the closest scope that a continue statement + /// would be affected by. + Scope *getContinueParent() { + return ContinueParent; + } + + const Scope *getContinueParent() const { + return const_cast<Scope*>(this)->getContinueParent(); + } + + // Set whether we're in the scope of a condition variable, where 'continue' + // is disallowed despite being a continue scope. + void setIsConditionVarScope(bool InConditionVarScope) { + Flags = (Flags & ~ConditionVarScope) | + (InConditionVarScope ? ConditionVarScope : 0); + } + + bool isConditionVarScope() const { + return Flags & ConditionVarScope; + } + + /// getBreakParent - Return the closest scope that a break statement + /// would be affected by. + Scope *getBreakParent() { + return BreakParent; + } + const Scope *getBreakParent() const { + return const_cast<Scope*>(this)->getBreakParent(); + } + + Scope *getBlockParent() { return BlockParent; } + const Scope *getBlockParent() const { return BlockParent; } + + Scope *getTemplateParamParent() { return TemplateParamParent; } + const Scope *getTemplateParamParent() const { return TemplateParamParent; } + + /// Returns the depth of this scope. The translation-unit has scope depth 0. + unsigned getDepth() const { return Depth; } + + /// Returns the number of function prototype scopes in this scope + /// chain. + unsigned getFunctionPrototypeDepth() const { + return PrototypeDepth; + } + + /// Return the number of parameters declared in this function + /// prototype, increasing it by one for the next call. + unsigned getNextFunctionPrototypeIndex() { + assert(isFunctionPrototypeScope()); + return PrototypeIndex++; + } + + using decl_range = llvm::iterator_range<DeclSetTy::iterator>; + + decl_range decls() const { + return decl_range(DeclsInScope.begin(), DeclsInScope.end()); + } + + bool decl_empty() const { return DeclsInScope.empty(); } + + void AddDecl(Decl *D) { + if (auto *VD = dyn_cast<VarDecl>(D)) + if (!isa<ParmVarDecl>(VD)) + ReturnSlots.insert(VD); + + DeclsInScope.insert(D); + } + + void RemoveDecl(Decl *D) { DeclsInScope.erase(D); } + + void incrementMSManglingNumber() { + if (Scope *MSLMP = getMSLastManglingParent()) { + MSLMP->MSLastManglingNumber += 1; + MSCurManglingNumber += 1; + } + } + + void decrementMSManglingNumber() { + if (Scope *MSLMP = getMSLastManglingParent()) { + MSLMP->MSLastManglingNumber -= 1; + MSCurManglingNumber -= 1; + } + } + + unsigned getMSLastManglingNumber() const { + if (const Scope *MSLMP = getMSLastManglingParent()) + return MSLMP->MSLastManglingNumber; + return 1; + } + + unsigned getMSCurManglingNumber() const { + return MSCurManglingNumber; + } + + /// isDeclScope - Return true if this is the scope that the specified decl is + /// declared in. + bool isDeclScope(const Decl *D) const { return DeclsInScope.contains(D); } + + /// Get the entity corresponding to this scope. + DeclContext *getEntity() const { + return isTemplateParamScope() ? nullptr : Entity; + } + + /// Get the DeclContext in which to continue unqualified lookup after a + /// lookup in this scope. + DeclContext *getLookupEntity() const { return Entity; } + + void setEntity(DeclContext *E) { + assert(!isTemplateParamScope() && + "entity associated with template param scope"); + Entity = E; + } + void setLookupEntity(DeclContext *E) { Entity = E; } + + /// Determine whether any unrecoverable errors have occurred within this + /// scope. Note that this may return false even if the scope contains invalid + /// declarations or statements, if the errors for those invalid constructs + /// were suppressed because some prior invalid construct was referenced. + bool hasUnrecoverableErrorOccurred() const { + return ErrorTrap.hasUnrecoverableErrorOccurred(); + } + + /// isFunctionScope() - Return true if this scope is a function scope. + bool isFunctionScope() const { return getFlags() & Scope::FnScope; } + + /// isClassScope - Return true if this scope is a class/struct/union scope. + bool isClassScope() const { return getFlags() & Scope::ClassScope; } + + /// Determines whether this scope is between inheritance colon and the real + /// class/struct definition. + bool isClassInheritanceScope() const { + return getFlags() & Scope::ClassInheritanceScope; + } + + /// isInCXXInlineMethodScope - Return true if this scope is a C++ inline + /// method scope or is inside one. + bool isInCXXInlineMethodScope() const { + if (const Scope *FnS = getFnParent()) { + assert(FnS->getParent() && "TUScope not created?"); + return FnS->getParent()->isClassScope(); + } + return false; + } + + /// isInObjcMethodScope - Return true if this scope is, or is contained in, an + /// Objective-C method body. Note that this method is not constant time. + bool isInObjcMethodScope() const { + for (const Scope *S = this; S; S = S->getParent()) { + // If this scope is an objc method scope, then we succeed. + if (S->getFlags() & ObjCMethodScope) + return true; + } + return false; + } + + /// isInObjcMethodOuterScope - Return true if this scope is an + /// Objective-C method outer most body. + bool isInObjcMethodOuterScope() const { + if (const Scope *S = this) { + // If this scope is an objc method scope, then we succeed. + if (S->getFlags() & ObjCMethodScope) + return true; + } + return false; + } + + /// isTemplateParamScope - Return true if this scope is a C++ + /// template parameter scope. + bool isTemplateParamScope() const { + return getFlags() & Scope::TemplateParamScope; + } + + /// isFunctionPrototypeScope - Return true if this scope is a + /// function prototype scope. + bool isFunctionPrototypeScope() const { + return getFlags() & Scope::FunctionPrototypeScope; + } + + /// isFunctionDeclarationScope - Return true if this scope is a + /// function prototype scope. + bool isFunctionDeclarationScope() const { + return getFlags() & Scope::FunctionDeclarationScope; + } + + /// isAtCatchScope - Return true if this scope is \@catch. + bool isAtCatchScope() const { + return getFlags() & Scope::AtCatchScope; + } + + /// isCatchScope - Return true if this scope is a C++ catch statement. + bool isCatchScope() const { return getFlags() & Scope::CatchScope; } + + /// isSwitchScope - Return true if this scope is a switch scope. + bool isSwitchScope() const { + for (const Scope *S = this; S; S = S->getParent()) { + if (S->getFlags() & Scope::SwitchScope) + return true; + else if (S->getFlags() & (Scope::FnScope | Scope::ClassScope | + Scope::BlockScope | Scope::TemplateParamScope | + Scope::FunctionPrototypeScope | + Scope::AtCatchScope | Scope::ObjCMethodScope)) + return false; + } + return false; + } + + /// Determines whether this scope is the OpenMP directive scope + bool isOpenMPDirectiveScope() const { + return (getFlags() & Scope::OpenMPDirectiveScope); + } + + /// Determine whether this scope is some OpenMP loop directive scope + /// (for example, 'omp for', 'omp simd'). + bool isOpenMPLoopDirectiveScope() const { + if (getFlags() & Scope::OpenMPLoopDirectiveScope) { + assert(isOpenMPDirectiveScope() && + "OpenMP loop directive scope is not a directive scope"); + return true; + } + return false; + } + + /// Determine whether this scope is (or is nested into) some OpenMP + /// loop simd directive scope (for example, 'omp simd', 'omp for simd'). + bool isOpenMPSimdDirectiveScope() const { + return getFlags() & Scope::OpenMPSimdDirectiveScope; + } + + /// Determine whether this scope is a loop having OpenMP loop + /// directive attached. + bool isOpenMPLoopScope() const { + const Scope *P = getParent(); + return P && P->isOpenMPLoopDirectiveScope(); + } + + /// Determine whether this scope is some OpenMP directive with + /// order clause which specifies concurrent scope. + bool isOpenMPOrderClauseScope() const { + return getFlags() & Scope::OpenMPOrderClauseScope; + } + + /// Determine whether this scope is a while/do/for statement, which can have + /// continue statements embedded into it. + bool isContinueScope() const { + return getFlags() & ScopeFlags::ContinueScope; + } + + /// Determine whether this scope is a C++ 'try' block. + bool isTryScope() const { return getFlags() & Scope::TryScope; } + + /// Determine whether this scope is a function-level C++ try or catch scope. + bool isFnTryCatchScope() const { + return getFlags() & ScopeFlags::FnTryCatchScope; + } + + /// Determine whether this scope is a SEH '__try' block. + bool isSEHTryScope() const { return getFlags() & Scope::SEHTryScope; } + + /// Determine whether this scope is a SEH '__except' block. + bool isSEHExceptScope() const { return getFlags() & Scope::SEHExceptScope; } + + /// Determine whether this scope is a compound statement scope. + bool isCompoundStmtScope() const { + return getFlags() & Scope::CompoundStmtScope; + } + + /// Determine whether this scope is a controlling scope in a + /// if/switch/while/for statement. + bool isControlScope() const { return getFlags() & Scope::ControlScope; } + + /// Returns if rhs has a higher scope depth than this. + /// + /// The caller is responsible for calling this only if one of the two scopes + /// is an ancestor of the other. + bool Contains(const Scope& rhs) const { return Depth < rhs.Depth; } + + /// containedInPrototypeScope - Return true if this or a parent scope + /// is a FunctionPrototypeScope. + bool containedInPrototypeScope() const; + + void PushUsingDirective(UsingDirectiveDecl *UDir) { + UsingDirectives.push_back(UDir); + } + + using using_directives_range = + llvm::iterator_range<UsingDirectivesTy::iterator>; + + using_directives_range using_directives() { + return using_directives_range(UsingDirectives.begin(), + UsingDirectives.end()); + } + + void updateNRVOCandidate(VarDecl *VD); + + void applyNRVO(); + + /// Init - This is used by the parser to implement scope caching. + void Init(Scope *parent, unsigned flags); + + /// Sets up the specified scope flags and adjusts the scope state + /// variables accordingly. + void AddFlags(unsigned Flags); + + void dumpImpl(raw_ostream &OS) const; + void dump() const; +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SCOPE_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/ScopeInfo.h b/contrib/libs/clang16/include/clang/Sema/ScopeInfo.h new file mode 100644 index 0000000000..8122f93acb --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/ScopeInfo.h @@ -0,0 +1,1078 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- ScopeInfo.h - Information about a semantic context -------*- 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 defines FunctionScopeInfo and its subclasses, which contain +// information about a single function, block, lambda, or method body. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SCOPEINFO_H +#define LLVM_CLANG_SEMA_SCOPEINFO_H + +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/Type.h" +#include "clang/Basic/CapturedStmt.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/CleanupInfo.h" +#include "clang/Sema/DeclSpec.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include <algorithm> +#include <cassert> +#include <utility> + +namespace clang { + +class BlockDecl; +class CapturedDecl; +class CXXMethodDecl; +class CXXRecordDecl; +class ImplicitParamDecl; +class NamedDecl; +class ObjCIvarRefExpr; +class ObjCMessageExpr; +class ObjCPropertyDecl; +class ObjCPropertyRefExpr; +class ParmVarDecl; +class RecordDecl; +class ReturnStmt; +class Scope; +class Stmt; +class SwitchStmt; +class TemplateParameterList; +class VarDecl; + +namespace sema { + +/// Contains information about the compound statement currently being +/// parsed. +class CompoundScopeInfo { +public: + /// Whether this compound stamement contains `for' or `while' loops + /// with empty bodies. + bool HasEmptyLoopBodies = false; + + /// Whether this compound statement corresponds to a GNU statement + /// expression. + bool IsStmtExpr; + + /// FP options at the beginning of the compound statement, prior to + /// any pragma. + FPOptions InitialFPFeatures; + + CompoundScopeInfo(bool IsStmtExpr, FPOptions FPO) + : IsStmtExpr(IsStmtExpr), InitialFPFeatures(FPO) {} + + void setHasEmptyLoopBodies() { + HasEmptyLoopBodies = true; + } +}; + +class PossiblyUnreachableDiag { +public: + PartialDiagnostic PD; + SourceLocation Loc; + llvm::TinyPtrVector<const Stmt*> Stmts; + + PossiblyUnreachableDiag(const PartialDiagnostic &PD, SourceLocation Loc, + ArrayRef<const Stmt *> Stmts) + : PD(PD), Loc(Loc), Stmts(Stmts) {} +}; + +/// Retains information about a function, method, or block that is +/// currently being parsed. +class FunctionScopeInfo { +protected: + enum ScopeKind { + SK_Function, + SK_Block, + SK_Lambda, + SK_CapturedRegion + }; + +public: + /// What kind of scope we are describing. + ScopeKind Kind : 3; + + /// Whether this function contains a VLA, \@try, try, C++ + /// initializer, or anything else that can't be jumped past. + bool HasBranchProtectedScope : 1; + + /// Whether this function contains any switches or direct gotos. + bool HasBranchIntoScope : 1; + + /// Whether this function contains any indirect gotos. + bool HasIndirectGoto : 1; + + /// Whether this function contains any statement marked with + /// \c [[clang::musttail]]. + bool HasMustTail : 1; + + /// Whether a statement was dropped because it was invalid. + bool HasDroppedStmt : 1; + + /// True if current scope is for OpenMP declare reduction combiner. + bool HasOMPDeclareReductionCombiner : 1; + + /// Whether there is a fallthrough statement in this function. + bool HasFallthroughStmt : 1; + + /// Whether this function uses constrained floating point intrinsics + bool UsesFPIntrin : 1; + + /// Whether we make reference to a declaration that could be + /// unavailable. + bool HasPotentialAvailabilityViolations : 1; + + /// A flag that is set when parsing a method that must call super's + /// implementation, such as \c -dealloc, \c -finalize, or any method marked + /// with \c __attribute__((objc_requires_super)). + bool ObjCShouldCallSuper : 1; + + /// True when this is a method marked as a designated initializer. + bool ObjCIsDesignatedInit : 1; + + /// This starts true for a method marked as designated initializer and will + /// be set to false if there is an invocation to a designated initializer of + /// the super class. + bool ObjCWarnForNoDesignatedInitChain : 1; + + /// True when this is an initializer method not marked as a designated + /// initializer within a class that has at least one initializer marked as a + /// designated initializer. + bool ObjCIsSecondaryInit : 1; + + /// This starts true for a secondary initializer method and will be set to + /// false if there is an invocation of an initializer on 'self'. + bool ObjCWarnForNoInitDelegation : 1; + + /// True only when this function has not already built, or attempted + /// to build, the initial and final coroutine suspend points + bool NeedsCoroutineSuspends : 1; + + /// An enumeration represeting the kind of the first coroutine statement + /// in the function. One of co_return, co_await, or co_yield. + unsigned char FirstCoroutineStmtKind : 2; + + /// First coroutine statement in the current function. + /// (ex co_return, co_await, co_yield) + SourceLocation FirstCoroutineStmtLoc; + + /// First 'return' statement in the current function. + SourceLocation FirstReturnLoc; + + /// First C++ 'try' or ObjC @try statement in the current function. + SourceLocation FirstCXXOrObjCTryLoc; + enum { TryLocIsCXX, TryLocIsObjC, Unknown } FirstTryType = Unknown; + + /// First SEH '__try' statement in the current function. + SourceLocation FirstSEHTryLoc; + +private: + /// Used to determine if errors occurred in this function or block. + DiagnosticErrorTrap ErrorTrap; + +public: + /// A SwitchStmt, along with a flag indicating if its list of case statements + /// is incomplete (because we dropped an invalid one while parsing). + using SwitchInfo = llvm::PointerIntPair<SwitchStmt*, 1, bool>; + + /// SwitchStack - This is the current set of active switch statements in the + /// block. + SmallVector<SwitchInfo, 8> SwitchStack; + + /// The list of return statements that occur within the function or + /// block, if there is any chance of applying the named return value + /// optimization, or if we need to infer a return type. + SmallVector<ReturnStmt*, 4> Returns; + + /// The promise object for this coroutine, if any. + VarDecl *CoroutinePromise = nullptr; + + /// A mapping between the coroutine function parameters that were moved + /// to the coroutine frame, and their move statements. + llvm::SmallMapVector<ParmVarDecl *, Stmt *, 4> CoroutineParameterMoves; + + /// The initial and final coroutine suspend points. + std::pair<Stmt *, Stmt *> CoroutineSuspends; + + /// The stack of currently active compound stamement scopes in the + /// function. + SmallVector<CompoundScopeInfo, 4> CompoundScopes; + + /// The set of blocks that are introduced in this function. + llvm::SmallPtrSet<const BlockDecl *, 1> Blocks; + + /// The set of __block variables that are introduced in this function. + llvm::TinyPtrVector<VarDecl *> ByrefBlockVars; + + /// A list of PartialDiagnostics created but delayed within the + /// current function scope. These diagnostics are vetted for reachability + /// prior to being emitted. + SmallVector<PossiblyUnreachableDiag, 4> PossiblyUnreachableDiags; + + /// A list of parameters which have the nonnull attribute and are + /// modified in the function. + llvm::SmallPtrSet<const ParmVarDecl *, 8> ModifiedNonNullParams; + + /// The set of GNU address of label extension "&&label". + llvm::SmallVector<AddrLabelExpr *, 4> AddrLabels; + +public: + /// Represents a simple identification of a weak object. + /// + /// Part of the implementation of -Wrepeated-use-of-weak. + /// + /// This is used to determine if two weak accesses refer to the same object. + /// Here are some examples of how various accesses are "profiled": + /// + /// Access Expression | "Base" Decl | "Property" Decl + /// :---------------: | :-----------------: | :------------------------------: + /// self.property | self (VarDecl) | property (ObjCPropertyDecl) + /// self.implicitProp | self (VarDecl) | -implicitProp (ObjCMethodDecl) + /// self->ivar.prop | ivar (ObjCIvarDecl) | prop (ObjCPropertyDecl) + /// cxxObj.obj.prop | obj (FieldDecl) | prop (ObjCPropertyDecl) + /// [self foo].prop | 0 (unknown) | prop (ObjCPropertyDecl) + /// self.prop1.prop2 | prop1 (ObjCPropertyDecl) | prop2 (ObjCPropertyDecl) + /// MyClass.prop | MyClass (ObjCInterfaceDecl) | -prop (ObjCMethodDecl) + /// MyClass.foo.prop | +foo (ObjCMethodDecl) | -prop (ObjCPropertyDecl) + /// weakVar | 0 (known) | weakVar (VarDecl) + /// self->weakIvar | self (VarDecl) | weakIvar (ObjCIvarDecl) + /// + /// Objects are identified with only two Decls to make it reasonably fast to + /// compare them. + class WeakObjectProfileTy { + /// The base object decl, as described in the class documentation. + /// + /// The extra flag is "true" if the Base and Property are enough to uniquely + /// identify the object in memory. + /// + /// \sa isExactProfile() + using BaseInfoTy = llvm::PointerIntPair<const NamedDecl *, 1, bool>; + BaseInfoTy Base; + + /// The "property" decl, as described in the class documentation. + /// + /// Note that this may not actually be an ObjCPropertyDecl, e.g. in the + /// case of "implicit" properties (regular methods accessed via dot syntax). + const NamedDecl *Property = nullptr; + + /// Used to find the proper base profile for a given base expression. + static BaseInfoTy getBaseInfo(const Expr *BaseE); + + inline WeakObjectProfileTy(); + static inline WeakObjectProfileTy getSentinel(); + + public: + WeakObjectProfileTy(const ObjCPropertyRefExpr *RE); + WeakObjectProfileTy(const Expr *Base, const ObjCPropertyDecl *Property); + WeakObjectProfileTy(const DeclRefExpr *RE); + WeakObjectProfileTy(const ObjCIvarRefExpr *RE); + + const NamedDecl *getBase() const { return Base.getPointer(); } + const NamedDecl *getProperty() const { return Property; } + + /// Returns true if the object base specifies a known object in memory, + /// rather than, say, an instance variable or property of another object. + /// + /// Note that this ignores the effects of aliasing; that is, \c foo.bar is + /// considered an exact profile if \c foo is a local variable, even if + /// another variable \c foo2 refers to the same object as \c foo. + /// + /// For increased precision, accesses with base variables that are + /// properties or ivars of 'self' (e.g. self.prop1.prop2) are considered to + /// be exact, though this is not true for arbitrary variables + /// (foo.prop1.prop2). + bool isExactProfile() const { + return Base.getInt(); + } + + bool operator==(const WeakObjectProfileTy &Other) const { + return Base == Other.Base && Property == Other.Property; + } + + // For use in DenseMap. + // We can't specialize the usual llvm::DenseMapInfo at the end of the file + // because by that point the DenseMap in FunctionScopeInfo has already been + // instantiated. + class DenseMapInfo { + public: + static inline WeakObjectProfileTy getEmptyKey() { + return WeakObjectProfileTy(); + } + + static inline WeakObjectProfileTy getTombstoneKey() { + return WeakObjectProfileTy::getSentinel(); + } + + static unsigned getHashValue(const WeakObjectProfileTy &Val) { + using Pair = std::pair<BaseInfoTy, const NamedDecl *>; + + return llvm::DenseMapInfo<Pair>::getHashValue(Pair(Val.Base, + Val.Property)); + } + + static bool isEqual(const WeakObjectProfileTy &LHS, + const WeakObjectProfileTy &RHS) { + return LHS == RHS; + } + }; + }; + + /// Represents a single use of a weak object. + /// + /// Stores both the expression and whether the access is potentially unsafe + /// (i.e. it could potentially be warned about). + /// + /// Part of the implementation of -Wrepeated-use-of-weak. + class WeakUseTy { + llvm::PointerIntPair<const Expr *, 1, bool> Rep; + + public: + WeakUseTy(const Expr *Use, bool IsRead) : Rep(Use, IsRead) {} + + const Expr *getUseExpr() const { return Rep.getPointer(); } + bool isUnsafe() const { return Rep.getInt(); } + void markSafe() { Rep.setInt(false); } + + bool operator==(const WeakUseTy &Other) const { + return Rep == Other.Rep; + } + }; + + /// Used to collect uses of a particular weak object in a function body. + /// + /// Part of the implementation of -Wrepeated-use-of-weak. + using WeakUseVector = SmallVector<WeakUseTy, 4>; + + /// Used to collect all uses of weak objects in a function body. + /// + /// Part of the implementation of -Wrepeated-use-of-weak. + using WeakObjectUseMap = + llvm::SmallDenseMap<WeakObjectProfileTy, WeakUseVector, 8, + WeakObjectProfileTy::DenseMapInfo>; + +private: + /// Used to collect all uses of weak objects in this function body. + /// + /// Part of the implementation of -Wrepeated-use-of-weak. + WeakObjectUseMap WeakObjectUses; + +protected: + FunctionScopeInfo(const FunctionScopeInfo&) = default; + +public: + FunctionScopeInfo(DiagnosticsEngine &Diag) + : Kind(SK_Function), HasBranchProtectedScope(false), + HasBranchIntoScope(false), HasIndirectGoto(false), HasMustTail(false), + HasDroppedStmt(false), HasOMPDeclareReductionCombiner(false), + HasFallthroughStmt(false), UsesFPIntrin(false), + HasPotentialAvailabilityViolations(false), ObjCShouldCallSuper(false), + ObjCIsDesignatedInit(false), ObjCWarnForNoDesignatedInitChain(false), + ObjCIsSecondaryInit(false), ObjCWarnForNoInitDelegation(false), + NeedsCoroutineSuspends(true), ErrorTrap(Diag) {} + + virtual ~FunctionScopeInfo(); + + /// Determine whether an unrecoverable error has occurred within this + /// function. Note that this may return false even if the function body is + /// invalid, because the errors may be suppressed if they're caused by prior + /// invalid declarations. + /// + /// FIXME: Migrate the caller of this to use containsErrors() instead once + /// it's ready. + bool hasUnrecoverableErrorOccurred() const { + return ErrorTrap.hasUnrecoverableErrorOccurred(); + } + + /// Record that a weak object was accessed. + /// + /// Part of the implementation of -Wrepeated-use-of-weak. + template <typename ExprT> + inline void recordUseOfWeak(const ExprT *E, bool IsRead = true); + + void recordUseOfWeak(const ObjCMessageExpr *Msg, + const ObjCPropertyDecl *Prop); + + /// Record that a given expression is a "safe" access of a weak object (e.g. + /// assigning it to a strong variable.) + /// + /// Part of the implementation of -Wrepeated-use-of-weak. + void markSafeWeakUse(const Expr *E); + + const WeakObjectUseMap &getWeakObjectUses() const { + return WeakObjectUses; + } + + void setHasBranchIntoScope() { + HasBranchIntoScope = true; + } + + void setHasBranchProtectedScope() { + HasBranchProtectedScope = true; + } + + void setHasIndirectGoto() { + HasIndirectGoto = true; + } + + void setHasMustTail() { HasMustTail = true; } + + void setHasDroppedStmt() { + HasDroppedStmt = true; + } + + void setHasOMPDeclareReductionCombiner() { + HasOMPDeclareReductionCombiner = true; + } + + void setHasFallthroughStmt() { + HasFallthroughStmt = true; + } + + void setUsesFPIntrin() { + UsesFPIntrin = true; + } + + void setHasCXXTry(SourceLocation TryLoc) { + setHasBranchProtectedScope(); + FirstCXXOrObjCTryLoc = TryLoc; + FirstTryType = TryLocIsCXX; + } + + void setHasObjCTry(SourceLocation TryLoc) { + setHasBranchProtectedScope(); + FirstCXXOrObjCTryLoc = TryLoc; + FirstTryType = TryLocIsObjC; + } + + void setHasSEHTry(SourceLocation TryLoc) { + setHasBranchProtectedScope(); + FirstSEHTryLoc = TryLoc; + } + + bool NeedsScopeChecking() const { + return !HasDroppedStmt && (HasIndirectGoto || HasMustTail || + (HasBranchProtectedScope && HasBranchIntoScope)); + } + + // Add a block introduced in this function. + void addBlock(const BlockDecl *BD) { + Blocks.insert(BD); + } + + // Add a __block variable introduced in this function. + void addByrefBlockVar(VarDecl *VD) { + ByrefBlockVars.push_back(VD); + } + + bool isCoroutine() const { return !FirstCoroutineStmtLoc.isInvalid(); } + + void setFirstCoroutineStmt(SourceLocation Loc, StringRef Keyword) { + assert(FirstCoroutineStmtLoc.isInvalid() && + "first coroutine statement location already set"); + FirstCoroutineStmtLoc = Loc; + FirstCoroutineStmtKind = llvm::StringSwitch<unsigned char>(Keyword) + .Case("co_return", 0) + .Case("co_await", 1) + .Case("co_yield", 2); + } + + StringRef getFirstCoroutineStmtKeyword() const { + assert(FirstCoroutineStmtLoc.isValid() + && "no coroutine statement available"); + switch (FirstCoroutineStmtKind) { + case 0: return "co_return"; + case 1: return "co_await"; + case 2: return "co_yield"; + default: + llvm_unreachable("FirstCoroutineStmtKind has an invalid value"); + }; + } + + void setNeedsCoroutineSuspends(bool value = true) { + assert((!value || CoroutineSuspends.first == nullptr) && + "we already have valid suspend points"); + NeedsCoroutineSuspends = value; + } + + bool hasInvalidCoroutineSuspends() const { + return !NeedsCoroutineSuspends && CoroutineSuspends.first == nullptr; + } + + void setCoroutineSuspends(Stmt *Initial, Stmt *Final) { + assert(Initial && Final && "suspend points cannot be null"); + assert(CoroutineSuspends.first == nullptr && "suspend points already set"); + NeedsCoroutineSuspends = false; + CoroutineSuspends.first = Initial; + CoroutineSuspends.second = Final; + } + + /// Clear out the information in this function scope, making it + /// suitable for reuse. + void Clear(); + + bool isPlainFunction() const { return Kind == SK_Function; } +}; + +class Capture { + // There are three categories of capture: capturing 'this', capturing + // local variables, and C++1y initialized captures (which can have an + // arbitrary initializer, and don't really capture in the traditional + // sense at all). + // + // There are three ways to capture a local variable: + // - capture by copy in the C++11 sense, + // - capture by reference in the C++11 sense, and + // - __block capture. + // Lambdas explicitly specify capture by copy or capture by reference. + // For blocks, __block capture applies to variables with that annotation, + // variables of reference type are captured by reference, and other + // variables are captured by copy. + enum CaptureKind { + Cap_ByCopy, Cap_ByRef, Cap_Block, Cap_VLA + }; + + union { + /// If Kind == Cap_VLA, the captured type. + const VariableArrayType *CapturedVLA; + + /// Otherwise, the captured variable (if any). + ValueDecl *CapturedVar; + }; + + /// The source location at which the first capture occurred. + SourceLocation Loc; + + /// The location of the ellipsis that expands a parameter pack. + SourceLocation EllipsisLoc; + + /// The type as it was captured, which is the type of the non-static data + /// member that would hold the capture. + QualType CaptureType; + + /// The CaptureKind of this capture. + unsigned Kind : 2; + + /// Whether this is a nested capture (a capture of an enclosing capturing + /// scope's capture). + unsigned Nested : 1; + + /// Whether this is a capture of '*this'. + unsigned CapturesThis : 1; + + /// Whether an explicit capture has been odr-used in the body of the + /// lambda. + unsigned ODRUsed : 1; + + /// Whether an explicit capture has been non-odr-used in the body of + /// the lambda. + unsigned NonODRUsed : 1; + + /// Whether the capture is invalid (a capture was required but the entity is + /// non-capturable). + unsigned Invalid : 1; + +public: + Capture(ValueDecl *Var, bool Block, bool ByRef, bool IsNested, + SourceLocation Loc, SourceLocation EllipsisLoc, QualType CaptureType, + bool Invalid) + : CapturedVar(Var), Loc(Loc), EllipsisLoc(EllipsisLoc), + CaptureType(CaptureType), Kind(Block ? Cap_Block + : ByRef ? Cap_ByRef + : Cap_ByCopy), + Nested(IsNested), CapturesThis(false), ODRUsed(false), + NonODRUsed(false), Invalid(Invalid) {} + + enum IsThisCapture { ThisCapture }; + Capture(IsThisCapture, bool IsNested, SourceLocation Loc, + QualType CaptureType, const bool ByCopy, bool Invalid) + : Loc(Loc), CaptureType(CaptureType), + Kind(ByCopy ? Cap_ByCopy : Cap_ByRef), Nested(IsNested), + CapturesThis(true), ODRUsed(false), NonODRUsed(false), + Invalid(Invalid) {} + + enum IsVLACapture { VLACapture }; + Capture(IsVLACapture, const VariableArrayType *VLA, bool IsNested, + SourceLocation Loc, QualType CaptureType) + : CapturedVLA(VLA), Loc(Loc), CaptureType(CaptureType), Kind(Cap_VLA), + Nested(IsNested), CapturesThis(false), ODRUsed(false), + NonODRUsed(false), Invalid(false) {} + + bool isThisCapture() const { return CapturesThis; } + bool isVariableCapture() const { + return !isThisCapture() && !isVLATypeCapture(); + } + + bool isCopyCapture() const { return Kind == Cap_ByCopy; } + bool isReferenceCapture() const { return Kind == Cap_ByRef; } + bool isBlockCapture() const { return Kind == Cap_Block; } + bool isVLATypeCapture() const { return Kind == Cap_VLA; } + + bool isNested() const { return Nested; } + + bool isInvalid() const { return Invalid; } + + /// Determine whether this capture is an init-capture. + bool isInitCapture() const; + + bool isODRUsed() const { return ODRUsed; } + bool isNonODRUsed() const { return NonODRUsed; } + void markUsed(bool IsODRUse) { + if (IsODRUse) + ODRUsed = true; + else + NonODRUsed = true; + } + + ValueDecl *getVariable() const { + assert(isVariableCapture()); + return CapturedVar; + } + + const VariableArrayType *getCapturedVLAType() const { + assert(isVLATypeCapture()); + return CapturedVLA; + } + + /// Retrieve the location at which this variable was captured. + SourceLocation getLocation() const { return Loc; } + + /// Retrieve the source location of the ellipsis, whose presence + /// indicates that the capture is a pack expansion. + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + + /// Retrieve the capture type for this capture, which is effectively + /// the type of the non-static data member in the lambda/block structure + /// that would store this capture. + QualType getCaptureType() const { return CaptureType; } +}; + +class CapturingScopeInfo : public FunctionScopeInfo { +protected: + CapturingScopeInfo(const CapturingScopeInfo&) = default; + +public: + enum ImplicitCaptureStyle { + ImpCap_None, ImpCap_LambdaByval, ImpCap_LambdaByref, ImpCap_Block, + ImpCap_CapturedRegion + }; + + ImplicitCaptureStyle ImpCaptureStyle; + + CapturingScopeInfo(DiagnosticsEngine &Diag, ImplicitCaptureStyle Style) + : FunctionScopeInfo(Diag), ImpCaptureStyle(Style) {} + + /// CaptureMap - A map of captured variables to (index+1) into Captures. + llvm::DenseMap<ValueDecl *, unsigned> CaptureMap; + + /// CXXThisCaptureIndex - The (index+1) of the capture of 'this'; + /// zero if 'this' is not captured. + unsigned CXXThisCaptureIndex = 0; + + /// Captures - The captures. + SmallVector<Capture, 4> Captures; + + /// - Whether the target type of return statements in this context + /// is deduced (e.g. a lambda or block with omitted return type). + bool HasImplicitReturnType = false; + + /// ReturnType - The target type of return statements in this context, + /// or null if unknown. + QualType ReturnType; + + void addCapture(ValueDecl *Var, bool isBlock, bool isByref, bool isNested, + SourceLocation Loc, SourceLocation EllipsisLoc, + QualType CaptureType, bool Invalid) { + Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc, + EllipsisLoc, CaptureType, Invalid)); + CaptureMap[Var] = Captures.size(); + } + + void addVLATypeCapture(SourceLocation Loc, const VariableArrayType *VLAType, + QualType CaptureType) { + Captures.push_back(Capture(Capture::VLACapture, VLAType, + /*FIXME: IsNested*/ false, Loc, CaptureType)); + } + + void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType, + bool ByCopy); + + /// Determine whether the C++ 'this' is captured. + bool isCXXThisCaptured() const { return CXXThisCaptureIndex != 0; } + + /// Retrieve the capture of C++ 'this', if it has been captured. + Capture &getCXXThisCapture() { + assert(isCXXThisCaptured() && "this has not been captured"); + return Captures[CXXThisCaptureIndex - 1]; + } + + /// Determine whether the given variable has been captured. + bool isCaptured(ValueDecl *Var) const { return CaptureMap.count(Var); } + + /// Determine whether the given variable-array type has been captured. + bool isVLATypeCaptured(const VariableArrayType *VAT) const; + + /// Retrieve the capture of the given variable, if it has been + /// captured already. + Capture &getCapture(ValueDecl *Var) { + assert(isCaptured(Var) && "Variable has not been captured"); + return Captures[CaptureMap[Var] - 1]; + } + + const Capture &getCapture(ValueDecl *Var) const { + llvm::DenseMap<ValueDecl *, unsigned>::const_iterator Known = + CaptureMap.find(Var); + assert(Known != CaptureMap.end() && "Variable has not been captured"); + return Captures[Known->second - 1]; + } + + static bool classof(const FunctionScopeInfo *FSI) { + return FSI->Kind == SK_Block || FSI->Kind == SK_Lambda + || FSI->Kind == SK_CapturedRegion; + } +}; + +/// Retains information about a block that is currently being parsed. +class BlockScopeInfo final : public CapturingScopeInfo { +public: + BlockDecl *TheDecl; + + /// TheScope - This is the scope for the block itself, which contains + /// arguments etc. + Scope *TheScope; + + /// BlockType - The function type of the block, if one was given. + /// Its return type may be BuiltinType::Dependent. + QualType FunctionType; + + BlockScopeInfo(DiagnosticsEngine &Diag, Scope *BlockScope, BlockDecl *Block) + : CapturingScopeInfo(Diag, ImpCap_Block), TheDecl(Block), + TheScope(BlockScope) { + Kind = SK_Block; + } + + ~BlockScopeInfo() override; + + static bool classof(const FunctionScopeInfo *FSI) { + return FSI->Kind == SK_Block; + } +}; + +/// Retains information about a captured region. +class CapturedRegionScopeInfo final : public CapturingScopeInfo { +public: + /// The CapturedDecl for this statement. + CapturedDecl *TheCapturedDecl; + + /// The captured record type. + RecordDecl *TheRecordDecl; + + /// This is the enclosing scope of the captured region. + Scope *TheScope; + + /// The implicit parameter for the captured variables. + ImplicitParamDecl *ContextParam; + + /// The kind of captured region. + unsigned short CapRegionKind; + + unsigned short OpenMPLevel; + unsigned short OpenMPCaptureLevel; + + CapturedRegionScopeInfo(DiagnosticsEngine &Diag, Scope *S, CapturedDecl *CD, + RecordDecl *RD, ImplicitParamDecl *Context, + CapturedRegionKind K, unsigned OpenMPLevel, + unsigned OpenMPCaptureLevel) + : CapturingScopeInfo(Diag, ImpCap_CapturedRegion), + TheCapturedDecl(CD), TheRecordDecl(RD), TheScope(S), + ContextParam(Context), CapRegionKind(K), OpenMPLevel(OpenMPLevel), + OpenMPCaptureLevel(OpenMPCaptureLevel) { + Kind = SK_CapturedRegion; + } + + ~CapturedRegionScopeInfo() override; + + /// A descriptive name for the kind of captured region this is. + StringRef getRegionName() const { + switch (CapRegionKind) { + case CR_Default: + return "default captured statement"; + case CR_ObjCAtFinally: + return "Objective-C @finally statement"; + case CR_OpenMP: + return "OpenMP region"; + } + llvm_unreachable("Invalid captured region kind!"); + } + + static bool classof(const FunctionScopeInfo *FSI) { + return FSI->Kind == SK_CapturedRegion; + } +}; + +class LambdaScopeInfo final : + public CapturingScopeInfo, public InventedTemplateParameterInfo { +public: + /// The class that describes the lambda. + CXXRecordDecl *Lambda = nullptr; + + /// The lambda's compiler-generated \c operator(). + CXXMethodDecl *CallOperator = nullptr; + + /// Source range covering the lambda introducer [...]. + SourceRange IntroducerRange; + + /// Source location of the '&' or '=' specifying the default capture + /// type, if any. + SourceLocation CaptureDefaultLoc; + + /// The number of captures in the \c Captures list that are + /// explicit captures. + unsigned NumExplicitCaptures = 0; + + /// Whether this is a mutable lambda. + bool Mutable = false; + + /// Whether the (empty) parameter list is explicit. + bool ExplicitParams = false; + + /// Whether any of the capture expressions requires cleanups. + CleanupInfo Cleanup; + + /// Whether the lambda contains an unexpanded parameter pack. + bool ContainsUnexpandedParameterPack = false; + + /// Packs introduced by this lambda, if any. + SmallVector<NamedDecl*, 4> LocalPacks; + + /// Source range covering the explicit template parameter list (if it exists). + SourceRange ExplicitTemplateParamsRange; + + /// The requires-clause immediately following the explicit template parameter + /// list, if any. (Note that there may be another requires-clause included as + /// part of the lambda-declarator.) + ExprResult RequiresClause; + + /// If this is a generic lambda, and the template parameter + /// list has been created (from the TemplateParams) then store + /// a reference to it (cache it to avoid reconstructing it). + TemplateParameterList *GLTemplateParameterList = nullptr; + + /// Contains all variable-referring-expressions (i.e. DeclRefExprs + /// or MemberExprs) that refer to local variables in a generic lambda + /// or a lambda in a potentially-evaluated-if-used context. + /// + /// Potentially capturable variables of a nested lambda that might need + /// to be captured by the lambda are housed here. + /// This is specifically useful for generic lambdas or + /// lambdas within a potentially evaluated-if-used context. + /// If an enclosing variable is named in an expression of a lambda nested + /// within a generic lambda, we don't always know whether the variable + /// will truly be odr-used (i.e. need to be captured) by that nested lambda, + /// until its instantiation. But we still need to capture it in the + /// enclosing lambda if all intervening lambdas can capture the variable. + llvm::SmallVector<Expr*, 4> PotentiallyCapturingExprs; + + /// Contains all variable-referring-expressions that refer + /// to local variables that are usable as constant expressions and + /// do not involve an odr-use (they may still need to be captured + /// if the enclosing full-expression is instantiation dependent). + llvm::SmallSet<Expr *, 8> NonODRUsedCapturingExprs; + + /// A map of explicit capture indices to their introducer source ranges. + llvm::DenseMap<unsigned, SourceRange> ExplicitCaptureRanges; + + /// Contains all of the variables defined in this lambda that shadow variables + /// that were defined in parent contexts. Used to avoid warnings when the + /// shadowed variables are uncaptured by this lambda. + struct ShadowedOuterDecl { + const VarDecl *VD; + const VarDecl *ShadowedDecl; + }; + llvm::SmallVector<ShadowedOuterDecl, 4> ShadowingDecls; + + SourceLocation PotentialThisCaptureLocation; + + LambdaScopeInfo(DiagnosticsEngine &Diag) + : CapturingScopeInfo(Diag, ImpCap_None) { + Kind = SK_Lambda; + } + + /// Note when all explicit captures have been added. + void finishedExplicitCaptures() { + NumExplicitCaptures = Captures.size(); + } + + static bool classof(const FunctionScopeInfo *FSI) { + return FSI->Kind == SK_Lambda; + } + + /// Is this scope known to be for a generic lambda? (This will be false until + /// we parse a template parameter list or the first 'auto'-typed parameter). + bool isGenericLambda() const { + return !TemplateParams.empty() || GLTemplateParameterList; + } + + /// Add a variable that might potentially be captured by the + /// lambda and therefore the enclosing lambdas. + /// + /// This is also used by enclosing lambda's to speculatively capture + /// variables that nested lambda's - depending on their enclosing + /// specialization - might need to capture. + /// Consider: + /// void f(int, int); <-- don't capture + /// void f(const int&, double); <-- capture + /// void foo() { + /// const int x = 10; + /// auto L = [=](auto a) { // capture 'x' + /// return [=](auto b) { + /// f(x, a); // we may or may not need to capture 'x' + /// }; + /// }; + /// } + void addPotentialCapture(Expr *VarExpr) { + assert(isa<DeclRefExpr>(VarExpr) || isa<MemberExpr>(VarExpr) || + isa<FunctionParmPackExpr>(VarExpr)); + PotentiallyCapturingExprs.push_back(VarExpr); + } + + void addPotentialThisCapture(SourceLocation Loc) { + PotentialThisCaptureLocation = Loc; + } + + bool hasPotentialThisCapture() const { + return PotentialThisCaptureLocation.isValid(); + } + + /// Mark a variable's reference in a lambda as non-odr using. + /// + /// For generic lambdas, if a variable is named in a potentially evaluated + /// expression, where the enclosing full expression is dependent then we + /// must capture the variable (given a default capture). + /// This is accomplished by recording all references to variables + /// (DeclRefExprs or MemberExprs) within said nested lambda in its array of + /// PotentialCaptures. All such variables have to be captured by that lambda, + /// except for as described below. + /// If that variable is usable as a constant expression and is named in a + /// manner that does not involve its odr-use (e.g. undergoes + /// lvalue-to-rvalue conversion, or discarded) record that it is so. Upon the + /// act of analyzing the enclosing full expression (ActOnFinishFullExpr) + /// if we can determine that the full expression is not instantiation- + /// dependent, then we can entirely avoid its capture. + /// + /// const int n = 0; + /// [&] (auto x) { + /// (void)+n + x; + /// }; + /// Interestingly, this strategy would involve a capture of n, even though + /// it's obviously not odr-used here, because the full-expression is + /// instantiation-dependent. It could be useful to avoid capturing such + /// variables, even when they are referred to in an instantiation-dependent + /// expression, if we can unambiguously determine that they shall never be + /// odr-used. This would involve removal of the variable-referring-expression + /// from the array of PotentialCaptures during the lvalue-to-rvalue + /// conversions. But per the working draft N3797, (post-chicago 2013) we must + /// capture such variables. + /// Before anyone is tempted to implement a strategy for not-capturing 'n', + /// consider the insightful warning in: + /// /cfe-commits/Week-of-Mon-20131104/092596.html + /// "The problem is that the set of captures for a lambda is part of the ABI + /// (since lambda layout can be made visible through inline functions and the + /// like), and there are no guarantees as to which cases we'll manage to build + /// an lvalue-to-rvalue conversion in, when parsing a template -- some + /// seemingly harmless change elsewhere in Sema could cause us to start or stop + /// building such a node. So we need a rule that anyone can implement and get + /// exactly the same result". + void markVariableExprAsNonODRUsed(Expr *CapturingVarExpr) { + assert(isa<DeclRefExpr>(CapturingVarExpr) || + isa<MemberExpr>(CapturingVarExpr) || + isa<FunctionParmPackExpr>(CapturingVarExpr)); + NonODRUsedCapturingExprs.insert(CapturingVarExpr); + } + bool isVariableExprMarkedAsNonODRUsed(Expr *CapturingVarExpr) const { + assert(isa<DeclRefExpr>(CapturingVarExpr) || + isa<MemberExpr>(CapturingVarExpr) || + isa<FunctionParmPackExpr>(CapturingVarExpr)); + return NonODRUsedCapturingExprs.count(CapturingVarExpr); + } + void removePotentialCapture(Expr *E) { + llvm::erase_value(PotentiallyCapturingExprs, E); + } + void clearPotentialCaptures() { + PotentiallyCapturingExprs.clear(); + PotentialThisCaptureLocation = SourceLocation(); + } + unsigned getNumPotentialVariableCaptures() const { + return PotentiallyCapturingExprs.size(); + } + + bool hasPotentialCaptures() const { + return getNumPotentialVariableCaptures() || + PotentialThisCaptureLocation.isValid(); + } + + void visitPotentialCaptures( + llvm::function_ref<void(ValueDecl *, Expr *)> Callback) const; +}; + +FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy() + : Base(nullptr, false) {} + +FunctionScopeInfo::WeakObjectProfileTy +FunctionScopeInfo::WeakObjectProfileTy::getSentinel() { + FunctionScopeInfo::WeakObjectProfileTy Result; + Result.Base.setInt(true); + return Result; +} + +template <typename ExprT> +void FunctionScopeInfo::recordUseOfWeak(const ExprT *E, bool IsRead) { + assert(E); + WeakUseVector &Uses = WeakObjectUses[WeakObjectProfileTy(E)]; + Uses.push_back(WeakUseTy(E, IsRead)); +} + +inline void CapturingScopeInfo::addThisCapture(bool isNested, + SourceLocation Loc, + QualType CaptureType, + bool ByCopy) { + Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, CaptureType, + ByCopy, /*Invalid*/ false)); + CXXThisCaptureIndex = Captures.size(); +} + +} // namespace sema + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SCOPEINFO_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/Sema.h b/contrib/libs/clang16/include/clang/Sema/Sema.h new file mode 100644 index 0000000000..75814f5e89 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/Sema.h @@ -0,0 +1,14016 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- Sema.h - Semantic Analysis & AST Building --------------*- 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 defines the Sema class, which performs semantic analysis and +// builds ASTs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMA_H +#define LLVM_CLANG_SEMA_SEMA_H + +#include "clang/AST/ASTConcept.h" +#include "clang/AST/ASTFwd.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Availability.h" +#include "clang/AST/ComparisonCategories.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprConcepts.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/LocInfoType.h" +#include "clang/AST/MangleNumberingContext.h" +#include "clang/AST/NSAPI.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtOpenMP.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeOrdering.h" +#include "clang/Basic/BitmaskEnum.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/DarwinSDKInfo.h" +#include "clang/Basic/ExpressionTraits.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/OpenCLOptions.h" +#include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/PragmaKinds.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/TemplateKinds.h" +#include "clang/Basic/TypeTraits.h" +#include "clang/Sema/AnalysisBasedWarnings.h" +#include "clang/Sema/CleanupInfo.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/ExternalSemaSource.h" +#include "clang/Sema/IdentifierResolver.h" +#include "clang/Sema/ObjCMethodList.h" +#include "clang/Sema/Ownership.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/SemaConcept.h" +#include "clang/Sema/TypoCorrection.h" +#include "clang/Sema/Weak.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallBitVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/Frontend/OpenMP/OMPConstants.h" +#include <deque> +#include <memory> +#include <optional> +#include <string> +#include <tuple> +#include <vector> + +namespace llvm { + class APSInt; + template <typename ValueT, typename ValueInfoT> class DenseSet; + class SmallBitVector; + struct InlineAsmIdentifierInfo; +} + +namespace clang { + class ADLResult; + class ASTConsumer; + class ASTContext; + class ASTMutationListener; + class ASTReader; + class ASTWriter; + class ArrayType; + class ParsedAttr; + class BindingDecl; + class BlockDecl; + class CapturedDecl; + class CXXBasePath; + class CXXBasePaths; + class CXXBindTemporaryExpr; + typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath; + class CXXConstructorDecl; + class CXXConversionDecl; + class CXXDeleteExpr; + class CXXDestructorDecl; + class CXXFieldCollector; + class CXXMemberCallExpr; + class CXXMethodDecl; + class CXXScopeSpec; + class CXXTemporary; + class CXXTryStmt; + class CallExpr; + class ClassTemplateDecl; + class ClassTemplatePartialSpecializationDecl; + class ClassTemplateSpecializationDecl; + class VarTemplatePartialSpecializationDecl; + class CodeCompleteConsumer; + class CodeCompletionAllocator; + class CodeCompletionTUInfo; + class CodeCompletionResult; + class CoroutineBodyStmt; + class Decl; + class DeclAccessPair; + class DeclContext; + class DeclRefExpr; + class DeclaratorDecl; + class DeducedTemplateArgument; + class DependentDiagnostic; + class DesignatedInitExpr; + class Designation; + class EnableIfAttr; + class EnumConstantDecl; + class Expr; + class ExtVectorType; + class FormatAttr; + class FriendDecl; + class FunctionDecl; + class FunctionProtoType; + class FunctionTemplateDecl; + class ImplicitConversionSequence; + typedef MutableArrayRef<ImplicitConversionSequence> ConversionSequenceList; + class InitListExpr; + class InitializationKind; + class InitializationSequence; + class InitializedEntity; + class IntegerLiteral; + class LabelStmt; + class LambdaExpr; + class LangOptions; + class LocalInstantiationScope; + class LookupResult; + class MacroInfo; + typedef ArrayRef<std::pair<IdentifierInfo *, SourceLocation>> ModuleIdPath; + class ModuleLoader; + class MultiLevelTemplateArgumentList; + class NamedDecl; + class ObjCCategoryDecl; + class ObjCCategoryImplDecl; + class ObjCCompatibleAliasDecl; + class ObjCContainerDecl; + class ObjCImplDecl; + class ObjCImplementationDecl; + class ObjCInterfaceDecl; + class ObjCIvarDecl; + template <class T> class ObjCList; + class ObjCMessageExpr; + class ObjCMethodDecl; + class ObjCPropertyDecl; + class ObjCProtocolDecl; + class OMPThreadPrivateDecl; + class OMPRequiresDecl; + class OMPDeclareReductionDecl; + class OMPDeclareSimdDecl; + class OMPClause; + struct OMPVarListLocTy; + struct OverloadCandidate; + enum class OverloadCandidateParamOrder : char; + enum OverloadCandidateRewriteKind : unsigned; + class OverloadCandidateSet; + class OverloadExpr; + class ParenListExpr; + class ParmVarDecl; + class Preprocessor; + class PseudoDestructorTypeStorage; + class PseudoObjectExpr; + class QualType; + class StandardConversionSequence; + class Stmt; + class StringLiteral; + class SwitchStmt; + class TemplateArgument; + class TemplateArgumentList; + class TemplateArgumentLoc; + class TemplateDecl; + class TemplateInstantiationCallback; + class TemplateParameterList; + class TemplatePartialOrderingContext; + class TemplateTemplateParmDecl; + class Token; + class TypeAliasDecl; + class TypedefDecl; + class TypedefNameDecl; + class TypeLoc; + class TypoCorrectionConsumer; + class UnqualifiedId; + class UnresolvedLookupExpr; + class UnresolvedMemberExpr; + class UnresolvedSetImpl; + class UnresolvedSetIterator; + class UsingDecl; + class UsingShadowDecl; + class ValueDecl; + class VarDecl; + class VarTemplateSpecializationDecl; + class VisibilityAttr; + class VisibleDeclConsumer; + class IndirectFieldDecl; + struct DeductionFailureInfo; + class TemplateSpecCandidateSet; + +namespace sema { + class AccessedEntity; + class BlockScopeInfo; + class Capture; + class CapturedRegionScopeInfo; + class CapturingScopeInfo; + class CompoundScopeInfo; + class DelayedDiagnostic; + class DelayedDiagnosticPool; + class FunctionScopeInfo; + class LambdaScopeInfo; + class PossiblyUnreachableDiag; + class RISCVIntrinsicManager; + class SemaPPCallbacks; + class TemplateDeductionInfo; +} + +namespace threadSafety { + class BeforeSet; + void threadSafetyCleanup(BeforeSet* Cache); +} + +// FIXME: No way to easily map from TemplateTypeParmTypes to +// TemplateTypeParmDecls, so we have this horrible PointerUnion. +typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *>, + SourceLocation> + UnexpandedParameterPack; + +/// Describes whether we've seen any nullability information for the given +/// file. +struct FileNullability { + /// The first pointer declarator (of any pointer kind) in the file that does + /// not have a corresponding nullability annotation. + SourceLocation PointerLoc; + + /// The end location for the first pointer declarator in the file. Used for + /// placing fix-its. + SourceLocation PointerEndLoc; + + /// Which kind of pointer declarator we saw. + uint8_t PointerKind; + + /// Whether we saw any type nullability annotations in the given file. + bool SawTypeNullability = false; +}; + +/// A mapping from file IDs to a record of whether we've seen nullability +/// information in that file. +class FileNullabilityMap { + /// A mapping from file IDs to the nullability information for each file ID. + llvm::DenseMap<FileID, FileNullability> Map; + + /// A single-element cache based on the file ID. + struct { + FileID File; + FileNullability Nullability; + } Cache; + +public: + FileNullability &operator[](FileID file) { + // Check the single-element cache. + if (file == Cache.File) + return Cache.Nullability; + + // It's not in the single-element cache; flush the cache if we have one. + if (!Cache.File.isInvalid()) { + Map[Cache.File] = Cache.Nullability; + } + + // Pull this entry into the cache. + Cache.File = file; + Cache.Nullability = Map[file]; + return Cache.Nullability; + } +}; + +/// Tracks expected type during expression parsing, for use in code completion. +/// The type is tied to a particular token, all functions that update or consume +/// the type take a start location of the token they are looking at as a +/// parameter. This avoids updating the type on hot paths in the parser. +class PreferredTypeBuilder { +public: + PreferredTypeBuilder(bool Enabled) : Enabled(Enabled) {} + + void enterCondition(Sema &S, SourceLocation Tok); + void enterReturn(Sema &S, SourceLocation Tok); + void enterVariableInit(SourceLocation Tok, Decl *D); + /// Handles e.g. BaseType{ .D = Tok... + void enterDesignatedInitializer(SourceLocation Tok, QualType BaseType, + const Designation &D); + /// Computing a type for the function argument may require running + /// overloading, so we postpone its computation until it is actually needed. + /// + /// Clients should be very careful when using this function, as it stores a + /// function_ref, clients should make sure all calls to get() with the same + /// location happen while function_ref is alive. + /// + /// The callback should also emit signature help as a side-effect, but only + /// if the completion point has been reached. + void enterFunctionArgument(SourceLocation Tok, + llvm::function_ref<QualType()> ComputeType); + + void enterParenExpr(SourceLocation Tok, SourceLocation LParLoc); + void enterUnary(Sema &S, SourceLocation Tok, tok::TokenKind OpKind, + SourceLocation OpLoc); + void enterBinary(Sema &S, SourceLocation Tok, Expr *LHS, tok::TokenKind Op); + void enterMemAccess(Sema &S, SourceLocation Tok, Expr *Base); + void enterSubscript(Sema &S, SourceLocation Tok, Expr *LHS); + /// Handles all type casts, including C-style cast, C++ casts, etc. + void enterTypeCast(SourceLocation Tok, QualType CastType); + + /// Get the expected type associated with this location, if any. + /// + /// If the location is a function argument, determining the expected type + /// involves considering all function overloads and the arguments so far. + /// In this case, signature help for these function overloads will be reported + /// as a side-effect (only if the completion point has been reached). + QualType get(SourceLocation Tok) const { + if (!Enabled || Tok != ExpectedLoc) + return QualType(); + if (!Type.isNull()) + return Type; + if (ComputeType) + return ComputeType(); + return QualType(); + } + +private: + bool Enabled; + /// Start position of a token for which we store expected type. + SourceLocation ExpectedLoc; + /// Expected type for a token starting at ExpectedLoc. + QualType Type; + /// A function to compute expected type at ExpectedLoc. It is only considered + /// if Type is null. + llvm::function_ref<QualType()> ComputeType; +}; + +/// Sema - This implements semantic analysis and AST building for C. +class Sema final { + Sema(const Sema &) = delete; + void operator=(const Sema &) = delete; + + ///Source of additional semantic information. + IntrusiveRefCntPtr<ExternalSemaSource> ExternalSource; + + static bool mightHaveNonExternalLinkage(const DeclaratorDecl *FD); + + /// Determine whether two declarations should be linked together, given that + /// the old declaration might not be visible and the new declaration might + /// not have external linkage. + bool shouldLinkPossiblyHiddenDecl(const NamedDecl *Old, + const NamedDecl *New) { + if (isVisible(Old)) + return true; + // See comment in below overload for why it's safe to compute the linkage + // of the new declaration here. + if (New->isExternallyDeclarable()) { + assert(Old->isExternallyDeclarable() && + "should not have found a non-externally-declarable previous decl"); + return true; + } + return false; + } + bool shouldLinkPossiblyHiddenDecl(LookupResult &Old, const NamedDecl *New); + + void setupImplicitSpecialMemberType(CXXMethodDecl *SpecialMem, + QualType ResultTy, + ArrayRef<QualType> Args); + +public: + /// The maximum alignment, same as in llvm::Value. We duplicate them here + /// because that allows us not to duplicate the constants in clang code, + /// which we must to since we can't directly use the llvm constants. + /// The value is verified against llvm here: lib/CodeGen/CGDecl.cpp + /// + /// This is the greatest alignment value supported by load, store, and alloca + /// instructions, and global values. + static const unsigned MaxAlignmentExponent = 32; + static const uint64_t MaximumAlignment = 1ull << MaxAlignmentExponent; + + typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy; + typedef OpaquePtr<TemplateName> TemplateTy; + typedef OpaquePtr<QualType> TypeTy; + + OpenCLOptions OpenCLFeatures; + FPOptions CurFPFeatures; + + const LangOptions &LangOpts; + Preprocessor &PP; + ASTContext &Context; + ASTConsumer &Consumer; + DiagnosticsEngine &Diags; + SourceManager &SourceMgr; + + /// Flag indicating whether or not to collect detailed statistics. + bool CollectStats; + + /// Code-completion consumer. + CodeCompleteConsumer *CodeCompleter; + + /// CurContext - This is the current declaration context of parsing. + DeclContext *CurContext; + + /// Generally null except when we temporarily switch decl contexts, + /// like in \see ActOnObjCTemporaryExitContainerContext. + DeclContext *OriginalLexicalContext; + + /// VAListTagName - The declaration name corresponding to __va_list_tag. + /// This is used as part of a hack to omit that class from ADL results. + DeclarationName VAListTagName; + + bool MSStructPragmaOn; // True when \#pragma ms_struct on + + /// Controls member pointer representation format under the MS ABI. + LangOptions::PragmaMSPointersToMembersKind + MSPointerToMemberRepresentationMethod; + + /// Stack of active SEH __finally scopes. Can be empty. + SmallVector<Scope*, 2> CurrentSEHFinally; + + /// Source location for newly created implicit MSInheritanceAttrs + SourceLocation ImplicitMSInheritanceAttrLoc; + + /// Holds TypoExprs that are created from `createDelayedTypo`. This is used by + /// `TransformTypos` in order to keep track of any TypoExprs that are created + /// recursively during typo correction and wipe them away if the correction + /// fails. + llvm::SmallVector<TypoExpr *, 2> TypoExprs; + + /// pragma clang section kind + enum PragmaClangSectionKind { + PCSK_Invalid = 0, + PCSK_BSS = 1, + PCSK_Data = 2, + PCSK_Rodata = 3, + PCSK_Text = 4, + PCSK_Relro = 5 + }; + + enum PragmaClangSectionAction { + PCSA_Set = 0, + PCSA_Clear = 1 + }; + + struct PragmaClangSection { + std::string SectionName; + bool Valid = false; + SourceLocation PragmaLocation; + }; + + PragmaClangSection PragmaClangBSSSection; + PragmaClangSection PragmaClangDataSection; + PragmaClangSection PragmaClangRodataSection; + PragmaClangSection PragmaClangRelroSection; + PragmaClangSection PragmaClangTextSection; + + enum PragmaMsStackAction { + PSK_Reset = 0x0, // #pragma () + PSK_Set = 0x1, // #pragma (value) + PSK_Push = 0x2, // #pragma (push[, id]) + PSK_Pop = 0x4, // #pragma (pop[, id]) + PSK_Show = 0x8, // #pragma (show) -- only for "pack"! + PSK_Push_Set = PSK_Push | PSK_Set, // #pragma (push[, id], value) + PSK_Pop_Set = PSK_Pop | PSK_Set, // #pragma (pop[, id], value) + }; + + // #pragma pack and align. + class AlignPackInfo { + public: + // `Native` represents default align mode, which may vary based on the + // platform. + enum Mode : unsigned char { Native, Natural, Packed, Mac68k }; + + // #pragma pack info constructor + AlignPackInfo(AlignPackInfo::Mode M, unsigned Num, bool IsXL) + : PackAttr(true), AlignMode(M), PackNumber(Num), XLStack(IsXL) { + assert(Num == PackNumber && "The pack number has been truncated."); + } + + // #pragma align info constructor + AlignPackInfo(AlignPackInfo::Mode M, bool IsXL) + : PackAttr(false), AlignMode(M), + PackNumber(M == Packed ? 1 : UninitPackVal), XLStack(IsXL) {} + + explicit AlignPackInfo(bool IsXL) : AlignPackInfo(Native, IsXL) {} + + AlignPackInfo() : AlignPackInfo(Native, false) {} + + // When a AlignPackInfo itself cannot be used, this returns an 32-bit + // integer encoding for it. This should only be passed to + // AlignPackInfo::getFromRawEncoding, it should not be inspected directly. + static uint32_t getRawEncoding(const AlignPackInfo &Info) { + std::uint32_t Encoding{}; + if (Info.IsXLStack()) + Encoding |= IsXLMask; + + Encoding |= static_cast<uint32_t>(Info.getAlignMode()) << 1; + + if (Info.IsPackAttr()) + Encoding |= PackAttrMask; + + Encoding |= static_cast<uint32_t>(Info.getPackNumber()) << 4; + + return Encoding; + } + + static AlignPackInfo getFromRawEncoding(unsigned Encoding) { + bool IsXL = static_cast<bool>(Encoding & IsXLMask); + AlignPackInfo::Mode M = + static_cast<AlignPackInfo::Mode>((Encoding & AlignModeMask) >> 1); + int PackNumber = (Encoding & PackNumMask) >> 4; + + if (Encoding & PackAttrMask) + return AlignPackInfo(M, PackNumber, IsXL); + + return AlignPackInfo(M, IsXL); + } + + bool IsPackAttr() const { return PackAttr; } + + bool IsAlignAttr() const { return !PackAttr; } + + Mode getAlignMode() const { return AlignMode; } + + unsigned getPackNumber() const { return PackNumber; } + + bool IsPackSet() const { + // #pragma align, #pragma pack(), and #pragma pack(0) do not set the pack + // attriute on a decl. + return PackNumber != UninitPackVal && PackNumber != 0; + } + + bool IsXLStack() const { return XLStack; } + + bool operator==(const AlignPackInfo &Info) const { + return std::tie(AlignMode, PackNumber, PackAttr, XLStack) == + std::tie(Info.AlignMode, Info.PackNumber, Info.PackAttr, + Info.XLStack); + } + + bool operator!=(const AlignPackInfo &Info) const { + return !(*this == Info); + } + + private: + /// \brief True if this is a pragma pack attribute, + /// not a pragma align attribute. + bool PackAttr; + + /// \brief The alignment mode that is in effect. + Mode AlignMode; + + /// \brief The pack number of the stack. + unsigned char PackNumber; + + /// \brief True if it is a XL #pragma align/pack stack. + bool XLStack; + + /// \brief Uninitialized pack value. + static constexpr unsigned char UninitPackVal = -1; + + // Masks to encode and decode an AlignPackInfo. + static constexpr uint32_t IsXLMask{0x0000'0001}; + static constexpr uint32_t AlignModeMask{0x0000'0006}; + static constexpr uint32_t PackAttrMask{0x00000'0008}; + static constexpr uint32_t PackNumMask{0x0000'01F0}; + }; + + template<typename ValueType> + struct PragmaStack { + struct Slot { + llvm::StringRef StackSlotLabel; + ValueType Value; + SourceLocation PragmaLocation; + SourceLocation PragmaPushLocation; + Slot(llvm::StringRef StackSlotLabel, ValueType Value, + SourceLocation PragmaLocation, SourceLocation PragmaPushLocation) + : StackSlotLabel(StackSlotLabel), Value(Value), + PragmaLocation(PragmaLocation), + PragmaPushLocation(PragmaPushLocation) {} + }; + + void Act(SourceLocation PragmaLocation, PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, ValueType Value) { + if (Action == PSK_Reset) { + CurrentValue = DefaultValue; + CurrentPragmaLocation = PragmaLocation; + return; + } + if (Action & PSK_Push) + Stack.emplace_back(StackSlotLabel, CurrentValue, CurrentPragmaLocation, + PragmaLocation); + else if (Action & PSK_Pop) { + if (!StackSlotLabel.empty()) { + // If we've got a label, try to find it and jump there. + auto I = llvm::find_if(llvm::reverse(Stack), [&](const Slot &x) { + return x.StackSlotLabel == StackSlotLabel; + }); + // If we found the label so pop from there. + if (I != Stack.rend()) { + CurrentValue = I->Value; + CurrentPragmaLocation = I->PragmaLocation; + Stack.erase(std::prev(I.base()), Stack.end()); + } + } else if (!Stack.empty()) { + // We do not have a label, just pop the last entry. + CurrentValue = Stack.back().Value; + CurrentPragmaLocation = Stack.back().PragmaLocation; + Stack.pop_back(); + } + } + if (Action & PSK_Set) { + CurrentValue = Value; + CurrentPragmaLocation = PragmaLocation; + } + } + + // MSVC seems to add artificial slots to #pragma stacks on entering a C++ + // method body to restore the stacks on exit, so it works like this: + // + // struct S { + // #pragma <name>(push, InternalPragmaSlot, <current_pragma_value>) + // void Method {} + // #pragma <name>(pop, InternalPragmaSlot) + // }; + // + // It works even with #pragma vtordisp, although MSVC doesn't support + // #pragma vtordisp(push [, id], n) + // syntax. + // + // Push / pop a named sentinel slot. + void SentinelAction(PragmaMsStackAction Action, StringRef Label) { + assert((Action == PSK_Push || Action == PSK_Pop) && + "Can only push / pop #pragma stack sentinels!"); + Act(CurrentPragmaLocation, Action, Label, CurrentValue); + } + + // Constructors. + explicit PragmaStack(const ValueType &Default) + : DefaultValue(Default), CurrentValue(Default) {} + + bool hasValue() const { return CurrentValue != DefaultValue; } + + SmallVector<Slot, 2> Stack; + ValueType DefaultValue; // Value used for PSK_Reset action. + ValueType CurrentValue; + SourceLocation CurrentPragmaLocation; + }; + // FIXME: We should serialize / deserialize these if they occur in a PCH (but + // we shouldn't do so if they're in a module). + + /// Whether to insert vtordisps prior to virtual bases in the Microsoft + /// C++ ABI. Possible values are 0, 1, and 2, which mean: + /// + /// 0: Suppress all vtordisps + /// 1: Insert vtordisps in the presence of vbase overrides and non-trivial + /// structors + /// 2: Always insert vtordisps to support RTTI on partially constructed + /// objects + PragmaStack<MSVtorDispMode> VtorDispStack; + PragmaStack<AlignPackInfo> AlignPackStack; + // The current #pragma align/pack values and locations at each #include. + struct AlignPackIncludeState { + AlignPackInfo CurrentValue; + SourceLocation CurrentPragmaLocation; + bool HasNonDefaultValue, ShouldWarnOnInclude; + }; + SmallVector<AlignPackIncludeState, 8> AlignPackIncludeStack; + // Segment #pragmas. + PragmaStack<StringLiteral *> DataSegStack; + PragmaStack<StringLiteral *> BSSSegStack; + PragmaStack<StringLiteral *> ConstSegStack; + PragmaStack<StringLiteral *> CodeSegStack; + + // #pragma strict_gs_check. + PragmaStack<bool> StrictGuardStackCheckStack; + + // This stack tracks the current state of Sema.CurFPFeatures. + PragmaStack<FPOptionsOverride> FpPragmaStack; + FPOptionsOverride CurFPFeatureOverrides() { + FPOptionsOverride result; + if (!FpPragmaStack.hasValue()) { + result = FPOptionsOverride(); + } else { + result = FpPragmaStack.CurrentValue; + } + return result; + } + + // RAII object to push / pop sentinel slots for all MS #pragma stacks. + // Actions should be performed only if we enter / exit a C++ method body. + class PragmaStackSentinelRAII { + public: + PragmaStackSentinelRAII(Sema &S, StringRef SlotLabel, bool ShouldAct); + ~PragmaStackSentinelRAII(); + + private: + Sema &S; + StringRef SlotLabel; + bool ShouldAct; + }; + + /// A mapping that describes the nullability we've seen in each header file. + FileNullabilityMap NullabilityMap; + + /// Last section used with #pragma init_seg. + StringLiteral *CurInitSeg; + SourceLocation CurInitSegLoc; + + /// Sections used with #pragma alloc_text. + llvm::StringMap<std::tuple<StringRef, SourceLocation>> FunctionToSectionMap; + + /// VisContext - Manages the stack for \#pragma GCC visibility. + void *VisContext; // Really a "PragmaVisStack*" + + /// This an attribute introduced by \#pragma clang attribute. + struct PragmaAttributeEntry { + SourceLocation Loc; + ParsedAttr *Attribute; + SmallVector<attr::SubjectMatchRule, 4> MatchRules; + bool IsUsed; + }; + + /// A push'd group of PragmaAttributeEntries. + struct PragmaAttributeGroup { + /// The location of the push attribute. + SourceLocation Loc; + /// The namespace of this push group. + const IdentifierInfo *Namespace; + SmallVector<PragmaAttributeEntry, 2> Entries; + }; + + SmallVector<PragmaAttributeGroup, 2> PragmaAttributeStack; + + /// The declaration that is currently receiving an attribute from the + /// #pragma attribute stack. + const Decl *PragmaAttributeCurrentTargetDecl; + + /// This represents the last location of a "#pragma clang optimize off" + /// directive if such a directive has not been closed by an "on" yet. If + /// optimizations are currently "on", this is set to an invalid location. + SourceLocation OptimizeOffPragmaLocation; + + /// The "on" or "off" argument passed by \#pragma optimize, that denotes + /// whether the optimizations in the list passed to the pragma should be + /// turned off or on. This boolean is true by default because command line + /// options are honored when `#pragma optimize("", on)`. + /// (i.e. `ModifyFnAttributeMSPragmaOptimze()` does nothing) + bool MSPragmaOptimizeIsOn = true; + + /// Set of no-builtin functions listed by \#pragma function. + llvm::SmallSetVector<StringRef, 4> MSFunctionNoBuiltins; + + /// Flag indicating if Sema is building a recovery call expression. + /// + /// This flag is used to avoid building recovery call expressions + /// if Sema is already doing so, which would cause infinite recursions. + bool IsBuildingRecoveryCallExpr; + + /// Used to control the generation of ExprWithCleanups. + CleanupInfo Cleanup; + + /// ExprCleanupObjects - This is the stack of objects requiring + /// cleanup that are created by the current full expression. + SmallVector<ExprWithCleanups::CleanupObject, 8> ExprCleanupObjects; + + /// Store a set of either DeclRefExprs or MemberExprs that contain a reference + /// to a variable (constant) that may or may not be odr-used in this Expr, and + /// we won't know until all lvalue-to-rvalue and discarded value conversions + /// have been applied to all subexpressions of the enclosing full expression. + /// This is cleared at the end of each full expression. + using MaybeODRUseExprSet = llvm::SetVector<Expr *, SmallVector<Expr *, 4>, + llvm::SmallPtrSet<Expr *, 4>>; + MaybeODRUseExprSet MaybeODRUseExprs; + + std::unique_ptr<sema::FunctionScopeInfo> CachedFunctionScope; + + /// Stack containing information about each of the nested + /// function, block, and method scopes that are currently active. + SmallVector<sema::FunctionScopeInfo *, 4> FunctionScopes; + + /// The index of the first FunctionScope that corresponds to the current + /// context. + unsigned FunctionScopesStart = 0; + + ArrayRef<sema::FunctionScopeInfo*> getFunctionScopes() const { + return llvm::ArrayRef(FunctionScopes.begin() + FunctionScopesStart, + FunctionScopes.end()); + } + + /// Stack containing information needed when in C++2a an 'auto' is encountered + /// in a function declaration parameter type specifier in order to invent a + /// corresponding template parameter in the enclosing abbreviated function + /// template. This information is also present in LambdaScopeInfo, stored in + /// the FunctionScopes stack. + SmallVector<InventedTemplateParameterInfo, 4> InventedParameterInfos; + + /// The index of the first InventedParameterInfo that refers to the current + /// context. + unsigned InventedParameterInfosStart = 0; + + ArrayRef<InventedTemplateParameterInfo> getInventedParameterInfos() const { + return llvm::ArrayRef(InventedParameterInfos.begin() + + InventedParameterInfosStart, + InventedParameterInfos.end()); + } + + typedef LazyVector<TypedefNameDecl *, ExternalSemaSource, + &ExternalSemaSource::ReadExtVectorDecls, 2, 2> + ExtVectorDeclsType; + + /// ExtVectorDecls - This is a list all the extended vector types. This allows + /// us to associate a raw vector type with one of the ext_vector type names. + /// This is only necessary for issuing pretty diagnostics. + ExtVectorDeclsType ExtVectorDecls; + + /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes. + std::unique_ptr<CXXFieldCollector> FieldCollector; + + typedef llvm::SmallSetVector<NamedDecl *, 16> NamedDeclSetType; + + /// Set containing all declared private fields that are not used. + NamedDeclSetType UnusedPrivateFields; + + /// Set containing all typedefs that are likely unused. + llvm::SmallSetVector<const TypedefNameDecl *, 4> + UnusedLocalTypedefNameCandidates; + + /// Delete-expressions to be analyzed at the end of translation unit + /// + /// This list contains class members, and locations of delete-expressions + /// that could not be proven as to whether they mismatch with new-expression + /// used in initializer of the field. + typedef std::pair<SourceLocation, bool> DeleteExprLoc; + typedef llvm::SmallVector<DeleteExprLoc, 4> DeleteLocs; + llvm::MapVector<FieldDecl *, DeleteLocs> DeleteExprs; + + typedef llvm::SmallPtrSet<const CXXRecordDecl*, 8> RecordDeclSetTy; + + /// PureVirtualClassDiagSet - a set of class declarations which we have + /// emitted a list of pure virtual functions. Used to prevent emitting the + /// same list more than once. + std::unique_ptr<RecordDeclSetTy> PureVirtualClassDiagSet; + + /// ParsingInitForAutoVars - a set of declarations with auto types for which + /// we are currently parsing the initializer. + llvm::SmallPtrSet<const Decl*, 4> ParsingInitForAutoVars; + + /// Look for a locally scoped extern "C" declaration by the given name. + NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name); + + typedef LazyVector<VarDecl *, ExternalSemaSource, + &ExternalSemaSource::ReadTentativeDefinitions, 2, 2> + TentativeDefinitionsType; + + /// All the tentative definitions encountered in the TU. + TentativeDefinitionsType TentativeDefinitions; + + /// All the external declarations encoutered and used in the TU. + SmallVector<VarDecl *, 4> ExternalDeclarations; + + typedef LazyVector<const DeclaratorDecl *, ExternalSemaSource, + &ExternalSemaSource::ReadUnusedFileScopedDecls, 2, 2> + UnusedFileScopedDeclsType; + + /// The set of file scoped decls seen so far that have not been used + /// and must warn if not used. Only contains the first declaration. + UnusedFileScopedDeclsType UnusedFileScopedDecls; + + typedef LazyVector<CXXConstructorDecl *, ExternalSemaSource, + &ExternalSemaSource::ReadDelegatingConstructors, 2, 2> + DelegatingCtorDeclsType; + + /// All the delegating constructors seen so far in the file, used for + /// cycle detection at the end of the TU. + DelegatingCtorDeclsType DelegatingCtorDecls; + + /// All the overriding functions seen during a class definition + /// that had their exception spec checks delayed, plus the overridden + /// function. + SmallVector<std::pair<const CXXMethodDecl*, const CXXMethodDecl*>, 2> + DelayedOverridingExceptionSpecChecks; + + /// All the function redeclarations seen during a class definition that had + /// their exception spec checks delayed, plus the prior declaration they + /// should be checked against. Except during error recovery, the new decl + /// should always be a friend declaration, as that's the only valid way to + /// redeclare a special member before its class is complete. + SmallVector<std::pair<FunctionDecl*, FunctionDecl*>, 2> + DelayedEquivalentExceptionSpecChecks; + + typedef llvm::MapVector<const FunctionDecl *, + std::unique_ptr<LateParsedTemplate>> + LateParsedTemplateMapT; + LateParsedTemplateMapT LateParsedTemplateMap; + + /// Callback to the parser to parse templated functions when needed. + typedef void LateTemplateParserCB(void *P, LateParsedTemplate &LPT); + typedef void LateTemplateParserCleanupCB(void *P); + LateTemplateParserCB *LateTemplateParser; + LateTemplateParserCleanupCB *LateTemplateParserCleanup; + void *OpaqueParser; + + void SetLateTemplateParser(LateTemplateParserCB *LTP, + LateTemplateParserCleanupCB *LTPCleanup, + void *P) { + LateTemplateParser = LTP; + LateTemplateParserCleanup = LTPCleanup; + OpaqueParser = P; + } + + class DelayedDiagnostics; + + class DelayedDiagnosticsState { + sema::DelayedDiagnosticPool *SavedPool; + friend class Sema::DelayedDiagnostics; + }; + typedef DelayedDiagnosticsState ParsingDeclState; + typedef DelayedDiagnosticsState ProcessingContextState; + + /// A class which encapsulates the logic for delaying diagnostics + /// during parsing and other processing. + class DelayedDiagnostics { + /// The current pool of diagnostics into which delayed + /// diagnostics should go. + sema::DelayedDiagnosticPool *CurPool; + + public: + DelayedDiagnostics() : CurPool(nullptr) {} + + /// Adds a delayed diagnostic. + void add(const sema::DelayedDiagnostic &diag); // in DelayedDiagnostic.h + + /// Determines whether diagnostics should be delayed. + bool shouldDelayDiagnostics() { return CurPool != nullptr; } + + /// Returns the current delayed-diagnostics pool. + sema::DelayedDiagnosticPool *getCurrentPool() const { + return CurPool; + } + + /// Enter a new scope. Access and deprecation diagnostics will be + /// collected in this pool. + DelayedDiagnosticsState push(sema::DelayedDiagnosticPool &pool) { + DelayedDiagnosticsState state; + state.SavedPool = CurPool; + CurPool = &pool; + return state; + } + + /// Leave a delayed-diagnostic state that was previously pushed. + /// Do not emit any of the diagnostics. This is performed as part + /// of the bookkeeping of popping a pool "properly". + void popWithoutEmitting(DelayedDiagnosticsState state) { + CurPool = state.SavedPool; + } + + /// Enter a new scope where access and deprecation diagnostics are + /// not delayed. + DelayedDiagnosticsState pushUndelayed() { + DelayedDiagnosticsState state; + state.SavedPool = CurPool; + CurPool = nullptr; + return state; + } + + /// Undo a previous pushUndelayed(). + void popUndelayed(DelayedDiagnosticsState state) { + assert(CurPool == nullptr); + CurPool = state.SavedPool; + } + } DelayedDiagnostics; + + /// A RAII object to temporarily push a declaration context. + class ContextRAII { + private: + Sema &S; + DeclContext *SavedContext; + ProcessingContextState SavedContextState; + QualType SavedCXXThisTypeOverride; + unsigned SavedFunctionScopesStart; + unsigned SavedInventedParameterInfosStart; + + public: + ContextRAII(Sema &S, DeclContext *ContextToPush, bool NewThisContext = true) + : S(S), SavedContext(S.CurContext), + SavedContextState(S.DelayedDiagnostics.pushUndelayed()), + SavedCXXThisTypeOverride(S.CXXThisTypeOverride), + SavedFunctionScopesStart(S.FunctionScopesStart), + SavedInventedParameterInfosStart(S.InventedParameterInfosStart) + { + assert(ContextToPush && "pushing null context"); + S.CurContext = ContextToPush; + if (NewThisContext) + S.CXXThisTypeOverride = QualType(); + // Any saved FunctionScopes do not refer to this context. + S.FunctionScopesStart = S.FunctionScopes.size(); + S.InventedParameterInfosStart = S.InventedParameterInfos.size(); + } + + void pop() { + if (!SavedContext) return; + S.CurContext = SavedContext; + S.DelayedDiagnostics.popUndelayed(SavedContextState); + S.CXXThisTypeOverride = SavedCXXThisTypeOverride; + S.FunctionScopesStart = SavedFunctionScopesStart; + S.InventedParameterInfosStart = SavedInventedParameterInfosStart; + SavedContext = nullptr; + } + + ~ContextRAII() { + pop(); + } + }; + + /// Whether the AST is currently being rebuilt to correct immediate + /// invocations. Immediate invocation candidates and references to consteval + /// functions aren't tracked when this is set. + bool RebuildingImmediateInvocation = false; + + /// Used to change context to isConstantEvaluated without pushing a heavy + /// ExpressionEvaluationContextRecord object. + bool isConstantEvaluatedOverride; + + bool isConstantEvaluated() { + return ExprEvalContexts.back().isConstantEvaluated() || + isConstantEvaluatedOverride; + } + + /// RAII object to handle the state changes required to synthesize + /// a function body. + class SynthesizedFunctionScope { + Sema &S; + Sema::ContextRAII SavedContext; + bool PushedCodeSynthesisContext = false; + + public: + SynthesizedFunctionScope(Sema &S, DeclContext *DC) + : S(S), SavedContext(S, DC) { + S.PushFunctionScope(); + S.PushExpressionEvaluationContext( + Sema::ExpressionEvaluationContext::PotentiallyEvaluated); + if (auto *FD = dyn_cast<FunctionDecl>(DC)) + FD->setWillHaveBody(true); + else + assert(isa<ObjCMethodDecl>(DC)); + } + + void addContextNote(SourceLocation UseLoc) { + assert(!PushedCodeSynthesisContext); + + Sema::CodeSynthesisContext Ctx; + Ctx.Kind = Sema::CodeSynthesisContext::DefiningSynthesizedFunction; + Ctx.PointOfInstantiation = UseLoc; + Ctx.Entity = cast<Decl>(S.CurContext); + S.pushCodeSynthesisContext(Ctx); + + PushedCodeSynthesisContext = true; + } + + ~SynthesizedFunctionScope() { + if (PushedCodeSynthesisContext) + S.popCodeSynthesisContext(); + if (auto *FD = dyn_cast<FunctionDecl>(S.CurContext)) + FD->setWillHaveBody(false); + S.PopExpressionEvaluationContext(); + S.PopFunctionScopeInfo(); + } + }; + + /// WeakUndeclaredIdentifiers - Identifiers contained in \#pragma weak before + /// declared. Rare. May alias another identifier, declared or undeclared. + /// + /// For aliases, the target identifier is used as a key for eventual + /// processing when the target is declared. For the single-identifier form, + /// the sole identifier is used as the key. Each entry is a `SetVector` + /// (ordered by parse order) of aliases (identified by the alias name) in case + /// of multiple aliases to the same undeclared identifier. + llvm::MapVector< + IdentifierInfo *, + llvm::SetVector< + WeakInfo, llvm::SmallVector<WeakInfo, 1u>, + llvm::SmallDenseSet<WeakInfo, 2u, WeakInfo::DenseMapInfoByAliasOnly>>> + WeakUndeclaredIdentifiers; + + /// ExtnameUndeclaredIdentifiers - Identifiers contained in + /// \#pragma redefine_extname before declared. Used in Solaris system headers + /// to define functions that occur in multiple standards to call the version + /// in the currently selected standard. + llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*> ExtnameUndeclaredIdentifiers; + + + /// Load weak undeclared identifiers from the external source. + void LoadExternalWeakUndeclaredIdentifiers(); + + /// WeakTopLevelDecl - Translation-unit scoped declarations generated by + /// \#pragma weak during processing of other Decls. + /// I couldn't figure out a clean way to generate these in-line, so + /// we store them here and handle separately -- which is a hack. + /// It would be best to refactor this. + SmallVector<Decl*,2> WeakTopLevelDecl; + + IdentifierResolver IdResolver; + + /// Translation Unit Scope - useful to Objective-C actions that need + /// to lookup file scope declarations in the "ordinary" C decl namespace. + /// For example, user-defined classes, built-in "id" type, etc. + Scope *TUScope; + + /// The C++ "std" namespace, where the standard library resides. + LazyDeclPtr StdNamespace; + + /// The C++ "std::bad_alloc" class, which is defined by the C++ + /// standard library. + LazyDeclPtr StdBadAlloc; + + /// The C++ "std::align_val_t" enum class, which is defined by the C++ + /// standard library. + LazyDeclPtr StdAlignValT; + + /// The C++ "std::experimental" namespace, where the experimental parts + /// of the standard library resides. + NamespaceDecl *StdExperimentalNamespaceCache; + + /// The C++ "std::initializer_list" template, which is defined in + /// \<initializer_list>. + ClassTemplateDecl *StdInitializerList; + + /// The C++ "std::coroutine_traits" template, which is defined in + /// \<coroutine_traits> + ClassTemplateDecl *StdCoroutineTraitsCache; + /// The namespace where coroutine components are defined. In standard, + /// they are defined in std namespace. And in the previous implementation, + /// they are defined in std::experimental namespace. + NamespaceDecl *CoroTraitsNamespaceCache; + + /// The C++ "type_info" declaration, which is defined in \<typeinfo>. + RecordDecl *CXXTypeInfoDecl; + + /// The MSVC "_GUID" struct, which is defined in MSVC header files. + RecordDecl *MSVCGuidDecl; + + /// The C++ "std::source_location::__impl" struct, defined in + /// \<source_location>. + RecordDecl *StdSourceLocationImplDecl; + + /// Caches identifiers/selectors for NSFoundation APIs. + std::unique_ptr<NSAPI> NSAPIObj; + + /// The declaration of the Objective-C NSNumber class. + ObjCInterfaceDecl *NSNumberDecl; + + /// The declaration of the Objective-C NSValue class. + ObjCInterfaceDecl *NSValueDecl; + + /// Pointer to NSNumber type (NSNumber *). + QualType NSNumberPointer; + + /// Pointer to NSValue type (NSValue *). + QualType NSValuePointer; + + /// The Objective-C NSNumber methods used to create NSNumber literals. + ObjCMethodDecl *NSNumberLiteralMethods[NSAPI::NumNSNumberLiteralMethods]; + + /// The declaration of the Objective-C NSString class. + ObjCInterfaceDecl *NSStringDecl; + + /// Pointer to NSString type (NSString *). + QualType NSStringPointer; + + /// The declaration of the stringWithUTF8String: method. + ObjCMethodDecl *StringWithUTF8StringMethod; + + /// The declaration of the valueWithBytes:objCType: method. + ObjCMethodDecl *ValueWithBytesObjCTypeMethod; + + /// The declaration of the Objective-C NSArray class. + ObjCInterfaceDecl *NSArrayDecl; + + /// The declaration of the arrayWithObjects:count: method. + ObjCMethodDecl *ArrayWithObjectsMethod; + + /// The declaration of the Objective-C NSDictionary class. + ObjCInterfaceDecl *NSDictionaryDecl; + + /// The declaration of the dictionaryWithObjects:forKeys:count: method. + ObjCMethodDecl *DictionaryWithObjectsMethod; + + /// id<NSCopying> type. + QualType QIDNSCopying; + + /// will hold 'respondsToSelector:' + Selector RespondsToSelectorSel; + + /// A flag to remember whether the implicit forms of operator new and delete + /// have been declared. + bool GlobalNewDeleteDeclared; + + /// Describes how the expressions currently being parsed are + /// evaluated at run-time, if at all. + enum class ExpressionEvaluationContext { + /// The current expression and its subexpressions occur within an + /// unevaluated operand (C++11 [expr]p7), such as the subexpression of + /// \c sizeof, where the type of the expression may be significant but + /// no code will be generated to evaluate the value of the expression at + /// run time. + Unevaluated, + + /// The current expression occurs within a braced-init-list within + /// an unevaluated operand. This is mostly like a regular unevaluated + /// context, except that we still instantiate constexpr functions that are + /// referenced here so that we can perform narrowing checks correctly. + UnevaluatedList, + + /// The current expression occurs within a discarded statement. + /// This behaves largely similarly to an unevaluated operand in preventing + /// definitions from being required, but not in other ways. + DiscardedStatement, + + /// The current expression occurs within an unevaluated + /// operand that unconditionally permits abstract references to + /// fields, such as a SIZE operator in MS-style inline assembly. + UnevaluatedAbstract, + + /// The current context is "potentially evaluated" in C++11 terms, + /// but the expression is evaluated at compile-time (like the values of + /// cases in a switch statement). + ConstantEvaluated, + + /// In addition of being constant evaluated, the current expression + /// occurs in an immediate function context - either a consteval function + /// or a consteval if function. + ImmediateFunctionContext, + + /// The current expression is potentially evaluated at run time, + /// which means that code may be generated to evaluate the value of the + /// expression at run time. + PotentiallyEvaluated, + + /// The current expression is potentially evaluated, but any + /// declarations referenced inside that expression are only used if + /// in fact the current expression is used. + /// + /// This value is used when parsing default function arguments, for which + /// we would like to provide diagnostics (e.g., passing non-POD arguments + /// through varargs) but do not want to mark declarations as "referenced" + /// until the default argument is used. + PotentiallyEvaluatedIfUsed + }; + + using ImmediateInvocationCandidate = llvm::PointerIntPair<ConstantExpr *, 1>; + + /// Data structure used to record current or nested + /// expression evaluation contexts. + struct ExpressionEvaluationContextRecord { + /// The expression evaluation context. + ExpressionEvaluationContext Context; + + /// Whether the enclosing context needed a cleanup. + CleanupInfo ParentCleanup; + + /// The number of active cleanup objects when we entered + /// this expression evaluation context. + unsigned NumCleanupObjects; + + /// The number of typos encountered during this expression evaluation + /// context (i.e. the number of TypoExprs created). + unsigned NumTypos; + + MaybeODRUseExprSet SavedMaybeODRUseExprs; + + /// The lambdas that are present within this context, if it + /// is indeed an unevaluated context. + SmallVector<LambdaExpr *, 2> Lambdas; + + /// The declaration that provides context for lambda expressions + /// and block literals if the normal declaration context does not + /// suffice, e.g., in a default function argument. + Decl *ManglingContextDecl; + + /// If we are processing a decltype type, a set of call expressions + /// for which we have deferred checking the completeness of the return type. + SmallVector<CallExpr *, 8> DelayedDecltypeCalls; + + /// If we are processing a decltype type, a set of temporary binding + /// expressions for which we have deferred checking the destructor. + SmallVector<CXXBindTemporaryExpr *, 8> DelayedDecltypeBinds; + + llvm::SmallPtrSet<const Expr *, 8> PossibleDerefs; + + /// Expressions appearing as the LHS of a volatile assignment in this + /// context. We produce a warning for these when popping the context if + /// they are not discarded-value expressions nor unevaluated operands. + SmallVector<Expr*, 2> VolatileAssignmentLHSs; + + /// Set of candidates for starting an immediate invocation. + llvm::SmallVector<ImmediateInvocationCandidate, 4> ImmediateInvocationCandidates; + + /// Set of DeclRefExprs referencing a consteval function when used in a + /// context not already known to be immediately invoked. + llvm::SmallPtrSet<DeclRefExpr *, 4> ReferenceToConsteval; + + /// \brief Describes whether we are in an expression constext which we have + /// to handle differently. + enum ExpressionKind { + EK_Decltype, EK_TemplateArgument, EK_Other + } ExprContext; + + // A context can be nested in both a discarded statement context and + // an immediate function context, so they need to be tracked independently. + bool InDiscardedStatement; + bool InImmediateFunctionContext; + + bool IsCurrentlyCheckingDefaultArgumentOrInitializer = false; + + // When evaluating immediate functions in the initializer of a default + // argument or default member initializer, this is the declaration whose + // default initializer is being evaluated and the location of the call + // or constructor definition. + struct InitializationContext { + InitializationContext(SourceLocation Loc, ValueDecl *Decl, + DeclContext *Context) + : Loc(Loc), Decl(Decl), Context(Context) { + assert(Decl && Context && "invalid initialization context"); + } + + SourceLocation Loc; + ValueDecl *Decl = nullptr; + DeclContext *Context = nullptr; + }; + std::optional<InitializationContext> DelayedDefaultInitializationContext; + + ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, + unsigned NumCleanupObjects, + CleanupInfo ParentCleanup, + Decl *ManglingContextDecl, + ExpressionKind ExprContext) + : Context(Context), ParentCleanup(ParentCleanup), + NumCleanupObjects(NumCleanupObjects), NumTypos(0), + ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext), + InDiscardedStatement(false), InImmediateFunctionContext(false) {} + + bool isUnevaluated() const { + return Context == ExpressionEvaluationContext::Unevaluated || + Context == ExpressionEvaluationContext::UnevaluatedAbstract || + Context == ExpressionEvaluationContext::UnevaluatedList; + } + + bool isConstantEvaluated() const { + return Context == ExpressionEvaluationContext::ConstantEvaluated || + Context == ExpressionEvaluationContext::ImmediateFunctionContext; + } + + bool isImmediateFunctionContext() const { + return Context == ExpressionEvaluationContext::ImmediateFunctionContext || + (Context == ExpressionEvaluationContext::DiscardedStatement && + InImmediateFunctionContext) || + // C++2b [expr.const]p14: + // An expression or conversion is in an immediate function + // context if it is potentially evaluated and either: + // * its innermost enclosing non-block scope is a function + // parameter scope of an immediate function, or + // * its enclosing statement is enclosed by the compound- + // statement of a consteval if statement. + (Context == ExpressionEvaluationContext::PotentiallyEvaluated && + InImmediateFunctionContext); + } + + bool isDiscardedStatementContext() const { + return Context == ExpressionEvaluationContext::DiscardedStatement || + (Context == + ExpressionEvaluationContext::ImmediateFunctionContext && + InDiscardedStatement); + } + }; + + /// A stack of expression evaluation contexts. + SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts; + + /// Emit a warning for all pending noderef expressions that we recorded. + void WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec); + + /// Compute the mangling number context for a lambda expression or + /// block literal. Also return the extra mangling decl if any. + /// + /// \param DC - The DeclContext containing the lambda expression or + /// block literal. + std::tuple<MangleNumberingContext *, Decl *> + getCurrentMangleNumberContext(const DeclContext *DC); + + + /// SpecialMemberOverloadResult - The overloading result for a special member + /// function. + /// + /// This is basically a wrapper around PointerIntPair. The lowest bits of the + /// integer are used to determine whether overload resolution succeeded. + class SpecialMemberOverloadResult { + public: + enum Kind { + NoMemberOrDeleted, + Ambiguous, + Success + }; + + private: + llvm::PointerIntPair<CXXMethodDecl *, 2> Pair; + + public: + SpecialMemberOverloadResult() {} + SpecialMemberOverloadResult(CXXMethodDecl *MD) + : Pair(MD, MD->isDeleted() ? NoMemberOrDeleted : Success) {} + + CXXMethodDecl *getMethod() const { return Pair.getPointer(); } + void setMethod(CXXMethodDecl *MD) { Pair.setPointer(MD); } + + Kind getKind() const { return static_cast<Kind>(Pair.getInt()); } + void setKind(Kind K) { Pair.setInt(K); } + }; + + class SpecialMemberOverloadResultEntry + : public llvm::FastFoldingSetNode, + public SpecialMemberOverloadResult { + public: + SpecialMemberOverloadResultEntry(const llvm::FoldingSetNodeID &ID) + : FastFoldingSetNode(ID) + {} + }; + + /// A cache of special member function overload resolution results + /// for C++ records. + llvm::FoldingSet<SpecialMemberOverloadResultEntry> SpecialMemberCache; + + /// A cache of the flags available in enumerations with the flag_bits + /// attribute. + mutable llvm::DenseMap<const EnumDecl*, llvm::APInt> FlagBitsCache; + + /// The kind of translation unit we are processing. + /// + /// When we're processing a complete translation unit, Sema will perform + /// end-of-translation-unit semantic tasks (such as creating + /// initializers for tentative definitions in C) once parsing has + /// completed. Modules and precompiled headers perform different kinds of + /// checks. + const TranslationUnitKind TUKind; + + llvm::BumpPtrAllocator BumpAlloc; + + /// The number of SFINAE diagnostics that have been trapped. + unsigned NumSFINAEErrors; + + typedef llvm::DenseMap<ParmVarDecl *, llvm::TinyPtrVector<ParmVarDecl *>> + UnparsedDefaultArgInstantiationsMap; + + /// A mapping from parameters with unparsed default arguments to the + /// set of instantiations of each parameter. + /// + /// This mapping is a temporary data structure used when parsing + /// nested class templates or nested classes of class templates, + /// where we might end up instantiating an inner class before the + /// default arguments of its methods have been parsed. + UnparsedDefaultArgInstantiationsMap UnparsedDefaultArgInstantiations; + + // Contains the locations of the beginning of unparsed default + // argument locations. + llvm::DenseMap<ParmVarDecl *, SourceLocation> UnparsedDefaultArgLocs; + + /// UndefinedInternals - all the used, undefined objects which require a + /// definition in this translation unit. + llvm::MapVector<NamedDecl *, SourceLocation> UndefinedButUsed; + + /// Determine if VD, which must be a variable or function, is an external + /// symbol that nonetheless can't be referenced from outside this translation + /// unit because its type has no linkage and it's not extern "C". + bool isExternalWithNoLinkageType(ValueDecl *VD); + + /// Obtain a sorted list of functions that are undefined but ODR-used. + void getUndefinedButUsed( + SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined); + + /// Retrieves list of suspicious delete-expressions that will be checked at + /// the end of translation unit. + const llvm::MapVector<FieldDecl *, DeleteLocs> & + getMismatchingDeleteExpressions() const; + + class GlobalMethodPool { + public: + using Lists = std::pair<ObjCMethodList, ObjCMethodList>; + using iterator = llvm::DenseMap<Selector, Lists>::iterator; + iterator begin() { return Methods.begin(); } + iterator end() { return Methods.end(); } + iterator find(Selector Sel) { return Methods.find(Sel); } + std::pair<iterator, bool> insert(std::pair<Selector, Lists> &&Val) { + return Methods.insert(Val); + } + int count(Selector Sel) const { return Methods.count(Sel); } + bool empty() const { return Methods.empty(); } + + private: + llvm::DenseMap<Selector, Lists> Methods; + }; + + /// Method Pool - allows efficient lookup when typechecking messages to "id". + /// We need to maintain a list, since selectors can have differing signatures + /// across classes. In Cocoa, this happens to be extremely uncommon (only 1% + /// of selectors are "overloaded"). + /// At the head of the list it is recorded whether there were 0, 1, or >= 2 + /// methods inside categories with a particular selector. + GlobalMethodPool MethodPool; + + /// Method selectors used in a \@selector expression. Used for implementation + /// of -Wselector. + llvm::MapVector<Selector, SourceLocation> ReferencedSelectors; + + /// List of SourceLocations where 'self' is implicitly retained inside a + /// block. + llvm::SmallVector<std::pair<SourceLocation, const BlockDecl *>, 1> + ImplicitlyRetainedSelfLocs; + + /// Kinds of C++ special members. + enum CXXSpecialMember { + CXXDefaultConstructor, + CXXCopyConstructor, + CXXMoveConstructor, + CXXCopyAssignment, + CXXMoveAssignment, + CXXDestructor, + CXXInvalid + }; + + typedef llvm::PointerIntPair<CXXRecordDecl *, 3, CXXSpecialMember> + SpecialMemberDecl; + + /// The C++ special members which we are currently in the process of + /// declaring. If this process recursively triggers the declaration of the + /// same special member, we should act as if it is not yet declared. + llvm::SmallPtrSet<SpecialMemberDecl, 4> SpecialMembersBeingDeclared; + + /// Kinds of defaulted comparison operator functions. + enum class DefaultedComparisonKind : unsigned char { + /// This is not a defaultable comparison operator. + None, + /// This is an operator== that should be implemented as a series of + /// subobject comparisons. + Equal, + /// This is an operator<=> that should be implemented as a series of + /// subobject comparisons. + ThreeWay, + /// This is an operator!= that should be implemented as a rewrite in terms + /// of a == comparison. + NotEqual, + /// This is an <, <=, >, or >= that should be implemented as a rewrite in + /// terms of a <=> comparison. + Relational, + }; + + /// The function definitions which were renamed as part of typo-correction + /// to match their respective declarations. We want to keep track of them + /// to ensure that we don't emit a "redefinition" error if we encounter a + /// correctly named definition after the renamed definition. + llvm::SmallPtrSet<const NamedDecl *, 4> TypoCorrectedFunctionDefinitions; + + /// Stack of types that correspond to the parameter entities that are + /// currently being copy-initialized. Can be empty. + llvm::SmallVector<QualType, 4> CurrentParameterCopyTypes; + + void ReadMethodPool(Selector Sel); + void updateOutOfDateSelector(Selector Sel); + + /// Private Helper predicate to check for 'self'. + bool isSelfExpr(Expr *RExpr); + bool isSelfExpr(Expr *RExpr, const ObjCMethodDecl *Method); + + /// Cause the active diagnostic on the DiagosticsEngine to be + /// emitted. This is closely coupled to the SemaDiagnosticBuilder class and + /// should not be used elsewhere. + void EmitCurrentDiagnostic(unsigned DiagID); + + /// Records and restores the CurFPFeatures state on entry/exit of compound + /// statements. + class FPFeaturesStateRAII { + public: + FPFeaturesStateRAII(Sema &S); + ~FPFeaturesStateRAII(); + FPOptionsOverride getOverrides() { return OldOverrides; } + + private: + Sema& S; + FPOptions OldFPFeaturesState; + FPOptionsOverride OldOverrides; + LangOptions::FPEvalMethodKind OldEvalMethod; + SourceLocation OldFPPragmaLocation; + }; + + void addImplicitTypedef(StringRef Name, QualType T); + + bool WarnedStackExhausted = false; + + /// Increment when we find a reference; decrement when we find an ignored + /// assignment. Ultimately the value is 0 if every reference is an ignored + /// assignment. + llvm::DenseMap<const VarDecl *, int> RefsMinusAssignments; + + /// Indicate RISC-V vector builtin functions enabled or not. + bool DeclareRISCVVBuiltins = false; + +private: + std::unique_ptr<sema::RISCVIntrinsicManager> RVIntrinsicManager; + + std::optional<std::unique_ptr<DarwinSDKInfo>> CachedDarwinSDKInfo; + + bool WarnedDarwinSDKInfoMissing = false; + +public: + Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, + TranslationUnitKind TUKind = TU_Complete, + CodeCompleteConsumer *CompletionConsumer = nullptr); + ~Sema(); + + /// Perform initialization that occurs after the parser has been + /// initialized but before it parses anything. + void Initialize(); + + /// This virtual key function only exists to limit the emission of debug info + /// describing the Sema class. GCC and Clang only emit debug info for a class + /// with a vtable when the vtable is emitted. Sema is final and not + /// polymorphic, but the debug info size savings are so significant that it is + /// worth adding a vtable just to take advantage of this optimization. + virtual void anchor(); + + const LangOptions &getLangOpts() const { return LangOpts; } + OpenCLOptions &getOpenCLOptions() { return OpenCLFeatures; } + FPOptions &getCurFPFeatures() { return CurFPFeatures; } + + DiagnosticsEngine &getDiagnostics() const { return Diags; } + SourceManager &getSourceManager() const { return SourceMgr; } + Preprocessor &getPreprocessor() const { return PP; } + ASTContext &getASTContext() const { return Context; } + ASTConsumer &getASTConsumer() const { return Consumer; } + ASTMutationListener *getASTMutationListener() const; + ExternalSemaSource *getExternalSource() const { return ExternalSource.get(); } + + DarwinSDKInfo *getDarwinSDKInfoForAvailabilityChecking(SourceLocation Loc, + StringRef Platform); + DarwinSDKInfo *getDarwinSDKInfoForAvailabilityChecking(); + + ///Registers an external source. If an external source already exists, + /// creates a multiplex external source and appends to it. + /// + ///\param[in] E - A non-null external sema source. + /// + void addExternalSource(ExternalSemaSource *E); + + void PrintStats() const; + + /// Warn that the stack is nearly exhausted. + void warnStackExhausted(SourceLocation Loc); + + /// Run some code with "sufficient" stack space. (Currently, at least 256K is + /// guaranteed). Produces a warning if we're low on stack space and allocates + /// more in that case. Use this in code that may recurse deeply (for example, + /// in template instantiation) to avoid stack overflow. + void runWithSufficientStackSpace(SourceLocation Loc, + llvm::function_ref<void()> Fn); + + /// Helper class that creates diagnostics with optional + /// template instantiation stacks. + /// + /// This class provides a wrapper around the basic DiagnosticBuilder + /// class that emits diagnostics. ImmediateDiagBuilder is + /// responsible for emitting the diagnostic (as DiagnosticBuilder + /// does) and, if the diagnostic comes from inside a template + /// instantiation, printing the template instantiation stack as + /// well. + class ImmediateDiagBuilder : public DiagnosticBuilder { + Sema &SemaRef; + unsigned DiagID; + + public: + ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) + : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} + ImmediateDiagBuilder(DiagnosticBuilder &&DB, Sema &SemaRef, unsigned DiagID) + : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} + + // This is a cunning lie. DiagnosticBuilder actually performs move + // construction in its copy constructor (but due to varied uses, it's not + // possible to conveniently express this as actual move construction). So + // the default copy ctor here is fine, because the base class disables the + // source anyway, so the user-defined ~ImmediateDiagBuilder is a safe no-op + // in that case anwyay. + ImmediateDiagBuilder(const ImmediateDiagBuilder &) = default; + + ~ImmediateDiagBuilder() { + // If we aren't active, there is nothing to do. + if (!isActive()) return; + + // Otherwise, we need to emit the diagnostic. First clear the diagnostic + // builder itself so it won't emit the diagnostic in its own destructor. + // + // This seems wasteful, in that as written the DiagnosticBuilder dtor will + // do its own needless checks to see if the diagnostic needs to be + // emitted. However, because we take care to ensure that the builder + // objects never escape, a sufficiently smart compiler will be able to + // eliminate that code. + Clear(); + + // Dispatch to Sema to emit the diagnostic. + SemaRef.EmitCurrentDiagnostic(DiagID); + } + + /// Teach operator<< to produce an object of the correct type. + template <typename T> + friend const ImmediateDiagBuilder & + operator<<(const ImmediateDiagBuilder &Diag, const T &Value) { + const DiagnosticBuilder &BaseDiag = Diag; + BaseDiag << Value; + return Diag; + } + + // It is necessary to limit this to rvalue reference to avoid calling this + // function with a bitfield lvalue argument since non-const reference to + // bitfield is not allowed. + template <typename T, + typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>> + const ImmediateDiagBuilder &operator<<(T &&V) const { + const DiagnosticBuilder &BaseDiag = *this; + BaseDiag << std::move(V); + return *this; + } + }; + + /// A generic diagnostic builder for errors which may or may not be deferred. + /// + /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch) + /// which are not allowed to appear inside __device__ functions and are + /// allowed to appear in __host__ __device__ functions only if the host+device + /// function is never codegen'ed. + /// + /// To handle this, we use the notion of "deferred diagnostics", where we + /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed. + /// + /// This class lets you emit either a regular diagnostic, a deferred + /// diagnostic, or no diagnostic at all, according to an argument you pass to + /// its constructor, thus simplifying the process of creating these "maybe + /// deferred" diagnostics. + class SemaDiagnosticBuilder { + public: + enum Kind { + /// Emit no diagnostics. + K_Nop, + /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()). + K_Immediate, + /// Emit the diagnostic immediately, and, if it's a warning or error, also + /// emit a call stack showing how this function can be reached by an a + /// priori known-emitted function. + K_ImmediateWithCallStack, + /// Create a deferred diagnostic, which is emitted only if the function + /// it's attached to is codegen'ed. Also emit a call stack as with + /// K_ImmediateWithCallStack. + K_Deferred + }; + + SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID, + FunctionDecl *Fn, Sema &S); + SemaDiagnosticBuilder(SemaDiagnosticBuilder &&D); + SemaDiagnosticBuilder(const SemaDiagnosticBuilder &) = default; + ~SemaDiagnosticBuilder(); + + bool isImmediate() const { return ImmediateDiag.has_value(); } + + /// Convertible to bool: True if we immediately emitted an error, false if + /// we didn't emit an error or we created a deferred error. + /// + /// Example usage: + /// + /// if (SemaDiagnosticBuilder(...) << foo << bar) + /// return ExprError(); + /// + /// But see CUDADiagIfDeviceCode() and CUDADiagIfHostCode() -- you probably + /// want to use these instead of creating a SemaDiagnosticBuilder yourself. + operator bool() const { return isImmediate(); } + + template <typename T> + friend const SemaDiagnosticBuilder & + operator<<(const SemaDiagnosticBuilder &Diag, const T &Value) { + if (Diag.ImmediateDiag) + *Diag.ImmediateDiag << Value; + else if (Diag.PartialDiagId) + Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second + << Value; + return Diag; + } + + // It is necessary to limit this to rvalue reference to avoid calling this + // function with a bitfield lvalue argument since non-const reference to + // bitfield is not allowed. + template <typename T, + typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>> + const SemaDiagnosticBuilder &operator<<(T &&V) const { + if (ImmediateDiag) + *ImmediateDiag << std::move(V); + else if (PartialDiagId) + S.DeviceDeferredDiags[Fn][*PartialDiagId].second << std::move(V); + return *this; + } + + friend const SemaDiagnosticBuilder & + operator<<(const SemaDiagnosticBuilder &Diag, const PartialDiagnostic &PD) { + if (Diag.ImmediateDiag) + PD.Emit(*Diag.ImmediateDiag); + else if (Diag.PartialDiagId) + Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second = PD; + return Diag; + } + + void AddFixItHint(const FixItHint &Hint) const { + if (ImmediateDiag) + ImmediateDiag->AddFixItHint(Hint); + else if (PartialDiagId) + S.DeviceDeferredDiags[Fn][*PartialDiagId].second.AddFixItHint(Hint); + } + + friend ExprResult ExprError(const SemaDiagnosticBuilder &) { + return ExprError(); + } + friend StmtResult StmtError(const SemaDiagnosticBuilder &) { + return StmtError(); + } + operator ExprResult() const { return ExprError(); } + operator StmtResult() const { return StmtError(); } + operator TypeResult() const { return TypeError(); } + operator DeclResult() const { return DeclResult(true); } + operator MemInitResult() const { return MemInitResult(true); } + + private: + Sema &S; + SourceLocation Loc; + unsigned DiagID; + FunctionDecl *Fn; + bool ShowCallStack; + + // Invariant: At most one of these Optionals has a value. + // FIXME: Switch these to a Variant once that exists. + std::optional<ImmediateDiagBuilder> ImmediateDiag; + std::optional<unsigned> PartialDiagId; + }; + + /// Is the last error level diagnostic immediate. This is used to determined + /// whether the next info diagnostic should be immediate. + bool IsLastErrorImmediate = true; + + /// Emit a diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, + bool DeferHint = false); + + /// Emit a partial diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD, + bool DeferHint = false); + + /// Build a partial diagnostic. + PartialDiagnostic PDiag(unsigned DiagID = 0); // in SemaInternal.h + + /// Whether deferrable diagnostics should be deferred. + bool DeferDiags = false; + + /// RAII class to control scope of DeferDiags. + class DeferDiagsRAII { + Sema &S; + bool SavedDeferDiags = false; + + public: + DeferDiagsRAII(Sema &S, bool DeferDiags) + : S(S), SavedDeferDiags(S.DeferDiags) { + S.DeferDiags = DeferDiags; + } + ~DeferDiagsRAII() { S.DeferDiags = SavedDeferDiags; } + }; + + /// Whether uncompilable error has occurred. This includes error happens + /// in deferred diagnostics. + bool hasUncompilableErrorOccurred() const; + + bool findMacroSpelling(SourceLocation &loc, StringRef name); + + /// Get a string to suggest for zero-initialization of a type. + std::string + getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const; + std::string getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const; + + /// Calls \c Lexer::getLocForEndOfToken() + SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0); + + /// Retrieve the module loader associated with the preprocessor. + ModuleLoader &getModuleLoader() const; + + /// Invent a new identifier for parameters of abbreviated templates. + IdentifierInfo * + InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName, + unsigned Index); + + void emitAndClearUnusedLocalTypedefWarnings(); + + private: + /// Function or variable declarations to be checked for whether the deferred + /// diagnostics should be emitted. + llvm::SmallSetVector<Decl *, 4> DeclsToCheckForDeferredDiags; + + public: + // Emit all deferred diagnostics. + void emitDeferredDiags(); + + enum TUFragmentKind { + /// The global module fragment, between 'module;' and a module-declaration. + Global, + /// A normal translation unit fragment. For a non-module unit, this is the + /// entire translation unit. Otherwise, it runs from the module-declaration + /// to the private-module-fragment (if any) or the end of the TU (if not). + Normal, + /// The private module fragment, between 'module :private;' and the end of + /// the translation unit. + Private + }; + + void ActOnStartOfTranslationUnit(); + void ActOnEndOfTranslationUnit(); + void ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind); + + void CheckDelegatingCtorCycles(); + + Scope *getScopeForContext(DeclContext *Ctx); + + void PushFunctionScope(); + void PushBlockScope(Scope *BlockScope, BlockDecl *Block); + sema::LambdaScopeInfo *PushLambdaScope(); + + /// This is used to inform Sema what the current TemplateParameterDepth + /// is during Parsing. Currently it is used to pass on the depth + /// when parsing generic lambda 'auto' parameters. + void RecordParsingTemplateParameterDepth(unsigned Depth); + + void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD, + RecordDecl *RD, CapturedRegionKind K, + unsigned OpenMPCaptureLevel = 0); + + /// Custom deleter to allow FunctionScopeInfos to be kept alive for a short + /// time after they've been popped. + class PoppedFunctionScopeDeleter { + Sema *Self; + + public: + explicit PoppedFunctionScopeDeleter(Sema *Self) : Self(Self) {} + void operator()(sema::FunctionScopeInfo *Scope) const; + }; + + using PoppedFunctionScopePtr = + std::unique_ptr<sema::FunctionScopeInfo, PoppedFunctionScopeDeleter>; + + PoppedFunctionScopePtr + PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP = nullptr, + const Decl *D = nullptr, + QualType BlockType = QualType()); + + sema::FunctionScopeInfo *getCurFunction() const { + return FunctionScopes.empty() ? nullptr : FunctionScopes.back(); + } + + sema::FunctionScopeInfo *getEnclosingFunction() const; + + void setFunctionHasBranchIntoScope(); + void setFunctionHasBranchProtectedScope(); + void setFunctionHasIndirectGoto(); + void setFunctionHasMustTail(); + + void PushCompoundScope(bool IsStmtExpr); + void PopCompoundScope(); + + sema::CompoundScopeInfo &getCurCompoundScope() const; + + bool hasAnyUnrecoverableErrorsInThisFunction() const; + + /// Retrieve the current block, if any. + sema::BlockScopeInfo *getCurBlock(); + + /// Get the innermost lambda enclosing the current location, if any. This + /// looks through intervening non-lambda scopes such as local functions and + /// blocks. + sema::LambdaScopeInfo *getEnclosingLambda() const; + + /// Retrieve the current lambda scope info, if any. + /// \param IgnoreNonLambdaCapturingScope true if should find the top-most + /// lambda scope info ignoring all inner capturing scopes that are not + /// lambda scopes. + sema::LambdaScopeInfo * + getCurLambda(bool IgnoreNonLambdaCapturingScope = false); + + /// Retrieve the current generic lambda info, if any. + sema::LambdaScopeInfo *getCurGenericLambda(); + + /// Retrieve the current captured region, if any. + sema::CapturedRegionScopeInfo *getCurCapturedRegion(); + + /// Retrieve the current function, if any, that should be analyzed for + /// potential availability violations. + sema::FunctionScopeInfo *getCurFunctionAvailabilityContext(); + + /// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls + SmallVectorImpl<Decl *> &WeakTopLevelDecls() { return WeakTopLevelDecl; } + + /// Called before parsing a function declarator belonging to a function + /// declaration. + void ActOnStartFunctionDeclarationDeclarator(Declarator &D, + unsigned TemplateParameterDepth); + + /// Called after parsing a function declarator belonging to a function + /// declaration. + void ActOnFinishFunctionDeclarationDeclarator(Declarator &D); + + void ActOnComment(SourceRange Comment); + + //===--------------------------------------------------------------------===// + // Type Analysis / Processing: SemaType.cpp. + // + + QualType BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs, + const DeclSpec *DS = nullptr); + QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVRA, + const DeclSpec *DS = nullptr); + QualType BuildPointerType(QualType T, + SourceLocation Loc, DeclarationName Entity); + QualType BuildReferenceType(QualType T, bool LValueRef, + SourceLocation Loc, DeclarationName Entity); + QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, + Expr *ArraySize, unsigned Quals, + SourceRange Brackets, DeclarationName Entity); + QualType BuildVectorType(QualType T, Expr *VecSize, SourceLocation AttrLoc); + QualType BuildExtVectorType(QualType T, Expr *ArraySize, + SourceLocation AttrLoc); + QualType BuildMatrixType(QualType T, Expr *NumRows, Expr *NumColumns, + SourceLocation AttrLoc); + + QualType BuildAddressSpaceAttr(QualType &T, LangAS ASIdx, Expr *AddrSpace, + SourceLocation AttrLoc); + + /// Same as above, but constructs the AddressSpace index if not provided. + QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, + SourceLocation AttrLoc); + + bool CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc); + + bool CheckFunctionReturnType(QualType T, SourceLocation Loc); + + /// Build a function type. + /// + /// This routine checks the function type according to C++ rules and + /// under the assumption that the result type and parameter types have + /// just been instantiated from a template. It therefore duplicates + /// some of the behavior of GetTypeForDeclarator, but in a much + /// simpler form that is only suitable for this narrow use case. + /// + /// \param T The return type of the function. + /// + /// \param ParamTypes The parameter types of the function. This array + /// will be modified to account for adjustments to the types of the + /// function parameters. + /// + /// \param Loc The location of the entity whose type involves this + /// function type or, if there is no such entity, the location of the + /// type that will have function type. + /// + /// \param Entity The name of the entity that involves the function + /// type, if known. + /// + /// \param EPI Extra information about the function type. Usually this will + /// be taken from an existing function with the same prototype. + /// + /// \returns A suitable function type, if there are no errors. The + /// unqualified type will always be a FunctionProtoType. + /// Otherwise, returns a NULL type. + QualType BuildFunctionType(QualType T, + MutableArrayRef<QualType> ParamTypes, + SourceLocation Loc, DeclarationName Entity, + const FunctionProtoType::ExtProtoInfo &EPI); + + QualType BuildMemberPointerType(QualType T, QualType Class, + SourceLocation Loc, + DeclarationName Entity); + QualType BuildBlockPointerType(QualType T, + SourceLocation Loc, DeclarationName Entity); + QualType BuildParenType(QualType T); + QualType BuildAtomicType(QualType T, SourceLocation Loc); + QualType BuildReadPipeType(QualType T, + SourceLocation Loc); + QualType BuildWritePipeType(QualType T, + SourceLocation Loc); + QualType BuildBitIntType(bool IsUnsigned, Expr *BitWidth, SourceLocation Loc); + + TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S); + TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy); + + /// Package the given type and TSI into a ParsedType. + ParsedType CreateParsedType(QualType T, TypeSourceInfo *TInfo); + DeclarationNameInfo GetNameForDeclarator(Declarator &D); + DeclarationNameInfo GetNameFromUnqualifiedId(const UnqualifiedId &Name); + static QualType GetTypeFromParser(ParsedType Ty, + TypeSourceInfo **TInfo = nullptr); + CanThrowResult canThrow(const Stmt *E); + /// Determine whether the callee of a particular function call can throw. + /// E, D and Loc are all optional. + static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D, + SourceLocation Loc = SourceLocation()); + const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc, + const FunctionProtoType *FPT); + void UpdateExceptionSpec(FunctionDecl *FD, + const FunctionProtoType::ExceptionSpecInfo &ESI); + bool CheckSpecifiedExceptionType(QualType &T, SourceRange Range); + bool CheckDistantExceptionSpec(QualType T); + bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New); + bool CheckEquivalentExceptionSpec( + const FunctionProtoType *Old, SourceLocation OldLoc, + const FunctionProtoType *New, SourceLocation NewLoc); + bool CheckEquivalentExceptionSpec( + const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, + const FunctionProtoType *Old, SourceLocation OldLoc, + const FunctionProtoType *New, SourceLocation NewLoc); + bool handlerCanCatch(QualType HandlerType, QualType ExceptionType); + bool CheckExceptionSpecSubset(const PartialDiagnostic &DiagID, + const PartialDiagnostic &NestedDiagID, + const PartialDiagnostic &NoteID, + const PartialDiagnostic &NoThrowDiagID, + const FunctionProtoType *Superset, + SourceLocation SuperLoc, + const FunctionProtoType *Subset, + SourceLocation SubLoc); + bool CheckParamExceptionSpec(const PartialDiagnostic &NestedDiagID, + const PartialDiagnostic &NoteID, + const FunctionProtoType *Target, + SourceLocation TargetLoc, + const FunctionProtoType *Source, + SourceLocation SourceLoc); + + TypeResult ActOnTypeName(Scope *S, Declarator &D); + + /// The parser has parsed the context-sensitive type 'instancetype' + /// in an Objective-C message declaration. Return the appropriate type. + ParsedType ActOnObjCInstanceType(SourceLocation Loc); + + /// Abstract class used to diagnose incomplete types. + struct TypeDiagnoser { + TypeDiagnoser() {} + + virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) = 0; + virtual ~TypeDiagnoser() {} + }; + + static int getPrintable(int I) { return I; } + static unsigned getPrintable(unsigned I) { return I; } + static bool getPrintable(bool B) { return B; } + static const char * getPrintable(const char *S) { return S; } + static StringRef getPrintable(StringRef S) { return S; } + static const std::string &getPrintable(const std::string &S) { return S; } + static const IdentifierInfo *getPrintable(const IdentifierInfo *II) { + return II; + } + static DeclarationName getPrintable(DeclarationName N) { return N; } + static QualType getPrintable(QualType T) { return T; } + static SourceRange getPrintable(SourceRange R) { return R; } + static SourceRange getPrintable(SourceLocation L) { return L; } + static SourceRange getPrintable(const Expr *E) { return E->getSourceRange(); } + static SourceRange getPrintable(TypeLoc TL) { return TL.getSourceRange();} + + template <typename... Ts> class BoundTypeDiagnoser : public TypeDiagnoser { + protected: + unsigned DiagID; + std::tuple<const Ts &...> Args; + + template <std::size_t... Is> + void emit(const SemaDiagnosticBuilder &DB, + std::index_sequence<Is...>) const { + // Apply all tuple elements to the builder in order. + bool Dummy[] = {false, (DB << getPrintable(std::get<Is>(Args)))...}; + (void)Dummy; + } + + public: + BoundTypeDiagnoser(unsigned DiagID, const Ts &...Args) + : TypeDiagnoser(), DiagID(DiagID), Args(Args...) { + assert(DiagID != 0 && "no diagnostic for type diagnoser"); + } + + void diagnose(Sema &S, SourceLocation Loc, QualType T) override { + const SemaDiagnosticBuilder &DB = S.Diag(Loc, DiagID); + emit(DB, std::index_sequence_for<Ts...>()); + DB << T; + } + }; + + /// Do a check to make sure \p Name looks like a legal argument for the + /// swift_name attribute applied to decl \p D. Raise a diagnostic if the name + /// is invalid for the given declaration. + /// + /// \p AL is used to provide caret diagnostics in case of a malformed name. + /// + /// \returns true if the name is a valid swift name for \p D, false otherwise. + bool DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc, + const ParsedAttr &AL, bool IsAsync); + + /// A derivative of BoundTypeDiagnoser for which the diagnostic's type + /// parameter is preceded by a 0/1 enum that is 1 if the type is sizeless. + /// For example, a diagnostic with no other parameters would generally have + /// the form "...%select{incomplete|sizeless}0 type %1...". + template <typename... Ts> + class SizelessTypeDiagnoser : public BoundTypeDiagnoser<Ts...> { + public: + SizelessTypeDiagnoser(unsigned DiagID, const Ts &... Args) + : BoundTypeDiagnoser<Ts...>(DiagID, Args...) {} + + void diagnose(Sema &S, SourceLocation Loc, QualType T) override { + const SemaDiagnosticBuilder &DB = S.Diag(Loc, this->DiagID); + this->emit(DB, std::index_sequence_for<Ts...>()); + DB << T->isSizelessType() << T; + } + }; + + enum class CompleteTypeKind { + /// Apply the normal rules for complete types. In particular, + /// treat all sizeless types as incomplete. + Normal, + + /// Relax the normal rules for complete types so that they include + /// sizeless built-in types. + AcceptSizeless, + + // FIXME: Eventually we should flip the default to Normal and opt in + // to AcceptSizeless rather than opt out of it. + Default = AcceptSizeless + }; + + enum class AcceptableKind { Visible, Reachable }; + +private: + /// Methods for marking which expressions involve dereferencing a pointer + /// marked with the 'noderef' attribute. Expressions are checked bottom up as + /// they are parsed, meaning that a noderef pointer may not be accessed. For + /// example, in `&*p` where `p` is a noderef pointer, we will first parse the + /// `*p`, but need to check that `address of` is called on it. This requires + /// keeping a container of all pending expressions and checking if the address + /// of them are eventually taken. + void CheckSubscriptAccessOfNoDeref(const ArraySubscriptExpr *E); + void CheckAddressOfNoDeref(const Expr *E); + void CheckMemberAccessOfNoDeref(const MemberExpr *E); + + bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T, + CompleteTypeKind Kind, TypeDiagnoser *Diagnoser); + + struct ModuleScope { + SourceLocation BeginLoc; + clang::Module *Module = nullptr; + bool ModuleInterface = false; + bool IsPartition = false; + bool ImplicitGlobalModuleFragment = false; + VisibleModuleSet OuterVisibleModules; + }; + /// The modules we're currently parsing. + llvm::SmallVector<ModuleScope, 16> ModuleScopes; + /// The global module fragment of the current translation unit. + clang::Module *GlobalModuleFragment = nullptr; + + /// The modules we imported directly. + llvm::SmallPtrSet<clang::Module *, 8> DirectModuleImports; + + /// Namespace definitions that we will export when they finish. + llvm::SmallPtrSet<const NamespaceDecl*, 8> DeferredExportedNamespaces; + + /// In a C++ standard module, inline declarations require a definition to be + /// present at the end of a definition domain. This set holds the decls to + /// be checked at the end of the TU. + llvm::SmallPtrSet<const FunctionDecl *, 8> PendingInlineFuncDecls; + + /// Helper function to judge if we are in module purview. + /// Return false if we are not in a module. + bool isCurrentModulePurview() const { + return getCurrentModule() ? getCurrentModule()->isModulePurview() : false; + } + + /// Enter the scope of the global module. + Module *PushGlobalModuleFragment(SourceLocation BeginLoc, bool IsImplicit); + /// Leave the scope of the global module. + void PopGlobalModuleFragment(); + + VisibleModuleSet VisibleModules; + + /// Cache for module units which is usable for current module. + llvm::DenseSet<const Module *> UsableModuleUnitsCache; + + bool isUsableModule(const Module *M); + + bool isAcceptableSlow(const NamedDecl *D, AcceptableKind Kind); + +public: + /// Get the module unit whose scope we are currently within. + Module *getCurrentModule() const { + return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module; + } + + /// Is the module scope we are an interface? + bool currentModuleIsInterface() const { + return ModuleScopes.empty() ? false : ModuleScopes.back().ModuleInterface; + } + + /// Is the module scope we are in a C++ Header Unit? + bool currentModuleIsHeaderUnit() const { + return ModuleScopes.empty() ? false + : ModuleScopes.back().Module->isHeaderUnit(); + } + + /// Get the module owning an entity. + Module *getOwningModule(const Decl *Entity) { + return Entity->getOwningModule(); + } + + bool isModuleDirectlyImported(const Module *M) { + return DirectModuleImports.contains(M); + } + + // Determine whether the module M belongs to the current TU. + bool isModuleUnitOfCurrentTU(const Module *M) const; + + /// Make a merged definition of an existing hidden definition \p ND + /// visible at the specified location. + void makeMergedDefinitionVisible(NamedDecl *ND); + + bool isModuleVisible(const Module *M, bool ModulePrivate = false); + + // When loading a non-modular PCH files, this is used to restore module + // visibility. + void makeModuleVisible(Module *Mod, SourceLocation ImportLoc) { + VisibleModules.setVisible(Mod, ImportLoc); + } + + /// Determine whether a declaration is visible to name lookup. + bool isVisible(const NamedDecl *D) { + return D->isUnconditionallyVisible() || + isAcceptableSlow(D, AcceptableKind::Visible); + } + + /// Determine whether a declaration is reachable. + bool isReachable(const NamedDecl *D) { + // All visible declarations are reachable. + return D->isUnconditionallyVisible() || + isAcceptableSlow(D, AcceptableKind::Reachable); + } + + /// Determine whether a declaration is acceptable (visible/reachable). + bool isAcceptable(const NamedDecl *D, AcceptableKind Kind) { + return Kind == AcceptableKind::Visible ? isVisible(D) : isReachable(D); + } + + /// Determine whether any declaration of an entity is visible. + bool + hasVisibleDeclaration(const NamedDecl *D, + llvm::SmallVectorImpl<Module *> *Modules = nullptr) { + return isVisible(D) || hasVisibleDeclarationSlow(D, Modules); + } + + bool hasVisibleDeclarationSlow(const NamedDecl *D, + llvm::SmallVectorImpl<Module *> *Modules); + /// Determine whether any declaration of an entity is reachable. + bool + hasReachableDeclaration(const NamedDecl *D, + llvm::SmallVectorImpl<Module *> *Modules = nullptr) { + return isReachable(D) || hasReachableDeclarationSlow(D, Modules); + } + bool hasReachableDeclarationSlow( + const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr); + + bool hasVisibleMergedDefinition(NamedDecl *Def); + bool hasMergedDefinitionInCurrentModule(NamedDecl *Def); + + /// Determine if \p D and \p Suggested have a structurally compatible + /// layout as described in C11 6.2.7/1. + bool hasStructuralCompatLayout(Decl *D, Decl *Suggested); + + /// Determine if \p D has a visible definition. If not, suggest a declaration + /// that should be made visible to expose the definition. + bool hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, + bool OnlyNeedComplete = false); + bool hasVisibleDefinition(const NamedDecl *D) { + NamedDecl *Hidden; + return hasVisibleDefinition(const_cast<NamedDecl*>(D), &Hidden); + } + + /// Determine if \p D has a reachable definition. If not, suggest a + /// declaration that should be made reachable to expose the definition. + bool hasReachableDefinition(NamedDecl *D, NamedDecl **Suggested, + bool OnlyNeedComplete = false); + bool hasReachableDefinition(NamedDecl *D) { + NamedDecl *Hidden; + return hasReachableDefinition(D, &Hidden); + } + + bool hasAcceptableDefinition(NamedDecl *D, NamedDecl **Suggested, + AcceptableKind Kind, + bool OnlyNeedComplete = false); + bool hasAcceptableDefinition(NamedDecl *D, AcceptableKind Kind) { + NamedDecl *Hidden; + return hasAcceptableDefinition(D, &Hidden, Kind); + } + + /// Determine if the template parameter \p D has a visible default argument. + bool + hasVisibleDefaultArgument(const NamedDecl *D, + llvm::SmallVectorImpl<Module *> *Modules = nullptr); + /// Determine if the template parameter \p D has a reachable default argument. + bool hasReachableDefaultArgument( + const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr); + /// Determine if the template parameter \p D has a reachable default argument. + bool hasAcceptableDefaultArgument(const NamedDecl *D, + llvm::SmallVectorImpl<Module *> *Modules, + Sema::AcceptableKind Kind); + + /// Determine if there is a visible declaration of \p D that is an explicit + /// specialization declaration for a specialization of a template. (For a + /// member specialization, use hasVisibleMemberSpecialization.) + bool hasVisibleExplicitSpecialization( + const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr); + /// Determine if there is a reachable declaration of \p D that is an explicit + /// specialization declaration for a specialization of a template. (For a + /// member specialization, use hasReachableMemberSpecialization.) + bool hasReachableExplicitSpecialization( + const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr); + + /// Determine if there is a visible declaration of \p D that is a member + /// specialization declaration (as opposed to an instantiated declaration). + bool hasVisibleMemberSpecialization( + const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr); + /// Determine if there is a reachable declaration of \p D that is a member + /// specialization declaration (as opposed to an instantiated declaration). + bool hasReachableMemberSpecialization( + const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr); + + /// Determine if \p A and \p B are equivalent internal linkage declarations + /// from different modules, and thus an ambiguity error can be downgraded to + /// an extension warning. + bool isEquivalentInternalLinkageDeclaration(const NamedDecl *A, + const NamedDecl *B); + void diagnoseEquivalentInternalLinkageDeclarations( + SourceLocation Loc, const NamedDecl *D, + ArrayRef<const NamedDecl *> Equiv); + + bool isUsualDeallocationFunction(const CXXMethodDecl *FD); + + // Check whether the size of array element of type \p EltTy is a multiple of + // its alignment and return false if it isn't. + bool checkArrayElementAlignment(QualType EltTy, SourceLocation Loc); + + bool isCompleteType(SourceLocation Loc, QualType T, + CompleteTypeKind Kind = CompleteTypeKind::Default) { + return !RequireCompleteTypeImpl(Loc, T, Kind, nullptr); + } + bool RequireCompleteType(SourceLocation Loc, QualType T, + CompleteTypeKind Kind, TypeDiagnoser &Diagnoser); + bool RequireCompleteType(SourceLocation Loc, QualType T, + CompleteTypeKind Kind, unsigned DiagID); + + bool RequireCompleteType(SourceLocation Loc, QualType T, + TypeDiagnoser &Diagnoser) { + return RequireCompleteType(Loc, T, CompleteTypeKind::Default, Diagnoser); + } + bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID) { + return RequireCompleteType(Loc, T, CompleteTypeKind::Default, DiagID); + } + + template <typename... Ts> + bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID, + const Ts &...Args) { + BoundTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...); + return RequireCompleteType(Loc, T, Diagnoser); + } + + template <typename... Ts> + bool RequireCompleteSizedType(SourceLocation Loc, QualType T, unsigned DiagID, + const Ts &... Args) { + SizelessTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...); + return RequireCompleteType(Loc, T, CompleteTypeKind::Normal, Diagnoser); + } + + /// Get the type of expression E, triggering instantiation to complete the + /// type if necessary -- that is, if the expression refers to a templated + /// static data member of incomplete array type. + /// + /// May still return an incomplete type if instantiation was not possible or + /// if the type is incomplete for a different reason. Use + /// RequireCompleteExprType instead if a diagnostic is expected for an + /// incomplete expression type. + QualType getCompletedType(Expr *E); + + void completeExprArrayBound(Expr *E); + bool RequireCompleteExprType(Expr *E, CompleteTypeKind Kind, + TypeDiagnoser &Diagnoser); + bool RequireCompleteExprType(Expr *E, unsigned DiagID); + + template <typename... Ts> + bool RequireCompleteExprType(Expr *E, unsigned DiagID, const Ts &...Args) { + BoundTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...); + return RequireCompleteExprType(E, CompleteTypeKind::Default, Diagnoser); + } + + template <typename... Ts> + bool RequireCompleteSizedExprType(Expr *E, unsigned DiagID, + const Ts &... Args) { + SizelessTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...); + return RequireCompleteExprType(E, CompleteTypeKind::Normal, Diagnoser); + } + + bool RequireLiteralType(SourceLocation Loc, QualType T, + TypeDiagnoser &Diagnoser); + bool RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID); + + template <typename... Ts> + bool RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID, + const Ts &...Args) { + BoundTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...); + return RequireLiteralType(Loc, T, Diagnoser); + } + + QualType getElaboratedType(ElaboratedTypeKeyword Keyword, + const CXXScopeSpec &SS, QualType T, + TagDecl *OwnedTagDecl = nullptr); + + // Returns the underlying type of a decltype with the given expression. + QualType getDecltypeForExpr(Expr *E); + + QualType BuildTypeofExprType(Expr *E, TypeOfKind Kind); + /// If AsUnevaluated is false, E is treated as though it were an evaluated + /// context, such as when building a type for decltype(auto). + QualType BuildDecltypeType(Expr *E, bool AsUnevaluated = true); + + using UTTKind = UnaryTransformType::UTTKind; + QualType BuildUnaryTransformType(QualType BaseType, UTTKind UKind, + SourceLocation Loc); + QualType BuiltinEnumUnderlyingType(QualType BaseType, SourceLocation Loc); + QualType BuiltinAddPointer(QualType BaseType, SourceLocation Loc); + QualType BuiltinRemovePointer(QualType BaseType, SourceLocation Loc); + QualType BuiltinDecay(QualType BaseType, SourceLocation Loc); + QualType BuiltinAddReference(QualType BaseType, UTTKind UKind, + SourceLocation Loc); + QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind, + SourceLocation Loc); + QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind, + SourceLocation Loc); + QualType BuiltinChangeCVRQualifiers(QualType BaseType, UTTKind UKind, + SourceLocation Loc); + QualType BuiltinChangeSignedness(QualType BaseType, UTTKind UKind, + SourceLocation Loc); + + //===--------------------------------------------------------------------===// + // Symbol table / Decl tracking callbacks: SemaDecl.cpp. + // + + struct SkipBodyInfo { + SkipBodyInfo() + : ShouldSkip(false), CheckSameAsPrevious(false), Previous(nullptr), + New(nullptr) {} + bool ShouldSkip; + bool CheckSameAsPrevious; + NamedDecl *Previous; + NamedDecl *New; + }; + + DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = nullptr); + + void DiagnoseUseOfUnimplementedSelectors(); + + bool isSimpleTypeSpecifier(tok::TokenKind Kind) const; + + ParsedType getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, CXXScopeSpec *SS = nullptr, + bool isClassName = false, bool HasTrailingDot = false, + ParsedType ObjectType = nullptr, + bool IsCtorOrDtorName = false, + bool WantNontrivialTypeSourceInfo = false, + bool IsClassTemplateDeductionContext = true, + ImplicitTypenameContext AllowImplicitTypename = + ImplicitTypenameContext::No, + IdentifierInfo **CorrectedII = nullptr); + TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S); + bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S); + void DiagnoseUnknownTypeName(IdentifierInfo *&II, + SourceLocation IILoc, + Scope *S, + CXXScopeSpec *SS, + ParsedType &SuggestedType, + bool IsTemplateName = false); + + /// Attempt to behave like MSVC in situations where lookup of an unqualified + /// type name has failed in a dependent context. In these situations, we + /// automatically form a DependentTypeName that will retry lookup in a related + /// scope during instantiation. + ParsedType ActOnMSVCUnknownTypeName(const IdentifierInfo &II, + SourceLocation NameLoc, + bool IsTemplateTypeArg); + + /// Describes the result of the name lookup and resolution performed + /// by \c ClassifyName(). + enum NameClassificationKind { + /// This name is not a type or template in this context, but might be + /// something else. + NC_Unknown, + /// Classification failed; an error has been produced. + NC_Error, + /// The name has been typo-corrected to a keyword. + NC_Keyword, + /// The name was classified as a type. + NC_Type, + /// The name was classified as a specific non-type, non-template + /// declaration. ActOnNameClassifiedAsNonType should be called to + /// convert the declaration to an expression. + NC_NonType, + /// The name was classified as an ADL-only function name. + /// ActOnNameClassifiedAsUndeclaredNonType should be called to convert the + /// result to an expression. + NC_UndeclaredNonType, + /// The name denotes a member of a dependent type that could not be + /// resolved. ActOnNameClassifiedAsDependentNonType should be called to + /// convert the result to an expression. + NC_DependentNonType, + /// The name was classified as an overload set, and an expression + /// representing that overload set has been formed. + /// ActOnNameClassifiedAsOverloadSet should be called to form a suitable + /// expression referencing the overload set. + NC_OverloadSet, + /// The name was classified as a template whose specializations are types. + NC_TypeTemplate, + /// The name was classified as a variable template name. + NC_VarTemplate, + /// The name was classified as a function template name. + NC_FunctionTemplate, + /// The name was classified as an ADL-only function template name. + NC_UndeclaredTemplate, + /// The name was classified as a concept name. + NC_Concept, + }; + + class NameClassification { + NameClassificationKind Kind; + union { + ExprResult Expr; + NamedDecl *NonTypeDecl; + TemplateName Template; + ParsedType Type; + }; + + explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {} + + public: + NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {} + + NameClassification(const IdentifierInfo *Keyword) : Kind(NC_Keyword) {} + + static NameClassification Error() { + return NameClassification(NC_Error); + } + + static NameClassification Unknown() { + return NameClassification(NC_Unknown); + } + + static NameClassification OverloadSet(ExprResult E) { + NameClassification Result(NC_OverloadSet); + Result.Expr = E; + return Result; + } + + static NameClassification NonType(NamedDecl *D) { + NameClassification Result(NC_NonType); + Result.NonTypeDecl = D; + return Result; + } + + static NameClassification UndeclaredNonType() { + return NameClassification(NC_UndeclaredNonType); + } + + static NameClassification DependentNonType() { + return NameClassification(NC_DependentNonType); + } + + static NameClassification TypeTemplate(TemplateName Name) { + NameClassification Result(NC_TypeTemplate); + Result.Template = Name; + return Result; + } + + static NameClassification VarTemplate(TemplateName Name) { + NameClassification Result(NC_VarTemplate); + Result.Template = Name; + return Result; + } + + static NameClassification FunctionTemplate(TemplateName Name) { + NameClassification Result(NC_FunctionTemplate); + Result.Template = Name; + return Result; + } + + static NameClassification Concept(TemplateName Name) { + NameClassification Result(NC_Concept); + Result.Template = Name; + return Result; + } + + static NameClassification UndeclaredTemplate(TemplateName Name) { + NameClassification Result(NC_UndeclaredTemplate); + Result.Template = Name; + return Result; + } + + NameClassificationKind getKind() const { return Kind; } + + ExprResult getExpression() const { + assert(Kind == NC_OverloadSet); + return Expr; + } + + ParsedType getType() const { + assert(Kind == NC_Type); + return Type; + } + + NamedDecl *getNonTypeDecl() const { + assert(Kind == NC_NonType); + return NonTypeDecl; + } + + TemplateName getTemplateName() const { + assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate || + Kind == NC_VarTemplate || Kind == NC_Concept || + Kind == NC_UndeclaredTemplate); + return Template; + } + + TemplateNameKind getTemplateNameKind() const { + switch (Kind) { + case NC_TypeTemplate: + return TNK_Type_template; + case NC_FunctionTemplate: + return TNK_Function_template; + case NC_VarTemplate: + return TNK_Var_template; + case NC_Concept: + return TNK_Concept_template; + case NC_UndeclaredTemplate: + return TNK_Undeclared_template; + default: + llvm_unreachable("unsupported name classification."); + } + } + }; + + /// Perform name lookup on the given name, classifying it based on + /// the results of name lookup and the following token. + /// + /// This routine is used by the parser to resolve identifiers and help direct + /// parsing. When the identifier cannot be found, this routine will attempt + /// to correct the typo and classify based on the resulting name. + /// + /// \param S The scope in which we're performing name lookup. + /// + /// \param SS The nested-name-specifier that precedes the name. + /// + /// \param Name The identifier. If typo correction finds an alternative name, + /// this pointer parameter will be updated accordingly. + /// + /// \param NameLoc The location of the identifier. + /// + /// \param NextToken The token following the identifier. Used to help + /// disambiguate the name. + /// + /// \param CCC The correction callback, if typo correction is desired. + NameClassification ClassifyName(Scope *S, CXXScopeSpec &SS, + IdentifierInfo *&Name, SourceLocation NameLoc, + const Token &NextToken, + CorrectionCandidateCallback *CCC = nullptr); + + /// Act on the result of classifying a name as an undeclared (ADL-only) + /// non-type declaration. + ExprResult ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name, + SourceLocation NameLoc); + /// Act on the result of classifying a name as an undeclared member of a + /// dependent base class. + ExprResult ActOnNameClassifiedAsDependentNonType(const CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool IsAddressOfOperand); + /// Act on the result of classifying a name as a specific non-type + /// declaration. + ExprResult ActOnNameClassifiedAsNonType(Scope *S, const CXXScopeSpec &SS, + NamedDecl *Found, + SourceLocation NameLoc, + const Token &NextToken); + /// Act on the result of classifying a name as an overload set. + ExprResult ActOnNameClassifiedAsOverloadSet(Scope *S, Expr *OverloadSet); + + /// Describes the detailed kind of a template name. Used in diagnostics. + enum class TemplateNameKindForDiagnostics { + ClassTemplate, + FunctionTemplate, + VarTemplate, + AliasTemplate, + TemplateTemplateParam, + Concept, + DependentTemplate + }; + TemplateNameKindForDiagnostics + getTemplateNameKindForDiagnostics(TemplateName Name); + + /// Determine whether it's plausible that E was intended to be a + /// template-name. + bool mightBeIntendedToBeTemplateName(ExprResult E, bool &Dependent) { + if (!getLangOpts().CPlusPlus || E.isInvalid()) + return false; + Dependent = false; + if (auto *DRE = dyn_cast<DeclRefExpr>(E.get())) + return !DRE->hasExplicitTemplateArgs(); + if (auto *ME = dyn_cast<MemberExpr>(E.get())) + return !ME->hasExplicitTemplateArgs(); + Dependent = true; + if (auto *DSDRE = dyn_cast<DependentScopeDeclRefExpr>(E.get())) + return !DSDRE->hasExplicitTemplateArgs(); + if (auto *DSME = dyn_cast<CXXDependentScopeMemberExpr>(E.get())) + return !DSME->hasExplicitTemplateArgs(); + // Any additional cases recognized here should also be handled by + // diagnoseExprIntendedAsTemplateName. + return false; + } + void diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, + SourceLocation Less, + SourceLocation Greater); + + void warnOnReservedIdentifier(const NamedDecl *D); + + Decl *ActOnDeclarator(Scope *S, Declarator &D); + + NamedDecl *HandleDeclarator(Scope *S, Declarator &D, + MultiTemplateParamsArg TemplateParameterLists); + bool tryToFixVariablyModifiedVarType(TypeSourceInfo *&TInfo, + QualType &T, SourceLocation Loc, + unsigned FailedFoldDiagID); + void RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S); + bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info); + bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, + DeclarationName Name, SourceLocation Loc, + bool IsTemplateId); + void + diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals, + SourceLocation FallbackLoc, + SourceLocation ConstQualLoc = SourceLocation(), + SourceLocation VolatileQualLoc = SourceLocation(), + SourceLocation RestrictQualLoc = SourceLocation(), + SourceLocation AtomicQualLoc = SourceLocation(), + SourceLocation UnalignedQualLoc = SourceLocation()); + + static bool adjustContextForLocalExternDecl(DeclContext *&DC); + void DiagnoseFunctionSpecifiers(const DeclSpec &DS); + NamedDecl *getShadowedDeclaration(const TypedefNameDecl *D, + const LookupResult &R); + NamedDecl *getShadowedDeclaration(const VarDecl *D, const LookupResult &R); + NamedDecl *getShadowedDeclaration(const BindingDecl *D, + const LookupResult &R); + void CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl, + const LookupResult &R); + void CheckShadow(Scope *S, VarDecl *D); + + /// Warn if 'E', which is an expression that is about to be modified, refers + /// to a shadowing declaration. + void CheckShadowingDeclModification(Expr *E, SourceLocation Loc); + + void DiagnoseShadowingLambdaDecls(const sema::LambdaScopeInfo *LSI); + +private: + /// Map of current shadowing declarations to shadowed declarations. Warn if + /// it looks like the user is trying to modify the shadowing declaration. + llvm::DenseMap<const NamedDecl *, const NamedDecl *> ShadowingDecls; + +public: + void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange); + void handleTagNumbering(const TagDecl *Tag, Scope *TagScope); + void setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec, + TypedefNameDecl *NewTD); + void CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *D); + NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, + TypeSourceInfo *TInfo, + LookupResult &Previous); + NamedDecl* ActOnTypedefNameDecl(Scope* S, DeclContext* DC, TypedefNameDecl *D, + LookupResult &Previous, bool &Redeclaration); + NamedDecl *ActOnVariableDeclarator( + Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, + LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, + bool &AddToScope, ArrayRef<BindingDecl *> Bindings = std::nullopt); + NamedDecl * + ActOnDecompositionDeclarator(Scope *S, Declarator &D, + MultiTemplateParamsArg TemplateParamLists); + // Returns true if the variable declaration is a redeclaration + bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous); + void CheckVariableDeclarationType(VarDecl *NewVD); + bool DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit, + Expr *Init); + void CheckCompleteVariableDeclaration(VarDecl *VD); + void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD); + void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D); + + NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, + TypeSourceInfo *TInfo, + LookupResult &Previous, + MultiTemplateParamsArg TemplateParamLists, + bool &AddToScope); + bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); + + enum class CheckConstexprKind { + /// Diagnose issues that are non-constant or that are extensions. + Diagnose, + /// Identify whether this function satisfies the formal rules for constexpr + /// functions in the current lanugage mode (with no extensions). + CheckValid + }; + + bool CheckConstexprFunctionDefinition(const FunctionDecl *FD, + CheckConstexprKind Kind); + + void DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD); + void FindHiddenVirtualMethods(CXXMethodDecl *MD, + SmallVectorImpl<CXXMethodDecl*> &OverloadedMethods); + void NoteHiddenVirtualMethods(CXXMethodDecl *MD, + SmallVectorImpl<CXXMethodDecl*> &OverloadedMethods); + // Returns true if the function declaration is a redeclaration + bool CheckFunctionDeclaration(Scope *S, + FunctionDecl *NewFD, LookupResult &Previous, + bool IsMemberSpecialization, bool DeclIsDefn); + bool shouldLinkDependentDeclWithPrevious(Decl *D, Decl *OldDecl); + bool canFullyTypeCheckRedeclaration(ValueDecl *NewD, ValueDecl *OldD, + QualType NewT, QualType OldT); + void CheckMain(FunctionDecl *FD, const DeclSpec &D); + void CheckMSVCRTEntryPoint(FunctionDecl *FD); + void CheckHLSLEntryPoint(FunctionDecl *FD); + Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, + bool IsDefinition); + void CheckFunctionOrTemplateParamDeclarator(Scope *S, Declarator &D); + Decl *ActOnParamDeclarator(Scope *S, Declarator &D); + ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC, + SourceLocation Loc, + QualType T); + ParmVarDecl *CheckParameter(DeclContext *DC, SourceLocation StartLoc, + SourceLocation NameLoc, IdentifierInfo *Name, + QualType T, TypeSourceInfo *TSInfo, + StorageClass SC); + void ActOnParamDefaultArgument(Decl *param, + SourceLocation EqualLoc, + Expr *defarg); + void ActOnParamUnparsedDefaultArgument(Decl *param, SourceLocation EqualLoc, + SourceLocation ArgLoc); + void ActOnParamDefaultArgumentError(Decl *param, SourceLocation EqualLoc); + ExprResult ConvertParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg, + SourceLocation EqualLoc); + void SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg, + SourceLocation EqualLoc); + + // Contexts where using non-trivial C union types can be disallowed. This is + // passed to err_non_trivial_c_union_in_invalid_context. + enum NonTrivialCUnionContext { + // Function parameter. + NTCUC_FunctionParam, + // Function return. + NTCUC_FunctionReturn, + // Default-initialized object. + NTCUC_DefaultInitializedObject, + // Variable with automatic storage duration. + NTCUC_AutoVar, + // Initializer expression that might copy from another object. + NTCUC_CopyInit, + // Assignment. + NTCUC_Assignment, + // Compound literal. + NTCUC_CompoundLiteral, + // Block capture. + NTCUC_BlockCapture, + // lvalue-to-rvalue conversion of volatile type. + NTCUC_LValueToRValueVolatile, + }; + + /// Emit diagnostics if the initializer or any of its explicit or + /// implicitly-generated subexpressions require copying or + /// default-initializing a type that is or contains a C union type that is + /// non-trivial to copy or default-initialize. + void checkNonTrivialCUnionInInitializer(const Expr *Init, SourceLocation Loc); + + // These flags are passed to checkNonTrivialCUnion. + enum NonTrivialCUnionKind { + NTCUK_Init = 0x1, + NTCUK_Destruct = 0x2, + NTCUK_Copy = 0x4, + }; + + /// Emit diagnostics if a non-trivial C union type or a struct that contains + /// a non-trivial C union is used in an invalid context. + void checkNonTrivialCUnion(QualType QT, SourceLocation Loc, + NonTrivialCUnionContext UseContext, + unsigned NonTrivialKind); + + void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit); + void ActOnUninitializedDecl(Decl *dcl); + void ActOnInitializerError(Decl *Dcl); + + void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc); + void ActOnCXXForRangeDecl(Decl *D); + StmtResult ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, + IdentifierInfo *Ident, + ParsedAttributes &Attrs); + void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); + void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc); + void CheckStaticLocalForDllExport(VarDecl *VD); + void CheckThreadLocalForLargeAlignment(VarDecl *VD); + void FinalizeDeclaration(Decl *D); + DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, + ArrayRef<Decl *> Group); + DeclGroupPtrTy BuildDeclaratorGroup(MutableArrayRef<Decl *> Group); + + /// Should be called on all declarations that might have attached + /// documentation comments. + void ActOnDocumentableDecl(Decl *D); + void ActOnDocumentableDecls(ArrayRef<Decl *> Group); + + enum class FnBodyKind { + /// C++ [dcl.fct.def.general]p1 + /// function-body: + /// ctor-initializer[opt] compound-statement + /// function-try-block + Other, + /// = default ; + Default, + /// = delete ; + Delete + }; + + void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, + SourceLocation LocAfterDecls); + void CheckForFunctionRedefinition( + FunctionDecl *FD, const FunctionDecl *EffectiveDefinition = nullptr, + SkipBodyInfo *SkipBody = nullptr); + Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D, + MultiTemplateParamsArg TemplateParamLists, + SkipBodyInfo *SkipBody = nullptr, + FnBodyKind BodyKind = FnBodyKind::Other); + Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D, + SkipBodyInfo *SkipBody = nullptr, + FnBodyKind BodyKind = FnBodyKind::Other); + void SetFunctionBodyKind(Decl *D, SourceLocation Loc, FnBodyKind BodyKind); + void ActOnStartTrailingRequiresClause(Scope *S, Declarator &D); + ExprResult ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr); + ExprResult ActOnRequiresClause(ExprResult ConstraintExpr); + void ActOnStartOfObjCMethodDef(Scope *S, Decl *D); + bool isObjCMethodDecl(Decl *D) { + return D && isa<ObjCMethodDecl>(D); + } + + /// Determine whether we can delay parsing the body of a function or + /// function template until it is used, assuming we don't care about emitting + /// code for that function. + /// + /// This will be \c false if we may need the body of the function in the + /// middle of parsing an expression (where it's impractical to switch to + /// parsing a different function), for instance, if it's constexpr in C++11 + /// or has an 'auto' return type in C++14. These cases are essentially bugs. + bool canDelayFunctionBody(const Declarator &D); + + /// Determine whether we can skip parsing the body of a function + /// definition, assuming we don't care about analyzing its body or emitting + /// code for that function. + /// + /// This will be \c false only if we may need the body of the function in + /// order to parse the rest of the program (for instance, if it is + /// \c constexpr in C++11 or has an 'auto' return type in C++14). + bool canSkipFunctionBody(Decl *D); + + /// Determine whether \param D is function like (function or function + /// template) for parsing. + bool isDeclaratorFunctionLike(Declarator &D); + + void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope); + Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body); + Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation); + Decl *ActOnSkippedFunctionBody(Decl *Decl); + void ActOnFinishInlineFunctionDef(FunctionDecl *D); + + /// ActOnFinishDelayedAttribute - Invoked when we have finished parsing an + /// attribute for which parsing is delayed. + void ActOnFinishDelayedAttribute(Scope *S, Decl *D, ParsedAttributes &Attrs); + + /// Diagnose any unused parameters in the given sequence of + /// ParmVarDecl pointers. + void DiagnoseUnusedParameters(ArrayRef<ParmVarDecl *> Parameters); + + /// Diagnose whether the size of parameters or return value of a + /// function or obj-c method definition is pass-by-value and larger than a + /// specified threshold. + void + DiagnoseSizeOfParametersAndReturnValue(ArrayRef<ParmVarDecl *> Parameters, + QualType ReturnTy, NamedDecl *D); + + void DiagnoseInvalidJumps(Stmt *Body); + Decl *ActOnFileScopeAsmDecl(Expr *expr, + SourceLocation AsmLoc, + SourceLocation RParenLoc); + + Decl *ActOnTopLevelStmtDecl(Stmt *Statement); + + /// Handle a C++11 empty-declaration and attribute-declaration. + Decl *ActOnEmptyDeclaration(Scope *S, const ParsedAttributesView &AttrList, + SourceLocation SemiLoc); + + enum class ModuleDeclKind { + Interface, ///< 'export module X;' + Implementation, ///< 'module X;' + PartitionInterface, ///< 'export module X:Y;' + PartitionImplementation, ///< 'module X:Y;' + }; + + /// An enumeration to represent the transition of states in parsing module + /// fragments and imports. If we are not parsing a C++20 TU, or we find + /// an error in state transition, the state is set to NotACXX20Module. + enum class ModuleImportState { + FirstDecl, ///< Parsing the first decl in a TU. + GlobalFragment, ///< after 'module;' but before 'module X;' + ImportAllowed, ///< after 'module X;' but before any non-import decl. + ImportFinished, ///< after any non-import decl. + PrivateFragmentImportAllowed, ///< after 'module :private;' but before any + ///< non-import decl. + PrivateFragmentImportFinished, ///< after 'module :private;' but a + ///< non-import decl has already been seen. + NotACXX20Module ///< Not a C++20 TU, or an invalid state was found. + }; + +private: + /// The parser has begun a translation unit to be compiled as a C++20 + /// Header Unit, helper for ActOnStartOfTranslationUnit() only. + void HandleStartOfHeaderUnit(); + +public: + /// The parser has processed a module-declaration that begins the definition + /// of a module interface or implementation. + DeclGroupPtrTy ActOnModuleDecl(SourceLocation StartLoc, + SourceLocation ModuleLoc, ModuleDeclKind MDK, + ModuleIdPath Path, ModuleIdPath Partition, + ModuleImportState &ImportState); + + /// The parser has processed a global-module-fragment declaration that begins + /// the definition of the global module fragment of the current module unit. + /// \param ModuleLoc The location of the 'module' keyword. + DeclGroupPtrTy ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc); + + /// The parser has processed a private-module-fragment declaration that begins + /// the definition of the private module fragment of the current module unit. + /// \param ModuleLoc The location of the 'module' keyword. + /// \param PrivateLoc The location of the 'private' keyword. + DeclGroupPtrTy ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc, + SourceLocation PrivateLoc); + + /// The parser has processed a module import declaration. + /// + /// \param StartLoc The location of the first token in the declaration. This + /// could be the location of an '@', 'export', or 'import'. + /// \param ExportLoc The location of the 'export' keyword, if any. + /// \param ImportLoc The location of the 'import' keyword. + /// \param Path The module toplevel name as an access path. + /// \param IsPartition If the name is for a partition. + DeclResult ActOnModuleImport(SourceLocation StartLoc, + SourceLocation ExportLoc, + SourceLocation ImportLoc, ModuleIdPath Path, + bool IsPartition = false); + DeclResult ActOnModuleImport(SourceLocation StartLoc, + SourceLocation ExportLoc, + SourceLocation ImportLoc, Module *M, + ModuleIdPath Path = {}); + + /// The parser has processed a module import translated from a + /// #include or similar preprocessing directive. + void ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod); + void BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod); + + /// The parsed has entered a submodule. + void ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod); + /// The parser has left a submodule. + void ActOnModuleEnd(SourceLocation DirectiveLoc, Module *Mod); + + /// Create an implicit import of the given module at the given + /// source location, for error recovery, if possible. + /// + /// This routine is typically used when an entity found by name lookup + /// is actually hidden within a module that we know about but the user + /// has forgotten to import. + void createImplicitModuleImportForErrorRecovery(SourceLocation Loc, + Module *Mod); + + /// Kinds of missing import. Note, the values of these enumerators correspond + /// to %select values in diagnostics. + enum class MissingImportKind { + Declaration, + Definition, + DefaultArgument, + ExplicitSpecialization, + PartialSpecialization + }; + + /// Diagnose that the specified declaration needs to be visible but + /// isn't, and suggest a module import that would resolve the problem. + void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, + MissingImportKind MIK, bool Recover = true); + void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, + SourceLocation DeclLoc, ArrayRef<Module *> Modules, + MissingImportKind MIK, bool Recover); + + Decl *ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, + SourceLocation LBraceLoc); + Decl *ActOnFinishExportDecl(Scope *S, Decl *ExportDecl, + SourceLocation RBraceLoc); + + /// We've found a use of a templated declaration that would trigger an + /// implicit instantiation. Check that any relevant explicit specializations + /// and partial specializations are visible/reachable, and diagnose if not. + void checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec); + void checkSpecializationReachability(SourceLocation Loc, NamedDecl *Spec); + + /// Retrieve a suitable printing policy for diagnostics. + PrintingPolicy getPrintingPolicy() const { + return getPrintingPolicy(Context, PP); + } + + /// Retrieve a suitable printing policy for diagnostics. + static PrintingPolicy getPrintingPolicy(const ASTContext &Ctx, + const Preprocessor &PP); + + /// Scope actions. + void ActOnPopScope(SourceLocation Loc, Scope *S); + void ActOnTranslationUnitScope(Scope *S); + + Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, + const ParsedAttributesView &DeclAttrs, + RecordDecl *&AnonRecord); + Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, + const ParsedAttributesView &DeclAttrs, + MultiTemplateParamsArg TemplateParams, + bool IsExplicitInstantiation, + RecordDecl *&AnonRecord); + + Decl *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, + AccessSpecifier AS, + RecordDecl *Record, + const PrintingPolicy &Policy); + + Decl *BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, + RecordDecl *Record); + + /// Common ways to introduce type names without a tag for use in diagnostics. + /// Keep in sync with err_tag_reference_non_tag. + enum NonTagKind { + NTK_NonStruct, + NTK_NonClass, + NTK_NonUnion, + NTK_NonEnum, + NTK_Typedef, + NTK_TypeAlias, + NTK_Template, + NTK_TypeAliasTemplate, + NTK_TemplateTemplateArgument, + }; + + /// Given a non-tag type declaration, returns an enum useful for indicating + /// what kind of non-tag type this is. + NonTagKind getNonTagTypeDeclKind(const Decl *D, TagTypeKind TTK); + + bool isAcceptableTagRedeclaration(const TagDecl *Previous, + TagTypeKind NewTag, bool isDefinition, + SourceLocation NewTagLoc, + const IdentifierInfo *Name); + + enum TagUseKind { + TUK_Reference, // Reference to a tag: 'struct foo *X;' + TUK_Declaration, // Fwd decl of a tag: 'struct foo;' + TUK_Definition, // Definition of a tag: 'struct foo { int X; } Y;' + TUK_Friend // Friend declaration: 'friend struct foo;' + }; + + enum OffsetOfKind { + // Not parsing a type within __builtin_offsetof. + OOK_Outside, + // Parsing a type within __builtin_offsetof. + OOK_Builtin, + // Parsing a type within macro "offsetof", defined in __buitin_offsetof + // To improve our diagnostic message. + OOK_Macro, + }; + + DeclResult ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, + SourceLocation KWLoc, CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + const ParsedAttributesView &Attr, AccessSpecifier AS, + SourceLocation ModulePrivateLoc, + MultiTemplateParamsArg TemplateParameterLists, + bool &OwnedDecl, bool &IsDependent, + SourceLocation ScopedEnumKWLoc, + bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, + bool IsTypeSpecifier, bool IsTemplateParamOrArg, + OffsetOfKind OOK, SkipBodyInfo *SkipBody = nullptr); + + DeclResult ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, + unsigned TagSpec, SourceLocation TagLoc, + CXXScopeSpec &SS, IdentifierInfo *Name, + SourceLocation NameLoc, + const ParsedAttributesView &Attr, + MultiTemplateParamsArg TempParamLists); + + TypeResult ActOnDependentTag(Scope *S, + unsigned TagSpec, + TagUseKind TUK, + const CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation TagLoc, + SourceLocation NameLoc); + + void ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, + IdentifierInfo *ClassName, + SmallVectorImpl<Decl *> &Decls); + Decl *ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, + Declarator &D, Expr *BitfieldWidth); + + FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, + Declarator &D, Expr *BitfieldWidth, + InClassInitStyle InitStyle, + AccessSpecifier AS); + MSPropertyDecl *HandleMSProperty(Scope *S, RecordDecl *TagD, + SourceLocation DeclStart, Declarator &D, + Expr *BitfieldWidth, + InClassInitStyle InitStyle, + AccessSpecifier AS, + const ParsedAttr &MSPropertyAttr); + + FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, + TypeSourceInfo *TInfo, + RecordDecl *Record, SourceLocation Loc, + bool Mutable, Expr *BitfieldWidth, + InClassInitStyle InitStyle, + SourceLocation TSSL, + AccessSpecifier AS, NamedDecl *PrevDecl, + Declarator *D = nullptr); + + bool CheckNontrivialField(FieldDecl *FD); + void DiagnoseNontrivial(const CXXRecordDecl *Record, CXXSpecialMember CSM); + + enum TrivialABIHandling { + /// The triviality of a method unaffected by "trivial_abi". + TAH_IgnoreTrivialABI, + + /// The triviality of a method affected by "trivial_abi". + TAH_ConsiderTrivialABI + }; + + bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, + TrivialABIHandling TAH = TAH_IgnoreTrivialABI, + bool Diagnose = false); + + /// For a defaulted function, the kind of defaulted function that it is. + class DefaultedFunctionKind { + CXXSpecialMember SpecialMember : 8; + DefaultedComparisonKind Comparison : 8; + + public: + DefaultedFunctionKind() + : SpecialMember(CXXInvalid), Comparison(DefaultedComparisonKind::None) { + } + DefaultedFunctionKind(CXXSpecialMember CSM) + : SpecialMember(CSM), Comparison(DefaultedComparisonKind::None) {} + DefaultedFunctionKind(DefaultedComparisonKind Comp) + : SpecialMember(CXXInvalid), Comparison(Comp) {} + + bool isSpecialMember() const { return SpecialMember != CXXInvalid; } + bool isComparison() const { + return Comparison != DefaultedComparisonKind::None; + } + + explicit operator bool() const { + return isSpecialMember() || isComparison(); + } + + CXXSpecialMember asSpecialMember() const { return SpecialMember; } + DefaultedComparisonKind asComparison() const { return Comparison; } + + /// Get the index of this function kind for use in diagnostics. + unsigned getDiagnosticIndex() const { + static_assert(CXXInvalid > CXXDestructor, + "invalid should have highest index"); + static_assert((unsigned)DefaultedComparisonKind::None == 0, + "none should be equal to zero"); + return SpecialMember + (unsigned)Comparison; + } + }; + + DefaultedFunctionKind getDefaultedFunctionKind(const FunctionDecl *FD); + + CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD) { + return getDefaultedFunctionKind(MD).asSpecialMember(); + } + DefaultedComparisonKind getDefaultedComparisonKind(const FunctionDecl *FD) { + return getDefaultedFunctionKind(FD).asComparison(); + } + + void ActOnLastBitfield(SourceLocation DeclStart, + SmallVectorImpl<Decl *> &AllIvarDecls); + Decl *ActOnIvar(Scope *S, SourceLocation DeclStart, + Declarator &D, Expr *BitfieldWidth, + tok::ObjCKeywordKind visibility); + + // This is used for both record definitions and ObjC interface declarations. + void ActOnFields(Scope *S, SourceLocation RecLoc, Decl *TagDecl, + ArrayRef<Decl *> Fields, SourceLocation LBrac, + SourceLocation RBrac, const ParsedAttributesView &AttrList); + + /// ActOnTagStartDefinition - Invoked when we have entered the + /// scope of a tag's definition (e.g., for an enumeration, class, + /// struct, or union). + void ActOnTagStartDefinition(Scope *S, Decl *TagDecl); + + /// Perform ODR-like check for C/ObjC when merging tag types from modules. + /// Differently from C++, actually parse the body and reject / error out + /// in case of a structural mismatch. + bool ActOnDuplicateDefinition(Decl *Prev, SkipBodyInfo &SkipBody); + + /// Check ODR hashes for C/ObjC when merging types from modules. + /// Differently from C++, actually parse the body and reject in case + /// of a mismatch. + template <typename T, + typename = std::enable_if_t<std::is_base_of<NamedDecl, T>::value>> + bool ActOnDuplicateODRHashDefinition(T *Duplicate, T *Previous) { + if (Duplicate->getODRHash() != Previous->getODRHash()) + return false; + + // Make the previous decl visible. + makeMergedDefinitionVisible(Previous); + return true; + } + + typedef void *SkippedDefinitionContext; + + /// Invoked when we enter a tag definition that we're skipping. + SkippedDefinitionContext ActOnTagStartSkippedDefinition(Scope *S, Decl *TD); + + void ActOnObjCContainerStartDefinition(ObjCContainerDecl *IDecl); + + /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a + /// C++ record definition's base-specifiers clause and are starting its + /// member declarations. + void ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagDecl, + SourceLocation FinalLoc, + bool IsFinalSpelledSealed, + bool IsAbstract, + SourceLocation LBraceLoc); + + /// ActOnTagFinishDefinition - Invoked once we have finished parsing + /// the definition of a tag (enumeration, class, struct, or union). + void ActOnTagFinishDefinition(Scope *S, Decl *TagDecl, + SourceRange BraceRange); + + void ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context); + + void ActOnObjCContainerFinishDefinition(); + + /// Invoked when we must temporarily exit the objective-c container + /// scope for parsing/looking-up C constructs. + /// + /// Must be followed by a call to \see ActOnObjCReenterContainerContext + void ActOnObjCTemporaryExitContainerContext(ObjCContainerDecl *ObjCCtx); + void ActOnObjCReenterContainerContext(ObjCContainerDecl *ObjCCtx); + + /// ActOnTagDefinitionError - Invoked when there was an unrecoverable + /// error parsing the definition of a tag. + void ActOnTagDefinitionError(Scope *S, Decl *TagDecl); + + EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum, + EnumConstantDecl *LastEnumConst, + SourceLocation IdLoc, + IdentifierInfo *Id, + Expr *val); + bool CheckEnumUnderlyingType(TypeSourceInfo *TI); + bool CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, + QualType EnumUnderlyingTy, bool IsFixed, + const EnumDecl *Prev); + + /// Determine whether the body of an anonymous enumeration should be skipped. + /// \param II The name of the first enumerator. + SkipBodyInfo shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II, + SourceLocation IILoc); + + Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant, + SourceLocation IdLoc, IdentifierInfo *Id, + const ParsedAttributesView &Attrs, + SourceLocation EqualLoc, Expr *Val); + void ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, + Decl *EnumDecl, ArrayRef<Decl *> Elements, Scope *S, + const ParsedAttributesView &Attr); + + /// Set the current declaration context until it gets popped. + void PushDeclContext(Scope *S, DeclContext *DC); + void PopDeclContext(); + + /// EnterDeclaratorContext - Used when we must lookup names in the context + /// of a declarator's nested name specifier. + void EnterDeclaratorContext(Scope *S, DeclContext *DC); + void ExitDeclaratorContext(Scope *S); + + /// Enter a template parameter scope, after it's been associated with a particular + /// DeclContext. Causes lookup within the scope to chain through enclosing contexts + /// in the correct order. + void EnterTemplatedContext(Scope *S, DeclContext *DC); + + /// Push the parameters of D, which must be a function, into scope. + void ActOnReenterFunctionContext(Scope* S, Decl* D); + void ActOnExitFunctionContext(); + + /// If \p AllowLambda is true, treat lambda as function. + DeclContext *getFunctionLevelDeclContext(bool AllowLambda = false); + + /// Returns a pointer to the innermost enclosing function, or nullptr if the + /// current context is not inside a function. If \p AllowLambda is true, + /// this can return the call operator of an enclosing lambda, otherwise + /// lambdas are skipped when looking for an enclosing function. + FunctionDecl *getCurFunctionDecl(bool AllowLambda = false); + + /// getCurMethodDecl - If inside of a method body, this returns a pointer to + /// the method decl for the method being parsed. If we're currently + /// in a 'block', this returns the containing context. + ObjCMethodDecl *getCurMethodDecl(); + + /// getCurFunctionOrMethodDecl - Return the Decl for the current ObjC method + /// or C function we're in, otherwise return null. If we're currently + /// in a 'block', this returns the containing context. + NamedDecl *getCurFunctionOrMethodDecl(); + + /// Add this decl to the scope shadowed decl chains. + void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true); + + /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true + /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns + /// true if 'D' belongs to the given declaration context. + /// + /// \param AllowInlineNamespace If \c true, allow the declaration to be in the + /// enclosing namespace set of the context, rather than contained + /// directly within it. + bool isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S = nullptr, + bool AllowInlineNamespace = false); + + /// Finds the scope corresponding to the given decl context, if it + /// happens to be an enclosing scope. Otherwise return NULL. + static Scope *getScopeForDeclContext(Scope *S, DeclContext *DC); + + /// Subroutines of ActOnDeclarator(). + TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, + TypeSourceInfo *TInfo); + bool isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New); + + /// Describes the kind of merge to perform for availability + /// attributes (including "deprecated", "unavailable", and "availability"). + enum AvailabilityMergeKind { + /// Don't merge availability attributes at all. + AMK_None, + /// Merge availability attributes for a redeclaration, which requires + /// an exact match. + AMK_Redeclaration, + /// Merge availability attributes for an override, which requires + /// an exact match or a weakening of constraints. + AMK_Override, + /// Merge availability attributes for an implementation of + /// a protocol requirement. + AMK_ProtocolImplementation, + /// Merge availability attributes for an implementation of + /// an optional protocol requirement. + AMK_OptionalProtocolImplementation + }; + + /// Describes the kind of priority given to an availability attribute. + /// + /// The sum of priorities deteremines the final priority of the attribute. + /// The final priority determines how the attribute will be merged. + /// An attribute with a lower priority will always remove higher priority + /// attributes for the specified platform when it is being applied. An + /// attribute with a higher priority will not be applied if the declaration + /// already has an availability attribute with a lower priority for the + /// specified platform. The final prirority values are not expected to match + /// the values in this enumeration, but instead should be treated as a plain + /// integer value. This enumeration just names the priority weights that are + /// used to calculate that final vaue. + enum AvailabilityPriority : int { + /// The availability attribute was specified explicitly next to the + /// declaration. + AP_Explicit = 0, + + /// The availability attribute was applied using '#pragma clang attribute'. + AP_PragmaClangAttribute = 1, + + /// The availability attribute for a specific platform was inferred from + /// an availability attribute for another platform. + AP_InferredFromOtherPlatform = 2 + }; + + /// Attribute merging methods. Return true if a new attribute was added. + AvailabilityAttr * + mergeAvailabilityAttr(NamedDecl *D, const AttributeCommonInfo &CI, + IdentifierInfo *Platform, bool Implicit, + VersionTuple Introduced, VersionTuple Deprecated, + VersionTuple Obsoleted, bool IsUnavailable, + StringRef Message, bool IsStrict, StringRef Replacement, + AvailabilityMergeKind AMK, int Priority); + TypeVisibilityAttr * + mergeTypeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI, + TypeVisibilityAttr::VisibilityType Vis); + VisibilityAttr *mergeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI, + VisibilityAttr::VisibilityType Vis); + UuidAttr *mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI, + StringRef UuidAsWritten, MSGuidDecl *GuidDecl); + DLLImportAttr *mergeDLLImportAttr(Decl *D, const AttributeCommonInfo &CI); + DLLExportAttr *mergeDLLExportAttr(Decl *D, const AttributeCommonInfo &CI); + MSInheritanceAttr *mergeMSInheritanceAttr(Decl *D, + const AttributeCommonInfo &CI, + bool BestCase, + MSInheritanceModel Model); + ErrorAttr *mergeErrorAttr(Decl *D, const AttributeCommonInfo &CI, + StringRef NewUserDiagnostic); + FormatAttr *mergeFormatAttr(Decl *D, const AttributeCommonInfo &CI, + IdentifierInfo *Format, int FormatIdx, + int FirstArg); + SectionAttr *mergeSectionAttr(Decl *D, const AttributeCommonInfo &CI, + StringRef Name); + CodeSegAttr *mergeCodeSegAttr(Decl *D, const AttributeCommonInfo &CI, + StringRef Name); + AlwaysInlineAttr *mergeAlwaysInlineAttr(Decl *D, + const AttributeCommonInfo &CI, + const IdentifierInfo *Ident); + MinSizeAttr *mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI); + SwiftNameAttr *mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA, + StringRef Name); + OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, + const AttributeCommonInfo &CI); + InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const ParsedAttr &AL); + InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, + const InternalLinkageAttr &AL); + WebAssemblyImportNameAttr *mergeImportNameAttr( + Decl *D, const WebAssemblyImportNameAttr &AL); + WebAssemblyImportModuleAttr *mergeImportModuleAttr( + Decl *D, const WebAssemblyImportModuleAttr &AL); + EnforceTCBAttr *mergeEnforceTCBAttr(Decl *D, const EnforceTCBAttr &AL); + EnforceTCBLeafAttr *mergeEnforceTCBLeafAttr(Decl *D, + const EnforceTCBLeafAttr &AL); + BTFDeclTagAttr *mergeBTFDeclTagAttr(Decl *D, const BTFDeclTagAttr &AL); + HLSLNumThreadsAttr *mergeHLSLNumThreadsAttr(Decl *D, + const AttributeCommonInfo &AL, + int X, int Y, int Z); + HLSLShaderAttr *mergeHLSLShaderAttr(Decl *D, const AttributeCommonInfo &AL, + HLSLShaderAttr::ShaderType ShaderType); + + void mergeDeclAttributes(NamedDecl *New, Decl *Old, + AvailabilityMergeKind AMK = AMK_Redeclaration); + void MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, + LookupResult &OldDecls); + bool MergeFunctionDecl(FunctionDecl *New, NamedDecl *&Old, Scope *S, + bool MergeTypeWithOld, bool NewDeclIsDefn); + bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old, + Scope *S, bool MergeTypeWithOld); + void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old); + void MergeVarDecl(VarDecl *New, LookupResult &Previous); + void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld); + void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old); + bool checkVarDeclRedefinition(VarDecl *OldDefn, VarDecl *NewDefn); + void notePreviousDefinition(const NamedDecl *Old, SourceLocation New); + bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S); + + // AssignmentAction - This is used by all the assignment diagnostic functions + // to represent what is actually causing the operation + enum AssignmentAction { + AA_Assigning, + AA_Passing, + AA_Returning, + AA_Converting, + AA_Initializing, + AA_Sending, + AA_Casting, + AA_Passing_CFAudited + }; + + /// C++ Overloading. + enum OverloadKind { + /// This is a legitimate overload: the existing declarations are + /// functions or function templates with different signatures. + Ovl_Overload, + + /// This is not an overload because the signature exactly matches + /// an existing declaration. + Ovl_Match, + + /// This is not an overload because the lookup results contain a + /// non-function. + Ovl_NonFunction + }; + OverloadKind CheckOverload(Scope *S, + FunctionDecl *New, + const LookupResult &OldDecls, + NamedDecl *&OldDecl, + bool UseMemberUsingDeclRules); + bool IsOverload(FunctionDecl *New, FunctionDecl *Old, + bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs = true, + bool ConsiderRequiresClauses = true); + + // Calculates whether the expression Constraint depends on an enclosing + // template, for the purposes of [temp.friend] p9. + // TemplateDepth is the 'depth' of the friend function, which is used to + // compare whether a declaration reference is referring to a containing + // template, or just the current friend function. A 'lower' TemplateDepth in + // the AST refers to a 'containing' template. As the constraint is + // uninstantiated, this is relative to the 'top' of the TU. + bool + ConstraintExpressionDependsOnEnclosingTemplate(const FunctionDecl *Friend, + unsigned TemplateDepth, + const Expr *Constraint); + + // Calculates whether the friend function depends on an enclosing template for + // the purposes of [temp.friend] p9. + bool FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD); + + // Calculates whether two constraint expressions are equal irrespective of a + // difference in 'depth'. This takes a pair of optional 'NamedDecl's 'Old' and + // 'New', which are the "source" of the constraint, since this is necessary + // for figuring out the relative 'depth' of the constraint. The depth of the + // 'primary template' and the 'instantiated from' templates aren't necessarily + // the same, such as a case when one is a 'friend' defined in a class. + bool AreConstraintExpressionsEqual(const NamedDecl *Old, + const Expr *OldConstr, + const NamedDecl *New, + const Expr *NewConstr); + + enum class AllowedExplicit { + /// Allow no explicit functions to be used. + None, + /// Allow explicit conversion functions but not explicit constructors. + Conversions, + /// Allow both explicit conversion functions and explicit constructors. + All + }; + + ImplicitConversionSequence + TryImplicitConversion(Expr *From, QualType ToType, + bool SuppressUserConversions, + AllowedExplicit AllowExplicit, + bool InOverloadResolution, + bool CStyle, + bool AllowObjCWritebackConversion); + + bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType); + bool IsFloatingPointPromotion(QualType FromType, QualType ToType); + bool IsComplexPromotion(QualType FromType, QualType ToType); + bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType, + bool InOverloadResolution, + QualType& ConvertedType, bool &IncompatibleObjC); + bool isObjCPointerConversion(QualType FromType, QualType ToType, + QualType& ConvertedType, bool &IncompatibleObjC); + bool isObjCWritebackConversion(QualType FromType, QualType ToType, + QualType &ConvertedType); + bool IsBlockPointerConversion(QualType FromType, QualType ToType, + QualType& ConvertedType); + bool FunctionParamTypesAreEqual(const FunctionProtoType *OldType, + const FunctionProtoType *NewType, + unsigned *ArgPos = nullptr, + bool Reversed = false); + void HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, + QualType FromType, QualType ToType); + + void maybeExtendBlockObject(ExprResult &E); + CastKind PrepareCastToObjCObjectPointer(ExprResult &E); + bool CheckPointerConversion(Expr *From, QualType ToType, + CastKind &Kind, + CXXCastPath& BasePath, + bool IgnoreBaseAccess, + bool Diagnose = true); + bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType, + bool InOverloadResolution, + QualType &ConvertedType); + bool CheckMemberPointerConversion(Expr *From, QualType ToType, + CastKind &Kind, + CXXCastPath &BasePath, + bool IgnoreBaseAccess); + bool IsQualificationConversion(QualType FromType, QualType ToType, + bool CStyle, bool &ObjCLifetimeConversion); + bool IsFunctionConversion(QualType FromType, QualType ToType, + QualType &ResultTy); + bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); + bool isSameOrCompatibleFunctionType(QualType Param, QualType Arg); + + bool CanPerformAggregateInitializationForOverloadResolution( + const InitializedEntity &Entity, InitListExpr *From); + + bool IsStringInit(Expr *Init, const ArrayType *AT); + + bool CanPerformCopyInitialization(const InitializedEntity &Entity, + ExprResult Init); + ExprResult PerformCopyInitialization(const InitializedEntity &Entity, + SourceLocation EqualLoc, + ExprResult Init, + bool TopLevelOfInitList = false, + bool AllowExplicit = false); + ExprResult PerformObjectArgumentInitialization(Expr *From, + NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, + CXXMethodDecl *Method); + + /// Check that the lifetime of the initializer (and its subobjects) is + /// sufficient for initializing the entity, and perform lifetime extension + /// (when permitted) if not. + void checkInitializerLifetime(const InitializedEntity &Entity, Expr *Init); + + ExprResult PerformContextuallyConvertToBool(Expr *From); + ExprResult PerformContextuallyConvertToObjCPointer(Expr *From); + + /// Contexts in which a converted constant expression is required. + enum CCEKind { + CCEK_CaseValue, ///< Expression in a case label. + CCEK_Enumerator, ///< Enumerator value with fixed underlying type. + CCEK_TemplateArg, ///< Value of a non-type template parameter. + CCEK_ArrayBound, ///< Array bound in array declarator or new-expression. + CCEK_ExplicitBool, ///< Condition in an explicit(bool) specifier. + CCEK_Noexcept ///< Condition in a noexcept(bool) specifier. + }; + ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, + llvm::APSInt &Value, CCEKind CCE); + ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, + APValue &Value, CCEKind CCE, + NamedDecl *Dest = nullptr); + + /// Abstract base class used to perform a contextual implicit + /// conversion from an expression to any type passing a filter. + class ContextualImplicitConverter { + public: + bool Suppress; + bool SuppressConversion; + + ContextualImplicitConverter(bool Suppress = false, + bool SuppressConversion = false) + : Suppress(Suppress), SuppressConversion(SuppressConversion) {} + + /// Determine whether the specified type is a valid destination type + /// for this conversion. + virtual bool match(QualType T) = 0; + + /// Emits a diagnostic complaining that the expression does not have + /// integral or enumeration type. + virtual SemaDiagnosticBuilder + diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) = 0; + + /// Emits a diagnostic when the expression has incomplete class type. + virtual SemaDiagnosticBuilder + diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) = 0; + + /// Emits a diagnostic when the only matching conversion function + /// is explicit. + virtual SemaDiagnosticBuilder diagnoseExplicitConv( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; + + /// Emits a note for the explicit conversion function. + virtual SemaDiagnosticBuilder + noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; + + /// Emits a diagnostic when there are multiple possible conversion + /// functions. + virtual SemaDiagnosticBuilder + diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) = 0; + + /// Emits a note for one of the candidate conversions. + virtual SemaDiagnosticBuilder + noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; + + /// Emits a diagnostic when we picked a conversion function + /// (for cases when we are not allowed to pick a conversion function). + virtual SemaDiagnosticBuilder diagnoseConversion( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; + + virtual ~ContextualImplicitConverter() {} + }; + + class ICEConvertDiagnoser : public ContextualImplicitConverter { + bool AllowScopedEnumerations; + + public: + ICEConvertDiagnoser(bool AllowScopedEnumerations, + bool Suppress, bool SuppressConversion) + : ContextualImplicitConverter(Suppress, SuppressConversion), + AllowScopedEnumerations(AllowScopedEnumerations) {} + + /// Match an integral or (possibly scoped) enumeration type. + bool match(QualType T) override; + + SemaDiagnosticBuilder + diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) override { + return diagnoseNotInt(S, Loc, T); + } + + /// Emits a diagnostic complaining that the expression does not have + /// integral or enumeration type. + virtual SemaDiagnosticBuilder + diagnoseNotInt(Sema &S, SourceLocation Loc, QualType T) = 0; + }; + + /// Perform a contextual implicit conversion. + ExprResult PerformContextualImplicitConversion( + SourceLocation Loc, Expr *FromE, ContextualImplicitConverter &Converter); + + + enum ObjCSubscriptKind { + OS_Array, + OS_Dictionary, + OS_Error + }; + ObjCSubscriptKind CheckSubscriptingKind(Expr *FromE); + + // Note that LK_String is intentionally after the other literals, as + // this is used for diagnostics logic. + enum ObjCLiteralKind { + LK_Array, + LK_Dictionary, + LK_Numeric, + LK_Boxed, + LK_String, + LK_Block, + LK_None + }; + ObjCLiteralKind CheckLiteralKind(Expr *FromE); + + ExprResult PerformObjectMemberConversion(Expr *From, + NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, + NamedDecl *Member); + + // Members have to be NamespaceDecl* or TranslationUnitDecl*. + // TODO: make this is a typesafe union. + typedef llvm::SmallSetVector<DeclContext *, 16> AssociatedNamespaceSet; + typedef llvm::SmallSetVector<CXXRecordDecl *, 16> AssociatedClassSet; + + using ADLCallKind = CallExpr::ADLCallKind; + + void AddOverloadCandidate( + FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, + bool PartialOverloading = false, bool AllowExplicit = true, + bool AllowExplicitConversion = false, + ADLCallKind IsADLCandidate = ADLCallKind::NotADL, + ConversionSequenceList EarlyConversions = std::nullopt, + OverloadCandidateParamOrder PO = {}); + void AddFunctionCandidates(const UnresolvedSetImpl &Functions, + ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, + TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, + bool SuppressUserConversions = false, + bool PartialOverloading = false, + bool FirstArgumentIsBase = false); + void AddMethodCandidate(DeclAccessPair FoundDecl, + QualType ObjectType, + Expr::Classification ObjectClassification, + ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversion = false, + OverloadCandidateParamOrder PO = {}); + void + AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, + ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet, + bool SuppressUserConversions = false, + bool PartialOverloading = false, + ConversionSequenceList EarlyConversions = std::nullopt, + OverloadCandidateParamOrder PO = {}); + void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, + DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, + TemplateArgumentListInfo *ExplicitTemplateArgs, + QualType ObjectType, + Expr::Classification ObjectClassification, + ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions = false, + bool PartialOverloading = false, + OverloadCandidateParamOrder PO = {}); + void AddTemplateOverloadCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, + bool PartialOverloading = false, bool AllowExplicit = true, + ADLCallKind IsADLCandidate = ADLCallKind::NotADL, + OverloadCandidateParamOrder PO = {}); + bool CheckNonDependentConversions( + FunctionTemplateDecl *FunctionTemplate, ArrayRef<QualType> ParamTypes, + ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet, + ConversionSequenceList &Conversions, bool SuppressUserConversions, + CXXRecordDecl *ActingContext = nullptr, QualType ObjectType = QualType(), + Expr::Classification ObjectClassification = {}, + OverloadCandidateParamOrder PO = {}); + void AddConversionCandidate( + CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, + OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, + bool AllowExplicit, bool AllowResultConversion = true); + void AddTemplateConversionCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, + OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, + bool AllowExplicit, bool AllowResultConversion = true); + void AddSurrogateCandidate(CXXConversionDecl *Conversion, + DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, + const FunctionProtoType *Proto, + Expr *Object, ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet); + void AddNonMemberOperatorCandidates( + const UnresolvedSetImpl &Functions, ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, + TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr); + void AddMemberOperatorCandidates(OverloadedOperatorKind Op, + SourceLocation OpLoc, ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, + OverloadCandidateParamOrder PO = {}); + void AddBuiltinCandidate(QualType *ParamTys, ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + bool IsAssignmentOperator = false, + unsigned NumContextualBoolArguments = 0); + void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, + SourceLocation OpLoc, ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet); + void AddArgumentDependentLookupCandidates(DeclarationName Name, + SourceLocation Loc, + ArrayRef<Expr *> Args, + TemplateArgumentListInfo *ExplicitTemplateArgs, + OverloadCandidateSet& CandidateSet, + bool PartialOverloading = false); + + // Emit as a 'note' the specific overload candidate + void NoteOverloadCandidate( + NamedDecl *Found, FunctionDecl *Fn, + OverloadCandidateRewriteKind RewriteKind = OverloadCandidateRewriteKind(), + QualType DestType = QualType(), bool TakingAddress = false); + + // Emit as a series of 'note's all template and non-templates identified by + // the expression Expr + void NoteAllOverloadCandidates(Expr *E, QualType DestType = QualType(), + bool TakingAddress = false); + + /// Check the enable_if expressions on the given function. Returns the first + /// failing attribute, or NULL if they were all successful. + EnableIfAttr *CheckEnableIf(FunctionDecl *Function, SourceLocation CallLoc, + ArrayRef<Expr *> Args, + bool MissingImplicitThis = false); + + /// Find the failed Boolean condition within a given Boolean + /// constant expression, and describe it with a string. + std::pair<Expr *, std::string> findFailedBooleanCondition(Expr *Cond); + + /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any + /// non-ArgDependent DiagnoseIfAttrs. + /// + /// Argument-dependent diagnose_if attributes should be checked each time a + /// function is used as a direct callee of a function call. + /// + /// Returns true if any errors were emitted. + bool diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function, + const Expr *ThisArg, + ArrayRef<const Expr *> Args, + SourceLocation Loc); + + /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any + /// ArgDependent DiagnoseIfAttrs. + /// + /// Argument-independent diagnose_if attributes should be checked on every use + /// of a function. + /// + /// Returns true if any errors were emitted. + bool diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND, + SourceLocation Loc); + + /// Returns whether the given function's address can be taken or not, + /// optionally emitting a diagnostic if the address can't be taken. + /// + /// Returns false if taking the address of the function is illegal. + bool checkAddressOfFunctionIsAvailable(const FunctionDecl *Function, + bool Complain = false, + SourceLocation Loc = SourceLocation()); + + // [PossiblyAFunctionType] --> [Return] + // NonFunctionType --> NonFunctionType + // R (A) --> R(A) + // R (*)(A) --> R (A) + // R (&)(A) --> R (A) + // R (S::*)(A) --> R (A) + QualType ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType); + + FunctionDecl * + ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, + QualType TargetType, + bool Complain, + DeclAccessPair &Found, + bool *pHadMultipleCandidates = nullptr); + + FunctionDecl * + resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &FoundResult); + + bool resolveAndFixAddressOfSingleOverloadCandidate( + ExprResult &SrcExpr, bool DoFunctionPointerConversion = false); + + FunctionDecl * + ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, + bool Complain = false, + DeclAccessPair *Found = nullptr); + + bool ResolveAndFixSingleFunctionTemplateSpecialization( + ExprResult &SrcExpr, bool DoFunctionPointerConversion = false, + bool Complain = false, SourceRange OpRangeForComplaining = SourceRange(), + QualType DestTypeForComplaining = QualType(), + unsigned DiagIDForComplaining = 0); + + Expr *FixOverloadedFunctionReference(Expr *E, + DeclAccessPair FoundDecl, + FunctionDecl *Fn); + ExprResult FixOverloadedFunctionReference(ExprResult, + DeclAccessPair FoundDecl, + FunctionDecl *Fn); + + void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, + ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, + bool PartialOverloading = false); + void AddOverloadedCallCandidates( + LookupResult &R, TemplateArgumentListInfo *ExplicitTemplateArgs, + ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet); + + // An enum used to represent the different possible results of building a + // range-based for loop. + enum ForRangeStatus { + FRS_Success, + FRS_NoViableFunction, + FRS_DiagnosticIssued + }; + + ForRangeStatus BuildForRangeBeginEndCall(SourceLocation Loc, + SourceLocation RangeLoc, + const DeclarationNameInfo &NameInfo, + LookupResult &MemberLookup, + OverloadCandidateSet *CandidateSet, + Expr *Range, ExprResult *CallExpr); + + ExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn, + UnresolvedLookupExpr *ULE, + SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation RParenLoc, + Expr *ExecConfig, + bool AllowTypoCorrection=true, + bool CalleesAddressIsTaken=false); + + bool buildOverloadedCallSet(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, + MultiExprArg Args, SourceLocation RParenLoc, + OverloadCandidateSet *CandidateSet, + ExprResult *Result); + + ExprResult CreateUnresolvedLookupExpr(CXXRecordDecl *NamingClass, + NestedNameSpecifierLoc NNSLoc, + DeclarationNameInfo DNI, + const UnresolvedSetImpl &Fns, + bool PerformADL = true); + + ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, + UnaryOperatorKind Opc, + const UnresolvedSetImpl &Fns, + Expr *input, bool RequiresADL = true); + + void LookupOverloadedBinOp(OverloadCandidateSet &CandidateSet, + OverloadedOperatorKind Op, + const UnresolvedSetImpl &Fns, + ArrayRef<Expr *> Args, bool RequiresADL = true); + ExprResult CreateOverloadedBinOp(SourceLocation OpLoc, + BinaryOperatorKind Opc, + const UnresolvedSetImpl &Fns, + Expr *LHS, Expr *RHS, + bool RequiresADL = true, + bool AllowRewrittenCandidates = true, + FunctionDecl *DefaultedFn = nullptr); + ExprResult BuildSynthesizedThreeWayComparison(SourceLocation OpLoc, + const UnresolvedSetImpl &Fns, + Expr *LHS, Expr *RHS, + FunctionDecl *DefaultedFn); + + ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, + SourceLocation RLoc, Expr *Base, + MultiExprArg Args); + + ExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr, + SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation RParenLoc, + Expr *ExecConfig = nullptr, + bool IsExecConfig = false, + bool AllowRecovery = false); + ExprResult + BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation RParenLoc); + + ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, + SourceLocation OpLoc, + bool *NoArrowOperatorFound = nullptr); + + /// CheckCallReturnType - Checks that a call expression's return type is + /// complete. Returns true on failure. The location passed in is the location + /// that best represents the call. + bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc, + CallExpr *CE, FunctionDecl *FD); + + /// Helpers for dealing with blocks and functions. + bool CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters, + bool CheckParameterNames); + void CheckCXXDefaultArguments(FunctionDecl *FD); + void CheckExtraCXXDefaultArguments(Declarator &D); + Scope *getNonFieldDeclScope(Scope *S); + + /// \name Name lookup + /// + /// These routines provide name lookup that is used during semantic + /// analysis to resolve the various kinds of names (identifiers, + /// overloaded operator names, constructor names, etc.) into zero or + /// more declarations within a particular scope. The major entry + /// points are LookupName, which performs unqualified name lookup, + /// and LookupQualifiedName, which performs qualified name lookup. + /// + /// All name lookup is performed based on some specific criteria, + /// which specify what names will be visible to name lookup and how + /// far name lookup should work. These criteria are important both + /// for capturing language semantics (certain lookups will ignore + /// certain names, for example) and for performance, since name + /// lookup is often a bottleneck in the compilation of C++. Name + /// lookup criteria is specified via the LookupCriteria enumeration. + /// + /// The results of name lookup can vary based on the kind of name + /// lookup performed, the current language, and the translation + /// unit. In C, for example, name lookup will either return nothing + /// (no entity found) or a single declaration. In C++, name lookup + /// can additionally refer to a set of overloaded functions or + /// result in an ambiguity. All of the possible results of name + /// lookup are captured by the LookupResult class, which provides + /// the ability to distinguish among them. + //@{ + + /// Describes the kind of name lookup to perform. + enum LookupNameKind { + /// Ordinary name lookup, which finds ordinary names (functions, + /// variables, typedefs, etc.) in C and most kinds of names + /// (functions, variables, members, types, etc.) in C++. + LookupOrdinaryName = 0, + /// Tag name lookup, which finds the names of enums, classes, + /// structs, and unions. + LookupTagName, + /// Label name lookup. + LookupLabel, + /// Member name lookup, which finds the names of + /// class/struct/union members. + LookupMemberName, + /// Look up of an operator name (e.g., operator+) for use with + /// operator overloading. This lookup is similar to ordinary name + /// lookup, but will ignore any declarations that are class members. + LookupOperatorName, + /// Look up a name following ~ in a destructor name. This is an ordinary + /// lookup, but prefers tags to typedefs. + LookupDestructorName, + /// Look up of a name that precedes the '::' scope resolution + /// operator in C++. This lookup completely ignores operator, object, + /// function, and enumerator names (C++ [basic.lookup.qual]p1). + LookupNestedNameSpecifierName, + /// Look up a namespace name within a C++ using directive or + /// namespace alias definition, ignoring non-namespace names (C++ + /// [basic.lookup.udir]p1). + LookupNamespaceName, + /// Look up all declarations in a scope with the given name, + /// including resolved using declarations. This is appropriate + /// for checking redeclarations for a using declaration. + LookupUsingDeclName, + /// Look up an ordinary name that is going to be redeclared as a + /// name with linkage. This lookup ignores any declarations that + /// are outside of the current scope unless they have linkage. See + /// C99 6.2.2p4-5 and C++ [basic.link]p6. + LookupRedeclarationWithLinkage, + /// Look up a friend of a local class. This lookup does not look + /// outside the innermost non-class scope. See C++11 [class.friend]p11. + LookupLocalFriendName, + /// Look up the name of an Objective-C protocol. + LookupObjCProtocolName, + /// Look up implicit 'self' parameter of an objective-c method. + LookupObjCImplicitSelfParam, + /// Look up the name of an OpenMP user-defined reduction operation. + LookupOMPReductionName, + /// Look up the name of an OpenMP user-defined mapper. + LookupOMPMapperName, + /// Look up any declaration with any name. + LookupAnyName + }; + + /// Specifies whether (or how) name lookup is being performed for a + /// redeclaration (vs. a reference). + enum RedeclarationKind { + /// The lookup is a reference to this name that is not for the + /// purpose of redeclaring the name. + NotForRedeclaration = 0, + /// The lookup results will be used for redeclaration of a name, + /// if an entity by that name already exists and is visible. + ForVisibleRedeclaration, + /// The lookup results will be used for redeclaration of a name + /// with external linkage; non-visible lookup results with external linkage + /// may also be found. + ForExternalRedeclaration + }; + + RedeclarationKind forRedeclarationInCurContext() { + // A declaration with an owning module for linkage can never link against + // anything that is not visible. We don't need to check linkage here; if + // the context has internal linkage, redeclaration lookup won't find things + // from other TUs, and we can't safely compute linkage yet in general. + if (cast<Decl>(CurContext) + ->getOwningModuleForLinkage(/*IgnoreLinkage*/true)) + return ForVisibleRedeclaration; + return ForExternalRedeclaration; + } + + /// The possible outcomes of name lookup for a literal operator. + enum LiteralOperatorLookupResult { + /// The lookup resulted in an error. + LOLR_Error, + /// The lookup found no match but no diagnostic was issued. + LOLR_ErrorNoDiagnostic, + /// The lookup found a single 'cooked' literal operator, which + /// expects a normal literal to be built and passed to it. + LOLR_Cooked, + /// The lookup found a single 'raw' literal operator, which expects + /// a string literal containing the spelling of the literal token. + LOLR_Raw, + /// The lookup found an overload set of literal operator templates, + /// which expect the characters of the spelling of the literal token to be + /// passed as a non-type template argument pack. + LOLR_Template, + /// The lookup found an overload set of literal operator templates, + /// which expect the character type and characters of the spelling of the + /// string literal token to be passed as template arguments. + LOLR_StringTemplatePack, + }; + + SpecialMemberOverloadResult LookupSpecialMember(CXXRecordDecl *D, + CXXSpecialMember SM, + bool ConstArg, + bool VolatileArg, + bool RValueThis, + bool ConstThis, + bool VolatileThis); + + typedef std::function<void(const TypoCorrection &)> TypoDiagnosticGenerator; + typedef std::function<ExprResult(Sema &, TypoExpr *, TypoCorrection)> + TypoRecoveryCallback; + +private: + bool CppLookupName(LookupResult &R, Scope *S); + + struct TypoExprState { + std::unique_ptr<TypoCorrectionConsumer> Consumer; + TypoDiagnosticGenerator DiagHandler; + TypoRecoveryCallback RecoveryHandler; + TypoExprState(); + TypoExprState(TypoExprState &&other) noexcept; + TypoExprState &operator=(TypoExprState &&other) noexcept; + }; + + /// The set of unhandled TypoExprs and their associated state. + llvm::MapVector<TypoExpr *, TypoExprState> DelayedTypos; + + /// Creates a new TypoExpr AST node. + TypoExpr *createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC, + TypoDiagnosticGenerator TDG, + TypoRecoveryCallback TRC, SourceLocation TypoLoc); + + // The set of known/encountered (unique, canonicalized) NamespaceDecls. + // + // The boolean value will be true to indicate that the namespace was loaded + // from an AST/PCH file, or false otherwise. + llvm::MapVector<NamespaceDecl*, bool> KnownNamespaces; + + /// Whether we have already loaded known namespaces from an extenal + /// source. + bool LoadedExternalKnownNamespaces; + + /// Helper for CorrectTypo and CorrectTypoDelayed used to create and + /// populate a new TypoCorrectionConsumer. Returns nullptr if typo correction + /// should be skipped entirely. + std::unique_ptr<TypoCorrectionConsumer> + makeTypoCorrectionConsumer(const DeclarationNameInfo &Typo, + Sema::LookupNameKind LookupKind, Scope *S, + CXXScopeSpec *SS, + CorrectionCandidateCallback &CCC, + DeclContext *MemberContext, bool EnteringContext, + const ObjCObjectPointerType *OPT, + bool ErrorRecovery); + +public: + const TypoExprState &getTypoExprState(TypoExpr *TE) const; + + /// Clears the state of the given TypoExpr. + void clearDelayedTypo(TypoExpr *TE); + + /// Look up a name, looking for a single declaration. Return + /// null if the results were absent, ambiguous, or overloaded. + /// + /// It is preferable to use the elaborated form and explicitly handle + /// ambiguity and overloaded. + NamedDecl *LookupSingleName(Scope *S, DeclarationName Name, + SourceLocation Loc, + LookupNameKind NameKind, + RedeclarationKind Redecl + = NotForRedeclaration); + bool LookupBuiltin(LookupResult &R); + void LookupNecessaryTypesForBuiltin(Scope *S, unsigned ID); + bool LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation = false, + bool ForceNoCPlusPlus = false); + bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, + bool InUnqualifiedLookup = false); + bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, + CXXScopeSpec &SS); + bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, + bool AllowBuiltinCreation = false, + bool EnteringContext = false); + ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc, + RedeclarationKind Redecl + = NotForRedeclaration); + bool LookupInSuper(LookupResult &R, CXXRecordDecl *Class); + + void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, + UnresolvedSetImpl &Functions); + + LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc, + SourceLocation GnuLabelLoc = SourceLocation()); + + DeclContextLookupResult LookupConstructors(CXXRecordDecl *Class); + CXXConstructorDecl *LookupDefaultConstructor(CXXRecordDecl *Class); + CXXConstructorDecl *LookupCopyingConstructor(CXXRecordDecl *Class, + unsigned Quals); + CXXMethodDecl *LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals, + bool RValueThis, unsigned ThisQuals); + CXXConstructorDecl *LookupMovingConstructor(CXXRecordDecl *Class, + unsigned Quals); + CXXMethodDecl *LookupMovingAssignment(CXXRecordDecl *Class, unsigned Quals, + bool RValueThis, unsigned ThisQuals); + CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class); + + bool checkLiteralOperatorId(const CXXScopeSpec &SS, const UnqualifiedId &Id, + bool IsUDSuffix); + LiteralOperatorLookupResult + LookupLiteralOperator(Scope *S, LookupResult &R, ArrayRef<QualType> ArgTys, + bool AllowRaw, bool AllowTemplate, + bool AllowStringTemplate, bool DiagnoseMissing, + StringLiteral *StringLit = nullptr); + bool isKnownName(StringRef name); + + /// Status of the function emission on the CUDA/HIP/OpenMP host/device attrs. + enum class FunctionEmissionStatus { + Emitted, + CUDADiscarded, // Discarded due to CUDA/HIP hostness + OMPDiscarded, // Discarded due to OpenMP hostness + TemplateDiscarded, // Discarded due to uninstantiated templates + Unknown, + }; + FunctionEmissionStatus getEmissionStatus(FunctionDecl *Decl, + bool Final = false); + + // Whether the callee should be ignored in CUDA/HIP/OpenMP host/device check. + bool shouldIgnoreInHostDeviceCheck(FunctionDecl *Callee); + + void ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, + ArrayRef<Expr *> Args, ADLResult &Functions); + + void LookupVisibleDecls(Scope *S, LookupNameKind Kind, + VisibleDeclConsumer &Consumer, + bool IncludeGlobalScope = true, + bool LoadExternal = true); + void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, + VisibleDeclConsumer &Consumer, + bool IncludeGlobalScope = true, + bool IncludeDependentBases = false, + bool LoadExternal = true); + + enum CorrectTypoKind { + CTK_NonError, // CorrectTypo used in a non error recovery situation. + CTK_ErrorRecovery // CorrectTypo used in normal error recovery. + }; + + TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, + Sema::LookupNameKind LookupKind, + Scope *S, CXXScopeSpec *SS, + CorrectionCandidateCallback &CCC, + CorrectTypoKind Mode, + DeclContext *MemberContext = nullptr, + bool EnteringContext = false, + const ObjCObjectPointerType *OPT = nullptr, + bool RecordFailure = true); + + TypoExpr *CorrectTypoDelayed(const DeclarationNameInfo &Typo, + Sema::LookupNameKind LookupKind, Scope *S, + CXXScopeSpec *SS, + CorrectionCandidateCallback &CCC, + TypoDiagnosticGenerator TDG, + TypoRecoveryCallback TRC, CorrectTypoKind Mode, + DeclContext *MemberContext = nullptr, + bool EnteringContext = false, + const ObjCObjectPointerType *OPT = nullptr); + + /// Process any TypoExprs in the given Expr and its children, + /// generating diagnostics as appropriate and returning a new Expr if there + /// were typos that were all successfully corrected and ExprError if one or + /// more typos could not be corrected. + /// + /// \param E The Expr to check for TypoExprs. + /// + /// \param InitDecl A VarDecl to avoid because the Expr being corrected is its + /// initializer. + /// + /// \param RecoverUncorrectedTypos If true, when typo correction fails, it + /// will rebuild the given Expr with all TypoExprs degraded to RecoveryExprs. + /// + /// \param Filter A function applied to a newly rebuilt Expr to determine if + /// it is an acceptable/usable result from a single combination of typo + /// corrections. As long as the filter returns ExprError, different + /// combinations of corrections will be tried until all are exhausted. + ExprResult CorrectDelayedTyposInExpr( + Expr *E, VarDecl *InitDecl = nullptr, + bool RecoverUncorrectedTypos = false, + llvm::function_ref<ExprResult(Expr *)> Filter = + [](Expr *E) -> ExprResult { return E; }); + + ExprResult CorrectDelayedTyposInExpr( + ExprResult ER, VarDecl *InitDecl = nullptr, + bool RecoverUncorrectedTypos = false, + llvm::function_ref<ExprResult(Expr *)> Filter = + [](Expr *E) -> ExprResult { return E; }) { + return ER.isInvalid() + ? ER + : CorrectDelayedTyposInExpr(ER.get(), InitDecl, + RecoverUncorrectedTypos, Filter); + } + + void diagnoseTypo(const TypoCorrection &Correction, + const PartialDiagnostic &TypoDiag, + bool ErrorRecovery = true); + + void diagnoseTypo(const TypoCorrection &Correction, + const PartialDiagnostic &TypoDiag, + const PartialDiagnostic &PrevNote, + bool ErrorRecovery = true); + + void MarkTypoCorrectedFunctionDefinition(const NamedDecl *F); + + void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc, + ArrayRef<Expr *> Args, + AssociatedNamespaceSet &AssociatedNamespaces, + AssociatedClassSet &AssociatedClasses); + + void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, + bool ConsiderLinkage, bool AllowInlineNamespace); + + bool CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old); + bool CheckRedeclarationExported(NamedDecl *New, NamedDecl *Old); + bool CheckRedeclarationInModule(NamedDecl *New, NamedDecl *Old); + bool IsRedefinitionInModule(const NamedDecl *New, + const NamedDecl *Old) const; + + void DiagnoseAmbiguousLookup(LookupResult &Result); + //@} + + /// Attempts to produce a RecoveryExpr after some AST node cannot be created. + ExprResult CreateRecoveryExpr(SourceLocation Begin, SourceLocation End, + ArrayRef<Expr *> SubExprs, + QualType T = QualType()); + + ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, + SourceLocation IdLoc, + bool TypoCorrection = false); + FunctionDecl *CreateBuiltin(IdentifierInfo *II, QualType Type, unsigned ID, + SourceLocation Loc); + NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, + Scope *S, bool ForRedeclaration, + SourceLocation Loc); + NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, + Scope *S); + void AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction( + FunctionDecl *FD); + void AddKnownFunctionAttributes(FunctionDecl *FD); + + // More parsing and symbol table subroutines. + + void ProcessPragmaWeak(Scope *S, Decl *D); + // Decl attributes - this routine is the top level dispatcher. + void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD); + // Helper for delayed processing of attributes. + void ProcessDeclAttributeDelayed(Decl *D, + const ParsedAttributesView &AttrList); + + // Options for ProcessDeclAttributeList(). + struct ProcessDeclAttributeOptions { + ProcessDeclAttributeOptions() + : IncludeCXX11Attributes(true), IgnoreTypeAttributes(false) {} + + ProcessDeclAttributeOptions WithIncludeCXX11Attributes(bool Val) { + ProcessDeclAttributeOptions Result = *this; + Result.IncludeCXX11Attributes = Val; + return Result; + } + + ProcessDeclAttributeOptions WithIgnoreTypeAttributes(bool Val) { + ProcessDeclAttributeOptions Result = *this; + Result.IgnoreTypeAttributes = Val; + return Result; + } + + // Should C++11 attributes be processed? + bool IncludeCXX11Attributes; + + // Should any type attributes encountered be ignored? + // If this option is false, a diagnostic will be emitted for any type + // attributes of a kind that does not "slide" from the declaration to + // the decl-specifier-seq. + bool IgnoreTypeAttributes; + }; + + void ProcessDeclAttributeList(Scope *S, Decl *D, + const ParsedAttributesView &AttrList, + const ProcessDeclAttributeOptions &Options = + ProcessDeclAttributeOptions()); + bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, + const ParsedAttributesView &AttrList); + + void checkUnusedDeclAttributes(Declarator &D); + + /// Handles semantic checking for features that are common to all attributes, + /// such as checking whether a parameter was properly specified, or the + /// correct number of arguments were passed, etc. Returns true if the + /// attribute has been diagnosed. + bool checkCommonAttributeFeatures(const Decl *D, const ParsedAttr &A, + bool SkipArgCountCheck = false); + bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr &A, + bool SkipArgCountCheck = false); + + /// Determine if type T is a valid subject for a nonnull and similar + /// attributes. By default, we look through references (the behavior used by + /// nonnull), but if the second parameter is true, then we treat a reference + /// type as valid. + bool isValidPointerAttrType(QualType T, bool RefOkay = false); + + bool CheckRegparmAttr(const ParsedAttr &attr, unsigned &value); + bool CheckCallingConvAttr(const ParsedAttr &attr, CallingConv &CC, + const FunctionDecl *FD = nullptr); + bool CheckAttrTarget(const ParsedAttr &CurrAttr); + bool CheckAttrNoArgs(const ParsedAttr &CurrAttr); + bool checkStringLiteralArgumentAttr(const AttributeCommonInfo &CI, + const Expr *E, StringRef &Str, + SourceLocation *ArgLocation = nullptr); + bool checkStringLiteralArgumentAttr(const ParsedAttr &Attr, unsigned ArgNum, + StringRef &Str, + SourceLocation *ArgLocation = nullptr); + llvm::Error isValidSectionSpecifier(StringRef Str); + bool checkSectionName(SourceLocation LiteralLoc, StringRef Str); + bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); + bool checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &Str, + bool &isDefault); + bool + checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str, + const StringLiteral *Literal, bool &HasDefault, + bool &HasCommas, bool &HasNotDefault, + SmallVectorImpl<SmallString<64>> &StringsBuffer); + bool checkMSInheritanceAttrOnDefinition( + CXXRecordDecl *RD, SourceRange Range, bool BestCase, + MSInheritanceModel SemanticSpelling); + + void CheckAlignasUnderalignment(Decl *D); + + /// Adjust the calling convention of a method to be the ABI default if it + /// wasn't specified explicitly. This handles method types formed from + /// function type typedefs and typename template arguments. + void adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor, + SourceLocation Loc); + + // Check if there is an explicit attribute, but only look through parens. + // The intent is to look for an attribute on the current declarator, but not + // one that came from a typedef. + bool hasExplicitCallingConv(QualType T); + + /// Get the outermost AttributedType node that sets a calling convention. + /// Valid types should not have multiple attributes with different CCs. + const AttributedType *getCallingConvAttributedType(QualType T) const; + + /// Process the attributes before creating an attributed statement. Returns + /// the semantic attributes that have been processed. + void ProcessStmtAttributes(Stmt *Stmt, const ParsedAttributes &InAttrs, + SmallVectorImpl<const Attr *> &OutAttrs); + + void WarnConflictingTypedMethods(ObjCMethodDecl *Method, + ObjCMethodDecl *MethodDecl, + bool IsProtocolMethodDecl); + + void CheckConflictingOverridingMethod(ObjCMethodDecl *Method, + ObjCMethodDecl *Overridden, + bool IsProtocolMethodDecl); + + /// WarnExactTypedMethods - This routine issues a warning if method + /// implementation declaration matches exactly that of its declaration. + void WarnExactTypedMethods(ObjCMethodDecl *Method, + ObjCMethodDecl *MethodDecl, + bool IsProtocolMethodDecl); + + typedef llvm::SmallPtrSet<Selector, 8> SelectorSet; + + /// CheckImplementationIvars - This routine checks if the instance variables + /// listed in the implelementation match those listed in the interface. + void CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, + ObjCIvarDecl **Fields, unsigned nIvars, + SourceLocation Loc); + + /// ImplMethodsVsClassMethods - This is main routine to warn if any method + /// remains unimplemented in the class or category \@implementation. + void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl, + bool IncompleteImpl = false); + + /// DiagnoseUnimplementedProperties - This routine warns on those properties + /// which must be implemented by this implementation. + void DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, + ObjCContainerDecl *CDecl, + bool SynthesizeProperties); + + /// Diagnose any null-resettable synthesized setters. + void diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl); + + /// DefaultSynthesizeProperties - This routine default synthesizes all + /// properties which must be synthesized in the class's \@implementation. + void DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl, + ObjCInterfaceDecl *IDecl, + SourceLocation AtEnd); + void DefaultSynthesizeProperties(Scope *S, Decl *D, SourceLocation AtEnd); + + /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is + /// an ivar synthesized for 'Method' and 'Method' is a property accessor + /// declared in class 'IFace'. + bool IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace, + ObjCMethodDecl *Method, ObjCIvarDecl *IV); + + /// DiagnoseUnusedBackingIvarInAccessor - Issue an 'unused' warning if ivar which + /// backs the property is not used in the property's accessor. + void DiagnoseUnusedBackingIvarInAccessor(Scope *S, + const ObjCImplementationDecl *ImplD); + + /// GetIvarBackingPropertyAccessor - If method is a property setter/getter and + /// it property has a backing ivar, returns this ivar; otherwise, returns NULL. + /// It also returns ivar's property on success. + ObjCIvarDecl *GetIvarBackingPropertyAccessor(const ObjCMethodDecl *Method, + const ObjCPropertyDecl *&PDecl) const; + + /// Called by ActOnProperty to handle \@property declarations in + /// class extensions. + ObjCPropertyDecl *HandlePropertyInClassExtension(Scope *S, + SourceLocation AtLoc, + SourceLocation LParenLoc, + FieldDeclarator &FD, + Selector GetterSel, + SourceLocation GetterNameLoc, + Selector SetterSel, + SourceLocation SetterNameLoc, + const bool isReadWrite, + unsigned &Attributes, + const unsigned AttributesAsWritten, + QualType T, + TypeSourceInfo *TSI, + tok::ObjCKeywordKind MethodImplKind); + + /// Called by ActOnProperty and HandlePropertyInClassExtension to + /// handle creating the ObjcPropertyDecl for a category or \@interface. + ObjCPropertyDecl *CreatePropertyDecl(Scope *S, + ObjCContainerDecl *CDecl, + SourceLocation AtLoc, + SourceLocation LParenLoc, + FieldDeclarator &FD, + Selector GetterSel, + SourceLocation GetterNameLoc, + Selector SetterSel, + SourceLocation SetterNameLoc, + const bool isReadWrite, + const unsigned Attributes, + const unsigned AttributesAsWritten, + QualType T, + TypeSourceInfo *TSI, + tok::ObjCKeywordKind MethodImplKind, + DeclContext *lexicalDC = nullptr); + + /// AtomicPropertySetterGetterRules - This routine enforces the rule (via + /// warning) when atomic property has one but not the other user-declared + /// setter or getter. + void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl, + ObjCInterfaceDecl* IDecl); + + void DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D); + + void DiagnoseMissingDesignatedInitOverrides( + const ObjCImplementationDecl *ImplD, + const ObjCInterfaceDecl *IFD); + + void DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID); + + enum MethodMatchStrategy { + MMS_loose, + MMS_strict + }; + + /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns + /// true, or false, accordingly. + bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, + const ObjCMethodDecl *PrevMethod, + MethodMatchStrategy strategy = MMS_strict); + + /// MatchAllMethodDeclarations - Check methods declaraed in interface or + /// or protocol against those declared in their implementations. + void MatchAllMethodDeclarations(const SelectorSet &InsMap, + const SelectorSet &ClsMap, + SelectorSet &InsMapSeen, + SelectorSet &ClsMapSeen, + ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl, + bool &IncompleteImpl, + bool ImmediateClass, + bool WarnCategoryMethodImpl=false); + + /// CheckCategoryVsClassMethodMatches - Checks that methods implemented in + /// category matches with those implemented in its primary class and + /// warns each time an exact match is found. + void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP); + + /// Add the given method to the list of globally-known methods. + void addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method); + + /// Returns default addr space for method qualifiers. + LangAS getDefaultCXXMethodAddrSpace() const; + +private: + /// AddMethodToGlobalPool - Add an instance or factory method to the global + /// pool. See descriptoin of AddInstanceMethodToGlobalPool. + void AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, bool instance); + + /// LookupMethodInGlobalPool - Returns the instance or factory method and + /// optionally warns if there are multiple signatures. + ObjCMethodDecl *LookupMethodInGlobalPool(Selector Sel, SourceRange R, + bool receiverIdOrClass, + bool instance); + +public: + /// - Returns instance or factory methods in global method pool for + /// given selector. It checks the desired kind first, if none is found, and + /// parameter checkTheOther is set, it then checks the other kind. If no such + /// method or only one method is found, function returns false; otherwise, it + /// returns true. + bool + CollectMultipleMethodsInGlobalPool(Selector Sel, + SmallVectorImpl<ObjCMethodDecl*>& Methods, + bool InstanceFirst, bool CheckTheOther, + const ObjCObjectType *TypeBound = nullptr); + + bool + AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod, + SourceRange R, bool receiverIdOrClass, + SmallVectorImpl<ObjCMethodDecl*>& Methods); + + void + DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl<ObjCMethodDecl*> &Methods, + Selector Sel, SourceRange R, + bool receiverIdOrClass); + +private: + /// - Returns a selector which best matches given argument list or + /// nullptr if none could be found + ObjCMethodDecl *SelectBestMethod(Selector Sel, MultiExprArg Args, + bool IsInstance, + SmallVectorImpl<ObjCMethodDecl*>& Methods); + + + /// Record the typo correction failure and return an empty correction. + TypoCorrection FailedCorrection(IdentifierInfo *Typo, SourceLocation TypoLoc, + bool RecordFailure = true) { + if (RecordFailure) + TypoCorrectionFailures[Typo].insert(TypoLoc); + return TypoCorrection(); + } + +public: + /// AddInstanceMethodToGlobalPool - All instance methods in a translation + /// unit are added to a global pool. This allows us to efficiently associate + /// a selector with a method declaraation for purposes of typechecking + /// messages sent to "id" (where the class of the object is unknown). + void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { + AddMethodToGlobalPool(Method, impl, /*instance*/true); + } + + /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. + void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { + AddMethodToGlobalPool(Method, impl, /*instance*/false); + } + + /// AddAnyMethodToGlobalPool - Add any method, instance or factory to global + /// pool. + void AddAnyMethodToGlobalPool(Decl *D); + + /// LookupInstanceMethodInGlobalPool - Returns the method and warns if + /// there are multiple signatures. + ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R, + bool receiverIdOrClass=false) { + return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, + /*instance*/true); + } + + /// LookupFactoryMethodInGlobalPool - Returns the method and warns if + /// there are multiple signatures. + ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R, + bool receiverIdOrClass=false) { + return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, + /*instance*/false); + } + + const ObjCMethodDecl *SelectorsForTypoCorrection(Selector Sel, + QualType ObjectType=QualType()); + /// LookupImplementedMethodInGlobalPool - Returns the method which has an + /// implementation. + ObjCMethodDecl *LookupImplementedMethodInGlobalPool(Selector Sel); + + /// CollectIvarsToConstructOrDestruct - Collect those ivars which require + /// initialization. + void CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI, + SmallVectorImpl<ObjCIvarDecl*> &Ivars); + + //===--------------------------------------------------------------------===// + // Statement Parsing Callbacks: SemaStmt.cpp. +public: + class FullExprArg { + public: + FullExprArg() : E(nullptr) { } + FullExprArg(Sema &actions) : E(nullptr) { } + + ExprResult release() { + return E; + } + + Expr *get() const { return E; } + + Expr *operator->() { + return E; + } + + private: + // FIXME: No need to make the entire Sema class a friend when it's just + // Sema::MakeFullExpr that needs access to the constructor below. + friend class Sema; + + explicit FullExprArg(Expr *expr) : E(expr) {} + + Expr *E; + }; + + FullExprArg MakeFullExpr(Expr *Arg) { + return MakeFullExpr(Arg, Arg ? Arg->getExprLoc() : SourceLocation()); + } + FullExprArg MakeFullExpr(Expr *Arg, SourceLocation CC) { + return FullExprArg( + ActOnFinishFullExpr(Arg, CC, /*DiscardedValue*/ false).get()); + } + FullExprArg MakeFullDiscardedValueExpr(Expr *Arg) { + ExprResult FE = + ActOnFinishFullExpr(Arg, Arg ? Arg->getExprLoc() : SourceLocation(), + /*DiscardedValue*/ true); + return FullExprArg(FE.get()); + } + + StmtResult ActOnExprStmt(ExprResult Arg, bool DiscardedValue = true); + StmtResult ActOnExprStmtError(); + + StmtResult ActOnNullStmt(SourceLocation SemiLoc, + bool HasLeadingEmptyMacro = false); + + void ActOnStartOfCompoundStmt(bool IsStmtExpr); + void ActOnAfterCompoundStatementLeadingPragmas(); + void ActOnFinishOfCompoundStmt(); + StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, + ArrayRef<Stmt *> Elts, bool isStmtExpr); + + /// A RAII object to enter scope of a compound statement. + class CompoundScopeRAII { + public: + CompoundScopeRAII(Sema &S, bool IsStmtExpr = false) : S(S) { + S.ActOnStartOfCompoundStmt(IsStmtExpr); + } + + ~CompoundScopeRAII() { + S.ActOnFinishOfCompoundStmt(); + } + + private: + Sema &S; + }; + + /// An RAII helper that pops function a function scope on exit. + struct FunctionScopeRAII { + Sema &S; + bool Active; + FunctionScopeRAII(Sema &S) : S(S), Active(true) {} + ~FunctionScopeRAII() { + if (Active) + S.PopFunctionScopeInfo(); + } + void disable() { Active = false; } + }; + + StmtResult ActOnDeclStmt(DeclGroupPtrTy Decl, + SourceLocation StartLoc, + SourceLocation EndLoc); + void ActOnForEachDeclStmt(DeclGroupPtrTy Decl); + StmtResult ActOnForEachLValueExpr(Expr *E); + ExprResult ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val); + StmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprResult LHS, + SourceLocation DotDotDotLoc, ExprResult RHS, + SourceLocation ColonLoc); + void ActOnCaseStmtBody(Stmt *CaseStmt, Stmt *SubStmt); + + StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, + SourceLocation ColonLoc, + Stmt *SubStmt, Scope *CurScope); + StmtResult ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, + SourceLocation ColonLoc, Stmt *SubStmt); + + StmtResult BuildAttributedStmt(SourceLocation AttrsLoc, + ArrayRef<const Attr *> Attrs, Stmt *SubStmt); + StmtResult ActOnAttributedStmt(const ParsedAttributes &AttrList, + Stmt *SubStmt); + + class ConditionResult; + + StmtResult ActOnIfStmt(SourceLocation IfLoc, IfStatementKind StatementKind, + SourceLocation LParenLoc, Stmt *InitStmt, + ConditionResult Cond, SourceLocation RParenLoc, + Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); + StmtResult BuildIfStmt(SourceLocation IfLoc, IfStatementKind StatementKind, + SourceLocation LParenLoc, Stmt *InitStmt, + ConditionResult Cond, SourceLocation RParenLoc, + Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); + StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, + SourceLocation LParenLoc, Stmt *InitStmt, + ConditionResult Cond, + SourceLocation RParenLoc); + StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, + Stmt *Switch, Stmt *Body); + StmtResult ActOnWhileStmt(SourceLocation WhileLoc, SourceLocation LParenLoc, + ConditionResult Cond, SourceLocation RParenLoc, + Stmt *Body); + StmtResult ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, + SourceLocation WhileLoc, SourceLocation CondLParen, + Expr *Cond, SourceLocation CondRParen); + + StmtResult ActOnForStmt(SourceLocation ForLoc, + SourceLocation LParenLoc, + Stmt *First, + ConditionResult Second, + FullExprArg Third, + SourceLocation RParenLoc, + Stmt *Body); + ExprResult CheckObjCForCollectionOperand(SourceLocation forLoc, + Expr *collection); + StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, + Stmt *First, Expr *collection, + SourceLocation RParenLoc); + StmtResult FinishObjCForCollectionStmt(Stmt *ForCollection, Stmt *Body); + + enum BuildForRangeKind { + /// Initial building of a for-range statement. + BFRK_Build, + /// Instantiation or recovery rebuild of a for-range statement. Don't + /// attempt any typo-correction. + BFRK_Rebuild, + /// Determining whether a for-range statement could be built. Avoid any + /// unnecessary or irreversible actions. + BFRK_Check + }; + + StmtResult ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, + SourceLocation CoawaitLoc, + Stmt *InitStmt, + Stmt *LoopVar, + SourceLocation ColonLoc, Expr *Collection, + SourceLocation RParenLoc, + BuildForRangeKind Kind); + StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc, + SourceLocation CoawaitLoc, + Stmt *InitStmt, + SourceLocation ColonLoc, + Stmt *RangeDecl, Stmt *Begin, Stmt *End, + Expr *Cond, Expr *Inc, + Stmt *LoopVarDecl, + SourceLocation RParenLoc, + BuildForRangeKind Kind); + StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body); + + StmtResult ActOnGotoStmt(SourceLocation GotoLoc, + SourceLocation LabelLoc, + LabelDecl *TheDecl); + StmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, + SourceLocation StarLoc, + Expr *DestExp); + StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope); + StmtResult ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope); + + void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, + CapturedRegionKind Kind, unsigned NumParams); + typedef std::pair<StringRef, QualType> CapturedParamNameType; + void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, + CapturedRegionKind Kind, + ArrayRef<CapturedParamNameType> Params, + unsigned OpenMPCaptureLevel = 0); + StmtResult ActOnCapturedRegionEnd(Stmt *S); + void ActOnCapturedRegionError(); + RecordDecl *CreateCapturedStmtRecordDecl(CapturedDecl *&CD, + SourceLocation Loc, + unsigned NumParams); + + struct NamedReturnInfo { + const VarDecl *Candidate; + + enum Status : uint8_t { None, MoveEligible, MoveEligibleAndCopyElidable }; + Status S; + + bool isMoveEligible() const { return S != None; }; + bool isCopyElidable() const { return S == MoveEligibleAndCopyElidable; } + }; + enum class SimplerImplicitMoveMode { ForceOff, Normal, ForceOn }; + NamedReturnInfo getNamedReturnInfo( + Expr *&E, SimplerImplicitMoveMode Mode = SimplerImplicitMoveMode::Normal); + NamedReturnInfo getNamedReturnInfo(const VarDecl *VD); + const VarDecl *getCopyElisionCandidate(NamedReturnInfo &Info, + QualType ReturnType); + + ExprResult + PerformMoveOrCopyInitialization(const InitializedEntity &Entity, + const NamedReturnInfo &NRInfo, Expr *Value, + bool SupressSimplerImplicitMoves = false); + + StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, + Scope *CurScope); + StmtResult BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, + bool AllowRecovery = false); + StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, + NamedReturnInfo &NRInfo, + bool SupressSimplerImplicitMoves); + + StmtResult ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, + bool IsVolatile, unsigned NumOutputs, + unsigned NumInputs, IdentifierInfo **Names, + MultiExprArg Constraints, MultiExprArg Exprs, + Expr *AsmString, MultiExprArg Clobbers, + unsigned NumLabels, + SourceLocation RParenLoc); + + void FillInlineAsmIdentifierInfo(Expr *Res, + llvm::InlineAsmIdentifierInfo &Info); + ExprResult LookupInlineAsmIdentifier(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + UnqualifiedId &Id, + bool IsUnevaluatedContext); + bool LookupInlineAsmField(StringRef Base, StringRef Member, + unsigned &Offset, SourceLocation AsmLoc); + ExprResult LookupInlineAsmVarDeclField(Expr *RefExpr, StringRef Member, + SourceLocation AsmLoc); + StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, + ArrayRef<Token> AsmToks, + StringRef AsmString, + unsigned NumOutputs, unsigned NumInputs, + ArrayRef<StringRef> Constraints, + ArrayRef<StringRef> Clobbers, + ArrayRef<Expr*> Exprs, + SourceLocation EndLoc); + LabelDecl *GetOrCreateMSAsmLabel(StringRef ExternalLabelName, + SourceLocation Location, + bool AlwaysCreate); + + VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + bool Invalid = false); + + Decl *ActOnObjCExceptionDecl(Scope *S, Declarator &D); + + StmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, + Decl *Parm, Stmt *Body); + + StmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, Stmt *Body); + + StmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, + MultiStmtArg Catch, Stmt *Finally); + + StmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw); + StmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, + Scope *CurScope); + ExprResult ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, + Expr *operand); + StmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, + Expr *SynchExpr, + Stmt *SynchBody); + + StmtResult ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body); + + VarDecl *BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, + SourceLocation StartLoc, + SourceLocation IdLoc, + IdentifierInfo *Id); + + Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D); + + StmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, + Decl *ExDecl, Stmt *HandlerBlock); + StmtResult ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, + ArrayRef<Stmt *> Handlers); + + StmtResult ActOnSEHTryBlock(bool IsCXXTry, // try (true) or __try (false) ? + SourceLocation TryLoc, Stmt *TryBlock, + Stmt *Handler); + StmtResult ActOnSEHExceptBlock(SourceLocation Loc, + Expr *FilterExpr, + Stmt *Block); + void ActOnStartSEHFinallyBlock(); + void ActOnAbortSEHFinallyBlock(); + StmtResult ActOnFinishSEHFinallyBlock(SourceLocation Loc, Stmt *Block); + StmtResult ActOnSEHLeaveStmt(SourceLocation Loc, Scope *CurScope); + + void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock); + + bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const; + + /// If it's a file scoped decl that must warn if not used, keep track + /// of it. + void MarkUnusedFileScopedDecl(const DeclaratorDecl *D); + + typedef llvm::function_ref<void(SourceLocation Loc, PartialDiagnostic PD)> + DiagReceiverTy; + + /// DiagnoseUnusedExprResult - If the statement passed in is an expression + /// whose result is unused, warn. + void DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID); + void DiagnoseUnusedNestedTypedefs(const RecordDecl *D); + void DiagnoseUnusedNestedTypedefs(const RecordDecl *D, + DiagReceiverTy DiagReceiver); + void DiagnoseUnusedDecl(const NamedDecl *ND); + void DiagnoseUnusedDecl(const NamedDecl *ND, DiagReceiverTy DiagReceiver); + + /// If VD is set but not otherwise used, diagnose, for a parameter or a + /// variable. + void DiagnoseUnusedButSetDecl(const VarDecl *VD, DiagReceiverTy DiagReceiver); + + /// Emit \p DiagID if statement located on \p StmtLoc has a suspicious null + /// statement as a \p Body, and it is located on the same line. + /// + /// This helps prevent bugs due to typos, such as: + /// if (condition); + /// do_stuff(); + void DiagnoseEmptyStmtBody(SourceLocation StmtLoc, + const Stmt *Body, + unsigned DiagID); + + /// Warn if a for/while loop statement \p S, which is followed by + /// \p PossibleBody, has a suspicious null statement as a body. + void DiagnoseEmptyLoopBody(const Stmt *S, + const Stmt *PossibleBody); + + /// Warn if a value is moved to itself. + void DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, + SourceLocation OpLoc); + + /// Returns a field in a CXXRecordDecl that has the same name as the decl \p + /// SelfAssigned when inside a CXXMethodDecl. + const FieldDecl * + getSelfAssignmentClassMemberCandidate(const ValueDecl *SelfAssigned); + + /// Warn if we're implicitly casting from a _Nullable pointer type to a + /// _Nonnull one. + void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType, + SourceLocation Loc); + + /// Warn when implicitly casting 0 to nullptr. + void diagnoseZeroToNullptrConversion(CastKind Kind, const Expr *E); + + ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) { + return DelayedDiagnostics.push(pool); + } + void PopParsingDeclaration(ParsingDeclState state, Decl *decl); + + typedef ProcessingContextState ParsingClassState; + ParsingClassState PushParsingClass() { + ParsingClassDepth++; + return DelayedDiagnostics.pushUndelayed(); + } + void PopParsingClass(ParsingClassState state) { + ParsingClassDepth--; + DelayedDiagnostics.popUndelayed(state); + } + + void redelayDiagnostics(sema::DelayedDiagnosticPool &pool); + + void DiagnoseAvailabilityOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, + const ObjCInterfaceDecl *UnknownObjCClass, + bool ObjCPropertyAccess, + bool AvoidPartialAvailabilityChecks = false, + ObjCInterfaceDecl *ClassReceiver = nullptr); + + bool makeUnavailableInSystemHeader(SourceLocation loc, + UnavailableAttr::ImplicitReason reason); + + /// Issue any -Wunguarded-availability warnings in \c FD + void DiagnoseUnguardedAvailabilityViolations(Decl *FD); + + void handleDelayedAvailabilityCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); + + //===--------------------------------------------------------------------===// + // Expression Parsing Callbacks: SemaExpr.cpp. + + bool CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid); + // A version of DiagnoseUseOfDecl that should be used if overload resolution + // has been used to find this declaration, which means we don't have to bother + // checking the trailing requires clause. + bool DiagnoseUseOfOverloadedDecl(NamedDecl *D, SourceLocation Loc) { + return DiagnoseUseOfDecl( + D, Loc, /*UnknownObjCClass=*/nullptr, /*ObjCPropertyAccess=*/false, + /*AvoidPartialAvailabilityChecks=*/false, /*ClassReceiver=*/nullptr, + /*SkipTrailingRequiresClause=*/true); + } + + bool DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, + const ObjCInterfaceDecl *UnknownObjCClass = nullptr, + bool ObjCPropertyAccess = false, + bool AvoidPartialAvailabilityChecks = false, + ObjCInterfaceDecl *ClassReciever = nullptr, + bool SkipTrailingRequiresClause = false); + void NoteDeletedFunction(FunctionDecl *FD); + void NoteDeletedInheritingConstructor(CXXConstructorDecl *CD); + bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, + ObjCMethodDecl *Getter, + SourceLocation Loc); + void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, + ArrayRef<Expr *> Args); + + void PushExpressionEvaluationContext( + ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, + ExpressionEvaluationContextRecord::ExpressionKind Type = + ExpressionEvaluationContextRecord::EK_Other); + enum ReuseLambdaContextDecl_t { ReuseLambdaContextDecl }; + void PushExpressionEvaluationContext( + ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, + ExpressionEvaluationContextRecord::ExpressionKind Type = + ExpressionEvaluationContextRecord::EK_Other); + void PopExpressionEvaluationContext(); + + void DiscardCleanupsInEvaluationContext(); + + ExprResult TransformToPotentiallyEvaluated(Expr *E); + TypeSourceInfo *TransformToPotentiallyEvaluated(TypeSourceInfo *TInfo); + ExprResult HandleExprEvaluationContextForTypeof(Expr *E); + + ExprResult CheckUnevaluatedOperand(Expr *E); + void CheckUnusedVolatileAssignment(Expr *E); + + ExprResult ActOnConstantExpression(ExprResult Res); + + // Functions for marking a declaration referenced. These functions also + // contain the relevant logic for marking if a reference to a function or + // variable is an odr-use (in the C++11 sense). There are separate variants + // for expressions referring to a decl; these exist because odr-use marking + // needs to be delayed for some constant variables when we build one of the + // named expressions. + // + // MightBeOdrUse indicates whether the use could possibly be an odr-use, and + // should usually be true. This only needs to be set to false if the lack of + // odr-use cannot be determined from the current context (for instance, + // because the name denotes a virtual function and was written without an + // explicit nested-name-specifier). + void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool MightBeOdrUse); + void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, + bool MightBeOdrUse = true); + void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var); + void MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base = nullptr); + void MarkMemberReferenced(MemberExpr *E); + void MarkFunctionParmPackReferenced(FunctionParmPackExpr *E); + void MarkCaptureUsedInEnclosingContext(ValueDecl *Capture, SourceLocation Loc, + unsigned CapturingScopeIndex); + + ExprResult CheckLValueToRValueConversionOperand(Expr *E); + void CleanupVarDeclMarking(); + + enum TryCaptureKind { + TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef + }; + + /// Try to capture the given variable. + /// + /// \param Var The variable to capture. + /// + /// \param Loc The location at which the capture occurs. + /// + /// \param Kind The kind of capture, which may be implicit (for either a + /// block or a lambda), or explicit by-value or by-reference (for a lambda). + /// + /// \param EllipsisLoc The location of the ellipsis, if one is provided in + /// an explicit lambda capture. + /// + /// \param BuildAndDiagnose Whether we are actually supposed to add the + /// captures or diagnose errors. If false, this routine merely check whether + /// the capture can occur without performing the capture itself or complaining + /// if the variable cannot be captured. + /// + /// \param CaptureType Will be set to the type of the field used to capture + /// this variable in the innermost block or lambda. Only valid when the + /// variable can be captured. + /// + /// \param DeclRefType Will be set to the type of a reference to the capture + /// from within the current scope. Only valid when the variable can be + /// captured. + /// + /// \param FunctionScopeIndexToStopAt If non-null, it points to the index + /// of the FunctionScopeInfo stack beyond which we do not attempt to capture. + /// This is useful when enclosing lambdas must speculatively capture + /// variables that may or may not be used in certain specializations of + /// a nested generic lambda. + /// + /// \returns true if an error occurred (i.e., the variable cannot be + /// captured) and false if the capture succeeded. + bool tryCaptureVariable(ValueDecl *Var, SourceLocation Loc, + TryCaptureKind Kind, SourceLocation EllipsisLoc, + bool BuildAndDiagnose, QualType &CaptureType, + QualType &DeclRefType, + const unsigned *const FunctionScopeIndexToStopAt); + + /// Try to capture the given variable. + bool tryCaptureVariable(ValueDecl *Var, SourceLocation Loc, + TryCaptureKind Kind = TryCapture_Implicit, + SourceLocation EllipsisLoc = SourceLocation()); + + /// Checks if the variable must be captured. + bool NeedToCaptureVariable(ValueDecl *Var, SourceLocation Loc); + + /// Given a variable, determine the type that a reference to that + /// variable will have in the given scope. + QualType getCapturedDeclRefType(ValueDecl *Var, SourceLocation Loc); + + /// Mark all of the declarations referenced within a particular AST node as + /// referenced. Used when template instantiation instantiates a non-dependent + /// type -- entities referenced by the type are now referenced. + void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); + void MarkDeclarationsReferencedInExpr( + Expr *E, bool SkipLocalVariables = false, + ArrayRef<const Expr *> StopAt = std::nullopt); + + /// Try to recover by turning the given expression into a + /// call. Returns true if recovery was attempted or an error was + /// emitted; this may also leave the ExprResult invalid. + bool tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, + bool ForceComplain = false, + bool (*IsPlausibleResult)(QualType) = nullptr); + + /// Figure out if an expression could be turned into a call. + bool tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, + UnresolvedSetImpl &NonTemplateOverloads); + + /// Try to convert an expression \p E to type \p Ty. Returns the result of the + /// conversion. + ExprResult tryConvertExprToType(Expr *E, QualType Ty); + + /// Conditionally issue a diagnostic based on the statements's reachability + /// analysis. + /// + /// \param Stmts If Stmts is non-empty, delay reporting the diagnostic until + /// the function body is parsed, and then do a basic reachability analysis to + /// determine if the statement is reachable. If it is unreachable, the + /// diagnostic will not be emitted. + bool DiagIfReachable(SourceLocation Loc, ArrayRef<const Stmt *> Stmts, + const PartialDiagnostic &PD); + + /// Conditionally issue a diagnostic based on the current + /// evaluation context. + /// + /// \param Statement If Statement is non-null, delay reporting the + /// diagnostic until the function body is parsed, and then do a basic + /// reachability analysis to determine if the statement is reachable. + /// If it is unreachable, the diagnostic will not be emitted. + bool DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, + const PartialDiagnostic &PD); + /// Similar, but diagnostic is only produced if all the specified statements + /// are reachable. + bool DiagRuntimeBehavior(SourceLocation Loc, ArrayRef<const Stmt*> Stmts, + const PartialDiagnostic &PD); + + // Primary Expressions. + SourceRange getExprRange(Expr *E) const; + + ExprResult ActOnIdExpression( + Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, + UnqualifiedId &Id, bool HasTrailingLParen, bool IsAddressOfOperand, + CorrectionCandidateCallback *CCC = nullptr, + bool IsInlineAsmIdentifier = false, Token *KeywordReplacement = nullptr); + + void DecomposeUnqualifiedId(const UnqualifiedId &Id, + TemplateArgumentListInfo &Buffer, + DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *&TemplateArgs); + + bool DiagnoseDependentMemberLookup(LookupResult &R); + + bool + DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, + CorrectionCandidateCallback &CCC, + TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, + ArrayRef<Expr *> Args = std::nullopt, + TypoExpr **Out = nullptr); + + DeclResult LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S, + IdentifierInfo *II); + ExprResult BuildIvarRefExpr(Scope *S, SourceLocation Loc, ObjCIvarDecl *IV); + + ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S, + IdentifierInfo *II, + bool AllowBuiltinCreation=false); + + ExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + bool isAddressOfOperand, + const TemplateArgumentListInfo *TemplateArgs); + + /// If \p D cannot be odr-used in the current expression evaluation context, + /// return a reason explaining why. Otherwise, return NOUR_None. + NonOdrUseReason getNonOdrUseReasonInCurrentContext(ValueDecl *D); + + DeclRefExpr *BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, + SourceLocation Loc, + const CXXScopeSpec *SS = nullptr); + DeclRefExpr * + BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, + const DeclarationNameInfo &NameInfo, + const CXXScopeSpec *SS = nullptr, + NamedDecl *FoundD = nullptr, + SourceLocation TemplateKWLoc = SourceLocation(), + const TemplateArgumentListInfo *TemplateArgs = nullptr); + DeclRefExpr * + BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, + const DeclarationNameInfo &NameInfo, + NestedNameSpecifierLoc NNS, + NamedDecl *FoundD = nullptr, + SourceLocation TemplateKWLoc = SourceLocation(), + const TemplateArgumentListInfo *TemplateArgs = nullptr); + + ExprResult + BuildAnonymousStructUnionMemberReference( + const CXXScopeSpec &SS, + SourceLocation nameLoc, + IndirectFieldDecl *indirectField, + DeclAccessPair FoundDecl = DeclAccessPair::make(nullptr, AS_none), + Expr *baseObjectExpr = nullptr, + SourceLocation opLoc = SourceLocation()); + + ExprResult BuildPossibleImplicitMemberExpr( + const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, const Scope *S, + UnresolvedLookupExpr *AsULE = nullptr); + ExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + bool IsDefiniteInstance, + const Scope *S); + bool UseArgumentDependentLookup(const CXXScopeSpec &SS, + const LookupResult &R, + bool HasTrailingLParen); + + ExprResult + BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + bool IsAddressOfOperand, const Scope *S, + TypeSourceInfo **RecoveryTSI = nullptr); + + ExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs); + + ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, + LookupResult &R, + bool NeedsADL, + bool AcceptInvalidDecl = false); + ExprResult BuildDeclarationNameExpr( + const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D, + NamedDecl *FoundD = nullptr, + const TemplateArgumentListInfo *TemplateArgs = nullptr, + bool AcceptInvalidDecl = false); + + ExprResult BuildLiteralOperatorCall(LookupResult &R, + DeclarationNameInfo &SuffixInfo, + ArrayRef<Expr *> Args, + SourceLocation LitEndLoc, + TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr); + + ExprResult BuildPredefinedExpr(SourceLocation Loc, + PredefinedExpr::IdentKind IK); + ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); + ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); + + ExprResult BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + TypeSourceInfo *TSI); + ExprResult ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + ParsedType ParsedTy); + + bool CheckLoopHintExpr(Expr *E, SourceLocation Loc); + + ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr); + ExprResult ActOnCharacterConstant(const Token &Tok, + Scope *UDLScope = nullptr); + ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E); + ExprResult ActOnParenListExpr(SourceLocation L, + SourceLocation R, + MultiExprArg Val); + + /// ActOnStringLiteral - The specified tokens were lexed as pasted string + /// fragments (e.g. "foo" "bar" L"baz"). + ExprResult ActOnStringLiteral(ArrayRef<Token> StringToks, + Scope *UDLScope = nullptr); + + ExprResult ActOnGenericSelectionExpr(SourceLocation KeyLoc, + SourceLocation DefaultLoc, + SourceLocation RParenLoc, + Expr *ControllingExpr, + ArrayRef<ParsedType> ArgTypes, + ArrayRef<Expr *> ArgExprs); + ExprResult CreateGenericSelectionExpr(SourceLocation KeyLoc, + SourceLocation DefaultLoc, + SourceLocation RParenLoc, + Expr *ControllingExpr, + ArrayRef<TypeSourceInfo *> Types, + ArrayRef<Expr *> Exprs); + + // Binary/Unary Operators. 'Tok' is the token for the operator. + ExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, + Expr *InputExpr, bool IsAfterAmp = false); + ExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc, UnaryOperatorKind Opc, + Expr *Input, bool IsAfterAmp = false); + ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, + Expr *Input, bool IsAfterAmp = false); + + bool isQualifiedMemberAccess(Expr *E); + QualType CheckAddressOfOperand(ExprResult &Operand, SourceLocation OpLoc); + + bool CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N); + + ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, + SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R); + ExprResult CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind); + ExprResult + ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + bool IsType, void *TyOrEx, + SourceRange ArgRange); + + ExprResult CheckPlaceholderExpr(Expr *E); + bool CheckVecStepExpr(Expr *E); + + bool CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind); + bool CheckUnaryExprOrTypeTraitOperand(QualType ExprType, SourceLocation OpLoc, + SourceRange ExprRange, + UnaryExprOrTypeTrait ExprKind); + ExprResult ActOnSizeofParameterPackExpr(Scope *S, + SourceLocation OpLoc, + IdentifierInfo &Name, + SourceLocation NameLoc, + SourceLocation RParenLoc); + ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Kind, Expr *Input); + + ExprResult ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, + MultiExprArg ArgExprs, + SourceLocation RLoc); + ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, + Expr *Idx, SourceLocation RLoc); + + ExprResult CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx, + Expr *ColumnIdx, + SourceLocation RBLoc); + + ExprResult ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, + Expr *LowerBound, + SourceLocation ColonLocFirst, + SourceLocation ColonLocSecond, + Expr *Length, Expr *Stride, + SourceLocation RBLoc); + ExprResult ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc, + SourceLocation RParenLoc, + ArrayRef<Expr *> Dims, + ArrayRef<SourceRange> Brackets); + + /// Data structure for iterator expression. + struct OMPIteratorData { + IdentifierInfo *DeclIdent = nullptr; + SourceLocation DeclIdentLoc; + ParsedType Type; + OMPIteratorExpr::IteratorRange Range; + SourceLocation AssignLoc; + SourceLocation ColonLoc; + SourceLocation SecColonLoc; + }; + + ExprResult ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc, + SourceLocation LLoc, SourceLocation RLoc, + ArrayRef<OMPIteratorData> Data); + + // This struct is for use by ActOnMemberAccess to allow + // BuildMemberReferenceExpr to be able to reinvoke ActOnMemberAccess after + // changing the access operator from a '.' to a '->' (to see if that is the + // change needed to fix an error about an unknown member, e.g. when the class + // defines a custom operator->). + struct ActOnMemberAccessExtraArgs { + Scope *S; + UnqualifiedId &Id; + Decl *ObjCImpDecl; + }; + + ExprResult BuildMemberReferenceExpr( + Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, + CXXScopeSpec &SS, SourceLocation TemplateKWLoc, + NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs, + const Scope *S, + ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); + + ExprResult + BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc, + bool IsArrow, const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + NamedDecl *FirstQualifierInScope, LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + const Scope *S, + bool SuppressQualifierCheck = false, + ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); + + ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, + SourceLocation OpLoc, + const CXXScopeSpec &SS, FieldDecl *Field, + DeclAccessPair FoundDecl, + const DeclarationNameInfo &MemberNameInfo); + + ExprResult PerformMemberExprBaseConversion(Expr *Base, bool IsArrow); + + bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, + const CXXScopeSpec &SS, + const LookupResult &R); + + ExprResult ActOnDependentMemberExpr(Expr *Base, QualType BaseType, + bool IsArrow, SourceLocation OpLoc, + const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + NamedDecl *FirstQualifierInScope, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs); + + ExprResult ActOnMemberAccessExpr(Scope *S, Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + UnqualifiedId &Member, + Decl *ObjCImpDecl); + + MemberExpr * + BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc, + const CXXScopeSpec *SS, SourceLocation TemplateKWLoc, + ValueDecl *Member, DeclAccessPair FoundDecl, + bool HadMultipleCandidates, + const DeclarationNameInfo &MemberNameInfo, QualType Ty, + ExprValueKind VK, ExprObjectKind OK, + const TemplateArgumentListInfo *TemplateArgs = nullptr); + MemberExpr * + BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc, + NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, + ValueDecl *Member, DeclAccessPair FoundDecl, + bool HadMultipleCandidates, + const DeclarationNameInfo &MemberNameInfo, QualType Ty, + ExprValueKind VK, ExprObjectKind OK, + const TemplateArgumentListInfo *TemplateArgs = nullptr); + + void ActOnDefaultCtorInitializers(Decl *CDtorDecl); + bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, + FunctionDecl *FDecl, + const FunctionProtoType *Proto, + ArrayRef<Expr *> Args, + SourceLocation RParenLoc, + bool ExecConfig = false); + void CheckStaticArrayArgument(SourceLocation CallLoc, + ParmVarDecl *Param, + const Expr *ArgExpr); + + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. + /// This provides the location of the left/right parens and a list of comma + /// locations. + ExprResult ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, + MultiExprArg ArgExprs, SourceLocation RParenLoc, + Expr *ExecConfig = nullptr); + ExprResult BuildCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, + MultiExprArg ArgExprs, SourceLocation RParenLoc, + Expr *ExecConfig = nullptr, + bool IsExecConfig = false, + bool AllowRecovery = false); + Expr *BuildBuiltinCallExpr(SourceLocation Loc, Builtin::ID Id, + MultiExprArg CallArgs); + enum class AtomicArgumentOrder { API, AST }; + ExprResult + BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, + SourceLocation RParenLoc, MultiExprArg Args, + AtomicExpr::AtomicOp Op, + AtomicArgumentOrder ArgOrder = AtomicArgumentOrder::API); + ExprResult + BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, + ArrayRef<Expr *> Arg, SourceLocation RParenLoc, + Expr *Config = nullptr, bool IsExecConfig = false, + ADLCallKind UsesADL = ADLCallKind::NotADL); + + ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, + MultiExprArg ExecConfig, + SourceLocation GGGLoc); + + ExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, + Declarator &D, ParsedType &Ty, + SourceLocation RParenLoc, Expr *CastExpr); + ExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, + TypeSourceInfo *Ty, + SourceLocation RParenLoc, + Expr *Op); + CastKind PrepareScalarCast(ExprResult &src, QualType destType); + + /// Build an altivec or OpenCL literal. + ExprResult BuildVectorLiteral(SourceLocation LParenLoc, + SourceLocation RParenLoc, Expr *E, + TypeSourceInfo *TInfo); + + ExprResult MaybeConvertParenListExprToParenExpr(Scope *S, Expr *ME); + + ExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, + ParsedType Ty, + SourceLocation RParenLoc, + Expr *InitExpr); + + ExprResult BuildCompoundLiteralExpr(SourceLocation LParenLoc, + TypeSourceInfo *TInfo, + SourceLocation RParenLoc, + Expr *LiteralExpr); + + ExprResult ActOnInitList(SourceLocation LBraceLoc, + MultiExprArg InitArgList, + SourceLocation RBraceLoc); + + ExprResult BuildInitList(SourceLocation LBraceLoc, + MultiExprArg InitArgList, + SourceLocation RBraceLoc); + + ExprResult ActOnDesignatedInitializer(Designation &Desig, + SourceLocation EqualOrColonLoc, + bool GNUSyntax, + ExprResult Init); + +private: + static BinaryOperatorKind ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind); + +public: + ExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, + tok::TokenKind Kind, Expr *LHSExpr, Expr *RHSExpr); + ExprResult BuildBinOp(Scope *S, SourceLocation OpLoc, + BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr); + ExprResult CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, + Expr *LHSExpr, Expr *RHSExpr); + void LookupBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc, + UnresolvedSetImpl &Functions); + + void DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc); + + /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null + /// in the case of a the GNU conditional expr extension. + ExprResult ActOnConditionalOp(SourceLocation QuestionLoc, + SourceLocation ColonLoc, + Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr); + + /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". + ExprResult ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, + LabelDecl *TheDecl); + + void ActOnStartStmtExpr(); + ExprResult ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt, + SourceLocation RPLoc); + ExprResult BuildStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, + SourceLocation RPLoc, unsigned TemplateDepth); + // Handle the final expression in a statement expression. + ExprResult ActOnStmtExprResult(ExprResult E); + void ActOnStmtExprError(); + + // __builtin_offsetof(type, identifier(.identifier|[expr])*) + struct OffsetOfComponent { + SourceLocation LocStart, LocEnd; + bool isBrackets; // true if [expr], false if .ident + union { + IdentifierInfo *IdentInfo; + Expr *E; + } U; + }; + + /// __builtin_offsetof(type, a.b[123][456].c) + ExprResult BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, + TypeSourceInfo *TInfo, + ArrayRef<OffsetOfComponent> Components, + SourceLocation RParenLoc); + ExprResult ActOnBuiltinOffsetOf(Scope *S, + SourceLocation BuiltinLoc, + SourceLocation TypeLoc, + ParsedType ParsedArgTy, + ArrayRef<OffsetOfComponent> Components, + SourceLocation RParenLoc); + + // __builtin_choose_expr(constExpr, expr1, expr2) + ExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, + Expr *CondExpr, Expr *LHSExpr, + Expr *RHSExpr, SourceLocation RPLoc); + + // __builtin_va_arg(expr, type) + ExprResult ActOnVAArg(SourceLocation BuiltinLoc, Expr *E, ParsedType Ty, + SourceLocation RPLoc); + ExprResult BuildVAArgExpr(SourceLocation BuiltinLoc, Expr *E, + TypeSourceInfo *TInfo, SourceLocation RPLoc); + + // __builtin_LINE(), __builtin_FUNCTION(), __builtin_FILE(), + // __builtin_COLUMN(), __builtin_source_location() + ExprResult ActOnSourceLocExpr(SourceLocExpr::IdentKind Kind, + SourceLocation BuiltinLoc, + SourceLocation RPLoc); + + // Build a potentially resolved SourceLocExpr. + ExprResult BuildSourceLocExpr(SourceLocExpr::IdentKind Kind, + QualType ResultTy, SourceLocation BuiltinLoc, + SourceLocation RPLoc, + DeclContext *ParentContext); + + // __null + ExprResult ActOnGNUNullExpr(SourceLocation TokenLoc); + + bool CheckCaseExpression(Expr *E); + + /// Describes the result of an "if-exists" condition check. + enum IfExistsResult { + /// The symbol exists. + IER_Exists, + + /// The symbol does not exist. + IER_DoesNotExist, + + /// The name is a dependent name, so the results will differ + /// from one instantiation to the next. + IER_Dependent, + + /// An error occurred. + IER_Error + }; + + IfExistsResult + CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, + const DeclarationNameInfo &TargetNameInfo); + + IfExistsResult + CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, + bool IsIfExists, CXXScopeSpec &SS, + UnqualifiedId &Name); + + StmtResult BuildMSDependentExistsStmt(SourceLocation KeywordLoc, + bool IsIfExists, + NestedNameSpecifierLoc QualifierLoc, + DeclarationNameInfo NameInfo, + Stmt *Nested); + StmtResult ActOnMSDependentExistsStmt(SourceLocation KeywordLoc, + bool IsIfExists, + CXXScopeSpec &SS, UnqualifiedId &Name, + Stmt *Nested); + + //===------------------------- "Block" Extension ------------------------===// + + /// ActOnBlockStart - This callback is invoked when a block literal is + /// started. + void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope); + + /// ActOnBlockArguments - This callback allows processing of block arguments. + /// If there are no arguments, this is still invoked. + void ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, + Scope *CurScope); + + /// ActOnBlockError - If there is an error parsing a block, this callback + /// is invoked to pop the information about the block from the action impl. + void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope); + + /// ActOnBlockStmtExpr - This is called when the body of a block statement + /// literal was successfully completed. ^(int x){...} + ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body, + Scope *CurScope); + + //===---------------------------- Clang Extensions ----------------------===// + + /// __builtin_convertvector(...) + ExprResult ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc); + + //===---------------------------- OpenCL Features -----------------------===// + + /// __builtin_astype(...) + ExprResult ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc); + ExprResult BuildAsTypeExpr(Expr *E, QualType DestTy, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc); + + //===---------------------------- HLSL Features -------------------------===// + Decl *ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer, + SourceLocation KwLoc, IdentifierInfo *Ident, + SourceLocation IdentLoc, SourceLocation LBrace); + void ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace); + + //===---------------------------- C++ Features --------------------------===// + + // Act on C++ namespaces + Decl *ActOnStartNamespaceDef(Scope *S, SourceLocation InlineLoc, + SourceLocation NamespaceLoc, + SourceLocation IdentLoc, IdentifierInfo *Ident, + SourceLocation LBrace, + const ParsedAttributesView &AttrList, + UsingDirectiveDecl *&UsingDecl, bool IsNested); + void ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace); + + NamespaceDecl *getStdNamespace() const; + NamespaceDecl *getOrCreateStdNamespace(); + + NamespaceDecl *lookupStdExperimentalNamespace(); + NamespaceDecl *getCachedCoroNamespace() { return CoroTraitsNamespaceCache; } + + CXXRecordDecl *getStdBadAlloc() const; + EnumDecl *getStdAlignValT() const; + +private: + // A cache representing if we've fully checked the various comparison category + // types stored in ASTContext. The bit-index corresponds to the integer value + // of a ComparisonCategoryType enumerator. + llvm::SmallBitVector FullyCheckedComparisonCategories; + + ValueDecl *tryLookupCtorInitMemberDecl(CXXRecordDecl *ClassDecl, + CXXScopeSpec &SS, + ParsedType TemplateTypeTy, + IdentifierInfo *MemberOrBase); + +public: + enum class ComparisonCategoryUsage { + /// The '<=>' operator was used in an expression and a builtin operator + /// was selected. + OperatorInExpression, + /// A defaulted 'operator<=>' needed the comparison category. This + /// typically only applies to 'std::strong_ordering', due to the implicit + /// fallback return value. + DefaultedOperator, + }; + + /// Lookup the specified comparison category types in the standard + /// library, an check the VarDecls possibly returned by the operator<=> + /// builtins for that type. + /// + /// \return The type of the comparison category type corresponding to the + /// specified Kind, or a null type if an error occurs + QualType CheckComparisonCategoryType(ComparisonCategoryType Kind, + SourceLocation Loc, + ComparisonCategoryUsage Usage); + + /// Tests whether Ty is an instance of std::initializer_list and, if + /// it is and Element is not NULL, assigns the element type to Element. + bool isStdInitializerList(QualType Ty, QualType *Element); + + /// Looks for the std::initializer_list template and instantiates it + /// with Element, or emits an error if it's not found. + /// + /// \returns The instantiated template, or null on error. + QualType BuildStdInitializerList(QualType Element, SourceLocation Loc); + + /// Determine whether Ctor is an initializer-list constructor, as + /// defined in [dcl.init.list]p2. + bool isInitListConstructor(const FunctionDecl *Ctor); + + Decl *ActOnUsingDirective(Scope *CurScope, SourceLocation UsingLoc, + SourceLocation NamespcLoc, CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *NamespcName, + const ParsedAttributesView &AttrList); + + void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir); + + Decl *ActOnNamespaceAliasDef(Scope *CurScope, + SourceLocation NamespaceLoc, + SourceLocation AliasLoc, + IdentifierInfo *Alias, + CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *Ident); + + void FilterUsingLookup(Scope *S, LookupResult &lookup); + void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow); + bool CheckUsingShadowDecl(BaseUsingDecl *BUD, NamedDecl *Target, + const LookupResult &PreviousDecls, + UsingShadowDecl *&PrevShadow); + UsingShadowDecl *BuildUsingShadowDecl(Scope *S, BaseUsingDecl *BUD, + NamedDecl *Target, + UsingShadowDecl *PrevDecl); + + bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc, + bool HasTypenameKeyword, + const CXXScopeSpec &SS, + SourceLocation NameLoc, + const LookupResult &Previous); + bool CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename, + const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + SourceLocation NameLoc, + const LookupResult *R = nullptr, + const UsingDecl *UD = nullptr); + + NamedDecl *BuildUsingDeclaration( + Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, + bool HasTypenameKeyword, SourceLocation TypenameLoc, CXXScopeSpec &SS, + DeclarationNameInfo NameInfo, SourceLocation EllipsisLoc, + const ParsedAttributesView &AttrList, bool IsInstantiation, + bool IsUsingIfExists); + NamedDecl *BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS, + SourceLocation UsingLoc, + SourceLocation EnumLoc, + SourceLocation NameLoc, + TypeSourceInfo *EnumType, EnumDecl *ED); + NamedDecl *BuildUsingPackDecl(NamedDecl *InstantiatedFrom, + ArrayRef<NamedDecl *> Expansions); + + bool CheckInheritingConstructorUsingDecl(UsingDecl *UD); + + /// Given a derived-class using shadow declaration for a constructor and the + /// correspnding base class constructor, find or create the implicit + /// synthesized derived class constructor to use for this initialization. + CXXConstructorDecl * + findInheritingConstructor(SourceLocation Loc, CXXConstructorDecl *BaseCtor, + ConstructorUsingShadowDecl *DerivedShadow); + + Decl *ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, + SourceLocation UsingLoc, + SourceLocation TypenameLoc, CXXScopeSpec &SS, + UnqualifiedId &Name, SourceLocation EllipsisLoc, + const ParsedAttributesView &AttrList); + Decl *ActOnUsingEnumDeclaration(Scope *CurScope, AccessSpecifier AS, + SourceLocation UsingLoc, + SourceLocation EnumLoc, + SourceLocation IdentLoc, IdentifierInfo &II, + CXXScopeSpec *SS = nullptr); + Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS, + MultiTemplateParamsArg TemplateParams, + SourceLocation UsingLoc, UnqualifiedId &Name, + const ParsedAttributesView &AttrList, + TypeResult Type, Decl *DeclFromDeclSpec); + + /// BuildCXXConstructExpr - Creates a complete call to a constructor, + /// including handling of its default argument expressions. + /// + /// \param ConstructKind - a CXXConstructExpr::ConstructionKind + ExprResult + BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + NamedDecl *FoundDecl, + CXXConstructorDecl *Constructor, MultiExprArg Exprs, + bool HadMultipleCandidates, bool IsListInitialization, + bool IsStdInitListInitialization, + bool RequiresZeroInit, unsigned ConstructKind, + SourceRange ParenRange); + + /// Build a CXXConstructExpr whose constructor has already been resolved if + /// it denotes an inherited constructor. + ExprResult + BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + CXXConstructorDecl *Constructor, bool Elidable, + MultiExprArg Exprs, + bool HadMultipleCandidates, bool IsListInitialization, + bool IsStdInitListInitialization, + bool RequiresZeroInit, unsigned ConstructKind, + SourceRange ParenRange); + + // FIXME: Can we remove this and have the above BuildCXXConstructExpr check if + // the constructor can be elidable? + ExprResult + BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + NamedDecl *FoundDecl, + CXXConstructorDecl *Constructor, bool Elidable, + MultiExprArg Exprs, bool HadMultipleCandidates, + bool IsListInitialization, + bool IsStdInitListInitialization, bool RequiresZeroInit, + unsigned ConstructKind, SourceRange ParenRange); + + ExprResult ConvertMemberDefaultInitExpression(FieldDecl *FD, Expr *InitExpr, + SourceLocation InitLoc); + + ExprResult BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field); + + + /// Instantiate or parse a C++ default argument expression as necessary. + /// Return true on error. + bool CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, + ParmVarDecl *Param, Expr *Init = nullptr, + bool SkipImmediateInvocations = true); + + /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating + /// the default expr if needed. + ExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, + ParmVarDecl *Param, Expr *Init = nullptr); + + /// FinalizeVarWithDestructor - Prepare for calling destructor on the + /// constructed variable. + void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType); + + /// Helper class that collects exception specifications for + /// implicitly-declared special member functions. + class ImplicitExceptionSpecification { + // Pointer to allow copying + Sema *Self; + // We order exception specifications thus: + // noexcept is the most restrictive, but is only used in C++11. + // throw() comes next. + // Then a throw(collected exceptions) + // Finally no specification, which is expressed as noexcept(false). + // throw(...) is used instead if any called function uses it. + ExceptionSpecificationType ComputedEST; + llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen; + SmallVector<QualType, 4> Exceptions; + + void ClearExceptions() { + ExceptionsSeen.clear(); + Exceptions.clear(); + } + + public: + explicit ImplicitExceptionSpecification(Sema &Self) + : Self(&Self), ComputedEST(EST_BasicNoexcept) { + if (!Self.getLangOpts().CPlusPlus11) + ComputedEST = EST_DynamicNone; + } + + /// Get the computed exception specification type. + ExceptionSpecificationType getExceptionSpecType() const { + assert(!isComputedNoexcept(ComputedEST) && + "noexcept(expr) should not be a possible result"); + return ComputedEST; + } + + /// The number of exceptions in the exception specification. + unsigned size() const { return Exceptions.size(); } + + /// The set of exceptions in the exception specification. + const QualType *data() const { return Exceptions.data(); } + + /// Integrate another called method into the collected data. + void CalledDecl(SourceLocation CallLoc, const CXXMethodDecl *Method); + + /// Integrate an invoked expression into the collected data. + void CalledExpr(Expr *E) { CalledStmt(E); } + + /// Integrate an invoked statement into the collected data. + void CalledStmt(Stmt *S); + + /// Overwrite an EPI's exception specification with this + /// computed exception specification. + FunctionProtoType::ExceptionSpecInfo getExceptionSpec() const { + FunctionProtoType::ExceptionSpecInfo ESI; + ESI.Type = getExceptionSpecType(); + if (ESI.Type == EST_Dynamic) { + ESI.Exceptions = Exceptions; + } else if (ESI.Type == EST_None) { + /// C++11 [except.spec]p14: + /// The exception-specification is noexcept(false) if the set of + /// potential exceptions of the special member function contains "any" + ESI.Type = EST_NoexceptFalse; + ESI.NoexceptExpr = Self->ActOnCXXBoolLiteral(SourceLocation(), + tok::kw_false).get(); + } + return ESI; + } + }; + + /// Evaluate the implicit exception specification for a defaulted + /// special member function. + void EvaluateImplicitExceptionSpec(SourceLocation Loc, FunctionDecl *FD); + + /// Check the given noexcept-specifier, convert its expression, and compute + /// the appropriate ExceptionSpecificationType. + ExprResult ActOnNoexceptSpec(Expr *NoexceptExpr, + ExceptionSpecificationType &EST); + + /// Check the given exception-specification and update the + /// exception specification information with the results. + void checkExceptionSpecification(bool IsTopLevel, + ExceptionSpecificationType EST, + ArrayRef<ParsedType> DynamicExceptions, + ArrayRef<SourceRange> DynamicExceptionRanges, + Expr *NoexceptExpr, + SmallVectorImpl<QualType> &Exceptions, + FunctionProtoType::ExceptionSpecInfo &ESI); + + /// Determine if we're in a case where we need to (incorrectly) eagerly + /// parse an exception specification to work around a libstdc++ bug. + bool isLibstdcxxEagerExceptionSpecHack(const Declarator &D); + + /// Add an exception-specification to the given member function + /// (or member function template). The exception-specification was parsed + /// after the method itself was declared. + void actOnDelayedExceptionSpecification(Decl *Method, + ExceptionSpecificationType EST, + SourceRange SpecificationRange, + ArrayRef<ParsedType> DynamicExceptions, + ArrayRef<SourceRange> DynamicExceptionRanges, + Expr *NoexceptExpr); + + class InheritedConstructorInfo; + + /// Determine if a special member function should have a deleted + /// definition when it is defaulted. + bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, + InheritedConstructorInfo *ICI = nullptr, + bool Diagnose = false); + + /// Produce notes explaining why a defaulted function was defined as deleted. + void DiagnoseDeletedDefaultedFunction(FunctionDecl *FD); + + /// Declare the implicit default constructor for the given class. + /// + /// \param ClassDecl The class declaration into which the implicit + /// default constructor will be added. + /// + /// \returns The implicitly-declared default constructor. + CXXConstructorDecl *DeclareImplicitDefaultConstructor( + CXXRecordDecl *ClassDecl); + + /// DefineImplicitDefaultConstructor - Checks for feasibility of + /// defining this constructor as the default constructor. + void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *Constructor); + + /// Declare the implicit destructor for the given class. + /// + /// \param ClassDecl The class declaration into which the implicit + /// destructor will be added. + /// + /// \returns The implicitly-declared destructor. + CXXDestructorDecl *DeclareImplicitDestructor(CXXRecordDecl *ClassDecl); + + /// DefineImplicitDestructor - Checks for feasibility of + /// defining this destructor as the default destructor. + void DefineImplicitDestructor(SourceLocation CurrentLocation, + CXXDestructorDecl *Destructor); + + /// Build an exception spec for destructors that don't have one. + /// + /// C++11 says that user-defined destructors with no exception spec get one + /// that looks as if the destructor was implicitly declared. + void AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor); + + /// Define the specified inheriting constructor. + void DefineInheritingConstructor(SourceLocation UseLoc, + CXXConstructorDecl *Constructor); + + /// Declare the implicit copy constructor for the given class. + /// + /// \param ClassDecl The class declaration into which the implicit + /// copy constructor will be added. + /// + /// \returns The implicitly-declared copy constructor. + CXXConstructorDecl *DeclareImplicitCopyConstructor(CXXRecordDecl *ClassDecl); + + /// DefineImplicitCopyConstructor - Checks for feasibility of + /// defining this constructor as the copy constructor. + void DefineImplicitCopyConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *Constructor); + + /// Declare the implicit move constructor for the given class. + /// + /// \param ClassDecl The Class declaration into which the implicit + /// move constructor will be added. + /// + /// \returns The implicitly-declared move constructor, or NULL if it wasn't + /// declared. + CXXConstructorDecl *DeclareImplicitMoveConstructor(CXXRecordDecl *ClassDecl); + + /// DefineImplicitMoveConstructor - Checks for feasibility of + /// defining this constructor as the move constructor. + void DefineImplicitMoveConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *Constructor); + + /// Declare the implicit copy assignment operator for the given class. + /// + /// \param ClassDecl The class declaration into which the implicit + /// copy assignment operator will be added. + /// + /// \returns The implicitly-declared copy assignment operator. + CXXMethodDecl *DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl); + + /// Defines an implicitly-declared copy assignment operator. + void DefineImplicitCopyAssignment(SourceLocation CurrentLocation, + CXXMethodDecl *MethodDecl); + + /// Declare the implicit move assignment operator for the given class. + /// + /// \param ClassDecl The Class declaration into which the implicit + /// move assignment operator will be added. + /// + /// \returns The implicitly-declared move assignment operator, or NULL if it + /// wasn't declared. + CXXMethodDecl *DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl); + + /// Defines an implicitly-declared move assignment operator. + void DefineImplicitMoveAssignment(SourceLocation CurrentLocation, + CXXMethodDecl *MethodDecl); + + /// Force the declaration of any implicitly-declared members of this + /// class. + void ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class); + + /// Check a completed declaration of an implicit special member. + void CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD); + + /// Determine whether the given function is an implicitly-deleted + /// special member function. + bool isImplicitlyDeleted(FunctionDecl *FD); + + /// Check whether 'this' shows up in the type of a static member + /// function after the (naturally empty) cv-qualifier-seq would be. + /// + /// \returns true if an error occurred. + bool checkThisInStaticMemberFunctionType(CXXMethodDecl *Method); + + /// Whether this' shows up in the exception specification of a static + /// member function. + bool checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method); + + /// Check whether 'this' shows up in the attributes of the given + /// static member function. + /// + /// \returns true if an error occurred. + bool checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method); + + /// MaybeBindToTemporary - If the passed in expression has a record type with + /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise + /// it simply returns the passed in expression. + ExprResult MaybeBindToTemporary(Expr *E); + + /// Wrap the expression in a ConstantExpr if it is a potential immediate + /// invocation. + ExprResult CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl); + + bool CompleteConstructorCall(CXXConstructorDecl *Constructor, + QualType DeclInitType, MultiExprArg ArgsPtr, + SourceLocation Loc, + SmallVectorImpl<Expr *> &ConvertedArgs, + bool AllowExplicit = false, + bool IsListInitialization = false); + + ParsedType getInheritingConstructorName(CXXScopeSpec &SS, + SourceLocation NameLoc, + IdentifierInfo &Name); + + ParsedType getConstructorName(IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, CXXScopeSpec &SS, + bool EnteringContext); + ParsedType getDestructorName(SourceLocation TildeLoc, + IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, CXXScopeSpec &SS, + ParsedType ObjectType, + bool EnteringContext); + + ParsedType getDestructorTypeForDecltype(const DeclSpec &DS, + ParsedType ObjectType); + + // Checks that reinterpret casts don't have undefined behavior. + void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, + bool IsDereference, SourceRange Range); + + // Checks that the vector type should be initialized from a scalar + // by splatting the value rather than populating a single element. + // This is the case for AltiVecVector types as well as with + // AltiVecPixel and AltiVecBool when -faltivec-src-compat=xl is specified. + bool ShouldSplatAltivecScalarInCast(const VectorType *VecTy); + + // Checks if the -faltivec-src-compat=gcc option is specified. + // If so, AltiVecVector, AltiVecBool and AltiVecPixel types are + // treated the same way as they are when trying to initialize + // these vectors on gcc (an error is emitted). + bool CheckAltivecInitFromScalar(SourceRange R, QualType VecTy, + QualType SrcTy); + + /// ActOnCXXNamedCast - Parse + /// {dynamic,static,reinterpret,const,addrspace}_cast's. + ExprResult ActOnCXXNamedCast(SourceLocation OpLoc, + tok::TokenKind Kind, + SourceLocation LAngleBracketLoc, + Declarator &D, + SourceLocation RAngleBracketLoc, + SourceLocation LParenLoc, + Expr *E, + SourceLocation RParenLoc); + + ExprResult BuildCXXNamedCast(SourceLocation OpLoc, + tok::TokenKind Kind, + TypeSourceInfo *Ty, + Expr *E, + SourceRange AngleBrackets, + SourceRange Parens); + + ExprResult ActOnBuiltinBitCastExpr(SourceLocation KWLoc, Declarator &Dcl, + ExprResult Operand, + SourceLocation RParenLoc); + + ExprResult BuildBuiltinBitCastExpr(SourceLocation KWLoc, TypeSourceInfo *TSI, + Expr *Operand, SourceLocation RParenLoc); + + ExprResult BuildCXXTypeId(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc); + ExprResult BuildCXXTypeId(QualType TypeInfoType, + SourceLocation TypeidLoc, + Expr *Operand, + SourceLocation RParenLoc); + + /// ActOnCXXTypeid - Parse typeid( something ). + ExprResult ActOnCXXTypeid(SourceLocation OpLoc, + SourceLocation LParenLoc, bool isType, + void *TyOrExpr, + SourceLocation RParenLoc); + + ExprResult BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc); + ExprResult BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + Expr *Operand, + SourceLocation RParenLoc); + + /// ActOnCXXUuidof - Parse __uuidof( something ). + ExprResult ActOnCXXUuidof(SourceLocation OpLoc, + SourceLocation LParenLoc, bool isType, + void *TyOrExpr, + SourceLocation RParenLoc); + + /// Handle a C++1z fold-expression: ( expr op ... op expr ). + ExprResult ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS, + tok::TokenKind Operator, + SourceLocation EllipsisLoc, Expr *RHS, + SourceLocation RParenLoc); + ExprResult BuildCXXFoldExpr(UnresolvedLookupExpr *Callee, + SourceLocation LParenLoc, Expr *LHS, + BinaryOperatorKind Operator, + SourceLocation EllipsisLoc, Expr *RHS, + SourceLocation RParenLoc, + std::optional<unsigned> NumExpansions); + ExprResult BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc, + BinaryOperatorKind Operator); + + //// ActOnCXXThis - Parse 'this' pointer. + ExprResult ActOnCXXThis(SourceLocation loc); + + /// Build a CXXThisExpr and mark it referenced in the current context. + Expr *BuildCXXThisExpr(SourceLocation Loc, QualType Type, bool IsImplicit); + void MarkThisReferenced(CXXThisExpr *This); + + /// Try to retrieve the type of the 'this' pointer. + /// + /// \returns The type of 'this', if possible. Otherwise, returns a NULL type. + QualType getCurrentThisType(); + + /// When non-NULL, the C++ 'this' expression is allowed despite the + /// current context not being a non-static member function. In such cases, + /// this provides the type used for 'this'. + QualType CXXThisTypeOverride; + + /// RAII object used to temporarily allow the C++ 'this' expression + /// to be used, with the given qualifiers on the current class type. + class CXXThisScopeRAII { + Sema &S; + QualType OldCXXThisTypeOverride; + bool Enabled; + + public: + /// Introduce a new scope where 'this' may be allowed (when enabled), + /// using the given declaration (which is either a class template or a + /// class) along with the given qualifiers. + /// along with the qualifiers placed on '*this'. + CXXThisScopeRAII(Sema &S, Decl *ContextDecl, Qualifiers CXXThisTypeQuals, + bool Enabled = true); + + ~CXXThisScopeRAII(); + }; + + /// Make sure the value of 'this' is actually available in the current + /// context, if it is a potentially evaluated context. + /// + /// \param Loc The location at which the capture of 'this' occurs. + /// + /// \param Explicit Whether 'this' is explicitly captured in a lambda + /// capture list. + /// + /// \param FunctionScopeIndexToStopAt If non-null, it points to the index + /// of the FunctionScopeInfo stack beyond which we do not attempt to capture. + /// This is useful when enclosing lambdas must speculatively capture + /// 'this' that may or may not be used in certain specializations of + /// a nested generic lambda (depending on whether the name resolves to + /// a non-static member function or a static function). + /// \return returns 'true' if failed, 'false' if success. + bool CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false, + bool BuildAndDiagnose = true, + const unsigned *const FunctionScopeIndexToStopAt = nullptr, + bool ByCopy = false); + + /// Determine whether the given type is the type of *this that is used + /// outside of the body of a member function for a type that is currently + /// being defined. + bool isThisOutsideMemberFunctionBody(QualType BaseType); + + /// ActOnCXXBoolLiteral - Parse {true,false} literals. + ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); + + + /// ActOnObjCBoolLiteral - Parse {__objc_yes,__objc_no} literals. + ExprResult ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); + + ExprResult + ActOnObjCAvailabilityCheckExpr(llvm::ArrayRef<AvailabilitySpec> AvailSpecs, + SourceLocation AtLoc, SourceLocation RParen); + + /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. + ExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc); + + //// ActOnCXXThrow - Parse throw expressions. + ExprResult ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *expr); + ExprResult BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, + bool IsThrownVarInScope); + bool CheckCXXThrowOperand(SourceLocation ThrowLoc, QualType ThrowTy, Expr *E); + + /// ActOnCXXTypeConstructExpr - 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()"). + ExprResult ActOnCXXTypeConstructExpr(ParsedType TypeRep, + SourceLocation LParenOrBraceLoc, + MultiExprArg Exprs, + SourceLocation RParenOrBraceLoc, + bool ListInitialization); + + ExprResult BuildCXXTypeConstructExpr(TypeSourceInfo *Type, + SourceLocation LParenLoc, + MultiExprArg Exprs, + SourceLocation RParenLoc, + bool ListInitialization); + + /// ActOnCXXNew - Parsed a C++ 'new' expression. + ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, + SourceLocation PlacementLParen, + MultiExprArg PlacementArgs, + SourceLocation PlacementRParen, + SourceRange TypeIdParens, Declarator &D, + Expr *Initializer); + ExprResult + BuildCXXNew(SourceRange Range, bool UseGlobal, SourceLocation PlacementLParen, + MultiExprArg PlacementArgs, SourceLocation PlacementRParen, + SourceRange TypeIdParens, QualType AllocType, + TypeSourceInfo *AllocTypeInfo, std::optional<Expr *> ArraySize, + SourceRange DirectInitRange, Expr *Initializer); + + /// Determine whether \p FD is an aligned allocation or deallocation + /// function that is unavailable. + bool isUnavailableAlignedAllocationFunction(const FunctionDecl &FD) const; + + /// Produce diagnostics if \p FD is an aligned allocation or deallocation + /// function that is unavailable. + void diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD, + SourceLocation Loc); + + bool CheckAllocatedType(QualType AllocType, SourceLocation Loc, + SourceRange R); + + /// The scope in which to find allocation functions. + enum AllocationFunctionScope { + /// Only look for allocation functions in the global scope. + AFS_Global, + /// Only look for allocation functions in the scope of the + /// allocated class. + AFS_Class, + /// Look for allocation functions in both the global scope + /// and in the scope of the allocated class. + AFS_Both + }; + + /// Finds the overloads of operator new and delete that are appropriate + /// for the allocation. + bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, + AllocationFunctionScope NewScope, + AllocationFunctionScope DeleteScope, + QualType AllocType, bool IsArray, + bool &PassAlignment, MultiExprArg PlaceArgs, + FunctionDecl *&OperatorNew, + FunctionDecl *&OperatorDelete, + bool Diagnose = true); + void DeclareGlobalNewDelete(); + void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, + ArrayRef<QualType> Params); + + bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, + DeclarationName Name, FunctionDecl *&Operator, + bool Diagnose = true, bool WantSize = false, + bool WantAligned = false); + FunctionDecl *FindUsualDeallocationFunction(SourceLocation StartLoc, + bool CanProvideSize, + bool Overaligned, + DeclarationName Name); + FunctionDecl *FindDeallocationFunctionForDestructor(SourceLocation StartLoc, + CXXRecordDecl *RD); + + /// ActOnCXXDelete - Parsed a C++ 'delete' expression + ExprResult ActOnCXXDelete(SourceLocation StartLoc, + bool UseGlobal, bool ArrayForm, + Expr *Operand); + void CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, + bool IsDelete, bool CallCanBeVirtual, + bool WarnOnNonAbstractTypes, + SourceLocation DtorLoc); + + ExprResult ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation LParen, + Expr *Operand, SourceLocation RParen); + ExprResult BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, + SourceLocation RParen); + + /// Parsed one of the type trait support pseudo-functions. + ExprResult ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, + ArrayRef<ParsedType> Args, + SourceLocation RParenLoc); + ExprResult BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc); + + /// ActOnArrayTypeTrait - Parsed one of the binary type trait support + /// pseudo-functions. + ExprResult ActOnArrayTypeTrait(ArrayTypeTrait ATT, + SourceLocation KWLoc, + ParsedType LhsTy, + Expr *DimExpr, + SourceLocation RParen); + + ExprResult BuildArrayTypeTrait(ArrayTypeTrait ATT, + SourceLocation KWLoc, + TypeSourceInfo *TSInfo, + Expr *DimExpr, + SourceLocation RParen); + + /// ActOnExpressionTrait - Parsed one of the unary type trait support + /// pseudo-functions. + ExprResult ActOnExpressionTrait(ExpressionTrait OET, + SourceLocation KWLoc, + Expr *Queried, + SourceLocation RParen); + + ExprResult BuildExpressionTrait(ExpressionTrait OET, + SourceLocation KWLoc, + Expr *Queried, + SourceLocation RParen); + + ExprResult ActOnStartCXXMemberReference(Scope *S, + Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + ParsedType &ObjectType, + bool &MayBePseudoDestructor); + + ExprResult BuildPseudoDestructorExpr(Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + TypeSourceInfo *ScopeType, + SourceLocation CCLoc, + SourceLocation TildeLoc, + PseudoDestructorTypeStorage DestroyedType); + + ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + UnqualifiedId &FirstTypeName, + SourceLocation CCLoc, + SourceLocation TildeLoc, + UnqualifiedId &SecondTypeName); + + ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation TildeLoc, + const DeclSpec& DS); + + /// MaybeCreateExprWithCleanups - If the current full-expression + /// requires any cleanups, surround it with a ExprWithCleanups node. + /// Otherwise, just returns the passed-in expression. + Expr *MaybeCreateExprWithCleanups(Expr *SubExpr); + Stmt *MaybeCreateStmtWithCleanups(Stmt *SubStmt); + ExprResult MaybeCreateExprWithCleanups(ExprResult SubExpr); + + MaterializeTemporaryExpr * + CreateMaterializeTemporaryExpr(QualType T, Expr *Temporary, + bool BoundToLvalueReference); + + ExprResult ActOnFinishFullExpr(Expr *Expr, bool DiscardedValue) { + return ActOnFinishFullExpr( + Expr, Expr ? Expr->getExprLoc() : SourceLocation(), DiscardedValue); + } + ExprResult ActOnFinishFullExpr(Expr *Expr, SourceLocation CC, + bool DiscardedValue, bool IsConstexpr = false, + bool IsTemplateArgument = false); + StmtResult ActOnFinishFullStmt(Stmt *Stmt); + + // Marks SS invalid if it represents an incomplete type. + bool RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC); + // Complete an enum decl, maybe without a scope spec. + bool RequireCompleteEnumDecl(EnumDecl *D, SourceLocation L, + CXXScopeSpec *SS = nullptr); + + DeclContext *computeDeclContext(QualType T); + DeclContext *computeDeclContext(const CXXScopeSpec &SS, + bool EnteringContext = false); + bool isDependentScopeSpecifier(const CXXScopeSpec &SS); + CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); + + /// The parser has parsed a global nested-name-specifier '::'. + /// + /// \param CCLoc The location of the '::'. + /// + /// \param SS The nested-name-specifier, which will be updated in-place + /// to reflect the parsed nested-name-specifier. + /// + /// \returns true if an error occurred, false otherwise. + bool ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc, CXXScopeSpec &SS); + + /// The parser has parsed a '__super' nested-name-specifier. + /// + /// \param SuperLoc The location of the '__super' keyword. + /// + /// \param ColonColonLoc The location of the '::'. + /// + /// \param SS The nested-name-specifier, which will be updated in-place + /// to reflect the parsed nested-name-specifier. + /// + /// \returns true if an error occurred, false otherwise. + bool ActOnSuperScopeSpecifier(SourceLocation SuperLoc, + SourceLocation ColonColonLoc, CXXScopeSpec &SS); + + bool isAcceptableNestedNameSpecifier(const NamedDecl *SD, + bool *CanCorrect = nullptr); + NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); + + /// Keeps information about an identifier in a nested-name-spec. + /// + struct NestedNameSpecInfo { + /// The type of the object, if we're parsing nested-name-specifier in + /// a member access expression. + ParsedType ObjectType; + + /// The identifier preceding the '::'. + IdentifierInfo *Identifier; + + /// The location of the identifier. + SourceLocation IdentifierLoc; + + /// The location of the '::'. + SourceLocation CCLoc; + + /// Creates info object for the most typical case. + NestedNameSpecInfo(IdentifierInfo *II, SourceLocation IdLoc, + SourceLocation ColonColonLoc, ParsedType ObjectType = ParsedType()) + : ObjectType(ObjectType), Identifier(II), IdentifierLoc(IdLoc), + CCLoc(ColonColonLoc) { + } + + NestedNameSpecInfo(IdentifierInfo *II, SourceLocation IdLoc, + SourceLocation ColonColonLoc, QualType ObjectType) + : ObjectType(ParsedType::make(ObjectType)), Identifier(II), + IdentifierLoc(IdLoc), CCLoc(ColonColonLoc) { + } + }; + + bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, + NestedNameSpecInfo &IdInfo); + + bool BuildCXXNestedNameSpecifier(Scope *S, + NestedNameSpecInfo &IdInfo, + bool EnteringContext, + CXXScopeSpec &SS, + NamedDecl *ScopeLookupResult, + bool ErrorRecoveryLookup, + bool *IsCorrectedToColon = nullptr, + bool OnlyNamespace = false); + + /// The parser has parsed a nested-name-specifier 'identifier::'. + /// + /// \param S The scope in which this nested-name-specifier occurs. + /// + /// \param IdInfo Parser information about an identifier in the + /// nested-name-spec. + /// + /// \param EnteringContext Whether we're entering the context nominated by + /// this nested-name-specifier. + /// + /// \param SS The nested-name-specifier, which is both an input + /// parameter (the nested-name-specifier before this type) and an + /// output parameter (containing the full nested-name-specifier, + /// including this new type). + /// + /// \param IsCorrectedToColon If not null, suggestions to replace '::' -> ':' + /// are allowed. The bool value pointed by this parameter is set to 'true' + /// if the identifier is treated as if it was followed by ':', not '::'. + /// + /// \param OnlyNamespace If true, only considers namespaces in lookup. + /// + /// \returns true if an error occurred, false otherwise. + bool ActOnCXXNestedNameSpecifier(Scope *S, + NestedNameSpecInfo &IdInfo, + bool EnteringContext, + CXXScopeSpec &SS, + bool *IsCorrectedToColon = nullptr, + bool OnlyNamespace = false); + + ExprResult ActOnDecltypeExpression(Expr *E); + + bool ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, + const DeclSpec &DS, + SourceLocation ColonColonLoc); + + bool IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, + NestedNameSpecInfo &IdInfo, + bool EnteringContext); + + /// The parser has parsed a nested-name-specifier + /// 'template[opt] template-name < template-args >::'. + /// + /// \param S The scope in which this nested-name-specifier occurs. + /// + /// \param SS The nested-name-specifier, which is both an input + /// parameter (the nested-name-specifier before this type) and an + /// output parameter (containing the full nested-name-specifier, + /// including this new type). + /// + /// \param TemplateKWLoc the location of the 'template' keyword, if any. + /// \param TemplateName the template name. + /// \param TemplateNameLoc The location of the template name. + /// \param LAngleLoc The location of the opening angle bracket ('<'). + /// \param TemplateArgs The template arguments. + /// \param RAngleLoc The location of the closing angle bracket ('>'). + /// \param CCLoc The location of the '::'. + /// + /// \param EnteringContext Whether we're entering the context of the + /// nested-name-specifier. + /// + /// + /// \returns true if an error occurred, false otherwise. + bool ActOnCXXNestedNameSpecifier(Scope *S, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + TemplateTy TemplateName, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation RAngleLoc, + SourceLocation CCLoc, + bool EnteringContext); + + /// Given a C++ nested-name-specifier, produce an annotation value + /// that the parser can use later to reconstruct the given + /// nested-name-specifier. + /// + /// \param SS A nested-name-specifier. + /// + /// \returns A pointer containing all of the information in the + /// nested-name-specifier \p SS. + void *SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS); + + /// Given an annotation pointer for a nested-name-specifier, restore + /// the nested-name-specifier structure. + /// + /// \param Annotation The annotation pointer, produced by + /// \c SaveNestedNameSpecifierAnnotation(). + /// + /// \param AnnotationRange The source range corresponding to the annotation. + /// + /// \param SS The nested-name-specifier that will be updated with the contents + /// of the annotation pointer. + void RestoreNestedNameSpecifierAnnotation(void *Annotation, + SourceRange AnnotationRange, + CXXScopeSpec &SS); + + bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + + /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global + /// scope or nested-name-specifier) is parsed, part of a declarator-id. + /// After this method is called, according to [C++ 3.4.3p3], names should be + /// looked up in the declarator-id's scope, until the declarator is parsed and + /// ActOnCXXExitDeclaratorScope is called. + /// The 'SS' should be a non-empty valid CXXScopeSpec. + bool ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS); + + /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously + /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same + /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well. + /// Used to indicate that names should revert to being looked up in the + /// defining scope. + void ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + + /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an + /// initializer for the declaration 'Dcl'. + /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a + /// static data member of class X, names should be looked up in the scope of + /// class X. + void ActOnCXXEnterDeclInitializer(Scope *S, Decl *Dcl); + + /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an + /// initializer for the declaration 'Dcl'. + void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl); + + /// Create a new lambda closure type. + CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange, + TypeSourceInfo *Info, + unsigned LambdaDependencyKind, + LambdaCaptureDefault CaptureDefault); + + /// Start the definition of a lambda expression. + CXXMethodDecl * + startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, + TypeSourceInfo *MethodType, SourceLocation EndLoc, + ArrayRef<ParmVarDecl *> Params, + ConstexprSpecKind ConstexprKind, StorageClass SC, + Expr *TrailingRequiresClause); + + /// Number lambda for linkage purposes if necessary. + void handleLambdaNumbering( + CXXRecordDecl *Class, CXXMethodDecl *Method, + std::optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling = + std::nullopt); + + /// Endow the lambda scope info with the relevant properties. + void buildLambdaScope(sema::LambdaScopeInfo *LSI, + CXXMethodDecl *CallOperator, + SourceRange IntroducerRange, + LambdaCaptureDefault CaptureDefault, + SourceLocation CaptureDefaultLoc, + bool ExplicitParams, + bool ExplicitResultType, + bool Mutable); + + /// Perform initialization analysis of the init-capture and perform + /// any implicit conversions such as an lvalue-to-rvalue conversion if + /// not being used to initialize a reference. + ParsedType actOnLambdaInitCaptureInitialization( + SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc, + IdentifierInfo *Id, LambdaCaptureInitKind InitKind, Expr *&Init) { + return ParsedType::make(buildLambdaInitCaptureInitialization( + Loc, ByRef, EllipsisLoc, std::nullopt, Id, + InitKind != LambdaCaptureInitKind::CopyInit, Init)); + } + QualType buildLambdaInitCaptureInitialization( + SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc, + std::optional<unsigned> NumExpansions, IdentifierInfo *Id, + bool DirectInit, Expr *&Init); + + /// Create a dummy variable within the declcontext of the lambda's + /// call operator, for name lookup purposes for a lambda init capture. + /// + /// CodeGen handles emission of lambda captures, ignoring these dummy + /// variables appropriately. + VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc, + QualType InitCaptureType, + SourceLocation EllipsisLoc, + IdentifierInfo *Id, + unsigned InitStyle, Expr *Init); + + /// Add an init-capture to a lambda scope. + void addInitCapture(sema::LambdaScopeInfo *LSI, VarDecl *Var, + bool isReferenceType); + + /// Note that we have finished the explicit captures for the + /// given lambda. + void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI); + + /// \brief This is called after parsing the explicit template parameter list + /// on a lambda (if it exists) in C++2a. + void ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc, + ArrayRef<NamedDecl *> TParams, + SourceLocation RAngleLoc, + ExprResult RequiresClause); + + /// Introduce the lambda parameters into scope. + void addLambdaParameters( + ArrayRef<LambdaIntroducer::LambdaCapture> Captures, + CXXMethodDecl *CallOperator, Scope *CurScope); + + /// Deduce a block or lambda's return type based on the return + /// statements present in the body. + void deduceClosureReturnType(sema::CapturingScopeInfo &CSI); + + /// ActOnStartOfLambdaDefinition - This is called just before we start + /// parsing the body of a lambda; it analyzes the explicit captures and + /// arguments, and sets up various data-structures for the body of the + /// lambda. + void ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, + Declarator &ParamInfo, Scope *CurScope); + + /// ActOnLambdaError - If there is an error parsing a lambda, this callback + /// is invoked to pop the information about the lambda. + void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, + bool IsInstantiation = false); + + /// ActOnLambdaExpr - This is called when the body of a lambda expression + /// was successfully completed. + ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, + Scope *CurScope); + + /// Does copying/destroying the captured variable have side effects? + bool CaptureHasSideEffects(const sema::Capture &From); + + /// Diagnose if an explicit lambda capture is unused. Returns true if a + /// diagnostic is emitted. + bool DiagnoseUnusedLambdaCapture(SourceRange CaptureRange, + const sema::Capture &From); + + /// Build a FieldDecl suitable to hold the given capture. + FieldDecl *BuildCaptureField(RecordDecl *RD, const sema::Capture &Capture); + + /// Initialize the given capture with a suitable expression. + ExprResult BuildCaptureInit(const sema::Capture &Capture, + SourceLocation ImplicitCaptureLoc, + bool IsOpenMPMapping = false); + + /// Complete a lambda-expression having processed and attached the + /// lambda body. + ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, + sema::LambdaScopeInfo *LSI); + + /// Get the return type to use for a lambda's conversion function(s) to + /// function pointer type, given the type of the call operator. + QualType + getLambdaConversionFunctionResultType(const FunctionProtoType *CallOpType, + CallingConv CC); + + /// Define the "body" of the conversion from a lambda object to a + /// function pointer. + /// + /// This routine doesn't actually define a sensible body; rather, it fills + /// in the initialization expression needed to copy the lambda object into + /// the block, and IR generation actually generates the real body of the + /// block pointer conversion. + void DefineImplicitLambdaToFunctionPointerConversion( + SourceLocation CurrentLoc, CXXConversionDecl *Conv); + + /// Define the "body" of the conversion from a lambda object to a + /// block pointer. + /// + /// This routine doesn't actually define a sensible body; rather, it fills + /// in the initialization expression needed to copy the lambda object into + /// the block, and IR generation actually generates the real body of the + /// block pointer conversion. + void DefineImplicitLambdaToBlockPointerConversion(SourceLocation CurrentLoc, + CXXConversionDecl *Conv); + + ExprResult BuildBlockForLambdaConversion(SourceLocation CurrentLocation, + SourceLocation ConvLocation, + CXXConversionDecl *Conv, + Expr *Src); + + /// Check whether the given expression is a valid constraint expression. + /// A diagnostic is emitted if it is not, false is returned, and + /// PossibleNonPrimary will be set to true if the failure might be due to a + /// non-primary expression being used as an atomic constraint. + bool CheckConstraintExpression(const Expr *CE, Token NextToken = Token(), + bool *PossibleNonPrimary = nullptr, + bool IsTrailingRequiresClause = false); + +private: + /// Caches pairs of template-like decls whose associated constraints were + /// checked for subsumption and whether or not the first's constraints did in + /// fact subsume the second's. + llvm::DenseMap<std::pair<NamedDecl *, NamedDecl *>, bool> SubsumptionCache; + /// Caches the normalized associated constraints of declarations (concepts or + /// constrained declarations). If an error occurred while normalizing the + /// associated constraints of the template or concept, nullptr will be cached + /// here. + llvm::DenseMap<NamedDecl *, NormalizedConstraint *> + NormalizationCache; + + llvm::ContextualFoldingSet<ConstraintSatisfaction, const ASTContext &> + SatisfactionCache; + + /// Introduce the instantiated function parameters into the local + /// instantiation scope, and set the parameter names to those used + /// in the template. + bool addInstantiatedParametersToScope( + FunctionDecl *Function, const FunctionDecl *PatternDecl, + LocalInstantiationScope &Scope, + const MultiLevelTemplateArgumentList &TemplateArgs); + + /// used by SetupConstraintCheckingTemplateArgumentsAndScope to recursively(in + /// the case of lambdas) set up the LocalInstantiationScope of the current + /// function. + bool SetupConstraintScope( + FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs, + MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope); + + /// Used during constraint checking, sets up the constraint template argument + /// lists, and calls SetupConstraintScope to set up the + /// LocalInstantiationScope to have the proper set of ParVarDecls configured. + std::optional<MultiLevelTemplateArgumentList> + SetupConstraintCheckingTemplateArgumentsAndScope( + FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs, + LocalInstantiationScope &Scope); + +private: + // The current stack of constraint satisfactions, so we can exit-early. + using SatisfactionStackEntryTy = + std::pair<const NamedDecl *, llvm::FoldingSetNodeID>; + llvm::SmallVector<SatisfactionStackEntryTy, 10> + SatisfactionStack; + +public: + void PushSatisfactionStackEntry(const NamedDecl *D, + const llvm::FoldingSetNodeID &ID) { + const NamedDecl *Can = cast<NamedDecl>(D->getCanonicalDecl()); + SatisfactionStack.emplace_back(Can, ID); + } + + void PopSatisfactionStackEntry() { SatisfactionStack.pop_back(); } + + bool SatisfactionStackContains(const NamedDecl *D, + const llvm::FoldingSetNodeID &ID) const { + const NamedDecl *Can = cast<NamedDecl>(D->getCanonicalDecl()); + return llvm::find(SatisfactionStack, + SatisfactionStackEntryTy{Can, ID}) != + SatisfactionStack.end(); + } + + // Resets the current SatisfactionStack for cases where we are instantiating + // constraints as a 'side effect' of normal instantiation in a way that is not + // indicative of recursive definition. + class SatisfactionStackResetRAII { + llvm::SmallVector<SatisfactionStackEntryTy, 10> + BackupSatisfactionStack; + Sema &SemaRef; + + public: + SatisfactionStackResetRAII(Sema &S) : SemaRef(S) { + SemaRef.SwapSatisfactionStack(BackupSatisfactionStack); + } + + ~SatisfactionStackResetRAII() { + SemaRef.SwapSatisfactionStack(BackupSatisfactionStack); + } + }; + + void SwapSatisfactionStack( + llvm::SmallVectorImpl<SatisfactionStackEntryTy> &NewSS) { + SatisfactionStack.swap(NewSS); + } + + const NormalizedConstraint * + getNormalizedAssociatedConstraints( + NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints); + + /// \brief Check whether the given declaration's associated constraints are + /// at least as constrained than another declaration's according to the + /// partial ordering of constraints. + /// + /// \param Result If no error occurred, receives the result of true if D1 is + /// at least constrained than D2, and false otherwise. + /// + /// \returns true if an error occurred, false otherwise. + bool IsAtLeastAsConstrained(NamedDecl *D1, MutableArrayRef<const Expr *> AC1, + NamedDecl *D2, MutableArrayRef<const Expr *> AC2, + bool &Result); + + /// If D1 was not at least as constrained as D2, but would've been if a pair + /// of atomic constraints involved had been declared in a concept and not + /// repeated in two separate places in code. + /// \returns true if such a diagnostic was emitted, false otherwise. + bool MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1, + ArrayRef<const Expr *> AC1, NamedDecl *D2, ArrayRef<const Expr *> AC2); + + /// \brief Check whether the given list of constraint expressions are + /// satisfied (as if in a 'conjunction') given template arguments. + /// \param Template the template-like entity that triggered the constraints + /// check (either a concept or a constrained entity). + /// \param ConstraintExprs a list of constraint expressions, treated as if + /// they were 'AND'ed together. + /// \param TemplateArgLists the list of template arguments to substitute into + /// the constraint expression. + /// \param TemplateIDRange The source range of the template id that + /// caused the constraints check. + /// \param Satisfaction if true is returned, will contain details of the + /// satisfaction, with enough information to diagnose an unsatisfied + /// expression. + /// \returns true if an error occurred and satisfaction could not be checked, + /// false otherwise. + bool CheckConstraintSatisfaction( + const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, + const MultiLevelTemplateArgumentList &TemplateArgLists, + SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) { + llvm::SmallVector<Expr *, 4> Converted; + return CheckConstraintSatisfaction(Template, ConstraintExprs, Converted, + TemplateArgLists, TemplateIDRange, + Satisfaction); + } + + /// \brief Check whether the given list of constraint expressions are + /// satisfied (as if in a 'conjunction') given template arguments. + /// Additionally, takes an empty list of Expressions which is populated with + /// the instantiated versions of the ConstraintExprs. + /// \param Template the template-like entity that triggered the constraints + /// check (either a concept or a constrained entity). + /// \param ConstraintExprs a list of constraint expressions, treated as if + /// they were 'AND'ed together. + /// \param ConvertedConstraints a out parameter that will get populated with + /// the instantiated version of the ConstraintExprs if we successfully checked + /// satisfaction. + /// \param TemplateArgList the multi-level list of template arguments to + /// substitute into the constraint expression. This should be relative to the + /// top-level (hence multi-level), since we need to instantiate fully at the + /// time of checking. + /// \param TemplateIDRange The source range of the template id that + /// caused the constraints check. + /// \param Satisfaction if true is returned, will contain details of the + /// satisfaction, with enough information to diagnose an unsatisfied + /// expression. + /// \returns true if an error occurred and satisfaction could not be checked, + /// false otherwise. + bool CheckConstraintSatisfaction( + const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, + llvm::SmallVectorImpl<Expr *> &ConvertedConstraints, + const MultiLevelTemplateArgumentList &TemplateArgList, + SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction); + + /// \brief Check whether the given non-dependent constraint expression is + /// satisfied. Returns false and updates Satisfaction with the satisfaction + /// verdict if successful, emits a diagnostic and returns true if an error + /// occurred and satisfaction could not be determined. + /// + /// \returns true if an error occurred, false otherwise. + bool CheckConstraintSatisfaction(const Expr *ConstraintExpr, + ConstraintSatisfaction &Satisfaction); + + /// Check whether the given function decl's trailing requires clause is + /// satisfied, if any. Returns false and updates Satisfaction with the + /// satisfaction verdict if successful, emits a diagnostic and returns true if + /// an error occurred and satisfaction could not be determined. + /// + /// \returns true if an error occurred, false otherwise. + bool CheckFunctionConstraints(const FunctionDecl *FD, + ConstraintSatisfaction &Satisfaction, + SourceLocation UsageLoc = SourceLocation(), + bool ForOverloadResolution = false); + + /// \brief Ensure that the given template arguments satisfy the constraints + /// associated with the given template, emitting a diagnostic if they do not. + /// + /// \param Template The template to which the template arguments are being + /// provided. + /// + /// \param TemplateArgs The converted, canonicalized template arguments. + /// + /// \param TemplateIDRange The source range of the template id that + /// caused the constraints check. + /// + /// \returns true if the constrains are not satisfied or could not be checked + /// for satisfaction, false if the constraints are satisfied. + bool EnsureTemplateArgumentListConstraints( + TemplateDecl *Template, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceRange TemplateIDRange); + + /// \brief Emit diagnostics explaining why a constraint expression was deemed + /// unsatisfied. + /// \param First whether this is the first time an unsatisfied constraint is + /// diagnosed for this error. + void + DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction &Satisfaction, + bool First = true); + + /// \brief Emit diagnostics explaining why a constraint expression was deemed + /// unsatisfied. + void + DiagnoseUnsatisfiedConstraint(const ASTConstraintSatisfaction &Satisfaction, + bool First = true); + + // ParseObjCStringLiteral - Parse Objective-C string literals. + ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, + ArrayRef<Expr *> Strings); + + ExprResult BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S); + + /// BuildObjCNumericLiteral - builds an ObjCBoxedExpr AST node for the + /// numeric literal expression. Type of the expression will be "NSNumber *" + /// or "id" if NSNumber is unavailable. + ExprResult BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number); + ExprResult ActOnObjCBoolLiteral(SourceLocation AtLoc, SourceLocation ValueLoc, + bool Value); + ExprResult BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements); + + /// BuildObjCBoxedExpr - builds an ObjCBoxedExpr AST node for the + /// '@' prefixed parenthesized expression. The type of the expression will + /// either be "NSNumber *", "NSString *" or "NSValue *" depending on the type + /// of ValueType, which is allowed to be a built-in numeric type, "char *", + /// "const char *" or C structure with attribute 'objc_boxable'. + ExprResult BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr); + + ExprResult BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr, + Expr *IndexExpr, + ObjCMethodDecl *getterMethod, + ObjCMethodDecl *setterMethod); + + ExprResult BuildObjCDictionaryLiteral(SourceRange SR, + MutableArrayRef<ObjCDictionaryElement> Elements); + + ExprResult BuildObjCEncodeExpression(SourceLocation AtLoc, + TypeSourceInfo *EncodedTypeInfo, + SourceLocation RParenLoc); + ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl, + CXXConversionDecl *Method, + bool HadMultipleCandidates); + + ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, + SourceLocation EncodeLoc, + SourceLocation LParenLoc, + ParsedType Ty, + SourceLocation RParenLoc); + + /// ParseObjCSelectorExpression - Build selector expression for \@selector + ExprResult ParseObjCSelectorExpression(Selector Sel, + SourceLocation AtLoc, + SourceLocation SelLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc, + bool WarnMultipleSelectors); + + /// ParseObjCProtocolExpression - Build protocol expression for \@protocol + ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, + SourceLocation AtLoc, + SourceLocation ProtoLoc, + SourceLocation LParenLoc, + SourceLocation ProtoIdLoc, + SourceLocation RParenLoc); + + //===--------------------------------------------------------------------===// + // C++ Declarations + // + Decl *ActOnStartLinkageSpecification(Scope *S, + SourceLocation ExternLoc, + Expr *LangStr, + SourceLocation LBraceLoc); + Decl *ActOnFinishLinkageSpecification(Scope *S, + Decl *LinkageSpec, + SourceLocation RBraceLoc); + + + //===--------------------------------------------------------------------===// + // C++ Classes + // + CXXRecordDecl *getCurrentClass(Scope *S, const CXXScopeSpec *SS); + bool isCurrentClassName(const IdentifierInfo &II, Scope *S, + const CXXScopeSpec *SS = nullptr); + bool isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS); + + bool ActOnAccessSpecifier(AccessSpecifier Access, SourceLocation ASLoc, + SourceLocation ColonLoc, + const ParsedAttributesView &Attrs); + + NamedDecl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, + Declarator &D, + MultiTemplateParamsArg TemplateParameterLists, + Expr *BitfieldWidth, const VirtSpecifiers &VS, + InClassInitStyle InitStyle); + + void ActOnStartCXXInClassMemberInitializer(); + void ActOnFinishCXXInClassMemberInitializer(Decl *VarDecl, + SourceLocation EqualLoc, + Expr *Init); + + MemInitResult ActOnMemInitializer(Decl *ConstructorD, + Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *MemberOrBase, + ParsedType TemplateTypeTy, + const DeclSpec &DS, + SourceLocation IdLoc, + SourceLocation LParenLoc, + ArrayRef<Expr *> Args, + SourceLocation RParenLoc, + SourceLocation EllipsisLoc); + + MemInitResult ActOnMemInitializer(Decl *ConstructorD, + Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *MemberOrBase, + ParsedType TemplateTypeTy, + const DeclSpec &DS, + SourceLocation IdLoc, + Expr *InitList, + SourceLocation EllipsisLoc); + + MemInitResult BuildMemInitializer(Decl *ConstructorD, + Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *MemberOrBase, + ParsedType TemplateTypeTy, + const DeclSpec &DS, + SourceLocation IdLoc, + Expr *Init, + SourceLocation EllipsisLoc); + + MemInitResult BuildMemberInitializer(ValueDecl *Member, + Expr *Init, + SourceLocation IdLoc); + + MemInitResult BuildBaseInitializer(QualType BaseType, + TypeSourceInfo *BaseTInfo, + Expr *Init, + CXXRecordDecl *ClassDecl, + SourceLocation EllipsisLoc); + + MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo, + Expr *Init, + CXXRecordDecl *ClassDecl); + + bool SetDelegatingInitializer(CXXConstructorDecl *Constructor, + CXXCtorInitializer *Initializer); + + bool SetCtorInitializers( + CXXConstructorDecl *Constructor, bool AnyErrors, + ArrayRef<CXXCtorInitializer *> Initializers = std::nullopt); + + void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation); + + + /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, + /// mark all the non-trivial destructors of its members and bases as + /// referenced. + void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc, + CXXRecordDecl *Record); + + /// Mark destructors of virtual bases of this class referenced. In the Itanium + /// C++ ABI, this is done when emitting a destructor for any non-abstract + /// class. In the Microsoft C++ ABI, this is done any time a class's + /// destructor is referenced. + void MarkVirtualBaseDestructorsReferenced( + SourceLocation Location, CXXRecordDecl *ClassDecl, + llvm::SmallPtrSetImpl<const RecordType *> *DirectVirtualBases = nullptr); + + /// Do semantic checks to allow the complete destructor variant to be emitted + /// when the destructor is defined in another translation unit. In the Itanium + /// C++ ABI, destructor variants are emitted together. In the MS C++ ABI, they + /// can be emitted in separate TUs. To emit the complete variant, run a subset + /// of the checks performed when emitting a regular destructor. + void CheckCompleteDestructorVariant(SourceLocation CurrentLocation, + CXXDestructorDecl *Dtor); + + /// The list of classes whose vtables have been used within + /// this translation unit, and the source locations at which the + /// first use occurred. + typedef std::pair<CXXRecordDecl*, SourceLocation> VTableUse; + + /// The list of vtables that are required but have not yet been + /// materialized. + SmallVector<VTableUse, 16> VTableUses; + + /// The set of classes whose vtables have been used within + /// this translation unit, and a bit that will be true if the vtable is + /// required to be emitted (otherwise, it should be emitted only if needed + /// by code generation). + llvm::DenseMap<CXXRecordDecl *, bool> VTablesUsed; + + /// Load any externally-stored vtable uses. + void LoadExternalVTableUses(); + + /// Note that the vtable for the given class was used at the + /// given location. + void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, + bool DefinitionRequired = false); + + /// Mark the exception specifications of all virtual member functions + /// in the given class as needed. + void MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, + const CXXRecordDecl *RD); + + /// MarkVirtualMembersReferenced - Will mark all members of the given + /// CXXRecordDecl referenced. + void MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD, + bool ConstexprOnly = false); + + /// Define all of the vtables that have been used in this + /// translation unit and reference any virtual members used by those + /// vtables. + /// + /// \returns true if any work was done, false otherwise. + bool DefineUsedVTables(); + + void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); + + void ActOnMemInitializers(Decl *ConstructorDecl, + SourceLocation ColonLoc, + ArrayRef<CXXCtorInitializer*> MemInits, + bool AnyErrors); + + /// Check class-level dllimport/dllexport attribute. The caller must + /// ensure that referenceDLLExportedClassMethods is called some point later + /// when all outer classes of Class are complete. + void checkClassLevelDLLAttribute(CXXRecordDecl *Class); + void checkClassLevelCodeSegAttribute(CXXRecordDecl *Class); + + void referenceDLLExportedClassMethods(); + + void propagateDLLAttrToBaseClassTemplate( + CXXRecordDecl *Class, Attr *ClassAttr, + ClassTemplateSpecializationDecl *BaseTemplateSpec, + SourceLocation BaseLoc); + + /// Add gsl::Pointer attribute to std::container::iterator + /// \param ND The declaration that introduces the name + /// std::container::iterator. \param UnderlyingRecord The record named by ND. + void inferGslPointerAttribute(NamedDecl *ND, CXXRecordDecl *UnderlyingRecord); + + /// Add [[gsl::Owner]] and [[gsl::Pointer]] attributes for std:: types. + void inferGslOwnerPointerAttribute(CXXRecordDecl *Record); + + /// Add [[gsl::Pointer]] attributes for std:: types. + void inferGslPointerAttribute(TypedefNameDecl *TD); + + void CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record); + + /// Check that the C++ class annoated with "trivial_abi" satisfies all the + /// conditions that are needed for the attribute to have an effect. + void checkIllFormedTrivialABIStruct(CXXRecordDecl &RD); + + void ActOnFinishCXXMemberSpecification(Scope *S, SourceLocation RLoc, + Decl *TagDecl, SourceLocation LBrac, + SourceLocation RBrac, + const ParsedAttributesView &AttrList); + void ActOnFinishCXXMemberDecls(); + void ActOnFinishCXXNonNestedClass(); + + void ActOnReenterCXXMethodParameter(Scope *S, ParmVarDecl *Param); + unsigned ActOnReenterTemplateScope(Decl *Template, + llvm::function_ref<Scope *()> EnterScope); + void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record); + void ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *Method); + void ActOnDelayedCXXMethodParameter(Scope *S, Decl *Param); + void ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *Record); + void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method); + void ActOnFinishDelayedMemberInitializers(Decl *Record); + void MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD, + CachedTokens &Toks); + void UnmarkAsLateParsedTemplate(FunctionDecl *FD); + bool IsInsideALocalClassWithinATemplateFunction(); + + Decl *ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, + Expr *AssertExpr, + Expr *AssertMessageExpr, + SourceLocation RParenLoc); + Decl *BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, + Expr *AssertExpr, + StringLiteral *AssertMessageExpr, + SourceLocation RParenLoc, + bool Failed); + void DiagnoseStaticAssertDetails(const Expr *E); + + FriendDecl *CheckFriendTypeDecl(SourceLocation LocStart, + SourceLocation FriendLoc, + TypeSourceInfo *TSInfo); + Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, + MultiTemplateParamsArg TemplateParams); + NamedDecl *ActOnFriendFunctionDecl(Scope *S, Declarator &D, + MultiTemplateParamsArg TemplateParams); + + QualType CheckConstructorDeclarator(Declarator &D, QualType R, + StorageClass& SC); + void CheckConstructor(CXXConstructorDecl *Constructor); + QualType CheckDestructorDeclarator(Declarator &D, QualType R, + StorageClass& SC); + bool CheckDestructor(CXXDestructorDecl *Destructor); + void CheckConversionDeclarator(Declarator &D, QualType &R, + StorageClass& SC); + Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion); + void CheckDeductionGuideDeclarator(Declarator &D, QualType &R, + StorageClass &SC); + void CheckDeductionGuideTemplate(FunctionTemplateDecl *TD); + + void CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *MD); + + bool CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, + CXXSpecialMember CSM, + SourceLocation DefaultLoc); + void CheckDelayedMemberExceptionSpecs(); + + bool CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *MD, + DefaultedComparisonKind DCK); + void DeclareImplicitEqualityComparison(CXXRecordDecl *RD, + FunctionDecl *Spaceship); + void DefineDefaultedComparison(SourceLocation Loc, FunctionDecl *FD, + DefaultedComparisonKind DCK); + + //===--------------------------------------------------------------------===// + // C++ Derived Classes + // + + /// ActOnBaseSpecifier - Parsed a base specifier + CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class, + SourceRange SpecifierRange, + bool Virtual, AccessSpecifier Access, + TypeSourceInfo *TInfo, + SourceLocation EllipsisLoc); + + BaseResult ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, + const ParsedAttributesView &Attrs, bool Virtual, + AccessSpecifier Access, ParsedType basetype, + SourceLocation BaseLoc, + SourceLocation EllipsisLoc); + + bool AttachBaseSpecifiers(CXXRecordDecl *Class, + MutableArrayRef<CXXBaseSpecifier *> Bases); + void ActOnBaseSpecifiers(Decl *ClassDecl, + MutableArrayRef<CXXBaseSpecifier *> Bases); + + bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base); + bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base, + CXXBasePaths &Paths); + + // FIXME: I don't like this name. + void BuildBasePathArray(const CXXBasePaths &Paths, CXXCastPath &BasePath); + + bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, + SourceLocation Loc, SourceRange Range, + CXXCastPath *BasePath = nullptr, + bool IgnoreAccess = false); + bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, + unsigned InaccessibleBaseID, + unsigned AmbiguousBaseConvID, + SourceLocation Loc, SourceRange Range, + DeclarationName Name, + CXXCastPath *BasePath, + bool IgnoreAccess = false); + + std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths); + + bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New, + const CXXMethodDecl *Old); + + /// CheckOverridingFunctionReturnType - Checks whether the return types are + /// covariant, according to C++ [class.virtual]p5. + bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New, + const CXXMethodDecl *Old); + + /// CheckOverridingFunctionExceptionSpec - Checks whether the exception + /// spec is a subset of base spec. + bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, + const CXXMethodDecl *Old); + + bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange); + + /// CheckOverrideControl - Check C++11 override control semantics. + void CheckOverrideControl(NamedDecl *D); + + /// DiagnoseAbsenceOfOverrideControl - Diagnose if 'override' keyword was + /// not used in the declaration of an overriding method. + void DiagnoseAbsenceOfOverrideControl(NamedDecl *D, bool Inconsistent); + + /// CheckForFunctionMarkedFinal - Checks whether a virtual member function + /// overrides a virtual member function marked 'final', according to + /// C++11 [class.virtual]p4. + bool CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, + const CXXMethodDecl *Old); + + + //===--------------------------------------------------------------------===// + // C++ Access Control + // + + enum AccessResult { + AR_accessible, + AR_inaccessible, + AR_dependent, + AR_delayed + }; + + bool SetMemberAccessSpecifier(NamedDecl *MemberDecl, + NamedDecl *PrevMemberDecl, + AccessSpecifier LexicalAS); + + AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, + DeclAccessPair FoundDecl); + AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, + DeclAccessPair FoundDecl); + AccessResult CheckAllocationAccess(SourceLocation OperatorLoc, + SourceRange PlacementRange, + CXXRecordDecl *NamingClass, + DeclAccessPair FoundDecl, + bool Diagnose = true); + AccessResult CheckConstructorAccess(SourceLocation Loc, + CXXConstructorDecl *D, + DeclAccessPair FoundDecl, + const InitializedEntity &Entity, + bool IsCopyBindingRefToTemp = false); + AccessResult CheckConstructorAccess(SourceLocation Loc, + CXXConstructorDecl *D, + DeclAccessPair FoundDecl, + const InitializedEntity &Entity, + const PartialDiagnostic &PDiag); + AccessResult CheckDestructorAccess(SourceLocation Loc, + CXXDestructorDecl *Dtor, + const PartialDiagnostic &PDiag, + QualType objectType = QualType()); + AccessResult CheckFriendAccess(NamedDecl *D); + AccessResult CheckMemberAccess(SourceLocation UseLoc, + CXXRecordDecl *NamingClass, + DeclAccessPair Found); + AccessResult + CheckStructuredBindingMemberAccess(SourceLocation UseLoc, + CXXRecordDecl *DecomposedClass, + DeclAccessPair Field); + AccessResult CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr, + const SourceRange &, + DeclAccessPair FoundDecl); + AccessResult CheckMemberOperatorAccess(SourceLocation Loc, + Expr *ObjectExpr, + Expr *ArgExpr, + DeclAccessPair FoundDecl); + AccessResult CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr, + ArrayRef<Expr *> ArgExprs, + DeclAccessPair FoundDecl); + AccessResult CheckAddressOfMemberAccess(Expr *OvlExpr, + DeclAccessPair FoundDecl); + AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, + QualType Base, QualType Derived, + const CXXBasePath &Path, + unsigned DiagID, + bool ForceCheck = false, + bool ForceUnprivileged = false); + void CheckLookupAccess(const LookupResult &R); + bool IsSimplyAccessible(NamedDecl *Decl, CXXRecordDecl *NamingClass, + QualType BaseType); + bool isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass, + DeclAccessPair Found, QualType ObjectType, + SourceLocation Loc, + const PartialDiagnostic &Diag); + bool isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass, + DeclAccessPair Found, + QualType ObjectType) { + return isMemberAccessibleForDeletion(NamingClass, Found, ObjectType, + SourceLocation(), PDiag()); + } + + void HandleDependentAccessCheck(const DependentDiagnostic &DD, + const MultiLevelTemplateArgumentList &TemplateArgs); + void PerformDependentDiagnostics(const DeclContext *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs); + + void HandleDelayedAccessCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); + + /// When true, access checking violations are treated as SFINAE + /// failures rather than hard errors. + bool AccessCheckingSFINAE; + + enum AbstractDiagSelID { + AbstractNone = -1, + AbstractReturnType, + AbstractParamType, + AbstractVariableType, + AbstractFieldType, + AbstractIvarType, + AbstractSynthesizedIvarType, + AbstractArrayType + }; + + bool isAbstractType(SourceLocation Loc, QualType T); + bool RequireNonAbstractType(SourceLocation Loc, QualType T, + TypeDiagnoser &Diagnoser); + template <typename... Ts> + bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, + const Ts &...Args) { + BoundTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...); + return RequireNonAbstractType(Loc, T, Diagnoser); + } + + void DiagnoseAbstractType(const CXXRecordDecl *RD); + + //===--------------------------------------------------------------------===// + // C++ Overloaded Operators [C++ 13.5] + // + + bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl); + + bool CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl); + + //===--------------------------------------------------------------------===// + // C++ Templates [C++ 14] + // + void FilterAcceptableTemplateNames(LookupResult &R, + bool AllowFunctionTemplates = true, + bool AllowDependent = true); + bool hasAnyAcceptableTemplateNames(LookupResult &R, + bool AllowFunctionTemplates = true, + bool AllowDependent = true, + bool AllowNonTemplateFunctions = false); + /// Try to interpret the lookup result D as a template-name. + /// + /// \param D A declaration found by name lookup. + /// \param AllowFunctionTemplates Whether function templates should be + /// considered valid results. + /// \param AllowDependent Whether unresolved using declarations (that might + /// name templates) should be considered valid results. + static NamedDecl *getAsTemplateNameDecl(NamedDecl *D, + bool AllowFunctionTemplates = true, + bool AllowDependent = true); + + enum TemplateNameIsRequiredTag { TemplateNameIsRequired }; + /// Whether and why a template name is required in this lookup. + class RequiredTemplateKind { + public: + /// Template name is required if TemplateKWLoc is valid. + RequiredTemplateKind(SourceLocation TemplateKWLoc = SourceLocation()) + : TemplateKW(TemplateKWLoc) {} + /// Template name is unconditionally required. + RequiredTemplateKind(TemplateNameIsRequiredTag) {} + + SourceLocation getTemplateKeywordLoc() const { + return TemplateKW.value_or(SourceLocation()); + } + bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } + bool isRequired() const { return TemplateKW != SourceLocation(); } + explicit operator bool() const { return isRequired(); } + + private: + std::optional<SourceLocation> TemplateKW; + }; + + enum class AssumedTemplateKind { + /// This is not assumed to be a template name. + None, + /// This is assumed to be a template name because lookup found nothing. + FoundNothing, + /// This is assumed to be a template name because lookup found one or more + /// functions (but no function templates). + FoundFunctions, + }; + bool LookupTemplateName( + LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType, + bool EnteringContext, bool &MemberOfUnknownSpecialization, + RequiredTemplateKind RequiredTemplate = SourceLocation(), + AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true); + + TemplateNameKind isTemplateName(Scope *S, + CXXScopeSpec &SS, + bool hasTemplateKeyword, + const UnqualifiedId &Name, + ParsedType ObjectType, + bool EnteringContext, + TemplateTy &Template, + bool &MemberOfUnknownSpecialization, + bool Disambiguation = false); + + /// Try to resolve an undeclared template name as a type template. + /// + /// Sets II to the identifier corresponding to the template name, and updates + /// Name to a corresponding (typo-corrected) type template name and TNK to + /// the corresponding kind, if possible. + void ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &Name, + TemplateNameKind &TNK, + SourceLocation NameLoc, + IdentifierInfo *&II); + + bool resolveAssumedTemplateNameAsType(Scope *S, TemplateName &Name, + SourceLocation NameLoc, + bool Diagnose = true); + + /// Determine whether a particular identifier might be the name in a C++1z + /// deduction-guide declaration. + bool isDeductionGuideName(Scope *S, const IdentifierInfo &Name, + SourceLocation NameLoc, + ParsedTemplateTy *Template = nullptr); + + bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, + SourceLocation IILoc, + Scope *S, + const CXXScopeSpec *SS, + TemplateTy &SuggestedTemplate, + TemplateNameKind &SuggestedKind); + + bool DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation, + NamedDecl *Instantiation, + bool InstantiatedFromMember, + const NamedDecl *Pattern, + const NamedDecl *PatternDef, + TemplateSpecializationKind TSK, + bool Complain = true); + + void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); + TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl); + + NamedDecl *ActOnTypeParameter(Scope *S, bool Typename, + SourceLocation EllipsisLoc, + SourceLocation KeyLoc, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc, + unsigned Depth, unsigned Position, + SourceLocation EqualLoc, + ParsedType DefaultArg, bool HasTypeConstraint); + + bool ActOnTypeConstraint(const CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstraint, + TemplateTypeParmDecl *ConstrainedParameter, + SourceLocation EllipsisLoc); + bool BuildTypeConstraint(const CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstraint, + TemplateTypeParmDecl *ConstrainedParameter, + SourceLocation EllipsisLoc, + bool AllowUnexpandedPack); + + bool AttachTypeConstraint(NestedNameSpecifierLoc NS, + DeclarationNameInfo NameInfo, + ConceptDecl *NamedConcept, + const TemplateArgumentListInfo *TemplateArgs, + TemplateTypeParmDecl *ConstrainedParameter, + SourceLocation EllipsisLoc); + + bool AttachTypeConstraint(AutoTypeLoc TL, + NonTypeTemplateParmDecl *ConstrainedParameter, + SourceLocation EllipsisLoc); + + bool RequireStructuralType(QualType T, SourceLocation Loc); + + QualType CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI, + SourceLocation Loc); + QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc); + + NamedDecl *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, + unsigned Depth, + unsigned Position, + SourceLocation EqualLoc, + Expr *DefaultArg); + NamedDecl *ActOnTemplateTemplateParameter(Scope *S, + SourceLocation TmpLoc, + TemplateParameterList *Params, + SourceLocation EllipsisLoc, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc, + unsigned Depth, + unsigned Position, + SourceLocation EqualLoc, + ParsedTemplateArgument DefaultArg); + + TemplateParameterList * + ActOnTemplateParameterList(unsigned Depth, + SourceLocation ExportLoc, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ArrayRef<NamedDecl *> Params, + SourceLocation RAngleLoc, + Expr *RequiresClause); + + /// The context in which we are checking a template parameter list. + enum TemplateParamListContext { + TPC_ClassTemplate, + TPC_VarTemplate, + TPC_FunctionTemplate, + TPC_ClassTemplateMember, + TPC_FriendClassTemplate, + TPC_FriendFunctionTemplate, + TPC_FriendFunctionTemplateDefinition, + TPC_TypeAliasTemplate + }; + + bool CheckTemplateParameterList(TemplateParameterList *NewParams, + TemplateParameterList *OldParams, + TemplateParamListContext TPC, + SkipBodyInfo *SkipBody = nullptr); + TemplateParameterList *MatchTemplateParametersToScopeSpecifier( + SourceLocation DeclStartLoc, SourceLocation DeclLoc, + const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, + ArrayRef<TemplateParameterList *> ParamLists, + bool IsFriend, bool &IsMemberSpecialization, bool &Invalid, + bool SuppressDiagnostic = false); + + DeclResult CheckClassTemplate( + Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, + CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, + const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams, + AccessSpecifier AS, SourceLocation ModulePrivateLoc, + SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, + TemplateParameterList **OuterTemplateParamLists, + SkipBodyInfo *SkipBody = nullptr); + + TemplateArgumentLoc getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, + QualType NTTPType, + SourceLocation Loc); + + /// Get a template argument mapping the given template parameter to itself, + /// e.g. for X in \c template<int X>, this would return an expression template + /// argument referencing X. + TemplateArgumentLoc getIdentityTemplateArgumentLoc(NamedDecl *Param, + SourceLocation Location); + + void translateTemplateArguments(const ASTTemplateArgsPtr &In, + TemplateArgumentListInfo &Out); + + ParsedTemplateArgument ActOnTemplateTypeArgument(TypeResult ParsedType); + + void NoteAllFoundTemplates(TemplateName Name); + + QualType CheckTemplateIdType(TemplateName Template, + SourceLocation TemplateLoc, + TemplateArgumentListInfo &TemplateArgs); + + TypeResult + ActOnTemplateIdType(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, + TemplateTy Template, IdentifierInfo *TemplateII, + SourceLocation TemplateIILoc, SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, + bool IsCtorOrDtorName = false, bool IsClassName = false, + ImplicitTypenameContext AllowImplicitTypename = + ImplicitTypenameContext::No); + + /// Parsed an elaborated-type-specifier that refers to a template-id, + /// such as \c class T::template apply<U>. + TypeResult ActOnTagTemplateIdType(TagUseKind TUK, + TypeSpecifierType TagSpec, + SourceLocation TagLoc, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + TemplateTy TemplateD, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation RAngleLoc); + + DeclResult ActOnVarTemplateSpecialization( + Scope *S, Declarator &D, TypeSourceInfo *DI, + SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, + StorageClass SC, bool IsPartialSpecialization); + + /// Get the specialization of the given variable template corresponding to + /// the specified argument list, or a null-but-valid result if the arguments + /// are dependent. + DeclResult CheckVarTemplateId(VarTemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation TemplateNameLoc, + const TemplateArgumentListInfo &TemplateArgs); + + /// Form a reference to the specialization of the given variable template + /// corresponding to the specified argument list, or a null-but-valid result + /// if the arguments are dependent. + ExprResult CheckVarTemplateId(const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + VarTemplateDecl *Template, + SourceLocation TemplateLoc, + const TemplateArgumentListInfo *TemplateArgs); + + ExprResult + CheckConceptTemplateId(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &ConceptNameInfo, + NamedDecl *FoundDecl, ConceptDecl *NamedConcept, + const TemplateArgumentListInfo *TemplateArgs); + + void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc); + + ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + LookupResult &R, + bool RequiresADL, + const TemplateArgumentListInfo *TemplateArgs); + + ExprResult BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs); + + TemplateNameKind ActOnTemplateName( + Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, + const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, + TemplateTy &Template, bool AllowInjectedClassName = false); + + DeclResult ActOnClassTemplateSpecialization( + Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, + SourceLocation ModulePrivateLoc, CXXScopeSpec &SS, + TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr, + MultiTemplateParamsArg TemplateParameterLists, + SkipBodyInfo *SkipBody = nullptr); + + bool CheckTemplatePartialSpecializationArgs(SourceLocation Loc, + TemplateDecl *PrimaryTemplate, + unsigned NumExplicitArgs, + ArrayRef<TemplateArgument> Args); + void CheckTemplatePartialSpecialization( + ClassTemplatePartialSpecializationDecl *Partial); + void CheckTemplatePartialSpecialization( + VarTemplatePartialSpecializationDecl *Partial); + + Decl *ActOnTemplateDeclarator(Scope *S, + MultiTemplateParamsArg TemplateParameterLists, + Declarator &D); + + bool + CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, + TemplateSpecializationKind NewTSK, + NamedDecl *PrevDecl, + TemplateSpecializationKind PrevTSK, + SourceLocation PrevPtOfInstantiation, + bool &SuppressNew); + + bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, + const TemplateArgumentListInfo &ExplicitTemplateArgs, + LookupResult &Previous); + + bool CheckFunctionTemplateSpecialization( + FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs, + LookupResult &Previous, bool QualifiedFriend = false); + bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous); + void CompleteMemberSpecialization(NamedDecl *Member, LookupResult &Previous); + + DeclResult ActOnExplicitInstantiation( + Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, + unsigned TagSpec, SourceLocation KWLoc, const CXXScopeSpec &SS, + TemplateTy Template, SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, + SourceLocation RAngleLoc, const ParsedAttributesView &Attr); + + DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, + SourceLocation TemplateLoc, + unsigned TagSpec, SourceLocation KWLoc, + CXXScopeSpec &SS, IdentifierInfo *Name, + SourceLocation NameLoc, + const ParsedAttributesView &Attr); + + DeclResult ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + Declarator &D); + + TemplateArgumentLoc SubstDefaultTemplateArgumentIfAvailable( + TemplateDecl *Template, SourceLocation TemplateLoc, + SourceLocation RAngleLoc, Decl *Param, + ArrayRef<TemplateArgument> SugaredConverted, + ArrayRef<TemplateArgument> CanonicalConverted, bool &HasDefaultArg); + + /// Specifies the context in which a particular template + /// argument is being checked. + enum CheckTemplateArgumentKind { + /// The template argument was specified in the code or was + /// instantiated with some deduced template arguments. + CTAK_Specified, + + /// The template argument was deduced via template argument + /// deduction. + CTAK_Deduced, + + /// The template argument was deduced from an array bound + /// via template argument deduction. + CTAK_DeducedFromArrayBound + }; + + bool + CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &Arg, + NamedDecl *Template, SourceLocation TemplateLoc, + SourceLocation RAngleLoc, unsigned ArgumentPackIndex, + SmallVectorImpl<TemplateArgument> &SugaredConverted, + SmallVectorImpl<TemplateArgument> &CanonicalConverted, + CheckTemplateArgumentKind CTAK); + + /// Check that the given template arguments can be provided to + /// the given template, converting the arguments along the way. + /// + /// \param Template The template to which the template arguments are being + /// provided. + /// + /// \param TemplateLoc The location of the template name in the source. + /// + /// \param TemplateArgs The list of template arguments. If the template is + /// a template template parameter, this function may extend the set of + /// template arguments to also include substituted, defaulted template + /// arguments. + /// + /// \param PartialTemplateArgs True if the list of template arguments is + /// intentionally partial, e.g., because we're checking just the initial + /// set of template arguments. + /// + /// \param Converted Will receive the converted, canonicalized template + /// arguments. + /// + /// \param UpdateArgsWithConversions If \c true, update \p TemplateArgs to + /// contain the converted forms of the template arguments as written. + /// Otherwise, \p TemplateArgs will not be modified. + /// + /// \param ConstraintsNotSatisfied If provided, and an error occurred, will + /// receive true if the cause for the error is the associated constraints of + /// the template not being satisfied by the template arguments. + /// + /// \returns true if an error occurred, false otherwise. + bool CheckTemplateArgumentList( + TemplateDecl *Template, SourceLocation TemplateLoc, + TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, + SmallVectorImpl<TemplateArgument> &SugaredConverted, + SmallVectorImpl<TemplateArgument> &CanonicalConverted, + bool UpdateArgsWithConversions = true, + bool *ConstraintsNotSatisfied = nullptr); + + bool CheckTemplateTypeArgument( + TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg, + SmallVectorImpl<TemplateArgument> &SugaredConverted, + SmallVectorImpl<TemplateArgument> &CanonicalConverted); + + bool CheckTemplateArgument(TypeSourceInfo *Arg); + ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param, + QualType InstantiatedParamType, Expr *Arg, + TemplateArgument &SugaredConverted, + TemplateArgument &CanonicalConverted, + CheckTemplateArgumentKind CTAK); + bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, + TemplateParameterList *Params, + TemplateArgumentLoc &Arg); + + ExprResult + BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, + QualType ParamType, + SourceLocation Loc); + ExprResult + BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, + SourceLocation Loc); + + /// Enumeration describing how template parameter lists are compared + /// for equality. + enum TemplateParameterListEqualKind { + /// We are matching the template parameter lists of two templates + /// that might be redeclarations. + /// + /// \code + /// template<typename T> struct X; + /// template<typename T> struct X; + /// \endcode + TPL_TemplateMatch, + + /// We are matching the template parameter lists of two template + /// template parameters as part of matching the template parameter lists + /// of two templates that might be redeclarations. + /// + /// \code + /// template<template<int I> class TT> struct X; + /// template<template<int Value> class Other> struct X; + /// \endcode + TPL_TemplateTemplateParmMatch, + + /// We are matching the template parameter lists of a template + /// template argument against the template parameter lists of a template + /// template parameter. + /// + /// \code + /// template<template<int Value> class Metafun> struct X; + /// template<int Value> struct integer_c; + /// X<integer_c> xic; + /// \endcode + TPL_TemplateTemplateArgumentMatch + }; + + bool TemplateParameterListsAreEqual( + const NamedDecl *NewInstFrom, TemplateParameterList *New, + const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain, + TemplateParameterListEqualKind Kind, + SourceLocation TemplateArgLoc = SourceLocation(), + bool PartialOrdering = false); + + bool TemplateParameterListsAreEqual( + TemplateParameterList *New, TemplateParameterList *Old, bool Complain, + TemplateParameterListEqualKind Kind, + SourceLocation TemplateArgLoc = SourceLocation(), + bool PartialOrdering = false) { + return TemplateParameterListsAreEqual(nullptr, New, nullptr, Old, Complain, + Kind, TemplateArgLoc, + PartialOrdering); + } + + bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams); + + /// Called when the parser has parsed a C++ typename + /// specifier, e.g., "typename T::type". + /// + /// \param S The scope in which this typename type occurs. + /// \param TypenameLoc the location of the 'typename' keyword + /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). + /// \param II the identifier we're retrieving (e.g., 'type' in the example). + /// \param IdLoc the location of the identifier. + /// \param IsImplicitTypename context where T::type refers to a type. + TypeResult ActOnTypenameType( + Scope *S, SourceLocation TypenameLoc, const CXXScopeSpec &SS, + const IdentifierInfo &II, SourceLocation IdLoc, + ImplicitTypenameContext IsImplicitTypename = ImplicitTypenameContext::No); + + /// Called when the parser has parsed a C++ typename + /// specifier that ends in a template-id, e.g., + /// "typename MetaFun::template apply<T1, T2>". + /// + /// \param S The scope in which this typename type occurs. + /// \param TypenameLoc the location of the 'typename' keyword + /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). + /// \param TemplateLoc the location of the 'template' keyword, if any. + /// \param TemplateName The template name. + /// \param TemplateII The identifier used to name the template. + /// \param TemplateIILoc The location of the template name. + /// \param LAngleLoc The location of the opening angle bracket ('<'). + /// \param TemplateArgs The template arguments. + /// \param RAngleLoc The location of the closing angle bracket ('>'). + TypeResult + ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, + const CXXScopeSpec &SS, + SourceLocation TemplateLoc, + TemplateTy TemplateName, + IdentifierInfo *TemplateII, + SourceLocation TemplateIILoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation RAngleLoc); + + QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, + SourceLocation KeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + const IdentifierInfo &II, + SourceLocation IILoc, + TypeSourceInfo **TSI, + bool DeducedTSTContext); + + QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, + SourceLocation KeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + const IdentifierInfo &II, + SourceLocation IILoc, + bool DeducedTSTContext = true); + + + TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, + SourceLocation Loc, + DeclarationName Name); + bool RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS); + + ExprResult RebuildExprInCurrentInstantiation(Expr *E); + bool RebuildTemplateParamsInCurrentInstantiation( + TemplateParameterList *Params); + + std::string + getTemplateArgumentBindingsText(const TemplateParameterList *Params, + const TemplateArgumentList &Args); + + std::string + getTemplateArgumentBindingsText(const TemplateParameterList *Params, + const TemplateArgument *Args, + unsigned NumArgs); + + //===--------------------------------------------------------------------===// + // C++ Concepts + //===--------------------------------------------------------------------===// + Decl *ActOnConceptDefinition( + Scope *S, MultiTemplateParamsArg TemplateParameterLists, + IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr); + + void CheckConceptRedefinition(ConceptDecl *NewDecl, LookupResult &Previous, + bool &AddToScope); + + RequiresExprBodyDecl * + ActOnStartRequiresExpr(SourceLocation RequiresKWLoc, + ArrayRef<ParmVarDecl *> LocalParameters, + Scope *BodyScope); + void ActOnFinishRequiresExpr(); + concepts::Requirement *ActOnSimpleRequirement(Expr *E); + concepts::Requirement *ActOnTypeRequirement( + SourceLocation TypenameKWLoc, CXXScopeSpec &SS, SourceLocation NameLoc, + IdentifierInfo *TypeName, TemplateIdAnnotation *TemplateId); + concepts::Requirement *ActOnCompoundRequirement(Expr *E, + SourceLocation NoexceptLoc); + concepts::Requirement * + ActOnCompoundRequirement( + Expr *E, SourceLocation NoexceptLoc, CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstraint, unsigned Depth); + concepts::Requirement *ActOnNestedRequirement(Expr *Constraint); + concepts::ExprRequirement * + BuildExprRequirement( + Expr *E, bool IsSatisfied, SourceLocation NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement); + concepts::ExprRequirement * + BuildExprRequirement( + concepts::Requirement::SubstitutionDiagnostic *ExprSubstDiag, + bool IsSatisfied, SourceLocation NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement); + concepts::TypeRequirement *BuildTypeRequirement(TypeSourceInfo *Type); + concepts::TypeRequirement * + BuildTypeRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag); + concepts::NestedRequirement *BuildNestedRequirement(Expr *E); + concepts::NestedRequirement * + BuildNestedRequirement(StringRef InvalidConstraintEntity, + const ASTConstraintSatisfaction &Satisfaction); + ExprResult ActOnRequiresExpr(SourceLocation RequiresKWLoc, + RequiresExprBodyDecl *Body, + ArrayRef<ParmVarDecl *> LocalParameters, + ArrayRef<concepts::Requirement *> Requirements, + SourceLocation ClosingBraceLoc); + + //===--------------------------------------------------------------------===// + // C++ Variadic Templates (C++0x [temp.variadic]) + //===--------------------------------------------------------------------===// + + /// Determine whether an unexpanded parameter pack might be permitted in this + /// location. Useful for error recovery. + bool isUnexpandedParameterPackPermitted(); + + /// The context in which an unexpanded parameter pack is + /// being diagnosed. + /// + /// Note that the values of this enumeration line up with the first + /// argument to the \c err_unexpanded_parameter_pack diagnostic. + enum UnexpandedParameterPackContext { + /// An arbitrary expression. + UPPC_Expression = 0, + + /// The base type of a class type. + UPPC_BaseType, + + /// The type of an arbitrary declaration. + UPPC_DeclarationType, + + /// The type of a data member. + UPPC_DataMemberType, + + /// The size of a bit-field. + UPPC_BitFieldWidth, + + /// The expression in a static assertion. + UPPC_StaticAssertExpression, + + /// The fixed underlying type of an enumeration. + UPPC_FixedUnderlyingType, + + /// The enumerator value. + UPPC_EnumeratorValue, + + /// A using declaration. + UPPC_UsingDeclaration, + + /// A friend declaration. + UPPC_FriendDeclaration, + + /// A declaration qualifier. + UPPC_DeclarationQualifier, + + /// An initializer. + UPPC_Initializer, + + /// A default argument. + UPPC_DefaultArgument, + + /// The type of a non-type template parameter. + UPPC_NonTypeTemplateParameterType, + + /// The type of an exception. + UPPC_ExceptionType, + + /// Partial specialization. + UPPC_PartialSpecialization, + + /// Microsoft __if_exists. + UPPC_IfExists, + + /// Microsoft __if_not_exists. + UPPC_IfNotExists, + + /// Lambda expression. + UPPC_Lambda, + + /// Block expression. + UPPC_Block, + + /// A type constraint. + UPPC_TypeConstraint, + + // A requirement in a requires-expression. + UPPC_Requirement, + + // A requires-clause. + UPPC_RequiresClause, + }; + + /// Diagnose unexpanded parameter packs. + /// + /// \param Loc The location at which we should emit the diagnostic. + /// + /// \param UPPC The context in which we are diagnosing unexpanded + /// parameter packs. + /// + /// \param Unexpanded the set of unexpanded parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPacks(SourceLocation Loc, + UnexpandedParameterPackContext UPPC, + ArrayRef<UnexpandedParameterPack> Unexpanded); + + /// If the given type contains an unexpanded parameter pack, + /// diagnose the error. + /// + /// \param Loc The source location where a diagnostc should be emitted. + /// + /// \param T The type that is being checked for unexpanded parameter + /// packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TypeSourceInfo *T, + UnexpandedParameterPackContext UPPC); + + /// If the given expression contains an unexpanded parameter + /// pack, diagnose the error. + /// + /// \param E The expression that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(Expr *E, + UnexpandedParameterPackContext UPPC = UPPC_Expression); + + /// If the given requirees-expression contains an unexpanded reference to one + /// of its own parameter packs, diagnose the error. + /// + /// \param RE The requiress-expression that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPackInRequiresExpr(RequiresExpr *RE); + + /// If the given nested-name-specifier contains an unexpanded + /// parameter pack, diagnose the error. + /// + /// \param SS The nested-name-specifier that is being checked for + /// unexpanded parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, + UnexpandedParameterPackContext UPPC); + + /// If the given name contains an unexpanded parameter pack, + /// diagnose the error. + /// + /// \param NameInfo The name (with source location information) that + /// is being checked for unexpanded parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, + UnexpandedParameterPackContext UPPC); + + /// If the given template name contains an unexpanded parameter pack, + /// diagnose the error. + /// + /// \param Loc The location of the template name. + /// + /// \param Template The template name that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, + TemplateName Template, + UnexpandedParameterPackContext UPPC); + + /// If the given template argument contains an unexpanded parameter + /// pack, diagnose the error. + /// + /// \param Arg The template argument that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, + UnexpandedParameterPackContext UPPC); + + /// Collect the set of unexpanded parameter packs within the given + /// template argument. + /// + /// \param Arg The template argument that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(TemplateArgument Arg, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// Collect the set of unexpanded parameter packs within the given + /// template argument. + /// + /// \param Arg The template argument that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// Collect the set of unexpanded parameter packs within the given + /// type. + /// + /// \param T The type that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(QualType T, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// Collect the set of unexpanded parameter packs within the given + /// type. + /// + /// \param TL The type that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(TypeLoc TL, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// Collect the set of unexpanded parameter packs within the given + /// nested-name-specifier. + /// + /// \param NNS The nested-name-specifier that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(NestedNameSpecifierLoc NNS, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// Collect the set of unexpanded parameter packs within the given + /// name. + /// + /// \param NameInfo The name that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// Invoked when parsing a template argument followed by an + /// ellipsis, which creates a pack expansion. + /// + /// \param Arg The template argument preceding the ellipsis, which + /// may already be invalid. + /// + /// \param EllipsisLoc The location of the ellipsis. + ParsedTemplateArgument ActOnPackExpansion(const ParsedTemplateArgument &Arg, + SourceLocation EllipsisLoc); + + /// Invoked when parsing a type followed by an ellipsis, which + /// creates a pack expansion. + /// + /// \param Type The type preceding the ellipsis, which will become + /// the pattern of the pack expansion. + /// + /// \param EllipsisLoc The location of the ellipsis. + TypeResult ActOnPackExpansion(ParsedType Type, SourceLocation EllipsisLoc); + + /// Construct a pack expansion type from the pattern of the pack + /// expansion. + TypeSourceInfo *CheckPackExpansion(TypeSourceInfo *Pattern, + SourceLocation EllipsisLoc, + std::optional<unsigned> NumExpansions); + + /// Construct a pack expansion type from the pattern of the pack + /// expansion. + QualType CheckPackExpansion(QualType Pattern, SourceRange PatternRange, + SourceLocation EllipsisLoc, + std::optional<unsigned> NumExpansions); + + /// Invoked when parsing an expression followed by an ellipsis, which + /// creates a pack expansion. + /// + /// \param Pattern The expression preceding the ellipsis, which will become + /// the pattern of the pack expansion. + /// + /// \param EllipsisLoc The location of the ellipsis. + ExprResult ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc); + + /// Invoked when parsing an expression followed by an ellipsis, which + /// creates a pack expansion. + /// + /// \param Pattern The expression preceding the ellipsis, which will become + /// the pattern of the pack expansion. + /// + /// \param EllipsisLoc The location of the ellipsis. + ExprResult CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, + std::optional<unsigned> NumExpansions); + + /// Determine whether we could expand a pack expansion with the + /// given set of parameter packs into separate arguments by repeatedly + /// transforming the pattern. + /// + /// \param EllipsisLoc The location of the ellipsis that identifies the + /// pack expansion. + /// + /// \param PatternRange The source range that covers the entire pattern of + /// the pack expansion. + /// + /// \param Unexpanded The set of unexpanded parameter packs within the + /// pattern. + /// + /// \param ShouldExpand Will be set to \c true if the transformer should + /// expand the corresponding pack expansions into separate arguments. When + /// set, \c NumExpansions must also be set. + /// + /// \param RetainExpansion Whether the caller should add an unexpanded + /// pack expansion after all of the expanded arguments. This is used + /// when extending explicitly-specified template argument packs per + /// C++0x [temp.arg.explicit]p9. + /// + /// \param NumExpansions The number of separate arguments that will be in + /// the expanded form of the corresponding pack expansion. This is both an + /// input and an output parameter, which can be set by the caller if the + /// number of expansions is known a priori (e.g., due to a prior substitution) + /// and will be set by the callee when the number of expansions is known. + /// The callee must set this value when \c ShouldExpand is \c true; it may + /// set this value in other cases. + /// + /// \returns true if an error occurred (e.g., because the parameter packs + /// are to be instantiated with arguments of different lengths), false + /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions) + /// must be set. + bool CheckParameterPacksForExpansion( + SourceLocation EllipsisLoc, SourceRange PatternRange, + ArrayRef<UnexpandedParameterPack> Unexpanded, + const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand, + bool &RetainExpansion, std::optional<unsigned> &NumExpansions); + + /// Determine the number of arguments in the given pack expansion + /// type. + /// + /// This routine assumes that the number of arguments in the expansion is + /// consistent across all of the unexpanded parameter packs in its pattern. + /// + /// Returns an empty Optional if the type can't be expanded. + std::optional<unsigned> getNumArgumentsInExpansion( + QualType T, const MultiLevelTemplateArgumentList &TemplateArgs); + + /// Determine whether the given declarator contains any unexpanded + /// parameter packs. + /// + /// This routine is used by the parser to disambiguate function declarators + /// with an ellipsis prior to the ')', e.g., + /// + /// \code + /// void f(T...); + /// \endcode + /// + /// To determine whether we have an (unnamed) function parameter pack or + /// a variadic function. + /// + /// \returns true if the declarator contains any unexpanded parameter packs, + /// false otherwise. + bool containsUnexpandedParameterPacks(Declarator &D); + + /// Returns the pattern of the pack expansion for a template argument. + /// + /// \param OrigLoc The template argument to expand. + /// + /// \param Ellipsis Will be set to the location of the ellipsis. + /// + /// \param NumExpansions Will be set to the number of expansions that will + /// be generated from this pack expansion, if known a priori. + TemplateArgumentLoc getTemplateArgumentPackExpansionPattern( + TemplateArgumentLoc OrigLoc, SourceLocation &Ellipsis, + std::optional<unsigned> &NumExpansions) const; + + /// Given a template argument that contains an unexpanded parameter pack, but + /// which has already been substituted, attempt to determine the number of + /// elements that will be produced once this argument is fully-expanded. + /// + /// This is intended for use when transforming 'sizeof...(Arg)' in order to + /// avoid actually expanding the pack where possible. + std::optional<unsigned> getFullyPackExpandedSize(TemplateArgument Arg); + + //===--------------------------------------------------------------------===// + // C++ Template Argument Deduction (C++ [temp.deduct]) + //===--------------------------------------------------------------------===// + + /// Adjust the type \p ArgFunctionType to match the calling convention, + /// noreturn, and optionally the exception specification of \p FunctionType. + /// Deduction often wants to ignore these properties when matching function + /// types. + QualType adjustCCAndNoReturn(QualType ArgFunctionType, QualType FunctionType, + bool AdjustExceptionSpec = false); + + /// Describes the result of template argument deduction. + /// + /// The TemplateDeductionResult enumeration describes the result of + /// template argument deduction, as returned from + /// DeduceTemplateArguments(). The separate TemplateDeductionInfo + /// structure provides additional information about the results of + /// template argument deduction, e.g., the deduced template argument + /// list (if successful) or the specific template parameters or + /// deduced arguments that were involved in the failure. + enum TemplateDeductionResult { + /// Template argument deduction was successful. + TDK_Success = 0, + /// The declaration was invalid; do nothing. + TDK_Invalid, + /// Template argument deduction exceeded the maximum template + /// instantiation depth (which has already been diagnosed). + TDK_InstantiationDepth, + /// Template argument deduction did not deduce a value + /// for every template parameter. + TDK_Incomplete, + /// Template argument deduction did not deduce a value for every + /// expansion of an expanded template parameter pack. + TDK_IncompletePack, + /// Template argument deduction produced inconsistent + /// deduced values for the given template parameter. + TDK_Inconsistent, + /// Template argument deduction failed due to inconsistent + /// cv-qualifiers on a template parameter type that would + /// otherwise be deduced, e.g., we tried to deduce T in "const T" + /// but were given a non-const "X". + TDK_Underqualified, + /// Substitution of the deduced template argument values + /// resulted in an error. + TDK_SubstitutionFailure, + /// After substituting deduced template arguments, a dependent + /// parameter type did not match the corresponding argument. + TDK_DeducedMismatch, + /// After substituting deduced template arguments, an element of + /// a dependent parameter type did not match the corresponding element + /// of the corresponding argument (when deducing from an initializer list). + TDK_DeducedMismatchNested, + /// A non-depnedent component of the parameter did not match the + /// corresponding component of the argument. + TDK_NonDeducedMismatch, + /// When performing template argument deduction for a function + /// template, there were too many call arguments. + TDK_TooManyArguments, + /// When performing template argument deduction for a function + /// template, there were too few call arguments. + TDK_TooFewArguments, + /// The explicitly-specified template arguments were not valid + /// template arguments for the given template. + TDK_InvalidExplicitArguments, + /// Checking non-dependent argument conversions failed. + TDK_NonDependentConversionFailure, + /// The deduced arguments did not satisfy the constraints associated + /// with the template. + TDK_ConstraintsNotSatisfied, + /// Deduction failed; that's all we know. + TDK_MiscellaneousDeductionFailure, + /// CUDA Target attributes do not match. + TDK_CUDATargetMismatch, + /// Some error which was already diagnosed. + TDK_AlreadyDiagnosed + }; + + TemplateDeductionResult + DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs, + sema::TemplateDeductionInfo &Info); + + TemplateDeductionResult + DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs, + sema::TemplateDeductionInfo &Info); + + TemplateDeductionResult SubstituteExplicitTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo &ExplicitTemplateArgs, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<QualType> &ParamTypes, QualType *FunctionType, + sema::TemplateDeductionInfo &Info); + + /// brief A function argument from which we performed template argument + // deduction for a call. + struct OriginalCallArg { + OriginalCallArg(QualType OriginalParamType, bool DecomposedParam, + unsigned ArgIdx, QualType OriginalArgType) + : OriginalParamType(OriginalParamType), + DecomposedParam(DecomposedParam), ArgIdx(ArgIdx), + OriginalArgType(OriginalArgType) {} + + QualType OriginalParamType; + bool DecomposedParam; + unsigned ArgIdx; + QualType OriginalArgType; + }; + + TemplateDeductionResult FinishTemplateArgumentDeduction( + FunctionTemplateDecl *FunctionTemplate, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, + sema::TemplateDeductionInfo &Info, + SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = nullptr, + bool PartialOverloading = false, + llvm::function_ref<bool()> CheckNonDependent = []{ return false; }); + + TemplateDeductionResult DeduceTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, + FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, + bool PartialOverloading, + llvm::function_ref<bool(ArrayRef<QualType>)> CheckNonDependent); + + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, + QualType ArgFunctionType, + FunctionDecl *&Specialization, + sema::TemplateDeductionInfo &Info, + bool IsAddressOfFunction = false); + + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + QualType ToType, + CXXConversionDecl *&Specialization, + sema::TemplateDeductionInfo &Info); + + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, + FunctionDecl *&Specialization, + sema::TemplateDeductionInfo &Info, + bool IsAddressOfFunction = false); + + /// Substitute Replacement for \p auto in \p TypeWithAuto + QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement); + /// Substitute Replacement for auto in TypeWithAuto + TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, + QualType Replacement); + + // Substitute auto in TypeWithAuto for a Dependent auto type + QualType SubstAutoTypeDependent(QualType TypeWithAuto); + + // Substitute auto in TypeWithAuto for a Dependent auto type + TypeSourceInfo * + SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto); + + /// Completely replace the \c auto in \p TypeWithAuto by + /// \p Replacement. This does not retain any \c auto type sugar. + QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement); + TypeSourceInfo *ReplaceAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, + QualType Replacement); + + TemplateDeductionResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *Initializer, + QualType &Result, + sema::TemplateDeductionInfo &Info, + bool DependentDeduction = false, + bool IgnoreConstraints = false); + void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init); + bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, + bool Diagnose = true); + + /// Declare implicit deduction guides for a class template if we've + /// not already done so. + void DeclareImplicitDeductionGuides(TemplateDecl *Template, + SourceLocation Loc); + + QualType DeduceTemplateSpecializationFromInitializer( + TypeSourceInfo *TInfo, const InitializedEntity &Entity, + const InitializationKind &Kind, MultiExprArg Init); + + QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name, + QualType Type, TypeSourceInfo *TSI, + SourceRange Range, bool DirectInit, + Expr *Init); + + TypeLoc getReturnTypeLoc(FunctionDecl *FD) const; + + bool DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, + SourceLocation ReturnLoc, Expr *RetExpr, + const AutoType *AT); + + FunctionTemplateDecl *getMoreSpecializedTemplate( + FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, + TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, + unsigned NumCallArguments2, bool Reversed = false); + UnresolvedSetIterator + getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd, + TemplateSpecCandidateSet &FailedCandidates, + SourceLocation Loc, + const PartialDiagnostic &NoneDiag, + const PartialDiagnostic &AmbigDiag, + const PartialDiagnostic &CandidateDiag, + bool Complain = true, QualType TargetType = QualType()); + + ClassTemplatePartialSpecializationDecl * + getMoreSpecializedPartialSpecialization( + ClassTemplatePartialSpecializationDecl *PS1, + ClassTemplatePartialSpecializationDecl *PS2, + SourceLocation Loc); + + bool isMoreSpecializedThanPrimary(ClassTemplatePartialSpecializationDecl *T, + sema::TemplateDeductionInfo &Info); + + VarTemplatePartialSpecializationDecl *getMoreSpecializedPartialSpecialization( + VarTemplatePartialSpecializationDecl *PS1, + VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); + + bool isMoreSpecializedThanPrimary(VarTemplatePartialSpecializationDecl *T, + sema::TemplateDeductionInfo &Info); + + bool isTemplateTemplateParameterAtLeastAsSpecializedAs( + TemplateParameterList *PParam, TemplateDecl *AArg, SourceLocation Loc); + + void MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced, + unsigned Depth, llvm::SmallBitVector &Used); + + void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, + bool OnlyDeduced, + unsigned Depth, + llvm::SmallBitVector &Used); + void MarkDeducedTemplateParameters( + const FunctionTemplateDecl *FunctionTemplate, + llvm::SmallBitVector &Deduced) { + return MarkDeducedTemplateParameters(Context, FunctionTemplate, Deduced); + } + static void MarkDeducedTemplateParameters(ASTContext &Ctx, + const FunctionTemplateDecl *FunctionTemplate, + llvm::SmallBitVector &Deduced); + + //===--------------------------------------------------------------------===// + // C++ Template Instantiation + // + + MultiLevelTemplateArgumentList + getTemplateInstantiationArgs(const NamedDecl *D, bool Final = false, + const TemplateArgumentList *Innermost = nullptr, + bool RelativeToPrimary = false, + const FunctionDecl *Pattern = nullptr, + bool ForConstraintInstantiation = false, + bool SkipForSpecialization = false); + + /// A context in which code is being synthesized (where a source location + /// alone is not sufficient to identify the context). This covers template + /// instantiation and various forms of implicitly-generated functions. + struct CodeSynthesisContext { + /// The kind of template instantiation we are performing + enum SynthesisKind { + /// We are instantiating a template declaration. The entity is + /// the declaration we're instantiating (e.g., a CXXRecordDecl). + TemplateInstantiation, + + /// We are instantiating a default argument for a template + /// parameter. The Entity is the template parameter whose argument is + /// being instantiated, the Template is the template, and the + /// TemplateArgs/NumTemplateArguments provide the template arguments as + /// specified. + DefaultTemplateArgumentInstantiation, + + /// We are instantiating a default argument for a function. + /// The Entity is the ParmVarDecl, and TemplateArgs/NumTemplateArgs + /// provides the template arguments as specified. + DefaultFunctionArgumentInstantiation, + + /// We are substituting explicit template arguments provided for + /// a function template. The entity is a FunctionTemplateDecl. + ExplicitTemplateArgumentSubstitution, + + /// We are substituting template argument determined as part of + /// template argument deduction for either a class template + /// partial specialization or a function template. The + /// Entity is either a {Class|Var}TemplatePartialSpecializationDecl or + /// a TemplateDecl. + DeducedTemplateArgumentSubstitution, + + /// We are substituting prior template arguments into a new + /// template parameter. The template parameter itself is either a + /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. + PriorTemplateArgumentSubstitution, + + /// We are checking the validity of a default template argument that + /// has been used when naming a template-id. + DefaultTemplateArgumentChecking, + + /// We are computing the exception specification for a defaulted special + /// member function. + ExceptionSpecEvaluation, + + /// We are instantiating the exception specification for a function + /// template which was deferred until it was needed. + ExceptionSpecInstantiation, + + /// We are instantiating a requirement of a requires expression. + RequirementInstantiation, + + /// We are checking the satisfaction of a nested requirement of a requires + /// expression. + NestedRequirementConstraintsCheck, + + /// We are declaring an implicit special member function. + DeclaringSpecialMember, + + /// We are declaring an implicit 'operator==' for a defaulted + /// 'operator<=>'. + DeclaringImplicitEqualityComparison, + + /// We are defining a synthesized function (such as a defaulted special + /// member). + DefiningSynthesizedFunction, + + // We are checking the constraints associated with a constrained entity or + // the constraint expression of a concept. This includes the checks that + // atomic constraints have the type 'bool' and that they can be constant + // evaluated. + ConstraintsCheck, + + // We are substituting template arguments into a constraint expression. + ConstraintSubstitution, + + // We are normalizing a constraint expression. + ConstraintNormalization, + + // Instantiating a Requires Expression parameter clause. + RequirementParameterInstantiation, + + // We are substituting into the parameter mapping of an atomic constraint + // during normalization. + ParameterMappingSubstitution, + + /// We are rewriting a comparison operator in terms of an operator<=>. + RewritingOperatorAsSpaceship, + + /// We are initializing a structured binding. + InitializingStructuredBinding, + + /// We are marking a class as __dllexport. + MarkingClassDllexported, + + /// We are building an implied call from __builtin_dump_struct. The + /// arguments are in CallArgs. + BuildingBuiltinDumpStructCall, + + /// Added for Template instantiation observation. + /// Memoization means we are _not_ instantiating a template because + /// it is already instantiated (but we entered a context where we + /// would have had to if it was not already instantiated). + Memoization + } Kind; + + /// Was the enclosing context a non-instantiation SFINAE context? + bool SavedInNonInstantiationSFINAEContext; + + /// The point of instantiation or synthesis within the source code. + SourceLocation PointOfInstantiation; + + /// The entity that is being synthesized. + Decl *Entity; + + /// The template (or partial specialization) in which we are + /// performing the instantiation, for substitutions of prior template + /// arguments. + NamedDecl *Template; + + union { + /// The list of template arguments we are substituting, if they + /// are not part of the entity. + const TemplateArgument *TemplateArgs; + + /// The list of argument expressions in a synthesized call. + const Expr *const *CallArgs; + }; + + // FIXME: Wrap this union around more members, or perhaps store the + // kind-specific members in the RAII object owning the context. + union { + /// The number of template arguments in TemplateArgs. + unsigned NumTemplateArgs; + + /// The number of expressions in CallArgs. + unsigned NumCallArgs; + + /// The special member being declared or defined. + CXXSpecialMember SpecialMember; + }; + + ArrayRef<TemplateArgument> template_arguments() const { + assert(Kind != DeclaringSpecialMember); + return {TemplateArgs, NumTemplateArgs}; + } + + /// The template deduction info object associated with the + /// substitution or checking of explicit or deduced template arguments. + sema::TemplateDeductionInfo *DeductionInfo; + + /// The source range that covers the construct that cause + /// the instantiation, e.g., the template-id that causes a class + /// template instantiation. + SourceRange InstantiationRange; + + CodeSynthesisContext() + : Kind(TemplateInstantiation), + SavedInNonInstantiationSFINAEContext(false), Entity(nullptr), + Template(nullptr), TemplateArgs(nullptr), NumTemplateArgs(0), + DeductionInfo(nullptr) {} + + /// Determines whether this template is an actual instantiation + /// that should be counted toward the maximum instantiation depth. + bool isInstantiationRecord() const; + }; + + /// List of active code synthesis contexts. + /// + /// This vector is treated as a stack. As synthesis of one entity requires + /// synthesis of another, additional contexts are pushed onto the stack. + SmallVector<CodeSynthesisContext, 16> CodeSynthesisContexts; + + /// Specializations whose definitions are currently being instantiated. + llvm::DenseSet<std::pair<Decl *, unsigned>> InstantiatingSpecializations; + + /// Non-dependent types used in templates that have already been instantiated + /// by some template instantiation. + llvm::DenseSet<QualType> InstantiatedNonDependentTypes; + + /// Extra modules inspected when performing a lookup during a template + /// instantiation. Computed lazily. + SmallVector<Module*, 16> CodeSynthesisContextLookupModules; + + /// Cache of additional modules that should be used for name lookup + /// within the current template instantiation. Computed lazily; use + /// getLookupModules() to get a complete set. + llvm::DenseSet<Module*> LookupModulesCache; + + /// Get the set of additional modules that should be checked during + /// name lookup. A module and its imports become visible when instanting a + /// template defined within it. + llvm::DenseSet<Module*> &getLookupModules(); + + /// Map from the most recent declaration of a namespace to the most + /// recent visible declaration of that namespace. + llvm::DenseMap<NamedDecl*, NamedDecl*> VisibleNamespaceCache; + + /// Whether we are in a SFINAE context that is not associated with + /// template instantiation. + /// + /// This is used when setting up a SFINAE trap (\c see SFINAETrap) outside + /// of a template instantiation or template argument deduction. + bool InNonInstantiationSFINAEContext; + + /// The number of \p CodeSynthesisContexts that are not template + /// instantiations and, therefore, should not be counted as part of the + /// instantiation depth. + /// + /// When the instantiation depth reaches the user-configurable limit + /// \p LangOptions::InstantiationDepth we will abort instantiation. + // FIXME: Should we have a similar limit for other forms of synthesis? + unsigned NonInstantiationEntries; + + /// The depth of the context stack at the point when the most recent + /// error or warning was produced. + /// + /// This value is used to suppress printing of redundant context stacks + /// when there are multiple errors or warnings in the same instantiation. + // FIXME: Does this belong in Sema? It's tough to implement it anywhere else. + unsigned LastEmittedCodeSynthesisContextDepth = 0; + + /// The template instantiation callbacks to trace or track + /// instantiations (objects can be chained). + /// + /// This callbacks is used to print, trace or track template + /// instantiations as they are being constructed. + std::vector<std::unique_ptr<TemplateInstantiationCallback>> + TemplateInstCallbacks; + + /// The current index into pack expansion arguments that will be + /// used for substitution of parameter packs. + /// + /// The pack expansion index will be -1 to indicate that parameter packs + /// should be instantiated as themselves. Otherwise, the index specifies + /// which argument within the parameter pack will be used for substitution. + int ArgumentPackSubstitutionIndex; + + /// RAII object used to change the argument pack substitution index + /// within a \c Sema object. + /// + /// See \c ArgumentPackSubstitutionIndex for more information. + class ArgumentPackSubstitutionIndexRAII { + Sema &Self; + int OldSubstitutionIndex; + + public: + ArgumentPackSubstitutionIndexRAII(Sema &Self, int NewSubstitutionIndex) + : Self(Self), OldSubstitutionIndex(Self.ArgumentPackSubstitutionIndex) { + Self.ArgumentPackSubstitutionIndex = NewSubstitutionIndex; + } + + ~ArgumentPackSubstitutionIndexRAII() { + Self.ArgumentPackSubstitutionIndex = OldSubstitutionIndex; + } + }; + + friend class ArgumentPackSubstitutionRAII; + + /// For each declaration that involved template argument deduction, the + /// set of diagnostics that were suppressed during that template argument + /// deduction. + /// + /// FIXME: Serialize this structure to the AST file. + typedef llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> > + SuppressedDiagnosticsMap; + SuppressedDiagnosticsMap SuppressedDiagnostics; + + /// A stack object to be created when performing template + /// instantiation. + /// + /// Construction of an object of type \c InstantiatingTemplate + /// pushes the current instantiation onto the stack of active + /// instantiations. If the size of this stack exceeds the maximum + /// number of recursive template instantiations, construction + /// produces an error and evaluates true. + /// + /// Destruction of this object will pop the named instantiation off + /// the stack. + struct InstantiatingTemplate { + /// Note that we are instantiating a class template, + /// function template, variable template, alias template, + /// or a member thereof. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + Decl *Entity, + SourceRange InstantiationRange = SourceRange()); + + struct ExceptionSpecification {}; + /// Note that we are instantiating an exception specification + /// of a function template. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + FunctionDecl *Entity, ExceptionSpecification, + SourceRange InstantiationRange = SourceRange()); + + /// Note that we are instantiating a default argument in a + /// template-id. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateParameter Param, TemplateDecl *Template, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange InstantiationRange = SourceRange()); + + /// Note that we are substituting either explicitly-specified or + /// deduced template arguments during function template argument deduction. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + FunctionTemplateDecl *FunctionTemplate, + ArrayRef<TemplateArgument> TemplateArgs, + CodeSynthesisContext::SynthesisKind Kind, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange = SourceRange()); + + /// Note that we are instantiating as part of template + /// argument deduction for a class template declaration. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + ArrayRef<TemplateArgument> TemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange = SourceRange()); + + /// Note that we are instantiating as part of template + /// argument deduction for a class template partial + /// specialization. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + ClassTemplatePartialSpecializationDecl *PartialSpec, + ArrayRef<TemplateArgument> TemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange = SourceRange()); + + /// Note that we are instantiating as part of template + /// argument deduction for a variable template partial + /// specialization. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + VarTemplatePartialSpecializationDecl *PartialSpec, + ArrayRef<TemplateArgument> TemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange = SourceRange()); + + /// Note that we are instantiating a default argument for a function + /// parameter. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + ParmVarDecl *Param, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange InstantiationRange = SourceRange()); + + /// Note that we are substituting prior template arguments into a + /// non-type parameter. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + NamedDecl *Template, + NonTypeTemplateParmDecl *Param, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange InstantiationRange); + + /// Note that we are substituting prior template arguments into a + /// template template parameter. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + NamedDecl *Template, + TemplateTemplateParmDecl *Param, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange InstantiationRange); + + /// Note that we are checking the default template argument + /// against the template parameter for a given template-id. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + NamedDecl *Param, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange InstantiationRange); + + struct ConstraintsCheck {}; + /// \brief Note that we are checking the constraints associated with some + /// constrained entity (a concept declaration or a template with associated + /// constraints). + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + ConstraintsCheck, NamedDecl *Template, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange InstantiationRange); + + struct ConstraintSubstitution {}; + /// \brief Note that we are checking a constraint expression associated + /// with a template declaration or as part of the satisfaction check of a + /// concept. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + ConstraintSubstitution, NamedDecl *Template, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange); + + struct ConstraintNormalization {}; + /// \brief Note that we are normalizing a constraint expression. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + ConstraintNormalization, NamedDecl *Template, + SourceRange InstantiationRange); + + struct ParameterMappingSubstitution {}; + /// \brief Note that we are subtituting into the parameter mapping of an + /// atomic constraint during constraint normalization. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + ParameterMappingSubstitution, NamedDecl *Template, + SourceRange InstantiationRange); + + /// \brief Note that we are substituting template arguments into a part of + /// a requirement of a requires expression. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + concepts::Requirement *Req, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are checking the satisfaction of the constraint + /// expression inside of a nested requirement. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + concepts::NestedRequirement *Req, ConstraintsCheck, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are checking a requires clause. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + const RequiresExpr *E, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange); + /// Note that we have finished instantiating this template. + void Clear(); + + ~InstantiatingTemplate() { Clear(); } + + /// Determines whether we have exceeded the maximum + /// recursive template instantiations. + bool isInvalid() const { return Invalid; } + + /// Determine whether we are already instantiating this + /// specialization in some surrounding active instantiation. + bool isAlreadyInstantiating() const { return AlreadyInstantiating; } + + private: + Sema &SemaRef; + bool Invalid; + bool AlreadyInstantiating; + bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, + SourceRange InstantiationRange); + + InstantiatingTemplate( + Sema &SemaRef, CodeSynthesisContext::SynthesisKind Kind, + SourceLocation PointOfInstantiation, SourceRange InstantiationRange, + Decl *Entity, NamedDecl *Template = nullptr, + ArrayRef<TemplateArgument> TemplateArgs = std::nullopt, + sema::TemplateDeductionInfo *DeductionInfo = nullptr); + + InstantiatingTemplate(const InstantiatingTemplate&) = delete; + + InstantiatingTemplate& + operator=(const InstantiatingTemplate&) = delete; + }; + + void pushCodeSynthesisContext(CodeSynthesisContext Ctx); + void popCodeSynthesisContext(); + + /// Determine whether we are currently performing template instantiation. + bool inTemplateInstantiation() const { + return CodeSynthesisContexts.size() > NonInstantiationEntries; + } + + void PrintContextStack() { + if (!CodeSynthesisContexts.empty() && + CodeSynthesisContexts.size() != LastEmittedCodeSynthesisContextDepth) { + PrintInstantiationStack(); + LastEmittedCodeSynthesisContextDepth = CodeSynthesisContexts.size(); + } + if (PragmaAttributeCurrentTargetDecl) + PrintPragmaAttributeInstantiationPoint(); + } + void PrintInstantiationStack(); + + void PrintPragmaAttributeInstantiationPoint(); + + /// Determines whether we are currently in a context where + /// template argument substitution failures are not considered + /// errors. + /// + /// \returns An empty \c Optional if we're not in a SFINAE context. + /// Otherwise, contains a pointer that, if non-NULL, contains the nearest + /// template-deduction context object, which can be used to capture + /// diagnostics that will be suppressed. + std::optional<sema::TemplateDeductionInfo *> isSFINAEContext() const; + + /// Determines whether we are currently in a context that + /// is not evaluated as per C++ [expr] p5. + bool isUnevaluatedContext() const { + assert(!ExprEvalContexts.empty() && + "Must be in an expression evaluation context"); + return ExprEvalContexts.back().isUnevaluated(); + } + + bool isConstantEvaluatedContext() const { + assert(!ExprEvalContexts.empty() && + "Must be in an expression evaluation context"); + return ExprEvalContexts.back().isConstantEvaluated(); + } + + bool isImmediateFunctionContext() const { + assert(!ExprEvalContexts.empty() && + "Must be in an expression evaluation context"); + return ExprEvalContexts.back().isImmediateFunctionContext(); + } + + bool isCheckingDefaultArgumentOrInitializer() const { + assert(!ExprEvalContexts.empty() && + "Must be in an expression evaluation context"); + const ExpressionEvaluationContextRecord &Ctx = ExprEvalContexts.back(); + return (Ctx.Context == + ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed) || + Ctx.IsCurrentlyCheckingDefaultArgumentOrInitializer; + } + + std::optional<ExpressionEvaluationContextRecord::InitializationContext> + InnermostDeclarationWithDelayedImmediateInvocations() const { + assert(!ExprEvalContexts.empty() && + "Must be in an expression evaluation context"); + for (const auto &Ctx : llvm::reverse(ExprEvalContexts)) { + if (Ctx.Context == ExpressionEvaluationContext::PotentiallyEvaluated && + Ctx.DelayedDefaultInitializationContext) + return Ctx.DelayedDefaultInitializationContext; + if (Ctx.isConstantEvaluated() || Ctx.isImmediateFunctionContext() || + Ctx.isUnevaluated()) + break; + } + return std::nullopt; + } + + std::optional<ExpressionEvaluationContextRecord::InitializationContext> + OutermostDeclarationWithDelayedImmediateInvocations() const { + assert(!ExprEvalContexts.empty() && + "Must be in an expression evaluation context"); + std::optional<ExpressionEvaluationContextRecord::InitializationContext> Res; + for (auto &Ctx : llvm::reverse(ExprEvalContexts)) { + if (Ctx.Context == ExpressionEvaluationContext::PotentiallyEvaluated && + !Ctx.DelayedDefaultInitializationContext && Res) + break; + if (Ctx.isConstantEvaluated() || Ctx.isImmediateFunctionContext() || + Ctx.isUnevaluated()) + break; + Res = Ctx.DelayedDefaultInitializationContext; + } + return Res; + } + + /// RAII class used to determine whether SFINAE has + /// trapped any errors that occur during template argument + /// deduction. + class SFINAETrap { + Sema &SemaRef; + unsigned PrevSFINAEErrors; + bool PrevInNonInstantiationSFINAEContext; + bool PrevAccessCheckingSFINAE; + bool PrevLastDiagnosticIgnored; + + public: + explicit SFINAETrap(Sema &SemaRef, bool AccessCheckingSFINAE = false) + : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors), + PrevInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext), + PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE), + PrevLastDiagnosticIgnored( + SemaRef.getDiagnostics().isLastDiagnosticIgnored()) + { + if (!SemaRef.isSFINAEContext()) + SemaRef.InNonInstantiationSFINAEContext = true; + SemaRef.AccessCheckingSFINAE = AccessCheckingSFINAE; + } + + ~SFINAETrap() { + SemaRef.NumSFINAEErrors = PrevSFINAEErrors; + SemaRef.InNonInstantiationSFINAEContext + = PrevInNonInstantiationSFINAEContext; + SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE; + SemaRef.getDiagnostics().setLastDiagnosticIgnored( + PrevLastDiagnosticIgnored); + } + + /// Determine whether any SFINAE errors have been trapped. + bool hasErrorOccurred() const { + return SemaRef.NumSFINAEErrors > PrevSFINAEErrors; + } + }; + + /// RAII class used to indicate that we are performing provisional + /// semantic analysis to determine the validity of a construct, so + /// typo-correction and diagnostics in the immediate context (not within + /// implicitly-instantiated templates) should be suppressed. + class TentativeAnalysisScope { + Sema &SemaRef; + // FIXME: Using a SFINAETrap for this is a hack. + SFINAETrap Trap; + bool PrevDisableTypoCorrection; + public: + explicit TentativeAnalysisScope(Sema &SemaRef) + : SemaRef(SemaRef), Trap(SemaRef, true), + PrevDisableTypoCorrection(SemaRef.DisableTypoCorrection) { + SemaRef.DisableTypoCorrection = true; + } + ~TentativeAnalysisScope() { + SemaRef.DisableTypoCorrection = PrevDisableTypoCorrection; + } + }; + + /// The current instantiation scope used to store local + /// variables. + LocalInstantiationScope *CurrentInstantiationScope; + + /// Tracks whether we are in a context where typo correction is + /// disabled. + bool DisableTypoCorrection; + + /// The number of typos corrected by CorrectTypo. + unsigned TyposCorrected; + + typedef llvm::SmallSet<SourceLocation, 2> SrcLocSet; + typedef llvm::DenseMap<IdentifierInfo *, SrcLocSet> IdentifierSourceLocations; + + /// A cache containing identifiers for which typo correction failed and + /// their locations, so that repeated attempts to correct an identifier in a + /// given location are ignored if typo correction already failed for it. + IdentifierSourceLocations TypoCorrectionFailures; + + /// Worker object for performing CFG-based warnings. + sema::AnalysisBasedWarnings AnalysisWarnings; + threadSafety::BeforeSet *ThreadSafetyDeclCache; + + /// An entity for which implicit template instantiation is required. + /// + /// The source location associated with the declaration is the first place in + /// the source code where the declaration was "used". It is not necessarily + /// the point of instantiation (which will be either before or after the + /// namespace-scope declaration that triggered this implicit instantiation), + /// However, it is the location that diagnostics should generally refer to, + /// because users will need to know what code triggered the instantiation. + typedef std::pair<ValueDecl *, SourceLocation> PendingImplicitInstantiation; + + /// The queue of implicit template instantiations that are required + /// but have not yet been performed. + std::deque<PendingImplicitInstantiation> PendingInstantiations; + + /// Queue of implicit template instantiations that cannot be performed + /// eagerly. + SmallVector<PendingImplicitInstantiation, 1> LateParsedInstantiations; + + class GlobalEagerInstantiationScope { + public: + GlobalEagerInstantiationScope(Sema &S, bool Enabled) + : S(S), Enabled(Enabled) { + if (!Enabled) return; + + SavedPendingInstantiations.swap(S.PendingInstantiations); + SavedVTableUses.swap(S.VTableUses); + } + + void perform() { + if (Enabled) { + S.DefineUsedVTables(); + S.PerformPendingInstantiations(); + } + } + + ~GlobalEagerInstantiationScope() { + if (!Enabled) return; + + // Restore the set of pending vtables. + assert(S.VTableUses.empty() && + "VTableUses should be empty before it is discarded."); + S.VTableUses.swap(SavedVTableUses); + + // Restore the set of pending implicit instantiations. + if (S.TUKind != TU_Prefix || !S.LangOpts.PCHInstantiateTemplates) { + assert(S.PendingInstantiations.empty() && + "PendingInstantiations should be empty before it is discarded."); + S.PendingInstantiations.swap(SavedPendingInstantiations); + } else { + // Template instantiations in the PCH may be delayed until the TU. + S.PendingInstantiations.swap(SavedPendingInstantiations); + S.PendingInstantiations.insert(S.PendingInstantiations.end(), + SavedPendingInstantiations.begin(), + SavedPendingInstantiations.end()); + } + } + + private: + Sema &S; + SmallVector<VTableUse, 16> SavedVTableUses; + std::deque<PendingImplicitInstantiation> SavedPendingInstantiations; + bool Enabled; + }; + + /// The queue of implicit template instantiations that are required + /// and must be performed within the current local scope. + /// + /// This queue is only used for member functions of local classes in + /// templates, which must be instantiated in the same scope as their + /// enclosing function, so that they can reference function-local + /// types, static variables, enumerators, etc. + std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations; + + class LocalEagerInstantiationScope { + public: + LocalEagerInstantiationScope(Sema &S) : S(S) { + SavedPendingLocalImplicitInstantiations.swap( + S.PendingLocalImplicitInstantiations); + } + + void perform() { S.PerformPendingInstantiations(/*LocalOnly=*/true); } + + ~LocalEagerInstantiationScope() { + assert(S.PendingLocalImplicitInstantiations.empty() && + "there shouldn't be any pending local implicit instantiations"); + SavedPendingLocalImplicitInstantiations.swap( + S.PendingLocalImplicitInstantiations); + } + + private: + Sema &S; + std::deque<PendingImplicitInstantiation> + SavedPendingLocalImplicitInstantiations; + }; + + /// A helper class for building up ExtParameterInfos. + class ExtParameterInfoBuilder { + SmallVector<FunctionProtoType::ExtParameterInfo, 16> Infos; + bool HasInteresting = false; + + public: + /// Set the ExtParameterInfo for the parameter at the given index, + /// + void set(unsigned index, FunctionProtoType::ExtParameterInfo info) { + assert(Infos.size() <= index); + Infos.resize(index); + Infos.push_back(info); + + if (!HasInteresting) + HasInteresting = (info != FunctionProtoType::ExtParameterInfo()); + } + + /// Return a pointer (suitable for setting in an ExtProtoInfo) to the + /// ExtParameterInfo array we've built up. + const FunctionProtoType::ExtParameterInfo * + getPointerOrNull(unsigned numParams) { + if (!HasInteresting) return nullptr; + Infos.resize(numParams); + return Infos.data(); + } + }; + + void PerformPendingInstantiations(bool LocalOnly = false); + + TypeSourceInfo *SubstType(TypeSourceInfo *T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity, + bool AllowDeducedTST = false); + + QualType SubstType(QualType T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity); + + TypeSourceInfo *SubstType(TypeLoc TL, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity); + + TypeSourceInfo *SubstFunctionDeclType( + TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity, CXXRecordDecl *ThisContext, + Qualifiers ThisTypeQuals, bool EvaluateConstraints = true); + void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto, + const MultiLevelTemplateArgumentList &Args); + bool SubstExceptionSpec(SourceLocation Loc, + FunctionProtoType::ExceptionSpecInfo &ESI, + SmallVectorImpl<QualType> &ExceptionStorage, + const MultiLevelTemplateArgumentList &Args); + ParmVarDecl * + SubstParmVarDecl(ParmVarDecl *D, + const MultiLevelTemplateArgumentList &TemplateArgs, + int indexAdjustment, std::optional<unsigned> NumExpansions, + bool ExpectParameterPack, bool EvaluateConstraints = true); + bool SubstParmTypes(SourceLocation Loc, ArrayRef<ParmVarDecl *> Params, + const FunctionProtoType::ExtParameterInfo *ExtParamInfos, + const MultiLevelTemplateArgumentList &TemplateArgs, + SmallVectorImpl<QualType> &ParamTypes, + SmallVectorImpl<ParmVarDecl *> *OutParams, + ExtParameterInfoBuilder &ParamInfos); + bool SubstDefaultArgument(SourceLocation Loc, ParmVarDecl *Param, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool ForCallExpr = false); + ExprResult SubstExpr(Expr *E, + const MultiLevelTemplateArgumentList &TemplateArgs); + + // A RAII type used by the TemplateDeclInstantiator and TemplateInstantiator + // to disable constraint evaluation, then restore the state. + template <typename InstTy> struct ConstraintEvalRAII { + InstTy &TI; + bool OldValue; + + ConstraintEvalRAII(InstTy &TI) + : TI(TI), OldValue(TI.getEvaluateConstraints()) { + TI.setEvaluateConstraints(false); + } + ~ConstraintEvalRAII() { TI.setEvaluateConstraints(OldValue); } + }; + + // Unlike the above, this evaluates constraints, which should only happen at + // 'constraint checking' time. + ExprResult + SubstConstraintExpr(Expr *E, + const MultiLevelTemplateArgumentList &TemplateArgs); + + /// Substitute the given template arguments into a list of + /// expressions, expanding pack expansions if required. + /// + /// \param Exprs The list of expressions to substitute into. + /// + /// \param IsCall Whether this is some form of call, in which case + /// default arguments will be dropped. + /// + /// \param TemplateArgs The set of template arguments to substitute. + /// + /// \param Outputs Will receive all of the substituted arguments. + /// + /// \returns true if an error occurred, false otherwise. + bool SubstExprs(ArrayRef<Expr *> Exprs, bool IsCall, + const MultiLevelTemplateArgumentList &TemplateArgs, + SmallVectorImpl<Expr *> &Outputs); + + StmtResult SubstStmt(Stmt *S, + const MultiLevelTemplateArgumentList &TemplateArgs); + + TemplateParameterList * + SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool EvaluateConstraints = true); + + bool + SubstTemplateArguments(ArrayRef<TemplateArgumentLoc> Args, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateArgumentListInfo &Outputs); + + Decl *SubstDecl(Decl *D, DeclContext *Owner, + const MultiLevelTemplateArgumentList &TemplateArgs); + + /// Substitute the name and return type of a defaulted 'operator<=>' to form + /// an implicit 'operator=='. + FunctionDecl *SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD, + FunctionDecl *Spaceship); + + ExprResult SubstInitializer(Expr *E, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool CXXDirectInit); + + bool + SubstBaseSpecifiers(CXXRecordDecl *Instantiation, + CXXRecordDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs); + + bool + InstantiateClass(SourceLocation PointOfInstantiation, + CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK, + bool Complain = true); + + bool InstantiateEnum(SourceLocation PointOfInstantiation, + EnumDecl *Instantiation, EnumDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK); + + bool InstantiateInClassInitializer( + SourceLocation PointOfInstantiation, FieldDecl *Instantiation, + FieldDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); + + struct LateInstantiatedAttribute { + const Attr *TmplAttr; + LocalInstantiationScope *Scope; + Decl *NewDecl; + + LateInstantiatedAttribute(const Attr *A, LocalInstantiationScope *S, + Decl *D) + : TmplAttr(A), Scope(S), NewDecl(D) + { } + }; + typedef SmallVector<LateInstantiatedAttribute, 16> LateInstantiatedAttrVec; + + void InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, + const Decl *Pattern, Decl *Inst, + LateInstantiatedAttrVec *LateAttrs = nullptr, + LocalInstantiationScope *OuterMostScope = nullptr); + + void + InstantiateAttrsForDecl(const MultiLevelTemplateArgumentList &TemplateArgs, + const Decl *Pattern, Decl *Inst, + LateInstantiatedAttrVec *LateAttrs = nullptr, + LocalInstantiationScope *OuterMostScope = nullptr); + + void InstantiateDefaultCtorDefaultArgs(CXXConstructorDecl *Ctor); + + bool usesPartialOrExplicitSpecialization( + SourceLocation Loc, ClassTemplateSpecializationDecl *ClassTemplateSpec); + + bool + InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation, + ClassTemplateSpecializationDecl *ClassTemplateSpec, + TemplateSpecializationKind TSK, + bool Complain = true); + + void InstantiateClassMembers(SourceLocation PointOfInstantiation, + CXXRecordDecl *Instantiation, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK); + + void InstantiateClassTemplateSpecializationMembers( + SourceLocation PointOfInstantiation, + ClassTemplateSpecializationDecl *ClassTemplateSpec, + TemplateSpecializationKind TSK); + + NestedNameSpecifierLoc + SubstNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, + const MultiLevelTemplateArgumentList &TemplateArgs); + + DeclarationNameInfo + SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo, + const MultiLevelTemplateArgumentList &TemplateArgs); + TemplateName + SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, TemplateName Name, + SourceLocation Loc, + const MultiLevelTemplateArgumentList &TemplateArgs); + + bool SubstTypeConstraint(TemplateTypeParmDecl *Inst, const TypeConstraint *TC, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool EvaluateConstraint); + + bool InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD, + ParmVarDecl *Param); + void InstantiateExceptionSpec(SourceLocation PointOfInstantiation, + FunctionDecl *Function); + bool CheckInstantiatedFunctionTemplateConstraints( + SourceLocation PointOfInstantiation, FunctionDecl *Decl, + ArrayRef<TemplateArgument> TemplateArgs, + ConstraintSatisfaction &Satisfaction); + FunctionDecl *InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD, + const TemplateArgumentList *Args, + SourceLocation Loc); + void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, + FunctionDecl *Function, + bool Recursive = false, + bool DefinitionRequired = false, + bool AtEndOfTU = false); + VarTemplateSpecializationDecl *BuildVarTemplateInstantiation( + VarTemplateDecl *VarTemplate, VarDecl *FromVar, + const TemplateArgumentList &TemplateArgList, + const TemplateArgumentListInfo &TemplateArgsInfo, + SmallVectorImpl<TemplateArgument> &Converted, + SourceLocation PointOfInstantiation, + LateInstantiatedAttrVec *LateAttrs = nullptr, + LocalInstantiationScope *StartingScope = nullptr); + VarTemplateSpecializationDecl *CompleteVarTemplateSpecializationDecl( + VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl, + const MultiLevelTemplateArgumentList &TemplateArgs); + void + BuildVariableInstantiation(VarDecl *NewVar, VarDecl *OldVar, + const MultiLevelTemplateArgumentList &TemplateArgs, + LateInstantiatedAttrVec *LateAttrs, + DeclContext *Owner, + LocalInstantiationScope *StartingScope, + bool InstantiatingVarTemplate = false, + VarTemplateSpecializationDecl *PrevVTSD = nullptr); + + void InstantiateVariableInitializer( + VarDecl *Var, VarDecl *OldVar, + const MultiLevelTemplateArgumentList &TemplateArgs); + void InstantiateVariableDefinition(SourceLocation PointOfInstantiation, + VarDecl *Var, bool Recursive = false, + bool DefinitionRequired = false, + bool AtEndOfTU = false); + + void InstantiateMemInitializers(CXXConstructorDecl *New, + const CXXConstructorDecl *Tmpl, + const MultiLevelTemplateArgumentList &TemplateArgs); + + NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool FindingInstantiatedContext = false); + DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, + const MultiLevelTemplateArgumentList &TemplateArgs); + + // Objective-C declarations. + enum ObjCContainerKind { + OCK_None = -1, + OCK_Interface = 0, + OCK_Protocol, + OCK_Category, + OCK_ClassExtension, + OCK_Implementation, + OCK_CategoryImplementation + }; + ObjCContainerKind getObjCContainerKind() const; + + DeclResult actOnObjCTypeParam(Scope *S, + ObjCTypeParamVariance variance, + SourceLocation varianceLoc, + unsigned index, + IdentifierInfo *paramName, + SourceLocation paramLoc, + SourceLocation colonLoc, + ParsedType typeBound); + + ObjCTypeParamList *actOnObjCTypeParamList(Scope *S, SourceLocation lAngleLoc, + ArrayRef<Decl *> typeParams, + SourceLocation rAngleLoc); + void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList); + + ObjCInterfaceDecl *ActOnStartClassInterface( + Scope *S, SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, + SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, + IdentifierInfo *SuperName, SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, SourceRange SuperTypeArgsRange, + Decl *const *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, + const ParsedAttributesView &AttrList, SkipBodyInfo *SkipBody); + + void ActOnSuperClassOfClassInterface(Scope *S, + SourceLocation AtInterfaceLoc, + ObjCInterfaceDecl *IDecl, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperName, + SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange); + + void ActOnTypedefedProtocols(SmallVectorImpl<Decl *> &ProtocolRefs, + SmallVectorImpl<SourceLocation> &ProtocolLocs, + IdentifierInfo *SuperName, + SourceLocation SuperLoc); + + Decl *ActOnCompatibilityAlias( + SourceLocation AtCompatibilityAliasLoc, + IdentifierInfo *AliasName, SourceLocation AliasLocation, + IdentifierInfo *ClassName, SourceLocation ClassLocation); + + bool CheckForwardProtocolDeclarationForCircularDependency( + IdentifierInfo *PName, + SourceLocation &PLoc, SourceLocation PrevLoc, + const ObjCList<ObjCProtocolDecl> &PList); + + ObjCProtocolDecl *ActOnStartProtocolInterface( + SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, + SourceLocation ProtocolLoc, Decl *const *ProtoRefNames, + unsigned NumProtoRefs, const SourceLocation *ProtoLocs, + SourceLocation EndProtoLoc, const ParsedAttributesView &AttrList, + SkipBodyInfo *SkipBody); + + ObjCCategoryDecl *ActOnStartCategoryInterface( + SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, + SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, + IdentifierInfo *CategoryName, SourceLocation CategoryLoc, + Decl *const *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, + const ParsedAttributesView &AttrList); + + ObjCImplementationDecl *ActOnStartClassImplementation( + SourceLocation AtClassImplLoc, IdentifierInfo *ClassName, + SourceLocation ClassLoc, IdentifierInfo *SuperClassname, + SourceLocation SuperClassLoc, const ParsedAttributesView &AttrList); + + ObjCCategoryImplDecl *ActOnStartCategoryImplementation( + SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, + SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc, + const ParsedAttributesView &AttrList); + + DeclGroupPtrTy ActOnFinishObjCImplementation(Decl *ObjCImpDecl, + ArrayRef<Decl *> Decls); + + DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc, + IdentifierInfo **IdentList, + SourceLocation *IdentLocs, + ArrayRef<ObjCTypeParamList *> TypeParamLists, + unsigned NumElts); + + DeclGroupPtrTy + ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc, + ArrayRef<IdentifierLocPair> IdentList, + const ParsedAttributesView &attrList); + + void FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer, + ArrayRef<IdentifierLocPair> ProtocolId, + SmallVectorImpl<Decl *> &Protocols); + + void DiagnoseTypeArgsAndProtocols(IdentifierInfo *ProtocolId, + SourceLocation ProtocolLoc, + IdentifierInfo *TypeArgId, + SourceLocation TypeArgLoc, + bool SelectProtocolFirst = false); + + /// Given a list of identifiers (and their locations), resolve the + /// names to either Objective-C protocol qualifiers or type + /// arguments, as appropriate. + void actOnObjCTypeArgsOrProtocolQualifiers( + Scope *S, + ParsedType baseType, + SourceLocation lAngleLoc, + ArrayRef<IdentifierInfo *> identifiers, + ArrayRef<SourceLocation> identifierLocs, + SourceLocation rAngleLoc, + SourceLocation &typeArgsLAngleLoc, + SmallVectorImpl<ParsedType> &typeArgs, + SourceLocation &typeArgsRAngleLoc, + SourceLocation &protocolLAngleLoc, + SmallVectorImpl<Decl *> &protocols, + SourceLocation &protocolRAngleLoc, + bool warnOnIncompleteProtocols); + + /// Build a an Objective-C protocol-qualified 'id' type where no + /// base type was specified. + TypeResult actOnObjCProtocolQualifierType( + SourceLocation lAngleLoc, + ArrayRef<Decl *> protocols, + ArrayRef<SourceLocation> protocolLocs, + SourceLocation rAngleLoc); + + /// Build a specialized and/or protocol-qualified Objective-C type. + TypeResult actOnObjCTypeArgsAndProtocolQualifiers( + Scope *S, + SourceLocation Loc, + ParsedType BaseType, + SourceLocation TypeArgsLAngleLoc, + ArrayRef<ParsedType> TypeArgs, + SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, + ArrayRef<Decl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc); + + /// Build an Objective-C type parameter type. + QualType BuildObjCTypeParamType(const ObjCTypeParamDecl *Decl, + SourceLocation ProtocolLAngleLoc, + ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc, + bool FailOnError = false); + + /// Build an Objective-C object pointer type. + QualType BuildObjCObjectType( + QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc, + ArrayRef<TypeSourceInfo *> TypeArgs, SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, SourceLocation ProtocolRAngleLoc, + bool FailOnError, bool Rebuilding); + + /// Ensure attributes are consistent with type. + /// \param [in, out] Attributes The attributes to check; they will + /// be modified to be consistent with \p PropertyTy. + void CheckObjCPropertyAttributes(Decl *PropertyPtrTy, + SourceLocation Loc, + unsigned &Attributes, + bool propertyInPrimaryClass); + + /// Process the specified property declaration and create decls for the + /// setters and getters as needed. + /// \param property The property declaration being processed + void ProcessPropertyDecl(ObjCPropertyDecl *property); + + + void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, + ObjCPropertyDecl *SuperProperty, + const IdentifierInfo *Name, + bool OverridingProtocolProperty); + + void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, + ObjCInterfaceDecl *ID); + + Decl *ActOnAtEnd(Scope *S, SourceRange AtEnd, + ArrayRef<Decl *> allMethods = std::nullopt, + ArrayRef<DeclGroupPtrTy> allTUVars = std::nullopt); + + Decl *ActOnProperty(Scope *S, SourceLocation AtLoc, + SourceLocation LParenLoc, + FieldDeclarator &FD, ObjCDeclSpec &ODS, + Selector GetterSel, Selector SetterSel, + tok::ObjCKeywordKind MethodImplKind, + DeclContext *lexicalDC = nullptr); + + Decl *ActOnPropertyImplDecl(Scope *S, + SourceLocation AtLoc, + SourceLocation PropertyLoc, + bool ImplKind, + IdentifierInfo *PropertyId, + IdentifierInfo *PropertyIvar, + SourceLocation PropertyIvarLoc, + ObjCPropertyQueryKind QueryKind); + + enum ObjCSpecialMethodKind { + OSMK_None, + OSMK_Alloc, + OSMK_New, + OSMK_Copy, + OSMK_RetainingInit, + OSMK_NonRetainingInit + }; + + struct ObjCArgInfo { + IdentifierInfo *Name; + SourceLocation NameLoc; + // The Type is null if no type was specified, and the DeclSpec is invalid + // in this case. + ParsedType Type; + ObjCDeclSpec DeclSpec; + + /// ArgAttrs - Attribute list for this argument. + ParsedAttributesView ArgAttrs; + }; + + Decl *ActOnMethodDeclaration( + Scope *S, + SourceLocation BeginLoc, // location of the + or -. + SourceLocation EndLoc, // location of the ; or {. + tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, + ArrayRef<SourceLocation> SelectorLocs, Selector Sel, + // optional arguments. The number of types/arguments is obtained + // from the Sel.getNumArgs(). + ObjCArgInfo *ArgInfo, DeclaratorChunk::ParamInfo *CParamInfo, + unsigned CNumArgs, // c-style args + const ParsedAttributesView &AttrList, tok::ObjCKeywordKind MethodImplKind, + bool isVariadic, bool MethodDefinition); + + ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel, + const ObjCObjectPointerType *OPT, + bool IsInstance); + ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty, + bool IsInstance); + + bool CheckARCMethodDecl(ObjCMethodDecl *method); + bool inferObjCARCLifetime(ValueDecl *decl); + + void deduceOpenCLAddressSpace(ValueDecl *decl); + + ExprResult + HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, + Expr *BaseExpr, + SourceLocation OpLoc, + DeclarationName MemberName, + SourceLocation MemberLoc, + SourceLocation SuperLoc, QualType SuperType, + bool Super); + + ExprResult + ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, + IdentifierInfo &propertyName, + SourceLocation receiverNameLoc, + SourceLocation propertyNameLoc); + + ObjCMethodDecl *tryCaptureObjCSelf(SourceLocation Loc); + + /// Describes the kind of message expression indicated by a message + /// send that starts with an identifier. + enum ObjCMessageKind { + /// The message is sent to 'super'. + ObjCSuperMessage, + /// The message is an instance message. + ObjCInstanceMessage, + /// The message is a class message, and the identifier is a type + /// name. + ObjCClassMessage + }; + + ObjCMessageKind getObjCMessageKind(Scope *S, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool IsSuper, + bool HasTrailingDot, + ParsedType &ReceiverType); + + ExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, + Selector Sel, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args); + + ExprResult BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args, + bool isImplicit = false); + + ExprResult BuildClassMessageImplicit(QualType ReceiverType, + bool isSuperReceiver, + SourceLocation Loc, + Selector Sel, + ObjCMethodDecl *Method, + MultiExprArg Args); + + ExprResult ActOnClassMessage(Scope *S, + ParsedType Receiver, + Selector Sel, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args); + + ExprResult BuildInstanceMessage(Expr *Receiver, + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args, + bool isImplicit = false); + + ExprResult BuildInstanceMessageImplicit(Expr *Receiver, + QualType ReceiverType, + SourceLocation Loc, + Selector Sel, + ObjCMethodDecl *Method, + MultiExprArg Args); + + ExprResult ActOnInstanceMessage(Scope *S, + Expr *Receiver, + Selector Sel, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args); + + ExprResult BuildObjCBridgedCast(SourceLocation LParenLoc, + ObjCBridgeCastKind Kind, + SourceLocation BridgeKeywordLoc, + TypeSourceInfo *TSInfo, + Expr *SubExpr); + + ExprResult ActOnObjCBridgedCast(Scope *S, + SourceLocation LParenLoc, + ObjCBridgeCastKind Kind, + SourceLocation BridgeKeywordLoc, + ParsedType Type, + SourceLocation RParenLoc, + Expr *SubExpr); + + void CheckTollFreeBridgeCast(QualType castType, Expr *castExpr); + + void CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr); + + bool CheckTollFreeBridgeStaticCast(QualType castType, Expr *castExpr, + CastKind &Kind); + + bool checkObjCBridgeRelatedComponents(SourceLocation Loc, + QualType DestType, QualType SrcType, + ObjCInterfaceDecl *&RelatedClass, + ObjCMethodDecl *&ClassMethod, + ObjCMethodDecl *&InstanceMethod, + TypedefNameDecl *&TDNDecl, + bool CfToNs, bool Diagnose = true); + + bool CheckObjCBridgeRelatedConversions(SourceLocation Loc, + QualType DestType, QualType SrcType, + Expr *&SrcExpr, bool Diagnose = true); + + bool CheckConversionToObjCLiteral(QualType DstType, Expr *&SrcExpr, + bool Diagnose = true); + + bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall); + + /// Check whether the given new method is a valid override of the + /// given overridden method, and set any properties that should be inherited. + void CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, + const ObjCMethodDecl *Overridden); + + /// Describes the compatibility of a result type with its method. + enum ResultTypeCompatibilityKind { + RTC_Compatible, + RTC_Incompatible, + RTC_Unknown + }; + + void CheckObjCMethodDirectOverrides(ObjCMethodDecl *method, + ObjCMethodDecl *overridden); + + void CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, + ObjCInterfaceDecl *CurrentClass, + ResultTypeCompatibilityKind RTC); + + enum PragmaOptionsAlignKind { + POAK_Native, // #pragma options align=native + POAK_Natural, // #pragma options align=natural + POAK_Packed, // #pragma options align=packed + POAK_Power, // #pragma options align=power + POAK_Mac68k, // #pragma options align=mac68k + POAK_Reset // #pragma options align=reset + }; + + /// ActOnPragmaClangSection - Called on well formed \#pragma clang section + void ActOnPragmaClangSection(SourceLocation PragmaLoc, + PragmaClangSectionAction Action, + PragmaClangSectionKind SecKind, StringRef SecName); + + /// ActOnPragmaOptionsAlign - Called on well formed \#pragma options align. + void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, + SourceLocation PragmaLoc); + + /// ActOnPragmaPack - Called on well formed \#pragma pack(...). + void ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, + StringRef SlotLabel, Expr *Alignment); + + enum class PragmaAlignPackDiagnoseKind { + NonDefaultStateAtInclude, + ChangedStateAtExit + }; + + void DiagnoseNonDefaultPragmaAlignPack(PragmaAlignPackDiagnoseKind Kind, + SourceLocation IncludeLoc); + void DiagnoseUnterminatedPragmaAlignPack(); + + /// ActOnPragmaMSStrictGuardStackCheck - Called on well formed \#pragma + /// strict_gs_check. + void ActOnPragmaMSStrictGuardStackCheck(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + bool Value); + + /// ActOnPragmaMSStruct - Called on well formed \#pragma ms_struct [on|off]. + void ActOnPragmaMSStruct(PragmaMSStructKind Kind); + + /// ActOnPragmaMSComment - Called on well formed + /// \#pragma comment(kind, "arg"). + void ActOnPragmaMSComment(SourceLocation CommentLoc, PragmaMSCommentKind Kind, + StringRef Arg); + + /// ActOnPragmaMSPointersToMembers - called on well formed \#pragma + /// pointers_to_members(representation method[, general purpose + /// representation]). + void ActOnPragmaMSPointersToMembers( + LangOptions::PragmaMSPointersToMembersKind Kind, + SourceLocation PragmaLoc); + + /// Called on well formed \#pragma vtordisp(). + void ActOnPragmaMSVtorDisp(PragmaMsStackAction Action, + SourceLocation PragmaLoc, + MSVtorDispMode Value); + + enum PragmaSectionKind { + PSK_DataSeg, + PSK_BSSSeg, + PSK_ConstSeg, + PSK_CodeSeg, + }; + + bool UnifySection(StringRef SectionName, int SectionFlags, + NamedDecl *TheDecl); + bool UnifySection(StringRef SectionName, + int SectionFlags, + SourceLocation PragmaSectionLocation); + + /// Called on well formed \#pragma bss_seg/data_seg/const_seg/code_seg. + void ActOnPragmaMSSeg(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + StringLiteral *SegmentName, + llvm::StringRef PragmaName); + + /// Called on well formed \#pragma section(). + void ActOnPragmaMSSection(SourceLocation PragmaLocation, + int SectionFlags, StringLiteral *SegmentName); + + /// Called on well-formed \#pragma init_seg(). + void ActOnPragmaMSInitSeg(SourceLocation PragmaLocation, + StringLiteral *SegmentName); + + /// Called on well-formed \#pragma alloc_text(). + void ActOnPragmaMSAllocText( + SourceLocation PragmaLocation, StringRef Section, + const SmallVector<std::tuple<IdentifierInfo *, SourceLocation>> + &Functions); + + /// Called on #pragma clang __debug dump II + void ActOnPragmaDump(Scope *S, SourceLocation Loc, IdentifierInfo *II); + + /// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch + void ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name, + StringRef Value); + + /// Are precise floating point semantics currently enabled? + bool isPreciseFPEnabled() { + return !CurFPFeatures.getAllowFPReassociate() && + !CurFPFeatures.getNoSignedZero() && + !CurFPFeatures.getAllowReciprocal() && + !CurFPFeatures.getAllowApproxFunc(); + } + + void ActOnPragmaFPEvalMethod(SourceLocation Loc, + LangOptions::FPEvalMethodKind Value); + + /// ActOnPragmaFloatControl - Call on well-formed \#pragma float_control + void ActOnPragmaFloatControl(SourceLocation Loc, PragmaMsStackAction Action, + PragmaFloatControlKind Value); + + /// ActOnPragmaUnused - Called on well-formed '\#pragma unused'. + void ActOnPragmaUnused(const Token &Identifier, + Scope *curScope, + SourceLocation PragmaLoc); + + /// ActOnPragmaVisibility - Called on well formed \#pragma GCC visibility... . + void ActOnPragmaVisibility(const IdentifierInfo* VisType, + SourceLocation PragmaLoc); + + NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, const IdentifierInfo *II, + SourceLocation Loc); + void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, const WeakInfo &W); + + /// ActOnPragmaWeakID - Called on well formed \#pragma weak ident. + void ActOnPragmaWeakID(IdentifierInfo* WeakName, + SourceLocation PragmaLoc, + SourceLocation WeakNameLoc); + + /// ActOnPragmaRedefineExtname - Called on well formed + /// \#pragma redefine_extname oldname newname. + void ActOnPragmaRedefineExtname(IdentifierInfo* WeakName, + IdentifierInfo* AliasName, + SourceLocation PragmaLoc, + SourceLocation WeakNameLoc, + SourceLocation AliasNameLoc); + + /// ActOnPragmaWeakAlias - Called on well formed \#pragma weak ident = ident. + void ActOnPragmaWeakAlias(IdentifierInfo* WeakName, + IdentifierInfo* AliasName, + SourceLocation PragmaLoc, + SourceLocation WeakNameLoc, + SourceLocation AliasNameLoc); + + /// ActOnPragmaFPContract - Called on well formed + /// \#pragma {STDC,OPENCL} FP_CONTRACT and + /// \#pragma clang fp contract + void ActOnPragmaFPContract(SourceLocation Loc, LangOptions::FPModeKind FPC); + + /// Called on well formed + /// \#pragma clang fp reassociate + void ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled); + + /// ActOnPragmaFenvAccess - Called on well formed + /// \#pragma STDC FENV_ACCESS + void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled); + + /// Called on well formed '\#pragma clang fp' that has option 'exceptions'. + void ActOnPragmaFPExceptions(SourceLocation Loc, + LangOptions::FPExceptionModeKind); + + /// Called to set constant rounding mode for floating point operations. + void ActOnPragmaFEnvRound(SourceLocation Loc, llvm::RoundingMode); + + /// Called to set exception behavior for floating point operations. + void setExceptionMode(SourceLocation Loc, LangOptions::FPExceptionModeKind); + + /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to + /// a the record decl, to handle '\#pragma pack' and '\#pragma options align'. + void AddAlignmentAttributesForRecord(RecordDecl *RD); + + /// AddMsStructLayoutForRecord - Adds ms_struct layout attribute to record. + void AddMsStructLayoutForRecord(RecordDecl *RD); + + /// PushNamespaceVisibilityAttr - Note that we've entered a + /// namespace with a visibility attribute. + void PushNamespaceVisibilityAttr(const VisibilityAttr *Attr, + SourceLocation Loc); + + /// AddPushedVisibilityAttribute - If '\#pragma GCC visibility' was used, + /// add an appropriate visibility attribute. + void AddPushedVisibilityAttribute(Decl *RD); + + /// PopPragmaVisibility - Pop the top element of the visibility stack; used + /// for '\#pragma GCC visibility' and visibility attributes on namespaces. + void PopPragmaVisibility(bool IsNamespaceEnd, SourceLocation EndLoc); + + /// FreeVisContext - Deallocate and null out VisContext. + void FreeVisContext(); + + /// AddCFAuditedAttribute - Check whether we're currently within + /// '\#pragma clang arc_cf_code_audited' and, if so, consider adding + /// the appropriate attribute. + void AddCFAuditedAttribute(Decl *D); + + void ActOnPragmaAttributeAttribute(ParsedAttr &Attribute, + SourceLocation PragmaLoc, + attr::ParsedSubjectMatchRuleSet Rules); + void ActOnPragmaAttributeEmptyPush(SourceLocation PragmaLoc, + const IdentifierInfo *Namespace); + + /// Called on well-formed '\#pragma clang attribute pop'. + void ActOnPragmaAttributePop(SourceLocation PragmaLoc, + const IdentifierInfo *Namespace); + + /// Adds the attributes that have been specified using the + /// '\#pragma clang attribute push' directives to the given declaration. + void AddPragmaAttributes(Scope *S, Decl *D); + + void DiagnoseUnterminatedPragmaAttribute(); + + /// Called on well formed \#pragma clang optimize. + void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc); + + /// #pragma optimize("[optimization-list]", on | off). + void ActOnPragmaMSOptimize(SourceLocation Loc, bool IsOn); + + /// Call on well formed \#pragma function. + void + ActOnPragmaMSFunction(SourceLocation Loc, + const llvm::SmallVectorImpl<StringRef> &NoBuiltins); + + /// Get the location for the currently active "\#pragma clang optimize + /// off". If this location is invalid, then the state of the pragma is "on". + SourceLocation getOptimizeOffPragmaLocation() const { + return OptimizeOffPragmaLocation; + } + + /// Only called on function definitions; if there is a pragma in scope + /// with the effect of a range-based optnone, consider marking the function + /// with attribute optnone. + void AddRangeBasedOptnone(FunctionDecl *FD); + + /// Only called on function definitions; if there is a `#pragma alloc_text` + /// that decides which code section the function should be in, add + /// attribute section to the function. + void AddSectionMSAllocText(FunctionDecl *FD); + + /// Adds the 'optnone' attribute to the function declaration if there + /// are no conflicts; Loc represents the location causing the 'optnone' + /// attribute to be added (usually because of a pragma). + void AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, SourceLocation Loc); + + /// Only called on function definitions; if there is a MSVC #pragma optimize + /// in scope, consider changing the function's attributes based on the + /// optimization list passed to the pragma. + void ModifyFnAttributesMSPragmaOptimize(FunctionDecl *FD); + + /// Only called on function definitions; if there is a pragma in scope + /// with the effect of a range-based no_builtin, consider marking the function + /// with attribute no_builtin. + void AddImplicitMSFunctionNoBuiltinAttr(FunctionDecl *FD); + + /// AddAlignedAttr - Adds an aligned attribute to a particular declaration. + void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, + bool IsPackExpansion); + void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, TypeSourceInfo *T, + bool IsPackExpansion); + + /// AddAssumeAlignedAttr - Adds an assume_aligned attribute to a particular + /// declaration. + void AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, + Expr *OE); + + /// AddAllocAlignAttr - Adds an alloc_align attribute to a particular + /// declaration. + void AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI, + Expr *ParamExpr); + + /// AddAlignValueAttr - Adds an align_value attribute to a particular + /// declaration. + void AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E); + + /// AddAnnotationAttr - Adds an annotation Annot with Args arguments to D. + void AddAnnotationAttr(Decl *D, const AttributeCommonInfo &CI, + StringRef Annot, MutableArrayRef<Expr *> Args); + + /// ConstantFoldAttrArgs - Folds attribute arguments into ConstantExprs + /// (unless they are value dependent or type dependent). Returns false + /// and emits a diagnostic if one or more of the arguments could not be + /// folded into a constant. + bool ConstantFoldAttrArgs(const AttributeCommonInfo &CI, + MutableArrayRef<Expr *> Args); + + /// AddLaunchBoundsAttr - Adds a launch_bounds attribute to a particular + /// declaration. + void AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI, + Expr *MaxThreads, Expr *MinBlocks); + + /// AddModeAttr - Adds a mode attribute to a particular declaration. + void AddModeAttr(Decl *D, const AttributeCommonInfo &CI, IdentifierInfo *Name, + bool InInstantiation = false); + + void AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI, + ParameterABI ABI); + + enum class RetainOwnershipKind {NS, CF, OS}; + void AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI, + RetainOwnershipKind K, bool IsTemplateInstantiation); + + /// addAMDGPUFlatWorkGroupSizeAttr - Adds an amdgpu_flat_work_group_size + /// attribute to a particular declaration. + void addAMDGPUFlatWorkGroupSizeAttr(Decl *D, const AttributeCommonInfo &CI, + Expr *Min, Expr *Max); + + /// addAMDGPUWavePersEUAttr - Adds an amdgpu_waves_per_eu attribute to a + /// particular declaration. + void addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI, + Expr *Min, Expr *Max); + + bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type); + + //===--------------------------------------------------------------------===// + // C++ Coroutines TS + // + bool ActOnCoroutineBodyStart(Scope *S, SourceLocation KwLoc, + StringRef Keyword); + ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E); + ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E); + StmtResult ActOnCoreturnStmt(Scope *S, SourceLocation KwLoc, Expr *E); + + ExprResult BuildOperatorCoawaitLookupExpr(Scope *S, SourceLocation Loc); + ExprResult BuildOperatorCoawaitCall(SourceLocation Loc, Expr *E, + UnresolvedLookupExpr *Lookup); + ExprResult BuildResolvedCoawaitExpr(SourceLocation KwLoc, Expr *Operand, + Expr *Awaiter, bool IsImplicit = false); + ExprResult BuildUnresolvedCoawaitExpr(SourceLocation KwLoc, Expr *Operand, + UnresolvedLookupExpr *Lookup); + ExprResult BuildCoyieldExpr(SourceLocation KwLoc, Expr *E); + StmtResult BuildCoreturnStmt(SourceLocation KwLoc, Expr *E, + bool IsImplicit = false); + StmtResult BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs); + bool buildCoroutineParameterMoves(SourceLocation Loc); + VarDecl *buildCoroutinePromise(SourceLocation Loc); + void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body); + /// Lookup 'coroutine_traits' in std namespace and std::experimental + /// namespace. The namespace found is recorded in Namespace. + ClassTemplateDecl *lookupCoroutineTraits(SourceLocation KwLoc, + SourceLocation FuncLoc, + NamespaceDecl *&Namespace); + /// Check that the expression co_await promise.final_suspend() shall not be + /// potentially-throwing. + bool checkFinalSuspendNoThrow(const Stmt *FinalSuspend); + + //===--------------------------------------------------------------------===// + // OpenMP directives and clauses. + // +private: + void *VarDataSharingAttributesStack; + + struct DeclareTargetContextInfo { + struct MapInfo { + OMPDeclareTargetDeclAttr::MapTypeTy MT; + SourceLocation Loc; + }; + /// Explicitly listed variables and functions in a 'to' or 'link' clause. + llvm::DenseMap<NamedDecl *, MapInfo> ExplicitlyMapped; + + /// The 'device_type' as parsed from the clause. + OMPDeclareTargetDeclAttr::DevTypeTy DT = OMPDeclareTargetDeclAttr::DT_Any; + + /// The directive kind, `begin declare target` or `declare target`. + OpenMPDirectiveKind Kind; + + /// The directive with indirect clause. + std::optional<Expr *> Indirect; + + /// The directive location. + SourceLocation Loc; + + DeclareTargetContextInfo(OpenMPDirectiveKind Kind, SourceLocation Loc) + : Kind(Kind), Loc(Loc) {} + }; + + /// Number of nested '#pragma omp declare target' directives. + SmallVector<DeclareTargetContextInfo, 4> DeclareTargetNesting; + + /// Initialization of data-sharing attributes stack. + void InitDataSharingAttributesStack(); + void DestroyDataSharingAttributesStack(); + ExprResult + VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind, + bool StrictlyPositive = true, + bool SuppressExprDiags = false); + /// Returns OpenMP nesting level for current directive. + unsigned getOpenMPNestingLevel() const; + + /// Adjusts the function scopes index for the target-based regions. + void adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex, + unsigned Level) const; + + /// Returns the number of scopes associated with the construct on the given + /// OpenMP level. + int getNumberOfConstructScopes(unsigned Level) const; + + /// Push new OpenMP function region for non-capturing function. + void pushOpenMPFunctionRegion(); + + /// Pop OpenMP function region for non-capturing function. + void popOpenMPFunctionRegion(const sema::FunctionScopeInfo *OldFSI); + + /// Analyzes and checks a loop nest for use by a loop transformation. + /// + /// \param Kind The loop transformation directive kind. + /// \param NumLoops How many nested loops the directive is expecting. + /// \param AStmt Associated statement of the transformation directive. + /// \param LoopHelpers [out] The loop analysis result. + /// \param Body [out] The body code nested in \p NumLoops loop. + /// \param OriginalInits [out] Collection of statements and declarations that + /// must have been executed/declared before entering the + /// loop. + /// + /// \return Whether there was any error. + bool checkTransformableLoopNest( + OpenMPDirectiveKind Kind, Stmt *AStmt, int NumLoops, + SmallVectorImpl<OMPLoopBasedDirective::HelperExprs> &LoopHelpers, + Stmt *&Body, + SmallVectorImpl<SmallVector<llvm::PointerUnion<Stmt *, Decl *>, 0>> + &OriginalInits); + + /// Helper to keep information about the current `omp begin/end declare + /// variant` nesting. + struct OMPDeclareVariantScope { + /// The associated OpenMP context selector. + OMPTraitInfo *TI; + + /// The associated OpenMP context selector mangling. + std::string NameSuffix; + + OMPDeclareVariantScope(OMPTraitInfo &TI); + }; + + /// Return the OMPTraitInfo for the surrounding scope, if any. + OMPTraitInfo *getOMPTraitInfoForSurroundingScope() { + return OMPDeclareVariantScopes.empty() ? nullptr + : OMPDeclareVariantScopes.back().TI; + } + + /// The current `omp begin/end declare variant` scopes. + SmallVector<OMPDeclareVariantScope, 4> OMPDeclareVariantScopes; + + /// The current `omp begin/end assumes` scopes. + SmallVector<AssumptionAttr *, 4> OMPAssumeScoped; + + /// All `omp assumes` we encountered so far. + SmallVector<AssumptionAttr *, 4> OMPAssumeGlobal; + +public: + /// The declarator \p D defines a function in the scope \p S which is nested + /// in an `omp begin/end declare variant` scope. In this method we create a + /// declaration for \p D and rename \p D according to the OpenMP context + /// selector of the surrounding scope. Return all base functions in \p Bases. + void ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope( + Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, + SmallVectorImpl<FunctionDecl *> &Bases); + + /// Register \p D as specialization of all base functions in \p Bases in the + /// current `omp begin/end declare variant` scope. + void ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope( + Decl *D, SmallVectorImpl<FunctionDecl *> &Bases); + + /// Act on \p D, a function definition inside of an `omp [begin/end] assumes`. + void ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(Decl *D); + + /// Can we exit an OpenMP declare variant scope at the moment. + bool isInOpenMPDeclareVariantScope() const { + return !OMPDeclareVariantScopes.empty(); + } + + /// Given the potential call expression \p Call, determine if there is a + /// specialization via the OpenMP declare variant mechanism available. If + /// there is, return the specialized call expression, otherwise return the + /// original \p Call. + ExprResult ActOnOpenMPCall(ExprResult Call, Scope *Scope, + SourceLocation LParenLoc, MultiExprArg ArgExprs, + SourceLocation RParenLoc, Expr *ExecConfig); + + /// Handle a `omp begin declare variant`. + void ActOnOpenMPBeginDeclareVariant(SourceLocation Loc, OMPTraitInfo &TI); + + /// Handle a `omp end declare variant`. + void ActOnOpenMPEndDeclareVariant(); + + /// Checks if the variant/multiversion functions are compatible. + bool areMultiversionVariantFunctionsCompatible( + const FunctionDecl *OldFD, const FunctionDecl *NewFD, + const PartialDiagnostic &NoProtoDiagID, + const PartialDiagnosticAt &NoteCausedDiagIDAt, + const PartialDiagnosticAt &NoSupportDiagIDAt, + const PartialDiagnosticAt &DiffDiagIDAt, bool TemplatesSupported, + bool ConstexprSupported, bool CLinkageMayDiffer); + + /// Function tries to capture lambda's captured variables in the OpenMP region + /// before the original lambda is captured. + void tryCaptureOpenMPLambdas(ValueDecl *V); + + /// Return true if the provided declaration \a VD should be captured by + /// reference. + /// \param Level Relative level of nested OpenMP construct for that the check + /// is performed. + /// \param OpenMPCaptureLevel Capture level within an OpenMP construct. + bool isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, + unsigned OpenMPCaptureLevel) const; + + /// Check if the specified variable is used in one of the private + /// clauses (private, firstprivate, lastprivate, reduction etc.) in OpenMP + /// constructs. + VarDecl *isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo = false, + unsigned StopAt = 0); + + /// The member expression(this->fd) needs to be rebuilt in the template + /// instantiation to generate private copy for OpenMP when default + /// clause is used. The function will return true if default + /// cluse is used. + bool isOpenMPRebuildMemberExpr(ValueDecl *D); + + ExprResult getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, + ExprObjectKind OK, SourceLocation Loc); + + /// If the current region is a loop-based region, mark the start of the loop + /// construct. + void startOpenMPLoop(); + + /// If the current region is a range loop-based region, mark the start of the + /// loop construct. + void startOpenMPCXXRangeFor(); + + /// Check if the specified variable is used in 'private' clause. + /// \param Level Relative level of nested OpenMP construct for that the check + /// is performed. + OpenMPClauseKind isOpenMPPrivateDecl(ValueDecl *D, unsigned Level, + unsigned CapLevel) const; + + /// Sets OpenMP capture kind (OMPC_private, OMPC_firstprivate, OMPC_map etc.) + /// for \p FD based on DSA for the provided corresponding captured declaration + /// \p D. + void setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D, unsigned Level); + + /// Check if the specified variable is captured by 'target' directive. + /// \param Level Relative level of nested OpenMP construct for that the check + /// is performed. + bool isOpenMPTargetCapturedDecl(const ValueDecl *D, unsigned Level, + unsigned CaptureLevel) const; + + /// Check if the specified global variable must be captured by outer capture + /// regions. + /// \param Level Relative level of nested OpenMP construct for that + /// the check is performed. + bool isOpenMPGlobalCapturedDecl(ValueDecl *D, unsigned Level, + unsigned CaptureLevel) const; + + ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc, + Expr *Op); + /// Called on start of new data sharing attribute block. + void StartOpenMPDSABlock(OpenMPDirectiveKind K, + const DeclarationNameInfo &DirName, Scope *CurScope, + SourceLocation Loc); + /// Start analysis of clauses. + void StartOpenMPClause(OpenMPClauseKind K); + /// End analysis of clauses. + void EndOpenMPClause(); + /// Called on end of data sharing attribute block. + void EndOpenMPDSABlock(Stmt *CurDirective); + + /// Check if the current region is an OpenMP loop region and if it is, + /// mark loop control variable, used in \p Init for loop initialization, as + /// private by default. + /// \param Init First part of the for loop. + void ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init); + + /// Called on well-formed '\#pragma omp metadirective' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPMetaDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + + // OpenMP directives and clauses. + /// Called on correct id-expression from the '#pragma omp + /// threadprivate'. + ExprResult ActOnOpenMPIdExpression(Scope *CurScope, CXXScopeSpec &ScopeSpec, + const DeclarationNameInfo &Id, + OpenMPDirectiveKind Kind); + /// Called on well-formed '#pragma omp threadprivate'. + DeclGroupPtrTy ActOnOpenMPThreadprivateDirective( + SourceLocation Loc, + ArrayRef<Expr *> VarList); + /// Builds a new OpenMPThreadPrivateDecl and checks its correctness. + OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl(SourceLocation Loc, + ArrayRef<Expr *> VarList); + /// Called on well-formed '#pragma omp allocate'. + DeclGroupPtrTy ActOnOpenMPAllocateDirective(SourceLocation Loc, + ArrayRef<Expr *> VarList, + ArrayRef<OMPClause *> Clauses, + DeclContext *Owner = nullptr); + + /// Called on well-formed '#pragma omp [begin] assume[s]'. + void ActOnOpenMPAssumesDirective(SourceLocation Loc, + OpenMPDirectiveKind DKind, + ArrayRef<std::string> Assumptions, + bool SkippedClauses); + + /// Check if there is an active global `omp begin assumes` directive. + bool isInOpenMPAssumeScope() const { return !OMPAssumeScoped.empty(); } + + /// Check if there is an active global `omp assumes` directive. + bool hasGlobalOpenMPAssumes() const { return !OMPAssumeGlobal.empty(); } + + /// Called on well-formed '#pragma omp end assumes'. + void ActOnOpenMPEndAssumesDirective(); + + /// Called on well-formed '#pragma omp requires'. + DeclGroupPtrTy ActOnOpenMPRequiresDirective(SourceLocation Loc, + ArrayRef<OMPClause *> ClauseList); + /// Check restrictions on Requires directive + OMPRequiresDecl *CheckOMPRequiresDecl(SourceLocation Loc, + ArrayRef<OMPClause *> Clauses); + /// Check if the specified type is allowed to be used in 'omp declare + /// reduction' construct. + QualType ActOnOpenMPDeclareReductionType(SourceLocation TyLoc, + TypeResult ParsedType); + /// Called on start of '#pragma omp declare reduction'. + DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveStart( + Scope *S, DeclContext *DC, DeclarationName Name, + ArrayRef<std::pair<QualType, SourceLocation>> ReductionTypes, + AccessSpecifier AS, Decl *PrevDeclInScope = nullptr); + /// Initialize declare reduction construct initializer. + void ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D); + /// Finish current declare reduction construct initializer. + void ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner); + /// Initialize declare reduction construct initializer. + /// \return omp_priv variable. + VarDecl *ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D); + /// Finish current declare reduction construct initializer. + void ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer, + VarDecl *OmpPrivParm); + /// Called at the end of '#pragma omp declare reduction'. + DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveEnd( + Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid); + + /// Check variable declaration in 'omp declare mapper' construct. + TypeResult ActOnOpenMPDeclareMapperVarDecl(Scope *S, Declarator &D); + /// Check if the specified type is allowed to be used in 'omp declare + /// mapper' construct. + QualType ActOnOpenMPDeclareMapperType(SourceLocation TyLoc, + TypeResult ParsedType); + /// Called on start of '#pragma omp declare mapper'. + DeclGroupPtrTy ActOnOpenMPDeclareMapperDirective( + Scope *S, DeclContext *DC, DeclarationName Name, QualType MapperType, + SourceLocation StartLoc, DeclarationName VN, AccessSpecifier AS, + Expr *MapperVarRef, ArrayRef<OMPClause *> Clauses, + Decl *PrevDeclInScope = nullptr); + /// Build the mapper variable of '#pragma omp declare mapper'. + ExprResult ActOnOpenMPDeclareMapperDirectiveVarDecl(Scope *S, + QualType MapperType, + SourceLocation StartLoc, + DeclarationName VN); + void ActOnOpenMPIteratorVarDecl(VarDecl *VD); + bool isOpenMPDeclareMapperVarDeclAllowed(const VarDecl *VD) const; + const ValueDecl *getOpenMPDeclareMapperVarName() const; + + /// Called on the start of target region i.e. '#pragma omp declare target'. + bool ActOnStartOpenMPDeclareTargetContext(DeclareTargetContextInfo &DTCI); + + /// Called at the end of target region i.e. '#pragma omp end declare target'. + const DeclareTargetContextInfo ActOnOpenMPEndDeclareTargetDirective(); + + /// Called once a target context is completed, that can be when a + /// '#pragma omp end declare target' was encountered or when a + /// '#pragma omp declare target' without declaration-definition-seq was + /// encountered. + void ActOnFinishedOpenMPDeclareTargetContext(DeclareTargetContextInfo &DTCI); + + /// Report unterminated 'omp declare target' or 'omp begin declare target' at + /// the end of a compilation unit. + void DiagnoseUnterminatedOpenMPDeclareTarget(); + + /// Searches for the provided declaration name for OpenMP declare target + /// directive. + NamedDecl *lookupOpenMPDeclareTargetName(Scope *CurScope, + CXXScopeSpec &ScopeSpec, + const DeclarationNameInfo &Id); + + /// Called on correct id-expression from the '#pragma omp declare target'. + void ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc, + OMPDeclareTargetDeclAttr::MapTypeTy MT, + DeclareTargetContextInfo &DTCI); + + /// Check declaration inside target region. + void + checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, + SourceLocation IdLoc = SourceLocation()); + /// Finishes analysis of the deferred functions calls that may be declared as + /// host/nohost during device/host compilation. + void finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller, + const FunctionDecl *Callee, + SourceLocation Loc); + + /// Return true if currently in OpenMP task with untied clause context. + bool isInOpenMPTaskUntiedContext() const; + + /// Return true inside OpenMP declare target region. + bool isInOpenMPDeclareTargetContext() const { + return !DeclareTargetNesting.empty(); + } + /// Return true inside OpenMP target region. + bool isInOpenMPTargetExecutionDirective() const; + + /// Return the number of captured regions created for an OpenMP directive. + static int getOpenMPCaptureLevels(OpenMPDirectiveKind Kind); + + /// Initialization of captured region for OpenMP region. + void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope); + + /// Called for syntactical loops (ForStmt or CXXForRangeStmt) associated to + /// an OpenMP loop directive. + StmtResult ActOnOpenMPCanonicalLoop(Stmt *AStmt); + + /// Process a canonical OpenMP loop nest that can either be a canonical + /// literal loop (ForStmt or CXXForRangeStmt), or the generated loop of an + /// OpenMP loop transformation construct. + StmtResult ActOnOpenMPLoopnest(Stmt *AStmt); + + /// End of OpenMP region. + /// + /// \param S Statement associated with the current OpenMP region. + /// \param Clauses List of clauses for the current OpenMP region. + /// + /// \returns Statement for finished OpenMP region. + StmtResult ActOnOpenMPRegionEnd(StmtResult S, ArrayRef<OMPClause *> Clauses); + StmtResult ActOnOpenMPExecutableDirective( + OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, + OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp parallel' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + using VarsWithInheritedDSAType = + llvm::SmallDenseMap<const ValueDecl *, const Expr *, 4>; + /// Called on well-formed '\#pragma omp simd' after parsing + /// of the associated statement. + StmtResult + ActOnOpenMPSimdDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '#pragma omp tile' after parsing of its clauses and + /// the associated statement. + StmtResult ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '#pragma omp unroll' after parsing of its clauses + /// and the associated statement. + StmtResult ActOnOpenMPUnrollDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp for' after parsing + /// of the associated statement. + StmtResult + ActOnOpenMPForDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp for simd' after parsing + /// of the associated statement. + StmtResult + ActOnOpenMPForSimdDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp sections' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp section' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPSectionDirective(Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp single' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPSingleDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp master' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPMasterDirective(Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp critical' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPCriticalDirective(const DeclarationNameInfo &DirName, + ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp parallel for' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPParallelForDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp parallel for simd' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPParallelForSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp parallel master' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPParallelMasterDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp parallel masked' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPParallelMaskedDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp parallel sections' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp task' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp taskyield'. + StmtResult ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp error'. + /// Error direcitive is allowed in both declared and excutable contexts. + /// Adding InExContext to identify which context is called from. + StmtResult ActOnOpenMPErrorDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc, + bool InExContext = true); + /// Called on well-formed '\#pragma omp barrier'. + StmtResult ActOnOpenMPBarrierDirective(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp taskwait'. + StmtResult ActOnOpenMPTaskwaitDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp taskgroup'. + StmtResult ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp flush'. + StmtResult ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp depobj'. + StmtResult ActOnOpenMPDepobjDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp scan'. + StmtResult ActOnOpenMPScanDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp ordered' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp atomic' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp target' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp target data' after parsing of + /// the associated statement. + StmtResult ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp target enter data' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AStmt); + /// Called on well-formed '\#pragma omp target exit data' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AStmt); + /// Called on well-formed '\#pragma omp target parallel' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPTargetParallelDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp target parallel for' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPTargetParallelForDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp teams' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp teams loop' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPTeamsGenericLoopDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp target teams loop' after parsing of + /// the associated statement. + StmtResult ActOnOpenMPTargetTeamsGenericLoopDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp parallel loop' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPParallelGenericLoopDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp target parallel loop' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPTargetParallelGenericLoopDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp cancellation point'. + StmtResult + ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPDirectiveKind CancelRegion); + /// Called on well-formed '\#pragma omp cancel'. + StmtResult ActOnOpenMPCancelDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPDirectiveKind CancelRegion); + /// Called on well-formed '\#pragma omp taskloop' after parsing of the + /// associated statement. + StmtResult + ActOnOpenMPTaskLoopDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp taskloop simd' after parsing of + /// the associated statement. + StmtResult ActOnOpenMPTaskLoopSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp master taskloop' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPMasterTaskLoopDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp master taskloop simd' after parsing of + /// the associated statement. + StmtResult ActOnOpenMPMasterTaskLoopSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp parallel master taskloop' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPParallelMasterTaskLoopDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp parallel master taskloop simd' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPParallelMasterTaskLoopSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp masked taskloop' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPMaskedTaskLoopDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp masked taskloop simd' after parsing of + /// the associated statement. + StmtResult ActOnOpenMPMaskedTaskLoopSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp parallel masked taskloop' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPParallelMaskedTaskLoopDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp parallel masked taskloop simd' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPParallelMaskedTaskLoopSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp distribute' after parsing + /// of the associated statement. + StmtResult + ActOnOpenMPDistributeDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp target update'. + StmtResult ActOnOpenMPTargetUpdateDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AStmt); + /// Called on well-formed '\#pragma omp distribute parallel for' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPDistributeParallelForDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp distribute parallel for simd' + /// after parsing of the associated statement. + StmtResult ActOnOpenMPDistributeParallelForSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp distribute simd' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPDistributeSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp target parallel for simd' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPTargetParallelForSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp target simd' after parsing of + /// the associated statement. + StmtResult + ActOnOpenMPTargetSimdDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp teams distribute' after parsing of + /// the associated statement. + StmtResult ActOnOpenMPTeamsDistributeDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp teams distribute simd' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPTeamsDistributeSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp teams distribute parallel for simd' + /// after parsing of the associated statement. + StmtResult ActOnOpenMPTeamsDistributeParallelForSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp teams distribute parallel for' + /// after parsing of the associated statement. + StmtResult ActOnOpenMPTeamsDistributeParallelForDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp target teams' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp target teams distribute' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPTargetTeamsDistributeDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp target teams distribute parallel for' + /// after parsing of the associated statement. + StmtResult ActOnOpenMPTargetTeamsDistributeParallelForDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp target teams distribute parallel for + /// simd' after parsing of the associated statement. + StmtResult ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp target teams distribute simd' after + /// parsing of the associated statement. + StmtResult ActOnOpenMPTargetTeamsDistributeSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp interop'. + StmtResult ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp dispatch' after parsing of the + // /associated statement. + StmtResult ActOnOpenMPDispatchDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp masked' after parsing of the + // /associated statement. + StmtResult ActOnOpenMPMaskedDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + + /// Called on well-formed '\#pragma omp loop' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPGenericLoopDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + + /// Checks correctness of linear modifiers. + bool CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, + SourceLocation LinLoc); + /// Checks that the specified declaration matches requirements for the linear + /// decls. + bool CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc, + OpenMPLinearClauseKind LinKind, QualType Type, + bool IsDeclareSimd = false); + + /// Called on well-formed '\#pragma omp declare simd' after parsing of + /// the associated method/function. + DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective( + DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, + Expr *Simdlen, ArrayRef<Expr *> Uniforms, ArrayRef<Expr *> Aligneds, + ArrayRef<Expr *> Alignments, ArrayRef<Expr *> Linears, + ArrayRef<unsigned> LinModifiers, ArrayRef<Expr *> Steps, SourceRange SR); + + /// Checks '\#pragma omp declare variant' variant function and original + /// functions after parsing of the associated method/function. + /// \param DG Function declaration to which declare variant directive is + /// applied to. + /// \param VariantRef Expression that references the variant function, which + /// must be used instead of the original one, specified in \p DG. + /// \param TI The trait info object representing the match clause. + /// \param NumAppendArgs The number of omp_interop_t arguments to account for + /// in checking. + /// \returns std::nullopt, if the function/variant function are not compatible + /// with the pragma, pair of original function/variant ref expression + /// otherwise. + std::optional<std::pair<FunctionDecl *, Expr *>> + checkOpenMPDeclareVariantFunction(DeclGroupPtrTy DG, Expr *VariantRef, + OMPTraitInfo &TI, unsigned NumAppendArgs, + SourceRange SR); + + /// Called on well-formed '\#pragma omp declare variant' after parsing of + /// the associated method/function. + /// \param FD Function declaration to which declare variant directive is + /// applied to. + /// \param VariantRef Expression that references the variant function, which + /// must be used instead of the original one, specified in \p DG. + /// \param TI The context traits associated with the function variant. + /// \param AdjustArgsNothing The list of 'nothing' arguments. + /// \param AdjustArgsNeedDevicePtr The list of 'need_device_ptr' arguments. + /// \param AppendArgs The list of 'append_args' arguments. + /// \param AdjustArgsLoc The Location of an 'adjust_args' clause. + /// \param AppendArgsLoc The Location of an 'append_args' clause. + /// \param SR The SourceRange of the 'declare variant' directive. + void ActOnOpenMPDeclareVariantDirective( + FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI, + ArrayRef<Expr *> AdjustArgsNothing, + ArrayRef<Expr *> AdjustArgsNeedDevicePtr, + ArrayRef<OMPInteropInfo> AppendArgs, SourceLocation AdjustArgsLoc, + SourceLocation AppendArgsLoc, SourceRange SR); + + OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, + Expr *Expr, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'allocator' clause. + OMPClause *ActOnOpenMPAllocatorClause(Expr *Allocator, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'if' clause. + OMPClause *ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, + Expr *Condition, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation NameModifierLoc, + SourceLocation ColonLoc, + SourceLocation EndLoc); + /// Called on well-formed 'final' clause. + OMPClause *ActOnOpenMPFinalClause(Expr *Condition, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'num_threads' clause. + OMPClause *ActOnOpenMPNumThreadsClause(Expr *NumThreads, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'align' clause. + OMPClause *ActOnOpenMPAlignClause(Expr *Alignment, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'safelen' clause. + OMPClause *ActOnOpenMPSafelenClause(Expr *Length, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'simdlen' clause. + OMPClause *ActOnOpenMPSimdlenClause(Expr *Length, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-form 'sizes' clause. + OMPClause *ActOnOpenMPSizesClause(ArrayRef<Expr *> SizeExprs, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-form 'full' clauses. + OMPClause *ActOnOpenMPFullClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-form 'partial' clauses. + OMPClause *ActOnOpenMPPartialClause(Expr *FactorExpr, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'collapse' clause. + OMPClause *ActOnOpenMPCollapseClause(Expr *NumForLoops, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'ordered' clause. + OMPClause * + ActOnOpenMPOrderedClause(SourceLocation StartLoc, SourceLocation EndLoc, + SourceLocation LParenLoc = SourceLocation(), + Expr *NumForLoops = nullptr); + /// Called on well-formed 'grainsize' clause. + OMPClause *ActOnOpenMPGrainsizeClause(OpenMPGrainsizeClauseModifier Modifier, + Expr *Size, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation ModifierLoc, + SourceLocation EndLoc); + /// Called on well-formed 'num_tasks' clause. + OMPClause *ActOnOpenMPNumTasksClause(OpenMPNumTasksClauseModifier Modifier, + Expr *NumTasks, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation ModifierLoc, + SourceLocation EndLoc); + /// Called on well-formed 'hint' clause. + OMPClause *ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'detach' clause. + OMPClause *ActOnOpenMPDetachClause(Expr *Evt, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + + OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, + unsigned Argument, + SourceLocation ArgumentLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'when' clause. + OMPClause *ActOnOpenMPWhenClause(OMPTraitInfo &TI, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'default' clause. + OMPClause *ActOnOpenMPDefaultClause(llvm::omp::DefaultKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'proc_bind' clause. + OMPClause *ActOnOpenMPProcBindClause(llvm::omp::ProcBindKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'order' clause. + OMPClause *ActOnOpenMPOrderClause(OpenMPOrderClauseModifier Modifier, + OpenMPOrderClauseKind Kind, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation MLoc, SourceLocation KindLoc, + SourceLocation EndLoc); + /// Called on well-formed 'update' clause. + OMPClause *ActOnOpenMPUpdateClause(OpenMPDependClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + + OMPClause *ActOnOpenMPSingleExprWithArgClause( + OpenMPClauseKind Kind, ArrayRef<unsigned> Arguments, Expr *Expr, + SourceLocation StartLoc, SourceLocation LParenLoc, + ArrayRef<SourceLocation> ArgumentsLoc, SourceLocation DelimLoc, + SourceLocation EndLoc); + /// Called on well-formed 'schedule' clause. + OMPClause *ActOnOpenMPScheduleClause( + OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2, + OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation M1Loc, SourceLocation M2Loc, + SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc); + + OMPClause *ActOnOpenMPClause(OpenMPClauseKind Kind, SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'nowait' clause. + OMPClause *ActOnOpenMPNowaitClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'untied' clause. + OMPClause *ActOnOpenMPUntiedClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'mergeable' clause. + OMPClause *ActOnOpenMPMergeableClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'read' clause. + OMPClause *ActOnOpenMPReadClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'write' clause. + OMPClause *ActOnOpenMPWriteClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'update' clause. + OMPClause *ActOnOpenMPUpdateClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'capture' clause. + OMPClause *ActOnOpenMPCaptureClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'compare' clause. + OMPClause *ActOnOpenMPCompareClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'seq_cst' clause. + OMPClause *ActOnOpenMPSeqCstClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'acq_rel' clause. + OMPClause *ActOnOpenMPAcqRelClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'acquire' clause. + OMPClause *ActOnOpenMPAcquireClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'release' clause. + OMPClause *ActOnOpenMPReleaseClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'relaxed' clause. + OMPClause *ActOnOpenMPRelaxedClause(SourceLocation StartLoc, + SourceLocation EndLoc); + + /// Called on well-formed 'init' clause. + OMPClause * + ActOnOpenMPInitClause(Expr *InteropVar, OMPInteropInfo &InteropInfo, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation VarLoc, SourceLocation EndLoc); + + /// Called on well-formed 'use' clause. + OMPClause *ActOnOpenMPUseClause(Expr *InteropVar, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation VarLoc, SourceLocation EndLoc); + + /// Called on well-formed 'destroy' clause. + OMPClause *ActOnOpenMPDestroyClause(Expr *InteropVar, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation VarLoc, + SourceLocation EndLoc); + /// Called on well-formed 'novariants' clause. + OMPClause *ActOnOpenMPNovariantsClause(Expr *Condition, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'nocontext' clause. + OMPClause *ActOnOpenMPNocontextClause(Expr *Condition, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'filter' clause. + OMPClause *ActOnOpenMPFilterClause(Expr *ThreadID, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'threads' clause. + OMPClause *ActOnOpenMPThreadsClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'simd' clause. + OMPClause *ActOnOpenMPSIMDClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'nogroup' clause. + OMPClause *ActOnOpenMPNogroupClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// Called on well-formed 'unified_address' clause. + OMPClause *ActOnOpenMPUnifiedAddressClause(SourceLocation StartLoc, + SourceLocation EndLoc); + + /// Called on well-formed 'unified_address' clause. + OMPClause *ActOnOpenMPUnifiedSharedMemoryClause(SourceLocation StartLoc, + SourceLocation EndLoc); + + /// Called on well-formed 'reverse_offload' clause. + OMPClause *ActOnOpenMPReverseOffloadClause(SourceLocation StartLoc, + SourceLocation EndLoc); + + /// Called on well-formed 'dynamic_allocators' clause. + OMPClause *ActOnOpenMPDynamicAllocatorsClause(SourceLocation StartLoc, + SourceLocation EndLoc); + + /// Called on well-formed 'atomic_default_mem_order' clause. + OMPClause *ActOnOpenMPAtomicDefaultMemOrderClause( + OpenMPAtomicDefaultMemOrderClauseKind Kind, SourceLocation KindLoc, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + + /// Called on well-formed 'at' clause. + OMPClause *ActOnOpenMPAtClause(OpenMPAtClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + + /// Called on well-formed 'severity' clause. + OMPClause *ActOnOpenMPSeverityClause(OpenMPSeverityClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + + /// Called on well-formed 'message' clause. + /// passing string for message. + OMPClause *ActOnOpenMPMessageClause(Expr *MS, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + + /// Data used for processing a list of variables in OpenMP clauses. + struct OpenMPVarListDataTy final { + Expr *DepModOrTailExpr = nullptr; + Expr *IteratorExpr = nullptr; + SourceLocation ColonLoc; + SourceLocation RLoc; + CXXScopeSpec ReductionOrMapperIdScopeSpec; + DeclarationNameInfo ReductionOrMapperId; + int ExtraModifier = -1; ///< Additional modifier for linear, map, depend or + ///< lastprivate clause. + SmallVector<OpenMPMapModifierKind, NumberOfOMPMapClauseModifiers> + MapTypeModifiers; + SmallVector<SourceLocation, NumberOfOMPMapClauseModifiers> + MapTypeModifiersLoc; + SmallVector<OpenMPMotionModifierKind, NumberOfOMPMotionModifiers> + MotionModifiers; + SmallVector<SourceLocation, NumberOfOMPMotionModifiers> MotionModifiersLoc; + bool IsMapTypeImplicit = false; + SourceLocation ExtraModifierLoc; + SourceLocation OmpAllMemoryLoc; + }; + + OMPClause *ActOnOpenMPVarListClause(OpenMPClauseKind Kind, + ArrayRef<Expr *> Vars, + const OMPVarListLocTy &Locs, + OpenMPVarListDataTy &Data); + /// Called on well-formed 'inclusive' clause. + OMPClause *ActOnOpenMPInclusiveClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'exclusive' clause. + OMPClause *ActOnOpenMPExclusiveClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'allocate' clause. + OMPClause * + ActOnOpenMPAllocateClause(Expr *Allocator, ArrayRef<Expr *> VarList, + SourceLocation StartLoc, SourceLocation ColonLoc, + SourceLocation LParenLoc, SourceLocation EndLoc); + /// Called on well-formed 'private' clause. + OMPClause *ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'firstprivate' clause. + OMPClause *ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'lastprivate' clause. + OMPClause *ActOnOpenMPLastprivateClause( + ArrayRef<Expr *> VarList, OpenMPLastprivateModifier LPKind, + SourceLocation LPKindLoc, SourceLocation ColonLoc, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// Called on well-formed 'shared' clause. + OMPClause *ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'reduction' clause. + OMPClause *ActOnOpenMPReductionClause( + ArrayRef<Expr *> VarList, OpenMPReductionClauseModifier Modifier, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId, + ArrayRef<Expr *> UnresolvedReductions = std::nullopt); + /// Called on well-formed 'task_reduction' clause. + OMPClause *ActOnOpenMPTaskReductionClause( + ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, + CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId, + ArrayRef<Expr *> UnresolvedReductions = std::nullopt); + /// Called on well-formed 'in_reduction' clause. + OMPClause *ActOnOpenMPInReductionClause( + ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, + CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId, + ArrayRef<Expr *> UnresolvedReductions = std::nullopt); + /// Called on well-formed 'linear' clause. + OMPClause * + ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, + SourceLocation StartLoc, SourceLocation LParenLoc, + OpenMPLinearClauseKind LinKind, SourceLocation LinLoc, + SourceLocation ColonLoc, SourceLocation EndLoc); + /// Called on well-formed 'aligned' clause. + OMPClause *ActOnOpenMPAlignedClause(ArrayRef<Expr *> VarList, + Expr *Alignment, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation ColonLoc, + SourceLocation EndLoc); + /// Called on well-formed 'copyin' clause. + OMPClause *ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'copyprivate' clause. + OMPClause *ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'flush' pseudo clause. + OMPClause *ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'depobj' pseudo clause. + OMPClause *ActOnOpenMPDepobjClause(Expr *Depobj, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'depend' clause. + OMPClause *ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data, + Expr *DepModifier, + ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'device' clause. + OMPClause *ActOnOpenMPDeviceClause(OpenMPDeviceClauseModifier Modifier, + Expr *Device, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation ModifierLoc, + SourceLocation EndLoc); + /// Called on well-formed 'map' clause. + OMPClause *ActOnOpenMPMapClause( + Expr *IteratorModifier, ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, + ArrayRef<SourceLocation> MapTypeModifiersLoc, + CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, + OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, + SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, + const OMPVarListLocTy &Locs, bool NoDiagnose = false, + ArrayRef<Expr *> UnresolvedMappers = std::nullopt); + /// Called on well-formed 'num_teams' clause. + OMPClause *ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'thread_limit' clause. + OMPClause *ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'priority' clause. + OMPClause *ActOnOpenMPPriorityClause(Expr *Priority, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// Called on well-formed 'dist_schedule' clause. + OMPClause *ActOnOpenMPDistScheduleClause( + OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation KindLoc, + SourceLocation CommaLoc, SourceLocation EndLoc); + /// Called on well-formed 'defaultmap' clause. + OMPClause *ActOnOpenMPDefaultmapClause( + OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc, + SourceLocation KindLoc, SourceLocation EndLoc); + /// Called on well-formed 'to' clause. + OMPClause * + ActOnOpenMPToClause(ArrayRef<OpenMPMotionModifierKind> MotionModifiers, + ArrayRef<SourceLocation> MotionModifiersLoc, + CXXScopeSpec &MapperIdScopeSpec, + DeclarationNameInfo &MapperId, SourceLocation ColonLoc, + ArrayRef<Expr *> VarList, const OMPVarListLocTy &Locs, + ArrayRef<Expr *> UnresolvedMappers = std::nullopt); + /// Called on well-formed 'from' clause. + OMPClause * + ActOnOpenMPFromClause(ArrayRef<OpenMPMotionModifierKind> MotionModifiers, + ArrayRef<SourceLocation> MotionModifiersLoc, + CXXScopeSpec &MapperIdScopeSpec, + DeclarationNameInfo &MapperId, SourceLocation ColonLoc, + ArrayRef<Expr *> VarList, const OMPVarListLocTy &Locs, + ArrayRef<Expr *> UnresolvedMappers = std::nullopt); + /// Called on well-formed 'use_device_ptr' clause. + OMPClause *ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList, + const OMPVarListLocTy &Locs); + /// Called on well-formed 'use_device_addr' clause. + OMPClause *ActOnOpenMPUseDeviceAddrClause(ArrayRef<Expr *> VarList, + const OMPVarListLocTy &Locs); + /// Called on well-formed 'is_device_ptr' clause. + OMPClause *ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList, + const OMPVarListLocTy &Locs); + /// Called on well-formed 'has_device_addr' clause. + OMPClause *ActOnOpenMPHasDeviceAddrClause(ArrayRef<Expr *> VarList, + const OMPVarListLocTy &Locs); + /// Called on well-formed 'nontemporal' clause. + OMPClause *ActOnOpenMPNontemporalClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + + /// Data for list of allocators. + struct UsesAllocatorsData { + /// Allocator. + Expr *Allocator = nullptr; + /// Allocator traits. + Expr *AllocatorTraits = nullptr; + /// Locations of '(' and ')' symbols. + SourceLocation LParenLoc, RParenLoc; + }; + /// Called on well-formed 'uses_allocators' clause. + OMPClause *ActOnOpenMPUsesAllocatorClause(SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + ArrayRef<UsesAllocatorsData> Data); + /// Called on well-formed 'affinity' clause. + OMPClause *ActOnOpenMPAffinityClause(SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation ColonLoc, + SourceLocation EndLoc, Expr *Modifier, + ArrayRef<Expr *> Locators); + /// Called on a well-formed 'bind' clause. + OMPClause *ActOnOpenMPBindClause(OpenMPBindClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + + /// Called on a well-formed 'ompx_dyn_cgroup_mem' clause. + OMPClause *ActOnOpenMPXDynCGroupMemClause(Expr *Size, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + + /// The kind of conversion being performed. + enum CheckedConversionKind { + /// An implicit conversion. + CCK_ImplicitConversion, + /// A C-style cast. + CCK_CStyleCast, + /// A functional-style cast. + CCK_FunctionalCast, + /// A cast other than a C-style cast. + CCK_OtherCast, + /// A conversion for an operand of a builtin overloaded operator. + CCK_ForBuiltinOverloadedOp + }; + + static bool isCast(CheckedConversionKind CCK) { + return CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast || + CCK == CCK_OtherCast; + } + + /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit + /// cast. If there is already an implicit cast, merge into the existing one. + /// If isLvalue, the result of the cast is an lvalue. + ExprResult + ImpCastExprToType(Expr *E, QualType Type, CastKind CK, + ExprValueKind VK = VK_PRValue, + const CXXCastPath *BasePath = nullptr, + CheckedConversionKind CCK = CCK_ImplicitConversion); + + /// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding + /// to the conversion from scalar type ScalarTy to the Boolean type. + static CastKind ScalarTypeToBooleanCastKind(QualType ScalarTy); + + /// IgnoredValueConversions - Given that an expression's result is + /// syntactically ignored, perform any conversions that are + /// required. + ExprResult IgnoredValueConversions(Expr *E); + + // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts + // functions and arrays to their respective pointers (C99 6.3.2.1). + ExprResult UsualUnaryConversions(Expr *E); + + /// CallExprUnaryConversions - a special case of an unary conversion + /// performed on a function designator of a call expression. + ExprResult CallExprUnaryConversions(Expr *E); + + // DefaultFunctionArrayConversion - converts functions and arrays + // to their respective pointers (C99 6.3.2.1). + ExprResult DefaultFunctionArrayConversion(Expr *E, bool Diagnose = true); + + // DefaultFunctionArrayLvalueConversion - converts functions and + // arrays to their respective pointers and performs the + // lvalue-to-rvalue conversion. + ExprResult DefaultFunctionArrayLvalueConversion(Expr *E, + bool Diagnose = true); + + // DefaultLvalueConversion - performs lvalue-to-rvalue conversion on + // the operand. This function is a no-op if the operand has a function type + // or an array type. + ExprResult DefaultLvalueConversion(Expr *E); + + // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that + // do not have a prototype. Integer promotions are performed on each + // argument, and arguments that have type float are promoted to double. + ExprResult DefaultArgumentPromotion(Expr *E); + + /// If \p E is a prvalue denoting an unmaterialized temporary, materialize + /// it as an xvalue. In C++98, the result will still be a prvalue, because + /// we don't have xvalues there. + ExprResult TemporaryMaterializationConversion(Expr *E); + + // Used for emitting the right warning by DefaultVariadicArgumentPromotion + enum VariadicCallType { + VariadicFunction, + VariadicBlock, + VariadicMethod, + VariadicConstructor, + VariadicDoesNotApply + }; + + VariadicCallType getVariadicCallType(FunctionDecl *FDecl, + const FunctionProtoType *Proto, + Expr *Fn); + + // Used for determining in which context a type is allowed to be passed to a + // vararg function. + enum VarArgKind { + VAK_Valid, + VAK_ValidInCXX11, + VAK_Undefined, + VAK_MSVCUndefined, + VAK_Invalid + }; + + // Determines which VarArgKind fits an expression. + VarArgKind isValidVarArgType(const QualType &Ty); + + /// Check to see if the given expression is a valid argument to a variadic + /// function, issuing a diagnostic if not. + void checkVariadicArgument(const Expr *E, VariadicCallType CT); + + /// Check whether the given statement can have musttail applied to it, + /// issuing a diagnostic and returning false if not. In the success case, + /// the statement is rewritten to remove implicit nodes from the return + /// value. + bool checkAndRewriteMustTailAttr(Stmt *St, const Attr &MTA); + +private: + /// Check whether the given statement can have musttail applied to it, + /// issuing a diagnostic and returning false if not. + bool checkMustTailAttr(const Stmt *St, const Attr &MTA); + +public: + /// Check to see if a given expression could have '.c_str()' called on it. + bool hasCStrMethod(const Expr *E); + + /// GatherArgumentsForCall - Collector argument expressions for various + /// form of call prototypes. + bool GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, + const FunctionProtoType *Proto, + unsigned FirstParam, ArrayRef<Expr *> Args, + SmallVectorImpl<Expr *> &AllArgs, + VariadicCallType CallType = VariadicDoesNotApply, + bool AllowExplicit = false, + bool IsListInitialization = false); + + // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but + // will create a runtime trap if the resulting type is not a POD type. + ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, + FunctionDecl *FDecl); + + /// Context in which we're performing a usual arithmetic conversion. + enum ArithConvKind { + /// An arithmetic operation. + ACK_Arithmetic, + /// A bitwise operation. + ACK_BitwiseOp, + /// A comparison. + ACK_Comparison, + /// A conditional (?:) operator. + ACK_Conditional, + /// A compound assignment expression. + ACK_CompAssign, + }; + + // UsualArithmeticConversions - performs the UsualUnaryConversions on it's + // operands and then handles various conversions that are common to binary + // operators (C99 6.3.1.8). If both operands aren't arithmetic, this + // routine returns the first non-arithmetic type found. The client is + // responsible for emitting appropriate error diagnostics. + QualType UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, ArithConvKind ACK); + + /// AssignConvertType - All of the 'assignment' semantic checks return this + /// enum to indicate whether the assignment was allowed. These checks are + /// done for simple assignments, as well as initialization, return from + /// function, argument passing, etc. The query is phrased in terms of a + /// source and destination type. + enum AssignConvertType { + /// Compatible - the types are compatible according to the standard. + Compatible, + + /// PointerToInt - The assignment converts a pointer to an int, which we + /// accept as an extension. + PointerToInt, + + /// IntToPointer - The assignment converts an int to a pointer, which we + /// accept as an extension. + IntToPointer, + + /// FunctionVoidPointer - The assignment is between a function pointer and + /// void*, which the standard doesn't allow, but we accept as an extension. + FunctionVoidPointer, + + /// IncompatiblePointer - The assignment is between two pointers types that + /// are not compatible, but we accept them as an extension. + IncompatiblePointer, + + /// IncompatibleFunctionPointer - The assignment is between two function + /// pointers types that are not compatible, but we accept them as an + /// extension. + IncompatibleFunctionPointer, + + /// IncompatibleFunctionPointerStrict - The assignment is between two + /// function pointer types that are not identical, but are compatible, + /// unless compiled with -fsanitize=cfi, in which case the type mismatch + /// may trip an indirect call runtime check. + IncompatibleFunctionPointerStrict, + + /// IncompatiblePointerSign - The assignment is between two pointers types + /// which point to integers which have a different sign, but are otherwise + /// identical. This is a subset of the above, but broken out because it's by + /// far the most common case of incompatible pointers. + IncompatiblePointerSign, + + /// CompatiblePointerDiscardsQualifiers - The assignment discards + /// c/v/r qualifiers, which we accept as an extension. + CompatiblePointerDiscardsQualifiers, + + /// IncompatiblePointerDiscardsQualifiers - The assignment + /// discards qualifiers that we don't permit to be discarded, + /// like address spaces. + IncompatiblePointerDiscardsQualifiers, + + /// IncompatibleNestedPointerAddressSpaceMismatch - The assignment + /// changes address spaces in nested pointer types which is not allowed. + /// For instance, converting __private int ** to __generic int ** is + /// illegal even though __private could be converted to __generic. + IncompatibleNestedPointerAddressSpaceMismatch, + + /// IncompatibleNestedPointerQualifiers - The assignment is between two + /// nested pointer types, and the qualifiers other than the first two + /// levels differ e.g. char ** -> const char **, but we accept them as an + /// extension. + IncompatibleNestedPointerQualifiers, + + /// IncompatibleVectors - The assignment is between two vector types that + /// have the same size, which we accept as an extension. + IncompatibleVectors, + + /// IntToBlockPointer - The assignment converts an int to a block + /// pointer. We disallow this. + IntToBlockPointer, + + /// IncompatibleBlockPointer - The assignment is between two block + /// pointers types that are not compatible. + IncompatibleBlockPointer, + + /// IncompatibleObjCQualifiedId - The assignment is between a qualified + /// id type and something else (that is incompatible with it). For example, + /// "id <XXX>" = "Foo *", where "Foo *" doesn't implement the XXX protocol. + IncompatibleObjCQualifiedId, + + /// IncompatibleObjCWeakRef - Assigning a weak-unavailable object to an + /// object with __weak qualifier. + IncompatibleObjCWeakRef, + + /// Incompatible - We reject this conversion outright, it is invalid to + /// represent it in the AST. + Incompatible + }; + + /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the + /// assignment conversion type specified by ConvTy. This returns true if the + /// conversion was invalid or false if the conversion was accepted. + bool DiagnoseAssignmentResult(AssignConvertType ConvTy, + SourceLocation Loc, + QualType DstType, QualType SrcType, + Expr *SrcExpr, AssignmentAction Action, + bool *Complained = nullptr); + + /// IsValueInFlagEnum - Determine if a value is allowed as part of a flag + /// enum. If AllowMask is true, then we also allow the complement of a valid + /// value, to be used as a mask. + bool IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val, + bool AllowMask) const; + + /// DiagnoseAssignmentEnum - Warn if assignment to enum is a constant + /// integer not in the range of enum values. + void DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, + Expr *SrcExpr); + + /// CheckAssignmentConstraints - Perform type checking for assignment, + /// argument passing, variable initialization, and function return values. + /// C99 6.5.16. + AssignConvertType CheckAssignmentConstraints(SourceLocation Loc, + QualType LHSType, + QualType RHSType); + + /// Check assignment constraints and optionally prepare for a conversion of + /// the RHS to the LHS type. The conversion is prepared for if ConvertRHS + /// is true. + AssignConvertType CheckAssignmentConstraints(QualType LHSType, + ExprResult &RHS, + CastKind &Kind, + bool ConvertRHS = true); + + /// Check assignment constraints for an assignment of RHS to LHSType. + /// + /// \param LHSType The destination type for the assignment. + /// \param RHS The source expression for the assignment. + /// \param Diagnose If \c true, diagnostics may be produced when checking + /// for assignability. If a diagnostic is produced, \p RHS will be + /// set to ExprError(). Note that this function may still return + /// without producing a diagnostic, even for an invalid assignment. + /// \param DiagnoseCFAudited If \c true, the target is a function parameter + /// in an audited Core Foundation API and does not need to be checked + /// for ARC retain issues. + /// \param ConvertRHS If \c true, \p RHS will be updated to model the + /// conversions necessary to perform the assignment. If \c false, + /// \p Diagnose must also be \c false. + AssignConvertType CheckSingleAssignmentConstraints( + QualType LHSType, ExprResult &RHS, bool Diagnose = true, + bool DiagnoseCFAudited = false, bool ConvertRHS = true); + + // If the lhs type is a transparent union, check whether we + // can initialize the transparent union with the given expression. + AssignConvertType CheckTransparentUnionArgumentConstraints(QualType ArgType, + ExprResult &RHS); + + bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); + + bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType); + + ExprResult PerformImplicitConversion(Expr *From, QualType ToType, + AssignmentAction Action, + bool AllowExplicit = false); + ExprResult PerformImplicitConversion(Expr *From, QualType ToType, + const ImplicitConversionSequence& ICS, + AssignmentAction Action, + CheckedConversionKind CCK + = CCK_ImplicitConversion); + ExprResult PerformImplicitConversion(Expr *From, QualType ToType, + const StandardConversionSequence& SCS, + AssignmentAction Action, + CheckedConversionKind CCK); + + ExprResult PerformQualificationConversion( + Expr *E, QualType Ty, ExprValueKind VK = VK_PRValue, + CheckedConversionKind CCK = CCK_ImplicitConversion); + + /// the following "Check" methods will return a valid/converted QualType + /// or a null QualType (indicating an error diagnostic was issued). + + /// type checking binary operators (subroutines of CreateBuiltinBinOp). + QualType InvalidOperands(SourceLocation Loc, ExprResult &LHS, + ExprResult &RHS); + QualType InvalidLogicalVectorOperands(SourceLocation Loc, ExprResult &LHS, + ExprResult &RHS); + QualType CheckPointerToMemberOperands( // C++ 5.5 + ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, + SourceLocation OpLoc, bool isIndirect); + QualType CheckMultiplyDivideOperands( // C99 6.5.5 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, + bool IsDivide); + QualType CheckRemainderOperands( // C99 6.5.5 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + bool IsCompAssign = false); + QualType CheckAdditionOperands( // C99 6.5.6 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + BinaryOperatorKind Opc, QualType* CompLHSTy = nullptr); + QualType CheckSubtractionOperands( // C99 6.5.6 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + QualType* CompLHSTy = nullptr); + QualType CheckShiftOperands( // C99 6.5.7 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + BinaryOperatorKind Opc, bool IsCompAssign = false); + void CheckPtrComparisonWithNullChar(ExprResult &E, ExprResult &NullE); + QualType CheckCompareOperands( // C99 6.5.8/9 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + BinaryOperatorKind Opc); + QualType CheckBitwiseOperands( // C99 6.5.[10...12] + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + BinaryOperatorKind Opc); + QualType CheckLogicalOperands( // C99 6.5.[13,14] + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + BinaryOperatorKind Opc); + // CheckAssignmentOperands is used for both simple and compound assignment. + // For simple assignment, pass both expressions and a null converted type. + // For compound assignment, pass both expressions and the converted type. + QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] + Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType, + BinaryOperatorKind Opc); + + ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc, + UnaryOperatorKind Opcode, Expr *Op); + ExprResult checkPseudoObjectAssignment(Scope *S, SourceLocation OpLoc, + BinaryOperatorKind Opcode, + Expr *LHS, Expr *RHS); + ExprResult checkPseudoObjectRValue(Expr *E); + Expr *recreateSyntacticForm(PseudoObjectExpr *E); + + QualType CheckConditionalOperands( // C99 6.5.15 + ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, + ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc); + QualType CXXCheckConditionalOperands( // C++ 5.16 + ExprResult &cond, ExprResult &lhs, ExprResult &rhs, + ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc); + QualType CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, + ExprResult &RHS, + SourceLocation QuestionLoc); + + QualType CheckSizelessVectorConditionalTypes(ExprResult &Cond, + ExprResult &LHS, ExprResult &RHS, + SourceLocation QuestionLoc); + QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, + bool ConvertArgs = true); + QualType FindCompositePointerType(SourceLocation Loc, + ExprResult &E1, ExprResult &E2, + bool ConvertArgs = true) { + Expr *E1Tmp = E1.get(), *E2Tmp = E2.get(); + QualType Composite = + FindCompositePointerType(Loc, E1Tmp, E2Tmp, ConvertArgs); + E1 = E1Tmp; + E2 = E2Tmp; + return Composite; + } + + QualType FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, + SourceLocation QuestionLoc); + + bool DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, + SourceLocation QuestionLoc); + + void DiagnoseAlwaysNonNullPointer(Expr *E, + Expr::NullPointerConstantKind NullType, + bool IsEqual, SourceRange Range); + + /// type checking for vector binary operators. + QualType CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, bool IsCompAssign, + bool AllowBothBool, bool AllowBoolConversion, + bool AllowBoolOperation, bool ReportInvalid); + QualType GetSignedVectorType(QualType V); + QualType GetSignedSizelessVectorType(QualType V); + QualType CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, + BinaryOperatorKind Opc); + QualType CheckSizelessVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, + BinaryOperatorKind Opc); + QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc); + + // type checking for sizeless vector binary operators. + QualType CheckSizelessVectorOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, bool IsCompAssign, + ArithConvKind OperationKind); + + /// Type checking for matrix binary operators. + QualType CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, + bool IsCompAssign); + QualType CheckMatrixMultiplyOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, bool IsCompAssign); + + bool isValidSveBitcast(QualType srcType, QualType destType); + + bool areMatrixTypesOfTheSameDimension(QualType srcTy, QualType destTy); + + bool areVectorTypesSameSize(QualType srcType, QualType destType); + bool areLaxCompatibleVectorTypes(QualType srcType, QualType destType); + bool isLaxVectorConversion(QualType srcType, QualType destType); + bool areSameVectorElemTypes(QualType srcType, QualType destType); + bool anyAltivecTypes(QualType srcType, QualType destType); + + /// type checking declaration initializers (C99 6.7.8) + bool CheckForConstantInitializer(Expr *e, QualType t); + + // type checking C++ declaration initializers (C++ [dcl.init]). + + /// ReferenceCompareResult - Expresses the result of comparing two + /// types (cv1 T1 and cv2 T2) to determine their compatibility for the + /// purposes of initialization by reference (C++ [dcl.init.ref]p4). + enum ReferenceCompareResult { + /// Ref_Incompatible - The two types are incompatible, so direct + /// reference binding is not possible. + Ref_Incompatible = 0, + /// Ref_Related - The two types are reference-related, which means + /// that their unqualified forms (T1 and T2) are either the same + /// or T1 is a base class of T2. + Ref_Related, + /// Ref_Compatible - The two types are reference-compatible. + Ref_Compatible + }; + + // Fake up a scoped enumeration that still contextually converts to bool. + struct ReferenceConversionsScope { + /// The conversions that would be performed on an lvalue of type T2 when + /// binding a reference of type T1 to it, as determined when evaluating + /// whether T1 is reference-compatible with T2. + enum ReferenceConversions { + Qualification = 0x1, + NestedQualification = 0x2, + Function = 0x4, + DerivedToBase = 0x8, + ObjC = 0x10, + ObjCLifetime = 0x20, + + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ObjCLifetime) + }; + }; + using ReferenceConversions = ReferenceConversionsScope::ReferenceConversions; + + ReferenceCompareResult + CompareReferenceRelationship(SourceLocation Loc, QualType T1, QualType T2, + ReferenceConversions *Conv = nullptr); + + ExprResult checkUnknownAnyCast(SourceRange TypeRange, QualType CastType, + Expr *CastExpr, CastKind &CastKind, + ExprValueKind &VK, CXXCastPath &Path); + + /// Force an expression with unknown-type to an expression of the + /// given type. + ExprResult forceUnknownAnyToType(Expr *E, QualType ToType); + + /// Type-check an expression that's being passed to an + /// __unknown_anytype parameter. + ExprResult checkUnknownAnyArg(SourceLocation callLoc, + Expr *result, QualType ¶mType); + + // CheckMatrixCast - Check type constraints for matrix casts. + // We allow casting between matrixes of the same dimensions i.e. when they + // have the same number of rows and column. Returns true if the cast is + // invalid. + bool CheckMatrixCast(SourceRange R, QualType DestTy, QualType SrcTy, + CastKind &Kind); + + // CheckVectorCast - check type constraints for vectors. + // Since vectors are an extension, there are no C standard reference for this. + // We allow casting between vectors and integer datatypes of the same size. + // returns true if the cast is invalid + bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, + CastKind &Kind); + + /// Prepare `SplattedExpr` for a vector splat operation, adding + /// implicit casts if necessary. + ExprResult prepareVectorSplat(QualType VectorTy, Expr *SplattedExpr); + + // CheckExtVectorCast - check type constraints for extended vectors. + // Since vectors are an extension, there are no C standard reference for this. + // We allow casting between vectors and integer datatypes of the same size, + // or vectors and the element type of that vector. + // returns the cast expr + ExprResult CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr, + CastKind &Kind); + + ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, QualType Type, + SourceLocation LParenLoc, + Expr *CastExpr, + SourceLocation RParenLoc); + + enum ARCConversionResult { ACR_okay, ACR_unbridged, ACR_error }; + + /// Checks for invalid conversions and casts between + /// retainable pointers and other pointer kinds for ARC and Weak. + ARCConversionResult CheckObjCConversion(SourceRange castRange, + QualType castType, Expr *&op, + CheckedConversionKind CCK, + bool Diagnose = true, + bool DiagnoseCFAudited = false, + BinaryOperatorKind Opc = BO_PtrMemD + ); + + Expr *stripARCUnbridgedCast(Expr *e); + void diagnoseARCUnbridgedCast(Expr *e); + + bool CheckObjCARCUnavailableWeakConversion(QualType castType, + QualType ExprType); + + /// checkRetainCycles - Check whether an Objective-C message send + /// might create an obvious retain cycle. + void checkRetainCycles(ObjCMessageExpr *msg); + void checkRetainCycles(Expr *receiver, Expr *argument); + void checkRetainCycles(VarDecl *Var, Expr *Init); + + /// checkUnsafeAssigns - Check whether +1 expr is being assigned + /// to weak/__unsafe_unretained type. + bool checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS); + + /// checkUnsafeExprAssigns - Check whether +1 expr is being assigned + /// to weak/__unsafe_unretained expression. + void checkUnsafeExprAssigns(SourceLocation Loc, Expr *LHS, Expr *RHS); + + /// CheckMessageArgumentTypes - Check types in an Obj-C message send. + /// \param Method - May be null. + /// \param [out] ReturnType - The return type of the send. + /// \return true iff there were any incompatible types. + bool CheckMessageArgumentTypes(const Expr *Receiver, QualType ReceiverType, + MultiExprArg Args, Selector Sel, + ArrayRef<SourceLocation> SelectorLocs, + ObjCMethodDecl *Method, bool isClassMessage, + bool isSuperMessage, SourceLocation lbrac, + SourceLocation rbrac, SourceRange RecRange, + QualType &ReturnType, ExprValueKind &VK); + + /// Determine the result of a message send expression based on + /// the type of the receiver, the method expected to receive the message, + /// and the form of the message send. + QualType getMessageSendResultType(const Expr *Receiver, QualType ReceiverType, + ObjCMethodDecl *Method, bool isClassMessage, + bool isSuperMessage); + + /// If the given expression involves a message send to a method + /// with a related result type, emit a note describing what happened. + void EmitRelatedResultTypeNote(const Expr *E); + + /// Given that we had incompatible pointer types in a return + /// statement, check whether we're in a method with a related result + /// type, and if so, emit a note describing what happened. + void EmitRelatedResultTypeNoteForReturn(QualType destType); + + class ConditionResult { + Decl *ConditionVar; + FullExprArg Condition; + bool Invalid; + bool HasKnownValue; + bool KnownValue; + + friend class Sema; + ConditionResult(Sema &S, Decl *ConditionVar, FullExprArg Condition, + bool IsConstexpr) + : ConditionVar(ConditionVar), Condition(Condition), Invalid(false), + HasKnownValue(IsConstexpr && Condition.get() && + !Condition.get()->isValueDependent()), + KnownValue(HasKnownValue && + !!Condition.get()->EvaluateKnownConstInt(S.Context)) {} + explicit ConditionResult(bool Invalid) + : ConditionVar(nullptr), Condition(nullptr), Invalid(Invalid), + HasKnownValue(false), KnownValue(false) {} + + public: + ConditionResult() : ConditionResult(false) {} + bool isInvalid() const { return Invalid; } + std::pair<VarDecl *, Expr *> get() const { + return std::make_pair(cast_or_null<VarDecl>(ConditionVar), + Condition.get()); + } + std::optional<bool> getKnownValue() const { + if (!HasKnownValue) + return std::nullopt; + return KnownValue; + } + }; + static ConditionResult ConditionError() { return ConditionResult(true); } + + enum class ConditionKind { + Boolean, ///< A boolean condition, from 'if', 'while', 'for', or 'do'. + ConstexprIf, ///< A constant boolean condition from 'if constexpr'. + Switch ///< An integral condition for a 'switch' statement. + }; + QualType PreferredConditionType(ConditionKind K) const { + return K == ConditionKind::Switch ? Context.IntTy : Context.BoolTy; + } + + ConditionResult ActOnCondition(Scope *S, SourceLocation Loc, Expr *SubExpr, + ConditionKind CK, bool MissingOK = false); + + ConditionResult ActOnConditionVariable(Decl *ConditionVar, + SourceLocation StmtLoc, + ConditionKind CK); + + DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D); + + ExprResult CheckConditionVariable(VarDecl *ConditionVar, + SourceLocation StmtLoc, + ConditionKind CK); + ExprResult CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond); + + /// CheckBooleanCondition - Diagnose problems involving the use of + /// the given expression as a boolean condition (e.g. in an if + /// statement). Also performs the standard function and array + /// decays, possibly changing the input variable. + /// + /// \param Loc - A location associated with the condition, e.g. the + /// 'if' keyword. + /// \return true iff there were any errors + ExprResult CheckBooleanCondition(SourceLocation Loc, Expr *E, + bool IsConstexpr = false); + + /// ActOnExplicitBoolSpecifier - Build an ExplicitSpecifier from an expression + /// found in an explicit(bool) specifier. + ExplicitSpecifier ActOnExplicitBoolSpecifier(Expr *E); + + /// tryResolveExplicitSpecifier - Attempt to resolve the explict specifier. + /// Returns true if the explicit specifier is now resolved. + bool tryResolveExplicitSpecifier(ExplicitSpecifier &ExplicitSpec); + + /// DiagnoseAssignmentAsCondition - Given that an expression is + /// being used as a boolean condition, warn if it's an assignment. + void DiagnoseAssignmentAsCondition(Expr *E); + + /// Redundant parentheses over an equality comparison can indicate + /// that the user intended an assignment used as condition. + void DiagnoseEqualityWithExtraParens(ParenExpr *ParenE); + + /// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid. + ExprResult CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr = false); + + /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have + /// the specified width and sign. If an overflow occurs, detect it and emit + /// the specified diagnostic. + void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal, + unsigned NewWidth, bool NewSign, + SourceLocation Loc, unsigned DiagID); + + /// Checks that the Objective-C declaration is declared in the global scope. + /// Emits an error and marks the declaration as invalid if it's not declared + /// in the global scope. + bool CheckObjCDeclScope(Decl *D); + + /// Abstract base class used for diagnosing integer constant + /// expression violations. + class VerifyICEDiagnoser { + public: + bool Suppress; + + VerifyICEDiagnoser(bool Suppress = false) : Suppress(Suppress) { } + + virtual SemaDiagnosticBuilder + diagnoseNotICEType(Sema &S, SourceLocation Loc, QualType T); + virtual SemaDiagnosticBuilder diagnoseNotICE(Sema &S, + SourceLocation Loc) = 0; + virtual SemaDiagnosticBuilder diagnoseFold(Sema &S, SourceLocation Loc); + virtual ~VerifyICEDiagnoser() {} + }; + + enum AllowFoldKind { + NoFold, + AllowFold, + }; + + /// VerifyIntegerConstantExpression - Verifies that an expression is an ICE, + /// and reports the appropriate diagnostics. Returns false on success. + /// Can optionally return the value of the expression. + ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, + VerifyICEDiagnoser &Diagnoser, + AllowFoldKind CanFold = NoFold); + ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, + unsigned DiagID, + AllowFoldKind CanFold = NoFold); + ExprResult VerifyIntegerConstantExpression(Expr *E, + llvm::APSInt *Result = nullptr, + AllowFoldKind CanFold = NoFold); + ExprResult VerifyIntegerConstantExpression(Expr *E, + AllowFoldKind CanFold = NoFold) { + return VerifyIntegerConstantExpression(E, nullptr, CanFold); + } + + /// VerifyBitField - verifies that a bit field expression is an ICE and has + /// the correct width, and that the field type is valid. + /// Returns false on success. + ExprResult VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, + QualType FieldTy, bool IsMsStruct, Expr *BitWidth); + +private: + unsigned ForceCUDAHostDeviceDepth = 0; + +public: + /// Increments our count of the number of times we've seen a pragma forcing + /// functions to be __host__ __device__. So long as this count is greater + /// than zero, all functions encountered will be __host__ __device__. + void PushForceCUDAHostDevice(); + + /// Decrements our count of the number of times we've seen a pragma forcing + /// functions to be __host__ __device__. Returns false if the count is 0 + /// before incrementing, so you can emit an error. + bool PopForceCUDAHostDevice(); + + /// Diagnostics that are emitted only if we discover that the given function + /// must be codegen'ed. Because handling these correctly adds overhead to + /// compilation, this is currently only enabled for CUDA compilations. + llvm::DenseMap<CanonicalDeclPtr<FunctionDecl>, + std::vector<PartialDiagnosticAt>> + DeviceDeferredDiags; + + /// A pair of a canonical FunctionDecl and a SourceLocation. When used as the + /// key in a hashtable, both the FD and location are hashed. + struct FunctionDeclAndLoc { + CanonicalDeclPtr<FunctionDecl> FD; + SourceLocation Loc; + }; + + /// FunctionDecls and SourceLocations for which CheckCUDACall has emitted a + /// (maybe deferred) "bad call" diagnostic. We use this to avoid emitting the + /// same deferred diag twice. + llvm::DenseSet<FunctionDeclAndLoc> LocsWithCUDACallDiags; + + /// An inverse call graph, mapping known-emitted functions to one of their + /// known-emitted callers (plus the location of the call). + /// + /// Functions that we can tell a priori must be emitted aren't added to this + /// map. + llvm::DenseMap</* Callee = */ CanonicalDeclPtr<FunctionDecl>, + /* Caller = */ FunctionDeclAndLoc> + DeviceKnownEmittedFns; + + /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current + /// context is "used as device code". + /// + /// - If CurContext is a __host__ function, does not emit any diagnostics + /// unless \p EmitOnBothSides is true. + /// - If CurContext is a __device__ or __global__ function, emits the + /// diagnostics immediately. + /// - If CurContext is a __host__ __device__ function and we are compiling for + /// the device, creates a diagnostic which is emitted if and when we realize + /// that the function will be codegen'ed. + /// + /// Example usage: + /// + /// // Variable-length arrays are not allowed in CUDA device code. + /// if (CUDADiagIfDeviceCode(Loc, diag::err_cuda_vla) << CurrentCUDATarget()) + /// return ExprError(); + /// // Otherwise, continue parsing as normal. + SemaDiagnosticBuilder CUDADiagIfDeviceCode(SourceLocation Loc, + unsigned DiagID); + + /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current + /// context is "used as host code". + /// + /// Same as CUDADiagIfDeviceCode, with "host" and "device" switched. + SemaDiagnosticBuilder CUDADiagIfHostCode(SourceLocation Loc, unsigned DiagID); + + /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current + /// context is "used as device code". + /// + /// - If CurContext is a `declare target` function or it is known that the + /// function is emitted for the device, emits the diagnostics immediately. + /// - If CurContext is a non-`declare target` function and we are compiling + /// for the device, creates a diagnostic which is emitted if and when we + /// realize that the function will be codegen'ed. + /// + /// Example usage: + /// + /// // Variable-length arrays are not allowed in NVPTX device code. + /// if (diagIfOpenMPDeviceCode(Loc, diag::err_vla_unsupported)) + /// return ExprError(); + /// // Otherwise, continue parsing as normal. + SemaDiagnosticBuilder + diagIfOpenMPDeviceCode(SourceLocation Loc, unsigned DiagID, FunctionDecl *FD); + + /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current + /// context is "used as host code". + /// + /// - If CurContext is a `declare target` function or it is known that the + /// function is emitted for the host, emits the diagnostics immediately. + /// - If CurContext is a non-host function, just ignore it. + /// + /// Example usage: + /// + /// // Variable-length arrays are not allowed in NVPTX device code. + /// if (diagIfOpenMPHostode(Loc, diag::err_vla_unsupported)) + /// return ExprError(); + /// // Otherwise, continue parsing as normal. + SemaDiagnosticBuilder diagIfOpenMPHostCode(SourceLocation Loc, + unsigned DiagID, FunctionDecl *FD); + + SemaDiagnosticBuilder targetDiag(SourceLocation Loc, unsigned DiagID, + FunctionDecl *FD = nullptr); + SemaDiagnosticBuilder targetDiag(SourceLocation Loc, + const PartialDiagnostic &PD, + FunctionDecl *FD = nullptr) { + return targetDiag(Loc, PD.getDiagID(), FD) << PD; + } + + /// Check if the type is allowed to be used for the current target. + void checkTypeSupport(QualType Ty, SourceLocation Loc, + ValueDecl *D = nullptr); + + enum CUDAFunctionTarget { + CFT_Device, + CFT_Global, + CFT_Host, + CFT_HostDevice, + CFT_InvalidTarget + }; + + /// Determines whether the given function is a CUDA device/host/kernel/etc. + /// function. + /// + /// Use this rather than examining the function's attributes yourself -- you + /// will get it wrong. Returns CFT_Host if D is null. + CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D, + bool IgnoreImplicitHDAttr = false); + CUDAFunctionTarget IdentifyCUDATarget(const ParsedAttributesView &Attrs); + + enum CUDAVariableTarget { + CVT_Device, /// Emitted on device side with a shadow variable on host side + CVT_Host, /// Emitted on host side only + CVT_Both, /// Emitted on both sides with different addresses + CVT_Unified, /// Emitted as a unified address, e.g. managed variables + }; + /// Determines whether the given variable is emitted on host or device side. + CUDAVariableTarget IdentifyCUDATarget(const VarDecl *D); + + /// Gets the CUDA target for the current context. + CUDAFunctionTarget CurrentCUDATarget() { + return IdentifyCUDATarget(dyn_cast<FunctionDecl>(CurContext)); + } + + static bool isCUDAImplicitHostDeviceFunction(const FunctionDecl *D); + + // CUDA function call preference. Must be ordered numerically from + // worst to best. + enum CUDAFunctionPreference { + CFP_Never, // Invalid caller/callee combination. + CFP_WrongSide, // Calls from host-device to host or device + // function that do not match current compilation + // mode. + CFP_HostDevice, // Any calls to host/device functions. + CFP_SameSide, // Calls from host-device to host or device + // function matching current compilation mode. + CFP_Native, // host-to-host or device-to-device calls. + }; + + /// Identifies relative preference of a given Caller/Callee + /// combination, based on their host/device attributes. + /// \param Caller function which needs address of \p Callee. + /// nullptr in case of global context. + /// \param Callee target function + /// + /// \returns preference value for particular Caller/Callee combination. + CUDAFunctionPreference IdentifyCUDAPreference(const FunctionDecl *Caller, + const FunctionDecl *Callee); + + /// Determines whether Caller may invoke Callee, based on their CUDA + /// host/device attributes. Returns false if the call is not allowed. + /// + /// Note: Will return true for CFP_WrongSide calls. These may appear in + /// semantically correct CUDA programs, but only if they're never codegen'ed. + bool IsAllowedCUDACall(const FunctionDecl *Caller, + const FunctionDecl *Callee) { + return IdentifyCUDAPreference(Caller, Callee) != CFP_Never; + } + + /// May add implicit CUDAHostAttr and CUDADeviceAttr attributes to FD, + /// depending on FD and the current compilation settings. + void maybeAddCUDAHostDeviceAttrs(FunctionDecl *FD, + const LookupResult &Previous); + + /// May add implicit CUDAConstantAttr attribute to VD, depending on VD + /// and current compilation settings. + void MaybeAddCUDAConstantAttr(VarDecl *VD); + +public: + /// Check whether we're allowed to call Callee from the current context. + /// + /// - If the call is never allowed in a semantically-correct program + /// (CFP_Never), emits an error and returns false. + /// + /// - If the call is allowed in semantically-correct programs, but only if + /// it's never codegen'ed (CFP_WrongSide), creates a deferred diagnostic to + /// be emitted if and when the caller is codegen'ed, and returns true. + /// + /// Will only create deferred diagnostics for a given SourceLocation once, + /// so you can safely call this multiple times without generating duplicate + /// deferred errors. + /// + /// - Otherwise, returns true without emitting any diagnostics. + bool CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee); + + void CUDACheckLambdaCapture(CXXMethodDecl *D, const sema::Capture &Capture); + + /// Set __device__ or __host__ __device__ attributes on the given lambda + /// operator() method. + /// + /// CUDA lambdas by default is host device function unless it has explicit + /// host or device attribute. + void CUDASetLambdaAttrs(CXXMethodDecl *Method); + + /// Finds a function in \p Matches with highest calling priority + /// from \p Caller context and erases all functions with lower + /// calling priority. + void EraseUnwantedCUDAMatches( + const FunctionDecl *Caller, + SmallVectorImpl<std::pair<DeclAccessPair, FunctionDecl *>> &Matches); + + /// Given a implicit special member, infer its CUDA target from the + /// calls it needs to make to underlying base/field special members. + /// \param ClassDecl the class for which the member is being created. + /// \param CSM the kind of special member. + /// \param MemberDecl the special member itself. + /// \param ConstRHS true if this is a copy operation with a const object on + /// its RHS. + /// \param Diagnose true if this call should emit diagnostics. + /// \return true if there was an error inferring. + /// The result of this call is implicit CUDA target attribute(s) attached to + /// the member declaration. + bool inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, + CXXSpecialMember CSM, + CXXMethodDecl *MemberDecl, + bool ConstRHS, + bool Diagnose); + + /// \return true if \p CD can be considered empty according to CUDA + /// (E.2.3.1 in CUDA 7.5 Programming guide). + bool isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD); + bool isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *CD); + + // \brief Checks that initializers of \p Var satisfy CUDA restrictions. In + // case of error emits appropriate diagnostic and invalidates \p Var. + // + // \details CUDA allows only empty constructors as initializers for global + // variables (see E.2.3.1, CUDA 7.5). The same restriction also applies to all + // __shared__ variables whether they are local or not (they all are implicitly + // static in CUDA). One exception is that CUDA allows constant initializers + // for __constant__ and __device__ variables. + void checkAllowedCUDAInitializer(VarDecl *VD); + + /// Check whether NewFD is a valid overload for CUDA. Emits + /// diagnostics and invalidates NewFD if not. + void checkCUDATargetOverload(FunctionDecl *NewFD, + const LookupResult &Previous); + /// Copies target attributes from the template TD to the function FD. + void inheritCUDATargetAttrs(FunctionDecl *FD, const FunctionTemplateDecl &TD); + + /// Returns the name of the launch configuration function. This is the name + /// of the function that will be called to configure kernel call, with the + /// parameters specified via <<<>>>. + std::string getCudaConfigureFuncName() const; + + /// \name Code completion + //@{ + /// Describes the context in which code completion occurs. + enum ParserCompletionContext { + /// Code completion occurs at top-level or namespace context. + PCC_Namespace, + /// Code completion occurs within a class, struct, or union. + PCC_Class, + /// Code completion occurs within an Objective-C interface, protocol, + /// or category. + PCC_ObjCInterface, + /// Code completion occurs within an Objective-C implementation or + /// category implementation + PCC_ObjCImplementation, + /// Code completion occurs within the list of instance variables + /// in an Objective-C interface, protocol, category, or implementation. + PCC_ObjCInstanceVariableList, + /// Code completion occurs following one or more template + /// headers. + PCC_Template, + /// Code completion occurs following one or more template + /// headers within a class. + PCC_MemberTemplate, + /// Code completion occurs within an expression. + PCC_Expression, + /// Code completion occurs within a statement, which may + /// also be an expression or a declaration. + PCC_Statement, + /// Code completion occurs at the beginning of the + /// initialization statement (or expression) in a for loop. + PCC_ForInit, + /// Code completion occurs within the condition of an if, + /// while, switch, or for statement. + PCC_Condition, + /// Code completion occurs within the body of a function on a + /// recovery path, where we do not have a specific handle on our position + /// in the grammar. + PCC_RecoveryInFunction, + /// Code completion occurs where only a type is permitted. + PCC_Type, + /// Code completion occurs in a parenthesized expression, which + /// might also be a type cast. + PCC_ParenthesizedExpression, + /// Code completion occurs within a sequence of declaration + /// specifiers within a function, method, or block. + PCC_LocalDeclarationSpecifiers + }; + + void CodeCompleteModuleImport(SourceLocation ImportLoc, ModuleIdPath Path); + void CodeCompleteOrdinaryName(Scope *S, + ParserCompletionContext CompletionContext); + void CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, + bool AllowNonIdentifiers, + bool AllowNestedNameSpecifiers); + + struct CodeCompleteExpressionData; + void CodeCompleteExpression(Scope *S, + const CodeCompleteExpressionData &Data); + void CodeCompleteExpression(Scope *S, QualType PreferredType, + bool IsParenthesized = false); + void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Expr *OtherOpBase, + SourceLocation OpLoc, bool IsArrow, + bool IsBaseExprStatement, + QualType PreferredType); + void CodeCompletePostfixExpression(Scope *S, ExprResult LHS, + QualType PreferredType); + void CodeCompleteTag(Scope *S, unsigned TagSpec); + void CodeCompleteTypeQualifiers(DeclSpec &DS); + void CodeCompleteFunctionQualifiers(DeclSpec &DS, Declarator &D, + const VirtSpecifiers *VS = nullptr); + void CodeCompleteBracketDeclarator(Scope *S); + void CodeCompleteCase(Scope *S); + enum class AttributeCompletion { + Attribute, + Scope, + None, + }; + void CodeCompleteAttribute( + AttributeCommonInfo::Syntax Syntax, + AttributeCompletion Completion = AttributeCompletion::Attribute, + const IdentifierInfo *Scope = nullptr); + /// Determines the preferred type of the current function argument, by + /// examining the signatures of all possible overloads. + /// Returns null if unknown or ambiguous, or if code completion is off. + /// + /// If the code completion point has been reached, also reports the function + /// signatures that were considered. + /// + /// FIXME: rename to GuessCallArgumentType to reduce confusion. + QualType ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args, + SourceLocation OpenParLoc); + QualType ProduceConstructorSignatureHelp(QualType Type, SourceLocation Loc, + ArrayRef<Expr *> Args, + SourceLocation OpenParLoc, + bool Braced); + QualType ProduceCtorInitMemberSignatureHelp( + Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy, + ArrayRef<Expr *> ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc, + bool Braced); + QualType ProduceTemplateArgumentSignatureHelp( + TemplateTy, ArrayRef<ParsedTemplateArgument>, SourceLocation LAngleLoc); + void CodeCompleteInitializer(Scope *S, Decl *D); + /// Trigger code completion for a record of \p BaseType. \p InitExprs are + /// expressions in the initializer list seen so far and \p D is the current + /// Designation being parsed. + void CodeCompleteDesignator(const QualType BaseType, + llvm::ArrayRef<Expr *> InitExprs, + const Designation &D); + void CodeCompleteAfterIf(Scope *S, bool IsBracedThen); + + void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext, + bool IsUsingDeclaration, QualType BaseType, + QualType PreferredType); + void CodeCompleteUsing(Scope *S); + void CodeCompleteUsingDirective(Scope *S); + void CodeCompleteNamespaceDecl(Scope *S); + void CodeCompleteNamespaceAliasDecl(Scope *S); + void CodeCompleteOperatorName(Scope *S); + void CodeCompleteConstructorInitializer( + Decl *Constructor, + ArrayRef<CXXCtorInitializer *> Initializers); + + void CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro, + bool AfterAmpersand); + void CodeCompleteAfterFunctionEquals(Declarator &D); + + void CodeCompleteObjCAtDirective(Scope *S); + void CodeCompleteObjCAtVisibility(Scope *S); + void CodeCompleteObjCAtStatement(Scope *S); + void CodeCompleteObjCAtExpression(Scope *S); + void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); + void CodeCompleteObjCPropertyGetter(Scope *S); + void CodeCompleteObjCPropertySetter(Scope *S); + void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, + bool IsParameter); + void CodeCompleteObjCMessageReceiver(Scope *S); + void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, + ArrayRef<IdentifierInfo *> SelIdents, + bool AtArgumentExpression); + void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, + ArrayRef<IdentifierInfo *> SelIdents, + bool AtArgumentExpression, + bool IsSuper = false); + void CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, + ArrayRef<IdentifierInfo *> SelIdents, + bool AtArgumentExpression, + ObjCInterfaceDecl *Super = nullptr); + void CodeCompleteObjCForCollection(Scope *S, + DeclGroupPtrTy IterationVar); + void CodeCompleteObjCSelector(Scope *S, + ArrayRef<IdentifierInfo *> SelIdents); + void CodeCompleteObjCProtocolReferences( + ArrayRef<IdentifierLocPair> Protocols); + void CodeCompleteObjCProtocolDecl(Scope *S); + void CodeCompleteObjCInterfaceDecl(Scope *S); + void CodeCompleteObjCSuperclass(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); + void CodeCompleteObjCImplementationDecl(Scope *S); + void CodeCompleteObjCInterfaceCategory(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); + void CodeCompleteObjCImplementationCategory(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); + void CodeCompleteObjCPropertyDefinition(Scope *S); + void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, + IdentifierInfo *PropertyName); + void CodeCompleteObjCMethodDecl(Scope *S, + std::optional<bool> IsInstanceMethod, + ParsedType ReturnType); + void CodeCompleteObjCMethodDeclSelector(Scope *S, + bool IsInstanceMethod, + bool AtParameterName, + ParsedType ReturnType, + ArrayRef<IdentifierInfo *> SelIdents); + void CodeCompleteObjCClassPropertyRefExpr(Scope *S, IdentifierInfo &ClassName, + SourceLocation ClassNameLoc, + bool IsBaseExprStatement); + void CodeCompletePreprocessorDirective(bool InConditional); + void CodeCompleteInPreprocessorConditionalExclusion(Scope *S); + void CodeCompletePreprocessorMacroName(bool IsDefinition); + void CodeCompletePreprocessorExpression(); + void CodeCompletePreprocessorMacroArgument(Scope *S, + IdentifierInfo *Macro, + MacroInfo *MacroInfo, + unsigned Argument); + void CodeCompleteIncludedFile(llvm::StringRef Dir, bool IsAngled); + void CodeCompleteNaturalLanguage(); + void CodeCompleteAvailabilityPlatformName(); + void GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo, + SmallVectorImpl<CodeCompletionResult> &Results); + //@} + + //===--------------------------------------------------------------------===// + // Extra semantic analysis beyond the C type system + +public: + SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL, + unsigned ByteNo) const; + + enum FormatArgumentPassingKind { + FAPK_Fixed, // values to format are fixed (no C-style variadic arguments) + FAPK_Variadic, // values to format are passed as variadic arguments + FAPK_VAList, // values to format are passed in a va_list + }; + + // Used to grab the relevant information from a FormatAttr and a + // FunctionDeclaration. + struct FormatStringInfo { + unsigned FormatIdx; + unsigned FirstDataArg; + FormatArgumentPassingKind ArgPassingKind; + }; + + static bool getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, + bool IsVariadic, FormatStringInfo *FSI); + +private: + void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, + const ArraySubscriptExpr *ASE = nullptr, + bool AllowOnePastEnd = true, bool IndexNegated = false); + void CheckArrayAccess(const Expr *E); + + bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, + const FunctionProtoType *Proto); + bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc, + ArrayRef<const Expr *> Args); + bool CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, + const FunctionProtoType *Proto); + bool CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto); + void CheckConstructorCall(FunctionDecl *FDecl, QualType ThisType, + ArrayRef<const Expr *> Args, + const FunctionProtoType *Proto, SourceLocation Loc); + + void checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg); + + void CheckArgAlignment(SourceLocation Loc, NamedDecl *FDecl, + StringRef ParamName, QualType ArgTy, QualType ParamTy); + + void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, + const Expr *ThisArg, ArrayRef<const Expr *> Args, + bool IsMemberFunction, SourceLocation Loc, SourceRange Range, + VariadicCallType CallType); + + bool CheckObjCString(Expr *Arg); + ExprResult CheckOSLogFormatStringArg(Expr *Arg); + + ExprResult CheckBuiltinFunctionCall(FunctionDecl *FDecl, + unsigned BuiltinID, CallExpr *TheCall); + + bool CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + + void checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, CallExpr *TheCall); + + bool CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, + unsigned MaxWidth); + bool CheckNeonBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + bool CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckCDEBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + bool CheckARMCoprocessorImmediate(const TargetInfo &TI, const Expr *CoprocArg, + bool WantCDE); + bool CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + + bool CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + bool CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall); + bool CheckMipsBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + bool CheckMipsBuiltinCpu(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + bool CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall); + bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall); + bool CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, CallExpr *TheCall); + bool CheckX86BuiltinTileArguments(unsigned BuiltinID, CallExpr *TheCall); + bool CheckX86BuiltinTileArgumentsRange(CallExpr *TheCall, + ArrayRef<int> ArgNums); + bool CheckX86BuiltinTileDuplicate(CallExpr *TheCall, ArrayRef<int> ArgNums); + bool CheckX86BuiltinTileRangeAndDuplicate(CallExpr *TheCall, + ArrayRef<int> ArgNums); + bool CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + bool CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + bool CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum); + bool CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); + bool CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, CallExpr *TheCall); + + bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); + bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call); + bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); + bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); + bool SemaBuiltinComplex(CallExpr *TheCall); + bool SemaBuiltinVSX(CallExpr *TheCall); + bool SemaBuiltinOSLogFormat(CallExpr *TheCall); + bool SemaValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum); + +public: + // Used by C++ template instantiation. + ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall); + ExprResult SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc); + +private: + bool SemaBuiltinPrefetch(CallExpr *TheCall); + bool SemaBuiltinAllocaWithAlign(CallExpr *TheCall); + bool SemaBuiltinArithmeticFence(CallExpr *TheCall); + bool SemaBuiltinAssume(CallExpr *TheCall); + bool SemaBuiltinAssumeAligned(CallExpr *TheCall); + bool SemaBuiltinLongjmp(CallExpr *TheCall); + bool SemaBuiltinSetjmp(CallExpr *TheCall); + ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult); + ExprResult SemaBuiltinNontemporalOverloaded(ExprResult TheCallResult); + ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult, + AtomicExpr::AtomicOp Op); + ExprResult SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, + bool IsDelete); + bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, + llvm::APSInt &Result); + bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, + int High, bool RangeIsError = true); + bool SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, + unsigned Multiple); + bool SemaBuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum); + bool SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, + unsigned ArgBits); + bool SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, int ArgNum, + unsigned ArgBits); + bool SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, + int ArgNum, unsigned ExpectedFieldNum, + bool AllowName); + bool SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall); + bool SemaBuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, + const char *TypeDesc); + + bool CheckPPCMMAType(QualType Type, SourceLocation TypeLoc); + + bool SemaBuiltinElementwiseMath(CallExpr *TheCall); + bool PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall); + bool PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall); + + // Matrix builtin handling. + ExprResult SemaBuiltinMatrixTranspose(CallExpr *TheCall, + ExprResult CallResult); + ExprResult SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall, + ExprResult CallResult); + ExprResult SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall, + ExprResult CallResult); + +public: + enum FormatStringType { + FST_Scanf, + FST_Printf, + FST_NSString, + FST_Strftime, + FST_Strfmon, + FST_Kprintf, + FST_FreeBSDKPrintf, + FST_OSTrace, + FST_OSLog, + FST_Unknown + }; + static FormatStringType GetFormatStringType(const FormatAttr *Format); + + bool FormatStringHasSArg(const StringLiteral *FExpr); + + static bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx); + +private: + bool CheckFormatArguments(const FormatAttr *Format, + ArrayRef<const Expr *> Args, bool IsCXXMember, + VariadicCallType CallType, SourceLocation Loc, + SourceRange Range, + llvm::SmallBitVector &CheckedVarArgs); + bool CheckFormatArguments(ArrayRef<const Expr *> Args, + FormatArgumentPassingKind FAPK, unsigned format_idx, + unsigned firstDataArg, FormatStringType Type, + VariadicCallType CallType, SourceLocation Loc, + SourceRange range, + llvm::SmallBitVector &CheckedVarArgs); + + void CheckAbsoluteValueFunction(const CallExpr *Call, + const FunctionDecl *FDecl); + + void CheckMaxUnsignedZero(const CallExpr *Call, const FunctionDecl *FDecl); + + void CheckMemaccessArguments(const CallExpr *Call, + unsigned BId, + IdentifierInfo *FnName); + + void CheckStrlcpycatArguments(const CallExpr *Call, + IdentifierInfo *FnName); + + void CheckStrncatArguments(const CallExpr *Call, + IdentifierInfo *FnName); + + void CheckFreeArguments(const CallExpr *E); + + void CheckReturnValExpr(Expr *RetValExp, QualType lhsType, + SourceLocation ReturnLoc, + bool isObjCMethod = false, + const AttrVec *Attrs = nullptr, + const FunctionDecl *FD = nullptr); + +public: + void CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS, + BinaryOperatorKind Opcode); + +private: + void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation()); + void CheckBoolLikeConversion(Expr *E, SourceLocation CC); + void CheckForIntOverflow(Expr *E); + void CheckUnsequencedOperations(const Expr *E); + + /// Perform semantic checks on a completed expression. This will either + /// be a full-expression or a default argument expression. + void CheckCompletedExpr(Expr *E, SourceLocation CheckLoc = SourceLocation(), + bool IsConstexpr = false); + + void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field, + Expr *Init); + + /// Check if there is a field shadowing. + void CheckShadowInheritedFields(const SourceLocation &Loc, + DeclarationName FieldName, + const CXXRecordDecl *RD, + bool DeclIsField = true); + + /// Check if the given expression contains 'break' or 'continue' + /// statement that produces control flow different from GCC. + void CheckBreakContinueBinding(Expr *E); + + /// Check whether receiver is mutable ObjC container which + /// attempts to add itself into the container + void CheckObjCCircularContainer(ObjCMessageExpr *Message); + + void CheckTCBEnforcement(const SourceLocation CallExprLoc, + const NamedDecl *Callee); + + void AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE); + void AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, + bool DeleteWasArrayForm); +public: + /// Register a magic integral constant to be used as a type tag. + void RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, + uint64_t MagicValue, QualType Type, + bool LayoutCompatible, bool MustBeNull); + + struct TypeTagData { + TypeTagData() {} + + TypeTagData(QualType Type, bool LayoutCompatible, bool MustBeNull) : + Type(Type), LayoutCompatible(LayoutCompatible), + MustBeNull(MustBeNull) + {} + + QualType Type; + + /// If true, \c Type should be compared with other expression's types for + /// layout-compatibility. + unsigned LayoutCompatible : 1; + unsigned MustBeNull : 1; + }; + + /// A pair of ArgumentKind identifier and magic value. This uniquely + /// identifies the magic value. + typedef std::pair<const IdentifierInfo *, uint64_t> TypeTagMagicValue; + +private: + /// A map from magic value to type information. + std::unique_ptr<llvm::DenseMap<TypeTagMagicValue, TypeTagData>> + TypeTagForDatatypeMagicValues; + + /// Peform checks on a call of a function with argument_with_type_tag + /// or pointer_with_type_tag attributes. + void CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, + const ArrayRef<const Expr *> ExprArgs, + SourceLocation CallSiteLoc); + + /// Check if we are taking the address of a packed field + /// as this may be a problem if the pointer value is dereferenced. + void CheckAddressOfPackedMember(Expr *rhs); + + /// The parser's current scope. + /// + /// The parser maintains this state here. + Scope *CurScope; + + mutable IdentifierInfo *Ident_super; + mutable IdentifierInfo *Ident___float128; + + /// Nullability type specifiers. + IdentifierInfo *Ident__Nonnull = nullptr; + IdentifierInfo *Ident__Nullable = nullptr; + IdentifierInfo *Ident__Nullable_result = nullptr; + IdentifierInfo *Ident__Null_unspecified = nullptr; + + IdentifierInfo *Ident_NSError = nullptr; + + /// The handler for the FileChanged preprocessor events. + /// + /// Used for diagnostics that implement custom semantic analysis for #include + /// directives, like -Wpragma-pack. + sema::SemaPPCallbacks *SemaPPCallbackHandler; + +protected: + friend class Parser; + friend class InitializationSequence; + friend class ASTReader; + friend class ASTDeclReader; + friend class ASTWriter; + +public: + /// Retrieve the keyword associated + IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability); + + /// The struct behind the CFErrorRef pointer. + RecordDecl *CFError = nullptr; + bool isCFError(RecordDecl *D); + + /// Retrieve the identifier "NSError". + IdentifierInfo *getNSErrorIdent(); + + /// Retrieve the parser's current scope. + /// + /// This routine must only be used when it is certain that semantic analysis + /// and the parser are in precisely the same context, which is not the case + /// when, e.g., we are performing any kind of template instantiation. + /// Therefore, the only safe places to use this scope are in the parser + /// itself and in routines directly invoked from the parser and *never* from + /// template substitution or instantiation. + Scope *getCurScope() const { return CurScope; } + + void incrementMSManglingNumber() const { + return CurScope->incrementMSManglingNumber(); + } + + IdentifierInfo *getSuperIdentifier() const; + IdentifierInfo *getFloat128Identifier() const; + + ObjCContainerDecl *getObjCDeclContext() const; + + DeclContext *getCurLexicalContext() const { + return OriginalLexicalContext ? OriginalLexicalContext : CurContext; + } + + const DeclContext *getCurObjCLexicalContext() const { + const DeclContext *DC = getCurLexicalContext(); + // A category implicitly has the attribute of the interface. + if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(DC)) + DC = CatD->getClassInterface(); + return DC; + } + + /// Determine the number of levels of enclosing template parameters. This is + /// only usable while parsing. Note that this does not include dependent + /// contexts in which no template parameters have yet been declared, such as + /// in a terse function template or generic lambda before the first 'auto' is + /// encountered. + unsigned getTemplateDepth(Scope *S) const; + + /// To be used for checking whether the arguments being passed to + /// function exceeds the number of parameters expected for it. + static bool TooManyArguments(size_t NumParams, size_t NumArgs, + bool PartialOverloading = false) { + // We check whether we're just after a comma in code-completion. + if (NumArgs > 0 && PartialOverloading) + return NumArgs + 1 > NumParams; // If so, we view as an extra argument. + return NumArgs > NumParams; + } + + // Emitting members of dllexported classes is delayed until the class + // (including field initializers) is fully parsed. + SmallVector<CXXRecordDecl*, 4> DelayedDllExportClasses; + SmallVector<CXXMethodDecl*, 4> DelayedDllExportMemberFunctions; + +private: + int ParsingClassDepth = 0; + + class SavePendingParsedClassStateRAII { + public: + SavePendingParsedClassStateRAII(Sema &S) : S(S) { swapSavedState(); } + + ~SavePendingParsedClassStateRAII() { + assert(S.DelayedOverridingExceptionSpecChecks.empty() && + "there shouldn't be any pending delayed exception spec checks"); + assert(S.DelayedEquivalentExceptionSpecChecks.empty() && + "there shouldn't be any pending delayed exception spec checks"); + swapSavedState(); + } + + private: + Sema &S; + decltype(DelayedOverridingExceptionSpecChecks) + SavedOverridingExceptionSpecChecks; + decltype(DelayedEquivalentExceptionSpecChecks) + SavedEquivalentExceptionSpecChecks; + + void swapSavedState() { + SavedOverridingExceptionSpecChecks.swap( + S.DelayedOverridingExceptionSpecChecks); + SavedEquivalentExceptionSpecChecks.swap( + S.DelayedEquivalentExceptionSpecChecks); + } + }; + + /// Helper class that collects misaligned member designations and + /// their location info for delayed diagnostics. + struct MisalignedMember { + Expr *E; + RecordDecl *RD; + ValueDecl *MD; + CharUnits Alignment; + + MisalignedMember() : E(), RD(), MD() {} + MisalignedMember(Expr *E, RecordDecl *RD, ValueDecl *MD, + CharUnits Alignment) + : E(E), RD(RD), MD(MD), Alignment(Alignment) {} + explicit MisalignedMember(Expr *E) + : MisalignedMember(E, nullptr, nullptr, CharUnits()) {} + + bool operator==(const MisalignedMember &m) { return this->E == m.E; } + }; + /// Small set of gathered accesses to potentially misaligned members + /// due to the packed attribute. + SmallVector<MisalignedMember, 4> MisalignedMembers; + + /// Adds an expression to the set of gathered misaligned members. + void AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD, + CharUnits Alignment); + +public: + /// Diagnoses the current set of gathered accesses. This typically + /// happens at full expression level. The set is cleared after emitting the + /// diagnostics. + void DiagnoseMisalignedMembers(); + + /// This function checks if the expression is in the sef of potentially + /// misaligned members and it is converted to some pointer type T with lower + /// or equal alignment requirements. If so it removes it. This is used when + /// we do not want to diagnose such misaligned access (e.g. in conversions to + /// void*). + void DiscardMisalignedMemberAddress(const Type *T, Expr *E); + + /// This function calls Action when it determines that E designates a + /// misaligned member due to the packed attribute. This is used to emit + /// local diagnostics like in reference binding. + void RefersToMemberWithReducedAlignment( + Expr *E, + llvm::function_ref<void(Expr *, RecordDecl *, FieldDecl *, CharUnits)> + Action); + + /// Describes the reason a calling convention specification was ignored, used + /// for diagnostics. + enum class CallingConventionIgnoredReason { + ForThisTarget = 0, + VariadicFunction, + ConstructorDestructor, + BuiltinFunction + }; + /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current + /// context is "used as device code". + /// + /// - If CurLexicalContext is a kernel function or it is known that the + /// function will be emitted for the device, emits the diagnostics + /// immediately. + /// - If CurLexicalContext is a function and we are compiling + /// for the device, but we don't know that this function will be codegen'ed + /// for devive yet, creates a diagnostic which is emitted if and when we + /// realize that the function will be codegen'ed. + /// + /// Example usage: + /// + /// Diagnose __float128 type usage only from SYCL device code if the current + /// target doesn't support it + /// if (!S.Context.getTargetInfo().hasFloat128Type() && + /// S.getLangOpts().SYCLIsDevice) + /// SYCLDiagIfDeviceCode(Loc, diag::err_type_unsupported) << "__float128"; + SemaDiagnosticBuilder SYCLDiagIfDeviceCode(SourceLocation Loc, + unsigned DiagID); + + /// Check whether we're allowed to call Callee from the current context. + /// + /// - If the call is never allowed in a semantically-correct program + /// emits an error and returns false. + /// + /// - If the call is allowed in semantically-correct programs, but only if + /// it's never codegen'ed, creates a deferred diagnostic to be emitted if + /// and when the caller is codegen'ed, and returns true. + /// + /// - Otherwise, returns true without emitting any diagnostics. + /// + /// Adds Callee to DeviceCallGraph if we don't know if its caller will be + /// codegen'ed yet. + bool checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee); + void deepTypeCheckForSYCLDevice(SourceLocation UsedAt, + llvm::DenseSet<QualType> Visited, + ValueDecl *DeclToCheck); +}; + +/// RAII object that enters a new expression evaluation context. +class EnterExpressionEvaluationContext { + Sema &Actions; + bool Entered = true; + +public: + EnterExpressionEvaluationContext( + Sema &Actions, Sema::ExpressionEvaluationContext NewContext, + Decl *LambdaContextDecl = nullptr, + Sema::ExpressionEvaluationContextRecord::ExpressionKind ExprContext = + Sema::ExpressionEvaluationContextRecord::EK_Other, + bool ShouldEnter = true) + : Actions(Actions), Entered(ShouldEnter) { + if (Entered) + Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl, + ExprContext); + } + EnterExpressionEvaluationContext( + Sema &Actions, Sema::ExpressionEvaluationContext NewContext, + Sema::ReuseLambdaContextDecl_t, + Sema::ExpressionEvaluationContextRecord::ExpressionKind ExprContext = + Sema::ExpressionEvaluationContextRecord::EK_Other) + : Actions(Actions) { + Actions.PushExpressionEvaluationContext( + NewContext, Sema::ReuseLambdaContextDecl, ExprContext); + } + + enum InitListTag { InitList }; + EnterExpressionEvaluationContext(Sema &Actions, InitListTag, + bool ShouldEnter = true) + : Actions(Actions), Entered(false) { + // In C++11 onwards, narrowing checks are performed on the contents of + // braced-init-lists, even when they occur within unevaluated operands. + // Therefore we still need to instantiate constexpr functions used in such + // a context. + if (ShouldEnter && Actions.isUnevaluatedContext() && + Actions.getLangOpts().CPlusPlus11) { + Actions.PushExpressionEvaluationContext( + Sema::ExpressionEvaluationContext::UnevaluatedList); + Entered = true; + } + } + + ~EnterExpressionEvaluationContext() { + if (Entered) + Actions.PopExpressionEvaluationContext(); + } +}; + +DeductionFailureInfo +MakeDeductionFailureInfo(ASTContext &Context, Sema::TemplateDeductionResult TDK, + sema::TemplateDeductionInfo &Info); + +/// Contains a late templated function. +/// Will be parsed at the end of the translation unit, used by Sema & Parser. +struct LateParsedTemplate { + CachedTokens Toks; + /// The template function declaration to be late parsed. + Decl *D; +}; + +template <> +void Sema::PragmaStack<Sema::AlignPackInfo>::Act(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + AlignPackInfo Value); + +std::unique_ptr<sema::RISCVIntrinsicManager> +CreateRISCVIntrinsicManager(Sema &S); +} // end namespace clang + +namespace llvm { +// Hash a FunctionDeclAndLoc by looking at both its FunctionDecl and its +// SourceLocation. +template <> struct DenseMapInfo<clang::Sema::FunctionDeclAndLoc> { + using FunctionDeclAndLoc = clang::Sema::FunctionDeclAndLoc; + using FDBaseInfo = DenseMapInfo<clang::CanonicalDeclPtr<clang::FunctionDecl>>; + + static FunctionDeclAndLoc getEmptyKey() { + return {FDBaseInfo::getEmptyKey(), clang::SourceLocation()}; + } + + static FunctionDeclAndLoc getTombstoneKey() { + return {FDBaseInfo::getTombstoneKey(), clang::SourceLocation()}; + } + + static unsigned getHashValue(const FunctionDeclAndLoc &FDL) { + return hash_combine(FDBaseInfo::getHashValue(FDL.FD), + FDL.Loc.getHashValue()); + } + + static bool isEqual(const FunctionDeclAndLoc &LHS, + const FunctionDeclAndLoc &RHS) { + return LHS.FD == RHS.FD && LHS.Loc == RHS.Loc; + } +}; +} // namespace llvm + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/SemaConcept.h b/contrib/libs/clang16/include/clang/Sema/SemaConcept.h new file mode 100644 index 0000000000..12dd0d6c91 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/SemaConcept.h @@ -0,0 +1,166 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- SemaConcept.h - Semantic Analysis for Constraints and Concepts ----===// +// +// 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 provides semantic analysis for C++ constraints and concepts. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMACONCEPT_H +#define LLVM_CLANG_SEMA_SEMACONCEPT_H +#include "clang/AST/ASTConcept.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SmallVector.h" +#include <optional> +#include <string> +#include <utility> + +namespace clang { +class Sema; + +struct AtomicConstraint { + const Expr *ConstraintExpr; + std::optional<ArrayRef<TemplateArgumentLoc>> ParameterMapping; + + AtomicConstraint(Sema &S, const Expr *ConstraintExpr) : + ConstraintExpr(ConstraintExpr) { }; + + bool hasMatchingParameterMapping(ASTContext &C, + const AtomicConstraint &Other) const { + if (!ParameterMapping != !Other.ParameterMapping) + return false; + if (!ParameterMapping) + return true; + if (ParameterMapping->size() != Other.ParameterMapping->size()) + return false; + + for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) { + llvm::FoldingSetNodeID IDA, IDB; + C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument()) + .Profile(IDA, C); + C.getCanonicalTemplateArgument((*Other.ParameterMapping)[I].getArgument()) + .Profile(IDB, C); + if (IDA != IDB) + return false; + } + return true; + } + + bool subsumes(ASTContext &C, const AtomicConstraint &Other) const { + // C++ [temp.constr.order] p2 + // - an atomic constraint A subsumes another atomic constraint B + // if and only if the A and B are identical [...] + // + // C++ [temp.constr.atomic] p2 + // Two atomic constraints are identical if they are formed from the + // same expression and the targets of the parameter mappings are + // equivalent according to the rules for expressions [...] + + // We do not actually substitute the parameter mappings into the + // constraint expressions, therefore the constraint expressions are + // the originals, and comparing them will suffice. + if (ConstraintExpr != Other.ConstraintExpr) + return false; + + // Check that the parameter lists are identical + return hasMatchingParameterMapping(C, Other); + } +}; + +/// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is +/// either an atomic constraint, a conjunction of normalized constraints or a +/// disjunction of normalized constraints. +struct NormalizedConstraint { + friend class Sema; + + enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction }; + + using CompoundConstraint = llvm::PointerIntPair< + std::pair<NormalizedConstraint, NormalizedConstraint> *, 1, + CompoundConstraintKind>; + + llvm::PointerUnion<AtomicConstraint *, CompoundConstraint> Constraint; + + NormalizedConstraint(AtomicConstraint *C): Constraint{C} { }; + NormalizedConstraint(ASTContext &C, NormalizedConstraint LHS, + NormalizedConstraint RHS, CompoundConstraintKind Kind) + : Constraint{CompoundConstraint{ + new (C) std::pair<NormalizedConstraint, NormalizedConstraint>{ + std::move(LHS), std::move(RHS)}, Kind}} { }; + + NormalizedConstraint(ASTContext &C, const NormalizedConstraint &Other) { + if (Other.isAtomic()) { + Constraint = new (C) AtomicConstraint(*Other.getAtomicConstraint()); + } else { + Constraint = CompoundConstraint( + new (C) std::pair<NormalizedConstraint, NormalizedConstraint>{ + NormalizedConstraint(C, Other.getLHS()), + NormalizedConstraint(C, Other.getRHS())}, + Other.getCompoundKind()); + } + } + NormalizedConstraint(NormalizedConstraint &&Other): + Constraint(Other.Constraint) { + Other.Constraint = nullptr; + } + NormalizedConstraint &operator=(const NormalizedConstraint &Other) = delete; + NormalizedConstraint &operator=(NormalizedConstraint &&Other) { + if (&Other != this) { + NormalizedConstraint Temp(std::move(Other)); + std::swap(Constraint, Temp.Constraint); + } + return *this; + } + + CompoundConstraintKind getCompoundKind() const { + assert(!isAtomic() && "getCompoundKind called on atomic constraint."); + return Constraint.get<CompoundConstraint>().getInt(); + } + + bool isAtomic() const { return Constraint.is<AtomicConstraint *>(); } + + NormalizedConstraint &getLHS() const { + assert(!isAtomic() && "getLHS called on atomic constraint."); + return Constraint.get<CompoundConstraint>().getPointer()->first; + } + + NormalizedConstraint &getRHS() const { + assert(!isAtomic() && "getRHS called on atomic constraint."); + return Constraint.get<CompoundConstraint>().getPointer()->second; + } + + AtomicConstraint *getAtomicConstraint() const { + assert(isAtomic() && + "getAtomicConstraint called on non-atomic constraint."); + return Constraint.get<AtomicConstraint *>(); + } + +private: + static std::optional<NormalizedConstraint> + fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef<const Expr *> E); + static std::optional<NormalizedConstraint> + fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E); +}; + +} // clang + +#endif // LLVM_CLANG_SEMA_SEMACONCEPT_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/SemaConsumer.h b/contrib/libs/clang16/include/clang/Sema/SemaConsumer.h new file mode 100644 index 0000000000..ca42099f68 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/SemaConsumer.h @@ -0,0 +1,58 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- SemaConsumer.h - Abstract interface for AST semantics --*- 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 defines the SemaConsumer class, a subclass of +// ASTConsumer that is used by AST clients that also require +// additional semantic analysis. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_SEMACONSUMER_H +#define LLVM_CLANG_SEMA_SEMACONSUMER_H + +#include "clang/AST/ASTConsumer.h" + +namespace clang { + class Sema; + + /// An abstract interface that should be implemented by + /// clients that read ASTs and then require further semantic + /// analysis of the entities in those ASTs. + class SemaConsumer : public ASTConsumer { + virtual void anchor(); + public: + SemaConsumer() { + ASTConsumer::SemaConsumer = true; + } + + /// Initialize the semantic consumer with the Sema instance + /// being used to perform semantic analysis on the abstract syntax + /// tree. + virtual void InitializeSema(Sema &S) {} + + /// Inform the semantic consumer that Sema is no longer available. + virtual void ForgetSema() {} + + // isa/cast/dyn_cast support + static bool classof(const ASTConsumer *Consumer) { + return Consumer->SemaConsumer; + } + }; +} + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/SemaDiagnostic.h b/contrib/libs/clang16/include/clang/Sema/SemaDiagnostic.h new file mode 100644 index 0000000000..149af51256 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/SemaDiagnostic.h @@ -0,0 +1,25 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- DiagnosticSema.h - Diagnostics for libsema -------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMADIAGNOSTIC_H +#define LLVM_CLANG_SEMA_SEMADIAGNOSTIC_H + +#include "clang/Basic/DiagnosticSema.h" + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/SemaFixItUtils.h b/contrib/libs/clang16/include/clang/Sema/SemaFixItUtils.h new file mode 100644 index 0000000000..d84583dd41 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/SemaFixItUtils.h @@ -0,0 +1,101 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- SemaFixItUtils.h - Sema FixIts -------------------------*- 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 defines helper classes for generation of Sema FixItHints. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_SEMAFIXITUTILS_H +#define LLVM_CLANG_SEMA_SEMAFIXITUTILS_H + +#include "clang/AST/Expr.h" + +namespace clang { + +enum OverloadFixItKind { + OFIK_Undefined = 0, + OFIK_Dereference, + OFIK_TakeAddress, + OFIK_RemoveDereference, + OFIK_RemoveTakeAddress +}; + +class Sema; + +/// The class facilities generation and storage of conversion FixIts. Hints for +/// new conversions are added using TryToFixConversion method. The default type +/// conversion checker can be reset. +struct ConversionFixItGenerator { + /// Performs a simple check to see if From type can be converted to To type. + static bool compareTypesSimple(CanQualType From, + CanQualType To, + Sema &S, + SourceLocation Loc, + ExprValueKind FromVK); + + /// The list of Hints generated so far. + std::vector<FixItHint> Hints; + + /// The number of Conversions fixed. This can be different from the size + /// of the Hints vector since we allow multiple FixIts per conversion. + unsigned NumConversionsFixed; + + /// The type of fix applied. If multiple conversions are fixed, corresponds + /// to the kid of the very first conversion. + OverloadFixItKind Kind; + + typedef bool (*TypeComparisonFuncTy) (const CanQualType FromTy, + const CanQualType ToTy, + Sema &S, + SourceLocation Loc, + ExprValueKind FromVK); + /// The type comparison function used to decide if expression FromExpr of + /// type FromTy can be converted to ToTy. For example, one could check if + /// an implicit conversion exists. Returns true if comparison exists. + TypeComparisonFuncTy CompareTypes; + + ConversionFixItGenerator(TypeComparisonFuncTy Foo): NumConversionsFixed(0), + Kind(OFIK_Undefined), + CompareTypes(Foo) {} + + ConversionFixItGenerator(): NumConversionsFixed(0), + Kind(OFIK_Undefined), + CompareTypes(compareTypesSimple) {} + + /// Resets the default conversion checker method. + void setConversionChecker(TypeComparisonFuncTy Foo) { + CompareTypes = Foo; + } + + /// If possible, generates and stores a fix for the given conversion. + bool tryToFixConversion(const Expr *FromExpr, + const QualType FromQTy, const QualType ToQTy, + Sema &S); + + void clear() { + Hints.clear(); + NumConversionsFixed = 0; + } + + bool isNull() { + return (NumConversionsFixed == 0); + } +}; + +} // endof namespace clang +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/SemaInternal.h b/contrib/libs/clang16/include/clang/Sema/SemaInternal.h new file mode 100644 index 0000000000..009c1a7a29 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/SemaInternal.h @@ -0,0 +1,348 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- SemaInternal.h - Internal Sema Interfaces --------------*- 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 provides common API and #includes for the internal +// implementation of Sema. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAINTERNAL_H +#define LLVM_CLANG_SEMA_SEMAINTERNAL_H + +#include "clang/AST/ASTContext.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaDiagnostic.h" + +namespace clang { + +inline PartialDiagnostic Sema::PDiag(unsigned DiagID) { + return PartialDiagnostic(DiagID, Context.getDiagAllocator()); +} + +inline bool +FTIHasSingleVoidParameter(const DeclaratorChunk::FunctionTypeInfo &FTI) { + return FTI.NumParams == 1 && !FTI.isVariadic && + FTI.Params[0].Ident == nullptr && FTI.Params[0].Param && + cast<ParmVarDecl>(FTI.Params[0].Param)->getType()->isVoidType(); +} + +inline bool +FTIHasNonVoidParameters(const DeclaratorChunk::FunctionTypeInfo &FTI) { + // Assume FTI is well-formed. + return FTI.NumParams && !FTIHasSingleVoidParameter(FTI); +} + +// Helper function to check whether D's attributes match current CUDA mode. +// Decls with mismatched attributes and related diagnostics may have to be +// ignored during this CUDA compilation pass. +inline bool DeclAttrsMatchCUDAMode(const LangOptions &LangOpts, Decl *D) { + if (!LangOpts.CUDA || !D) + return true; + bool isDeviceSideDecl = D->hasAttr<CUDADeviceAttr>() || + D->hasAttr<CUDASharedAttr>() || + D->hasAttr<CUDAGlobalAttr>(); + return isDeviceSideDecl == LangOpts.CUDAIsDevice; +} + +/// Return a DLL attribute from the declaration. +inline InheritableAttr *getDLLAttr(Decl *D) { + assert(!(D->hasAttr<DLLImportAttr>() && D->hasAttr<DLLExportAttr>()) && + "A declaration cannot be both dllimport and dllexport."); + if (auto *Import = D->getAttr<DLLImportAttr>()) + return Import; + if (auto *Export = D->getAttr<DLLExportAttr>()) + return Export; + return nullptr; +} + +/// Retrieve the depth and index of a template parameter. +inline std::pair<unsigned, unsigned> getDepthAndIndex(NamedDecl *ND) { + if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) + return std::make_pair(TTP->getDepth(), TTP->getIndex()); + + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND)) + return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); + + const auto *TTP = cast<TemplateTemplateParmDecl>(ND); + return std::make_pair(TTP->getDepth(), TTP->getIndex()); +} + +/// Retrieve the depth and index of an unexpanded parameter pack. +inline std::pair<unsigned, unsigned> +getDepthAndIndex(UnexpandedParameterPack UPP) { + if (const auto *TTP = UPP.first.dyn_cast<const TemplateTypeParmType *>()) + return std::make_pair(TTP->getDepth(), TTP->getIndex()); + + return getDepthAndIndex(UPP.first.get<NamedDecl *>()); +} + +class TypoCorrectionConsumer : public VisibleDeclConsumer { + typedef SmallVector<TypoCorrection, 1> TypoResultList; + typedef llvm::StringMap<TypoResultList> TypoResultsMap; + typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap; + +public: + TypoCorrectionConsumer(Sema &SemaRef, + const DeclarationNameInfo &TypoName, + Sema::LookupNameKind LookupKind, + Scope *S, CXXScopeSpec *SS, + std::unique_ptr<CorrectionCandidateCallback> CCC, + DeclContext *MemberContext, + bool EnteringContext) + : Typo(TypoName.getName().getAsIdentifierInfo()), CurrentTCIndex(0), + SavedTCIndex(0), SemaRef(SemaRef), S(S), + SS(SS ? std::make_unique<CXXScopeSpec>(*SS) : nullptr), + CorrectionValidator(std::move(CCC)), MemberContext(MemberContext), + Result(SemaRef, TypoName, LookupKind), + Namespaces(SemaRef.Context, SemaRef.CurContext, SS), + EnteringContext(EnteringContext), SearchNamespaces(false) { + Result.suppressDiagnostics(); + // Arrange for ValidatedCorrections[0] to always be an empty correction. + ValidatedCorrections.push_back(TypoCorrection()); + } + + bool includeHiddenDecls() const override { return true; } + + // Methods for adding potential corrections to the consumer. + void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, + bool InBaseClass) override; + void FoundName(StringRef Name); + void addKeywordResult(StringRef Keyword); + void addCorrection(TypoCorrection Correction); + + bool empty() const { + return CorrectionResults.empty() && ValidatedCorrections.size() == 1; + } + + /// Return the list of TypoCorrections for the given identifier from + /// the set of corrections that have the closest edit distance, if any. + TypoResultList &operator[](StringRef Name) { + return CorrectionResults.begin()->second[Name]; + } + + /// Return the edit distance of the corrections that have the + /// closest/best edit distance from the original typop. + unsigned getBestEditDistance(bool Normalized) { + if (CorrectionResults.empty()) + return (std::numeric_limits<unsigned>::max)(); + + unsigned BestED = CorrectionResults.begin()->first; + return Normalized ? TypoCorrection::NormalizeEditDistance(BestED) : BestED; + } + + /// Set-up method to add to the consumer the set of namespaces to use + /// in performing corrections to nested name specifiers. This method also + /// implicitly adds all of the known classes in the current AST context to the + /// to the consumer for correcting nested name specifiers. + void + addNamespaces(const llvm::MapVector<NamespaceDecl *, bool> &KnownNamespaces); + + /// Return the next typo correction that passes all internal filters + /// and is deemed valid by the consumer's CorrectionCandidateCallback, + /// starting with the corrections that have the closest edit distance. An + /// empty TypoCorrection is returned once no more viable corrections remain + /// in the consumer. + const TypoCorrection &getNextCorrection(); + + /// Get the last correction returned by getNextCorrection(). + const TypoCorrection &getCurrentCorrection() { + return CurrentTCIndex < ValidatedCorrections.size() + ? ValidatedCorrections[CurrentTCIndex] + : ValidatedCorrections[0]; // The empty correction. + } + + /// Return the next typo correction like getNextCorrection, but keep + /// the internal state pointed to the current correction (i.e. the next time + /// getNextCorrection is called, it will return the same correction returned + /// by peekNextcorrection). + const TypoCorrection &peekNextCorrection() { + auto Current = CurrentTCIndex; + const TypoCorrection &TC = getNextCorrection(); + CurrentTCIndex = Current; + return TC; + } + + /// In the case of deeply invalid expressions, `getNextCorrection()` will + /// never be called since the transform never makes progress. If we don't + /// detect this we risk trying to correct typos forever. + bool hasMadeAnyCorrectionProgress() const { return CurrentTCIndex != 0; } + + /// Reset the consumer's position in the stream of viable corrections + /// (i.e. getNextCorrection() will return each of the previously returned + /// corrections in order before returning any new corrections). + void resetCorrectionStream() { + CurrentTCIndex = 0; + } + + /// Return whether the end of the stream of corrections has been + /// reached. + bool finished() { + return CorrectionResults.empty() && + CurrentTCIndex >= ValidatedCorrections.size(); + } + + /// Save the current position in the correction stream (overwriting any + /// previously saved position). + void saveCurrentPosition() { + SavedTCIndex = CurrentTCIndex; + } + + /// Restore the saved position in the correction stream. + void restoreSavedPosition() { + CurrentTCIndex = SavedTCIndex; + } + + ASTContext &getContext() const { return SemaRef.Context; } + const LookupResult &getLookupResult() const { return Result; } + + bool isAddressOfOperand() const { return CorrectionValidator->IsAddressOfOperand; } + const CXXScopeSpec *getSS() const { return SS.get(); } + Scope *getScope() const { return S; } + CorrectionCandidateCallback *getCorrectionValidator() const { + return CorrectionValidator.get(); + } + +private: + class NamespaceSpecifierSet { + struct SpecifierInfo { + DeclContext* DeclCtx; + NestedNameSpecifier* NameSpecifier; + unsigned EditDistance; + }; + + typedef SmallVector<DeclContext*, 4> DeclContextList; + typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList; + + ASTContext &Context; + DeclContextList CurContextChain; + std::string CurNameSpecifier; + SmallVector<const IdentifierInfo*, 4> CurContextIdentifiers; + SmallVector<const IdentifierInfo*, 4> CurNameSpecifierIdentifiers; + + std::map<unsigned, SpecifierInfoList> DistanceMap; + + /// Helper for building the list of DeclContexts between the current + /// context and the top of the translation unit + static DeclContextList buildContextChain(DeclContext *Start); + + unsigned buildNestedNameSpecifier(DeclContextList &DeclChain, + NestedNameSpecifier *&NNS); + + public: + NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext, + CXXScopeSpec *CurScopeSpec); + + /// Add the DeclContext (a namespace or record) to the set, computing + /// the corresponding NestedNameSpecifier and its distance in the process. + void addNameSpecifier(DeclContext *Ctx); + + /// Provides flat iteration over specifiers, sorted by distance. + class iterator + : public llvm::iterator_facade_base<iterator, std::forward_iterator_tag, + SpecifierInfo> { + /// Always points to the last element in the distance map. + const std::map<unsigned, SpecifierInfoList>::iterator OuterBack; + /// Iterator on the distance map. + std::map<unsigned, SpecifierInfoList>::iterator Outer; + /// Iterator on an element in the distance map. + SpecifierInfoList::iterator Inner; + + public: + iterator(NamespaceSpecifierSet &Set, bool IsAtEnd) + : OuterBack(std::prev(Set.DistanceMap.end())), + Outer(Set.DistanceMap.begin()), + Inner(!IsAtEnd ? Outer->second.begin() : OuterBack->second.end()) { + assert(!Set.DistanceMap.empty()); + } + + iterator &operator++() { + ++Inner; + if (Inner == Outer->second.end() && Outer != OuterBack) { + ++Outer; + Inner = Outer->second.begin(); + } + return *this; + } + + SpecifierInfo &operator*() { return *Inner; } + bool operator==(const iterator &RHS) const { return Inner == RHS.Inner; } + }; + + iterator begin() { return iterator(*this, /*IsAtEnd=*/false); } + iterator end() { return iterator(*this, /*IsAtEnd=*/true); } + }; + + void addName(StringRef Name, NamedDecl *ND, + NestedNameSpecifier *NNS = nullptr, bool isKeyword = false); + + /// Find any visible decls for the given typo correction candidate. + /// If none are found, it to the set of candidates for which qualified lookups + /// will be performed to find possible nested name specifier changes. + bool resolveCorrection(TypoCorrection &Candidate); + + /// Perform qualified lookups on the queued set of typo correction + /// candidates and add the nested name specifier changes to each candidate if + /// a lookup succeeds (at which point the candidate will be returned to the + /// main pool of potential corrections). + void performQualifiedLookups(); + + /// The name written that is a typo in the source. + IdentifierInfo *Typo; + + /// The results found that have the smallest edit distance + /// found (so far) with the typo name. + /// + /// The pointer value being set to the current DeclContext indicates + /// whether there is a keyword with this name. + TypoEditDistanceMap CorrectionResults; + + SmallVector<TypoCorrection, 4> ValidatedCorrections; + size_t CurrentTCIndex; + size_t SavedTCIndex; + + Sema &SemaRef; + Scope *S; + std::unique_ptr<CXXScopeSpec> SS; + std::unique_ptr<CorrectionCandidateCallback> CorrectionValidator; + DeclContext *MemberContext; + LookupResult Result; + NamespaceSpecifierSet Namespaces; + SmallVector<TypoCorrection, 2> QualifiedResults; + bool EnteringContext; + bool SearchNamespaces; +}; + +inline Sema::TypoExprState::TypoExprState() {} + +inline Sema::TypoExprState::TypoExprState(TypoExprState &&other) noexcept { + *this = std::move(other); +} + +inline Sema::TypoExprState &Sema::TypoExprState:: +operator=(Sema::TypoExprState &&other) noexcept { + Consumer = std::move(other.Consumer); + DiagHandler = std::move(other.DiagHandler); + RecoveryHandler = std::move(other.RecoveryHandler); + return *this; +} + +} // end namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/SemaLambda.h b/contrib/libs/clang16/include/clang/Sema/SemaLambda.h new file mode 100644 index 0000000000..095024f23c --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/SemaLambda.h @@ -0,0 +1,51 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- SemaLambda.h - Lambda Helper Functions --------------*- 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file provides some common utility functions for processing +/// Lambdas. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMALAMBDA_H +#define LLVM_CLANG_SEMA_SEMALAMBDA_H + +#include "clang/AST/ASTLambda.h" +#include <optional> + +namespace clang { +namespace sema { +class FunctionScopeInfo; +} +class Sema; + +/// Examines the FunctionScopeInfo stack to determine the nearest +/// enclosing lambda (to the current lambda) that is 'capture-capable' for +/// the variable referenced in the current lambda (i.e. \p VarToCapture). +/// If successful, returns the index into Sema's FunctionScopeInfo stack +/// of the capture-capable lambda's LambdaScopeInfo. +/// See Implementation for more detailed comments. + +std::optional<unsigned> getStackIndexOfNearestEnclosingCaptureCapableLambda( + ArrayRef<const sema::FunctionScopeInfo *> FunctionScopes, + ValueDecl *VarToCapture, Sema &S); + +} // clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/Template.h b/contrib/libs/clang16/include/clang/Sema/Template.h new file mode 100644 index 0000000000..0eba6e7528 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/Template.h @@ -0,0 +1,713 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- SemaTemplate.h - C++ Templates ---------------------------*- 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 provides types used in the semantic analysis of C++ templates. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_TEMPLATE_H +#define LLVM_CLANG_SEMA_TEMPLATE_H + +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" +#include "clang/Basic/LLVM.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> +#include <optional> +#include <utility> + +namespace clang { + +class ASTContext; +class BindingDecl; +class CXXMethodDecl; +class Decl; +class DeclaratorDecl; +class DeclContext; +class EnumDecl; +class FunctionDecl; +class NamedDecl; +class ParmVarDecl; +class TagDecl; +class TypedefNameDecl; +class TypeSourceInfo; +class VarDecl; + +/// The kind of template substitution being performed. +enum class TemplateSubstitutionKind : char { + /// We are substituting template parameters for template arguments in order + /// to form a template specialization. + Specialization, + /// We are substituting template parameters for (typically) other template + /// parameters in order to rewrite a declaration as a different declaration + /// (for example, when forming a deduction guide from a constructor). + Rewrite, +}; + + /// Data structure that captures multiple levels of template argument + /// lists for use in template instantiation. + /// + /// Multiple levels of template arguments occur when instantiating the + /// definitions of member templates. For example: + /// + /// \code + /// template<typename T> + /// struct X { + /// template<T Value> + /// struct Y { + /// void f(); + /// }; + /// }; + /// \endcode + /// + /// When instantiating X<int>::Y<17>::f, the multi-level template argument + /// list will contain a template argument list (int) at depth 0 and a + /// template argument list (17) at depth 1. + class MultiLevelTemplateArgumentList { + /// The template argument list at a certain template depth + + using ArgList = ArrayRef<TemplateArgument>; + struct ArgumentListLevel { + llvm::PointerIntPair<Decl *, 1, bool> AssociatedDeclAndFinal; + ArgList Args; + }; + using ContainerType = SmallVector<ArgumentListLevel, 4>; + + using ArgListsIterator = ContainerType::iterator; + using ConstArgListsIterator = ContainerType::const_iterator; + + /// The template argument lists, stored from the innermost template + /// argument list (first) to the outermost template argument list (last). + ContainerType TemplateArgumentLists; + + /// The number of outer levels of template arguments that are not + /// being substituted. + unsigned NumRetainedOuterLevels = 0; + + /// The kind of substitution described by this argument list. + TemplateSubstitutionKind Kind = TemplateSubstitutionKind::Specialization; + + public: + /// Construct an empty set of template argument lists. + MultiLevelTemplateArgumentList() = default; + + /// Construct a single-level template argument list. + MultiLevelTemplateArgumentList(Decl *D, ArgList Args, bool Final) { + addOuterTemplateArguments(D, Args, Final); + } + + void setKind(TemplateSubstitutionKind K) { Kind = K; } + + /// Determine the kind of template substitution being performed. + TemplateSubstitutionKind getKind() const { return Kind; } + + /// Determine whether we are rewriting template parameters rather than + /// substituting for them. If so, we should not leave references to the + /// original template parameters behind. + bool isRewrite() const { + return Kind == TemplateSubstitutionKind::Rewrite; + } + + /// Determine the number of levels in this template argument + /// list. + unsigned getNumLevels() const { + return TemplateArgumentLists.size() + NumRetainedOuterLevels; + } + + /// Determine the number of substituted levels in this template + /// argument list. + unsigned getNumSubstitutedLevels() const { + return TemplateArgumentLists.size(); + } + + // Determine the number of substituted args at 'Depth'. + unsigned getNumSubsitutedArgs(unsigned Depth) const { + assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); + return TemplateArgumentLists[getNumLevels() - Depth - 1].Args.size(); + } + + unsigned getNumRetainedOuterLevels() const { + return NumRetainedOuterLevels; + } + + /// Determine how many of the \p OldDepth outermost template parameter + /// lists would be removed by substituting these arguments. + unsigned getNewDepth(unsigned OldDepth) const { + if (OldDepth < NumRetainedOuterLevels) + return OldDepth; + if (OldDepth < getNumLevels()) + return NumRetainedOuterLevels; + return OldDepth - TemplateArgumentLists.size(); + } + + /// Retrieve the template argument at a given depth and index. + const TemplateArgument &operator()(unsigned Depth, unsigned Index) const { + assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); + assert(Index < + TemplateArgumentLists[getNumLevels() - Depth - 1].Args.size()); + return TemplateArgumentLists[getNumLevels() - Depth - 1].Args[Index]; + } + + /// A template-like entity which owns the whole pattern being substituted. + /// This will usually own a set of template parameters, or in some + /// cases might even be a template parameter itself. + std::pair<Decl *, bool> getAssociatedDecl(unsigned Depth) const { + assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); + auto AD = TemplateArgumentLists[getNumLevels() - Depth - 1] + .AssociatedDeclAndFinal; + return {AD.getPointer(), AD.getInt()}; + } + + /// Determine whether there is a non-NULL template argument at the + /// given depth and index. + /// + /// There must exist a template argument list at the given depth. + bool hasTemplateArgument(unsigned Depth, unsigned Index) const { + assert(Depth < getNumLevels()); + + if (Depth < NumRetainedOuterLevels) + return false; + + if (Index >= + TemplateArgumentLists[getNumLevels() - Depth - 1].Args.size()) + return false; + + return !(*this)(Depth, Index).isNull(); + } + + bool isAnyArgInstantiationDependent() const { + for (ArgumentListLevel ListLevel : TemplateArgumentLists) + for (const TemplateArgument &TA : ListLevel.Args) + if (TA.isInstantiationDependent()) + return true; + return false; + } + + /// Clear out a specific template argument. + void setArgument(unsigned Depth, unsigned Index, + TemplateArgument Arg) { + assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); + assert(Index < + TemplateArgumentLists[getNumLevels() - Depth - 1].Args.size()); + const_cast<TemplateArgument &>( + TemplateArgumentLists[getNumLevels() - Depth - 1].Args[Index]) = Arg; + } + + /// Add a new outmost level to the multi-level template argument + /// list. + /// A 'Final' substitution means that Subst* nodes won't be built + /// for the replacements. + void addOuterTemplateArguments(Decl *AssociatedDecl, ArgList Args, + bool Final) { + assert(!NumRetainedOuterLevels && + "substituted args outside retained args?"); + assert(getKind() == TemplateSubstitutionKind::Specialization); + TemplateArgumentLists.push_back( + {{AssociatedDecl->getCanonicalDecl(), Final}, Args}); + } + + void addOuterTemplateArguments(ArgList Args) { + assert(!NumRetainedOuterLevels && + "substituted args outside retained args?"); + assert(getKind() == TemplateSubstitutionKind::Rewrite); + TemplateArgumentLists.push_back({{}, Args}); + } + + void addOuterTemplateArguments(std::nullopt_t) { + assert(!NumRetainedOuterLevels && + "substituted args outside retained args?"); + TemplateArgumentLists.push_back({}); + } + + /// Replaces the current 'innermost' level with the provided argument list. + /// This is useful for type deduction cases where we need to get the entire + /// list from the AST, but then add the deduced innermost list. + void replaceInnermostTemplateArguments(ArgList Args) { + assert(TemplateArgumentLists.size() > 0 && "Replacing in an empty list?"); + TemplateArgumentLists[0].Args = Args; + } + + /// Add an outermost level that we are not substituting. We have no + /// arguments at this level, and do not remove it from the depth of inner + /// template parameters that we instantiate. + void addOuterRetainedLevel() { + ++NumRetainedOuterLevels; + } + void addOuterRetainedLevels(unsigned Num) { + NumRetainedOuterLevels += Num; + } + + /// Retrieve the innermost template argument list. + const ArgList &getInnermost() const { + return TemplateArgumentLists.front().Args; + } + /// Retrieve the outermost template argument list. + const ArgList &getOutermost() const { + return TemplateArgumentLists.back().Args; + } + ArgListsIterator begin() { return TemplateArgumentLists.begin(); } + ConstArgListsIterator begin() const { + return TemplateArgumentLists.begin(); + } + ArgListsIterator end() { return TemplateArgumentLists.end(); } + ConstArgListsIterator end() const { return TemplateArgumentLists.end(); } + }; + + /// The context in which partial ordering of function templates occurs. + enum TPOC { + /// Partial ordering of function templates for a function call. + TPOC_Call, + + /// Partial ordering of function templates for a call to a + /// conversion function. + TPOC_Conversion, + + /// Partial ordering of function templates in other contexts, e.g., + /// taking the address of a function template or matching a function + /// template specialization to a function template. + TPOC_Other + }; + + // This is lame but unavoidable in a world without forward + // declarations of enums. The alternatives are to either pollute + // Sema.h (by including this file) or sacrifice type safety (by + // making Sema.h declare things as enums). + class TemplatePartialOrderingContext { + TPOC Value; + + public: + TemplatePartialOrderingContext(TPOC Value) : Value(Value) {} + + operator TPOC() const { return Value; } + }; + + /// Captures a template argument whose value has been deduced + /// via c++ template argument deduction. + class DeducedTemplateArgument : public TemplateArgument { + /// For a non-type template argument, whether the value was + /// deduced from an array bound. + bool DeducedFromArrayBound = false; + + public: + DeducedTemplateArgument() = default; + + DeducedTemplateArgument(const TemplateArgument &Arg, + bool DeducedFromArrayBound = false) + : TemplateArgument(Arg), DeducedFromArrayBound(DeducedFromArrayBound) {} + + /// Construct an integral non-type template argument that + /// has been deduced, possibly from an array bound. + DeducedTemplateArgument(ASTContext &Ctx, + const llvm::APSInt &Value, + QualType ValueType, + bool DeducedFromArrayBound) + : TemplateArgument(Ctx, Value, ValueType), + DeducedFromArrayBound(DeducedFromArrayBound) {} + + /// For a non-type template argument, determine whether the + /// template argument was deduced from an array bound. + bool wasDeducedFromArrayBound() const { return DeducedFromArrayBound; } + + /// Specify whether the given non-type template argument + /// was deduced from an array bound. + void setDeducedFromArrayBound(bool Deduced) { + DeducedFromArrayBound = Deduced; + } + }; + + /// A stack-allocated class that identifies which local + /// variable declaration instantiations are present in this scope. + /// + /// A new instance of this class type will be created whenever we + /// instantiate a new function declaration, which will have its own + /// set of parameter declarations. + class LocalInstantiationScope { + public: + /// A set of declarations. + using DeclArgumentPack = SmallVector<VarDecl *, 4>; + + private: + /// Reference to the semantic analysis that is performing + /// this template instantiation. + Sema &SemaRef; + + using LocalDeclsMap = + llvm::SmallDenseMap<const Decl *, + llvm::PointerUnion<Decl *, DeclArgumentPack *>, 4>; + + /// A mapping from local declarations that occur + /// within a template to their instantiations. + /// + /// This mapping is used during instantiation to keep track of, + /// e.g., function parameter and variable declarations. For example, + /// given: + /// + /// \code + /// template<typename T> T add(T x, T y) { return x + y; } + /// \endcode + /// + /// when we instantiate add<int>, we will introduce a mapping from + /// the ParmVarDecl for 'x' that occurs in the template to the + /// instantiated ParmVarDecl for 'x'. + /// + /// For a parameter pack, the local instantiation scope may contain a + /// set of instantiated parameters. This is stored as a DeclArgumentPack + /// pointer. + LocalDeclsMap LocalDecls; + + /// The set of argument packs we've allocated. + SmallVector<DeclArgumentPack *, 1> ArgumentPacks; + + /// The outer scope, which contains local variable + /// definitions from some other instantiation (that may not be + /// relevant to this particular scope). + LocalInstantiationScope *Outer; + + /// Whether we have already exited this scope. + bool Exited = false; + + /// Whether to combine this scope with the outer scope, such that + /// lookup will search our outer scope. + bool CombineWithOuterScope; + + /// If non-NULL, the template parameter pack that has been + /// partially substituted per C++0x [temp.arg.explicit]p9. + NamedDecl *PartiallySubstitutedPack = nullptr; + + /// If \c PartiallySubstitutedPack is non-null, the set of + /// explicitly-specified template arguments in that pack. + const TemplateArgument *ArgsInPartiallySubstitutedPack; + + /// If \c PartiallySubstitutedPack, the number of + /// explicitly-specified template arguments in + /// ArgsInPartiallySubstitutedPack. + unsigned NumArgsInPartiallySubstitutedPack; + + public: + LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) + : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), + CombineWithOuterScope(CombineWithOuterScope) { + SemaRef.CurrentInstantiationScope = this; + } + + LocalInstantiationScope(const LocalInstantiationScope &) = delete; + LocalInstantiationScope & + operator=(const LocalInstantiationScope &) = delete; + + ~LocalInstantiationScope() { + Exit(); + } + + const Sema &getSema() const { return SemaRef; } + + /// Exit this local instantiation scope early. + void Exit() { + if (Exited) + return; + + for (unsigned I = 0, N = ArgumentPacks.size(); I != N; ++I) + delete ArgumentPacks[I]; + + SemaRef.CurrentInstantiationScope = Outer; + Exited = true; + } + + /// Clone this scope, and all outer scopes, down to the given + /// outermost scope. + LocalInstantiationScope *cloneScopes(LocalInstantiationScope *Outermost) { + if (this == Outermost) return this; + + // Save the current scope from SemaRef since the LocalInstantiationScope + // will overwrite it on construction + LocalInstantiationScope *oldScope = SemaRef.CurrentInstantiationScope; + + LocalInstantiationScope *newScope = + new LocalInstantiationScope(SemaRef, CombineWithOuterScope); + + newScope->Outer = nullptr; + if (Outer) + newScope->Outer = Outer->cloneScopes(Outermost); + + newScope->PartiallySubstitutedPack = PartiallySubstitutedPack; + newScope->ArgsInPartiallySubstitutedPack = ArgsInPartiallySubstitutedPack; + newScope->NumArgsInPartiallySubstitutedPack = + NumArgsInPartiallySubstitutedPack; + + for (LocalDeclsMap::iterator I = LocalDecls.begin(), E = LocalDecls.end(); + I != E; ++I) { + const Decl *D = I->first; + llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = + newScope->LocalDecls[D]; + if (I->second.is<Decl *>()) { + Stored = I->second.get<Decl *>(); + } else { + DeclArgumentPack *OldPack = I->second.get<DeclArgumentPack *>(); + DeclArgumentPack *NewPack = new DeclArgumentPack(*OldPack); + Stored = NewPack; + newScope->ArgumentPacks.push_back(NewPack); + } + } + // Restore the saved scope to SemaRef + SemaRef.CurrentInstantiationScope = oldScope; + return newScope; + } + + /// deletes the given scope, and all outer scopes, down to the + /// given outermost scope. + static void deleteScopes(LocalInstantiationScope *Scope, + LocalInstantiationScope *Outermost) { + while (Scope && Scope != Outermost) { + LocalInstantiationScope *Out = Scope->Outer; + delete Scope; + Scope = Out; + } + } + + /// Find the instantiation of the declaration D within the current + /// instantiation scope. + /// + /// \param D The declaration whose instantiation we are searching for. + /// + /// \returns A pointer to the declaration or argument pack of declarations + /// to which the declaration \c D is instantiated, if found. Otherwise, + /// returns NULL. + llvm::PointerUnion<Decl *, DeclArgumentPack *> * + findInstantiationOf(const Decl *D); + + void InstantiatedLocal(const Decl *D, Decl *Inst); + void InstantiatedLocalPackArg(const Decl *D, VarDecl *Inst); + void MakeInstantiatedLocalArgPack(const Decl *D); + + /// Note that the given parameter pack has been partially substituted + /// via explicit specification of template arguments + /// (C++0x [temp.arg.explicit]p9). + /// + /// \param Pack The parameter pack, which will always be a template + /// parameter pack. + /// + /// \param ExplicitArgs The explicitly-specified template arguments provided + /// for this parameter pack. + /// + /// \param NumExplicitArgs The number of explicitly-specified template + /// arguments provided for this parameter pack. + void SetPartiallySubstitutedPack(NamedDecl *Pack, + const TemplateArgument *ExplicitArgs, + unsigned NumExplicitArgs); + + /// Reset the partially-substituted pack when it is no longer of + /// interest. + void ResetPartiallySubstitutedPack() { + assert(PartiallySubstitutedPack && "No partially-substituted pack"); + PartiallySubstitutedPack = nullptr; + ArgsInPartiallySubstitutedPack = nullptr; + NumArgsInPartiallySubstitutedPack = 0; + } + + /// Retrieve the partially-substitued template parameter pack. + /// + /// If there is no partially-substituted parameter pack, returns NULL. + NamedDecl * + getPartiallySubstitutedPack(const TemplateArgument **ExplicitArgs = nullptr, + unsigned *NumExplicitArgs = nullptr) const; + + /// Determine whether D is a pack expansion created in this scope. + bool isLocalPackExpansion(const Decl *D); + }; + + class TemplateDeclInstantiator + : public DeclVisitor<TemplateDeclInstantiator, Decl *> + { + Sema &SemaRef; + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex; + DeclContext *Owner; + const MultiLevelTemplateArgumentList &TemplateArgs; + Sema::LateInstantiatedAttrVec* LateAttrs = nullptr; + LocalInstantiationScope *StartingScope = nullptr; + bool EvaluateConstraints = true; + + /// A list of out-of-line class template partial + /// specializations that will need to be instantiated after the + /// enclosing class's instantiation is complete. + SmallVector<std::pair<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *>, 4> + OutOfLinePartialSpecs; + + /// A list of out-of-line variable template partial + /// specializations that will need to be instantiated after the + /// enclosing variable's instantiation is complete. + /// FIXME: Verify that this is needed. + SmallVector< + std::pair<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>, 4> + OutOfLineVarPartialSpecs; + + public: + TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner, + const MultiLevelTemplateArgumentList &TemplateArgs) + : SemaRef(SemaRef), + SubstIndex(SemaRef, SemaRef.ArgumentPackSubstitutionIndex), + Owner(Owner), TemplateArgs(TemplateArgs) {} + + void setEvaluateConstraints(bool B) { + EvaluateConstraints = B; + } + bool getEvaluateConstraints() { + return EvaluateConstraints; + } + +// Define all the decl visitors using DeclNodes.inc +#define DECL(DERIVED, BASE) \ + Decl *Visit ## DERIVED ## Decl(DERIVED ## Decl *D); +#define ABSTRACT_DECL(DECL) + +// Decls which never appear inside a class or function. +#define OBJCCONTAINER(DERIVED, BASE) +#define FILESCOPEASM(DERIVED, BASE) +#define TOPLEVELSTMT(DERIVED, BASE) +#define IMPORT(DERIVED, BASE) +#define EXPORT(DERIVED, BASE) +#define LINKAGESPEC(DERIVED, BASE) +#define OBJCCOMPATIBLEALIAS(DERIVED, BASE) +#define OBJCMETHOD(DERIVED, BASE) +#define OBJCTYPEPARAM(DERIVED, BASE) +#define OBJCIVAR(DERIVED, BASE) +#define OBJCPROPERTY(DERIVED, BASE) +#define OBJCPROPERTYIMPL(DERIVED, BASE) +#define EMPTY(DERIVED, BASE) +#define LIFETIMEEXTENDEDTEMPORARY(DERIVED, BASE) + + // Decls which use special-case instantiation code. +#define BLOCK(DERIVED, BASE) +#define CAPTURED(DERIVED, BASE) +#define IMPLICITPARAM(DERIVED, BASE) + +#include "clang/AST/DeclNodes.inc" + + enum class RewriteKind { None, RewriteSpaceshipAsEqualEqual }; + + void adjustForRewrite(RewriteKind RK, FunctionDecl *Orig, QualType &T, + TypeSourceInfo *&TInfo, + DeclarationNameInfo &NameInfo); + + // A few supplemental visitor functions. + Decl *VisitCXXMethodDecl(CXXMethodDecl *D, + TemplateParameterList *TemplateParams, + std::optional<const ASTTemplateArgumentListInfo *> + ClassScopeSpecializationArgs = std::nullopt, + RewriteKind RK = RewriteKind::None); + Decl *VisitFunctionDecl(FunctionDecl *D, + TemplateParameterList *TemplateParams, + RewriteKind RK = RewriteKind::None); + Decl *VisitDecl(Decl *D); + Decl *VisitVarDecl(VarDecl *D, bool InstantiatingVarTemplate, + ArrayRef<BindingDecl *> *Bindings = nullptr); + Decl *VisitBaseUsingDecls(BaseUsingDecl *D, BaseUsingDecl *Inst, + LookupResult *Lookup); + + // Enable late instantiation of attributes. Late instantiated attributes + // will be stored in LA. + void enableLateAttributeInstantiation(Sema::LateInstantiatedAttrVec *LA) { + LateAttrs = LA; + StartingScope = SemaRef.CurrentInstantiationScope; + } + + // Disable late instantiation of attributes. + void disableLateAttributeInstantiation() { + LateAttrs = nullptr; + StartingScope = nullptr; + } + + LocalInstantiationScope *getStartingScope() const { return StartingScope; } + + using delayed_partial_spec_iterator = SmallVectorImpl<std::pair< + ClassTemplateDecl *, ClassTemplatePartialSpecializationDecl *>>::iterator; + + using delayed_var_partial_spec_iterator = SmallVectorImpl<std::pair< + VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>>::iterator; + + /// Return an iterator to the beginning of the set of + /// "delayed" partial specializations, which must be passed to + /// InstantiateClassTemplatePartialSpecialization once the class + /// definition has been completed. + delayed_partial_spec_iterator delayed_partial_spec_begin() { + return OutOfLinePartialSpecs.begin(); + } + + delayed_var_partial_spec_iterator delayed_var_partial_spec_begin() { + return OutOfLineVarPartialSpecs.begin(); + } + + /// Return an iterator to the end of the set of + /// "delayed" partial specializations, which must be passed to + /// InstantiateClassTemplatePartialSpecialization once the class + /// definition has been completed. + delayed_partial_spec_iterator delayed_partial_spec_end() { + return OutOfLinePartialSpecs.end(); + } + + delayed_var_partial_spec_iterator delayed_var_partial_spec_end() { + return OutOfLineVarPartialSpecs.end(); + } + + // Helper functions for instantiating methods. + TypeSourceInfo *SubstFunctionType(FunctionDecl *D, + SmallVectorImpl<ParmVarDecl *> &Params); + bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl); + bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); + + bool SubstDefaultedFunction(FunctionDecl *New, FunctionDecl *Tmpl); + + TemplateParameterList * + SubstTemplateParams(TemplateParameterList *List); + + bool SubstQualifier(const DeclaratorDecl *OldDecl, + DeclaratorDecl *NewDecl); + bool SubstQualifier(const TagDecl *OldDecl, + TagDecl *NewDecl); + + Decl *VisitVarTemplateSpecializationDecl( + VarTemplateDecl *VarTemplate, VarDecl *FromVar, + const TemplateArgumentListInfo &TemplateArgsInfo, + ArrayRef<TemplateArgument> Converted, + VarTemplateSpecializationDecl *PrevDecl = nullptr); + + Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias); + ClassTemplatePartialSpecializationDecl * + InstantiateClassTemplatePartialSpecialization( + ClassTemplateDecl *ClassTemplate, + ClassTemplatePartialSpecializationDecl *PartialSpec); + VarTemplatePartialSpecializationDecl * + InstantiateVarTemplatePartialSpecialization( + VarTemplateDecl *VarTemplate, + VarTemplatePartialSpecializationDecl *PartialSpec); + void InstantiateEnumDefinition(EnumDecl *Enum, EnumDecl *Pattern); + + private: + template<typename T> + Decl *instantiateUnresolvedUsingDecl(T *D, + bool InstantiatingPackElement = false); + }; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_TEMPLATE_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/TemplateDeduction.h b/contrib/libs/clang16/include/clang/Sema/TemplateDeduction.h new file mode 100644 index 0000000000..b7c52f477b --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/TemplateDeduction.h @@ -0,0 +1,386 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- TemplateDeduction.h - C++ template argument deduction ----*- 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 provides types used with Sema's template argument deduction +// routines. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H +#define LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H + +#include "clang/Sema/Ownership.h" +#include "clang/Sema/SemaConcept.h" +#include "clang/AST/ASTConcept.h" +#include "clang/AST/DeclAccessPair.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/TemplateBase.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> +#include <cstddef> +#include <optional> +#include <utility> + +namespace clang { + +class Decl; +struct DeducedPack; +class Sema; + +namespace sema { + +/// Provides information about an attempted template argument +/// deduction, whose success or failure was described by a +/// TemplateDeductionResult value. +class TemplateDeductionInfo { + /// The deduced template argument list. + TemplateArgumentList *DeducedSugared = nullptr, *DeducedCanonical = nullptr; + + /// The source location at which template argument + /// deduction is occurring. + SourceLocation Loc; + + /// Have we suppressed an error during deduction? + bool HasSFINAEDiagnostic = false; + + /// The template parameter depth for which we're performing deduction. + unsigned DeducedDepth; + + /// The number of parameters with explicitly-specified template arguments, + /// up to and including the partially-specified pack (if any). + unsigned ExplicitArgs = 0; + + /// Warnings (and follow-on notes) that were suppressed due to + /// SFINAE while performing template argument deduction. + SmallVector<PartialDiagnosticAt, 4> SuppressedDiagnostics; + +public: + TemplateDeductionInfo(SourceLocation Loc, unsigned DeducedDepth = 0) + : Loc(Loc), DeducedDepth(DeducedDepth) {} + TemplateDeductionInfo(const TemplateDeductionInfo &) = delete; + TemplateDeductionInfo &operator=(const TemplateDeductionInfo &) = delete; + + enum ForBaseTag { ForBase }; + /// Create temporary template deduction info for speculatively deducing + /// against a base class of an argument's type. + TemplateDeductionInfo(ForBaseTag, const TemplateDeductionInfo &Info) + : DeducedSugared(Info.DeducedSugared), Loc(Info.Loc), + DeducedDepth(Info.DeducedDepth), ExplicitArgs(Info.ExplicitArgs) {} + + /// Returns the location at which template argument is + /// occurring. + SourceLocation getLocation() const { + return Loc; + } + + /// The depth of template parameters for which deduction is being + /// performed. + unsigned getDeducedDepth() const { + return DeducedDepth; + } + + /// Get the number of explicitly-specified arguments. + unsigned getNumExplicitArgs() const { + return ExplicitArgs; + } + + /// Take ownership of the deduced template argument lists. + TemplateArgumentList *takeSugared() { + TemplateArgumentList *Result = DeducedSugared; + DeducedSugared = nullptr; + return Result; + } + TemplateArgumentList *takeCanonical() { + TemplateArgumentList *Result = DeducedCanonical; + DeducedCanonical = nullptr; + return Result; + } + + /// Take ownership of the SFINAE diagnostic. + void takeSFINAEDiagnostic(PartialDiagnosticAt &PD) { + assert(HasSFINAEDiagnostic); + PD.first = SuppressedDiagnostics.front().first; + PD.second.swap(SuppressedDiagnostics.front().second); + clearSFINAEDiagnostic(); + } + + /// Discard any SFINAE diagnostics. + void clearSFINAEDiagnostic() { + SuppressedDiagnostics.clear(); + HasSFINAEDiagnostic = false; + } + + /// Peek at the SFINAE diagnostic. + const PartialDiagnosticAt &peekSFINAEDiagnostic() const { + assert(HasSFINAEDiagnostic); + return SuppressedDiagnostics.front(); + } + + /// Provide an initial template argument list that contains the + /// explicitly-specified arguments. + void setExplicitArgs(TemplateArgumentList *NewDeducedSugared, + TemplateArgumentList *NewDeducedCanonical) { + assert(NewDeducedSugared->size() == NewDeducedCanonical->size()); + DeducedSugared = NewDeducedSugared; + DeducedCanonical = NewDeducedCanonical; + ExplicitArgs = DeducedSugared->size(); + } + + /// Provide a new template argument list that contains the + /// results of template argument deduction. + void reset(TemplateArgumentList *NewDeducedSugared, + TemplateArgumentList *NewDeducedCanonical) { + DeducedSugared = NewDeducedSugared; + DeducedCanonical = NewDeducedCanonical; + } + + /// Is a SFINAE diagnostic available? + bool hasSFINAEDiagnostic() const { + return HasSFINAEDiagnostic; + } + + /// Set the diagnostic which caused the SFINAE failure. + void addSFINAEDiagnostic(SourceLocation Loc, PartialDiagnostic PD) { + // Only collect the first diagnostic. + if (HasSFINAEDiagnostic) + return; + SuppressedDiagnostics.clear(); + SuppressedDiagnostics.emplace_back(Loc, std::move(PD)); + HasSFINAEDiagnostic = true; + } + + /// Add a new diagnostic to the set of diagnostics + void addSuppressedDiagnostic(SourceLocation Loc, + PartialDiagnostic PD) { + if (HasSFINAEDiagnostic) + return; + SuppressedDiagnostics.emplace_back(Loc, std::move(PD)); + } + + /// Iterator over the set of suppressed diagnostics. + using diag_iterator = SmallVectorImpl<PartialDiagnosticAt>::const_iterator; + + /// Returns an iterator at the beginning of the sequence of suppressed + /// diagnostics. + diag_iterator diag_begin() const { return SuppressedDiagnostics.begin(); } + + /// Returns an iterator at the end of the sequence of suppressed + /// diagnostics. + diag_iterator diag_end() const { return SuppressedDiagnostics.end(); } + + /// The template parameter to which a template argument + /// deduction failure refers. + /// + /// Depending on the result of template argument deduction, this + /// template parameter may have different meanings: + /// + /// TDK_Incomplete: this is the first template parameter whose + /// corresponding template argument was not deduced. + /// + /// TDK_IncompletePack: this is the expanded parameter pack for + /// which we deduced too few arguments. + /// + /// TDK_Inconsistent: this is the template parameter for which + /// two different template argument values were deduced. + TemplateParameter Param; + + /// The first template argument to which the template + /// argument deduction failure refers. + /// + /// Depending on the result of the template argument deduction, + /// this template argument may have different meanings: + /// + /// TDK_IncompletePack: this is the number of arguments we deduced + /// for the pack. + /// + /// TDK_Inconsistent: this argument is the first value deduced + /// for the corresponding template parameter. + /// + /// TDK_SubstitutionFailure: this argument is the template + /// argument we were instantiating when we encountered an error. + /// + /// TDK_DeducedMismatch: this is the parameter type, after substituting + /// deduced arguments. + /// + /// TDK_NonDeducedMismatch: this is the component of the 'parameter' + /// of the deduction, directly provided in the source code. + TemplateArgument FirstArg; + + /// The second template argument to which the template + /// argument deduction failure refers. + /// + /// TDK_Inconsistent: this argument is the second value deduced + /// for the corresponding template parameter. + /// + /// TDK_DeducedMismatch: this is the (adjusted) call argument type. + /// + /// TDK_NonDeducedMismatch: this is the mismatching component of the + /// 'argument' of the deduction, from which we are deducing arguments. + /// + /// FIXME: Finish documenting this. + TemplateArgument SecondArg; + + /// The index of the function argument that caused a deduction + /// failure. + /// + /// TDK_DeducedMismatch: this is the index of the argument that had a + /// different argument type from its substituted parameter type. + unsigned CallArgIndex = 0; + + /// Information on packs that we're currently expanding. + /// + /// FIXME: This should be kept internal to SemaTemplateDeduction. + SmallVector<DeducedPack *, 8> PendingDeducedPacks; + + /// \brief The constraint satisfaction details resulting from the associated + /// constraints satisfaction tests. + ConstraintSatisfaction AssociatedConstraintsSatisfaction; +}; + +} // namespace sema + +/// A structure used to record information about a failed +/// template argument deduction, for diagnosis. +struct DeductionFailureInfo { + /// A Sema::TemplateDeductionResult. + unsigned Result : 8; + + /// Indicates whether a diagnostic is stored in Diagnostic. + unsigned HasDiagnostic : 1; + + /// Opaque pointer containing additional data about + /// this deduction failure. + void *Data; + + /// A diagnostic indicating why deduction failed. + alignas(PartialDiagnosticAt) char Diagnostic[sizeof(PartialDiagnosticAt)]; + + /// Retrieve the diagnostic which caused this deduction failure, + /// if any. + PartialDiagnosticAt *getSFINAEDiagnostic(); + + /// Retrieve the template parameter this deduction failure + /// refers to, if any. + TemplateParameter getTemplateParameter(); + + /// Retrieve the template argument list associated with this + /// deduction failure, if any. + TemplateArgumentList *getTemplateArgumentList(); + + /// Return the first template argument this deduction failure + /// refers to, if any. + const TemplateArgument *getFirstArg(); + + /// Return the second template argument this deduction failure + /// refers to, if any. + const TemplateArgument *getSecondArg(); + + /// Return the index of the call argument that this deduction + /// failure refers to, if any. + std::optional<unsigned> getCallArgIndex(); + + /// Free any memory associated with this deduction failure. + void Destroy(); +}; + +/// TemplateSpecCandidate - This is a generalization of OverloadCandidate +/// which keeps track of template argument deduction failure info, when +/// handling explicit specializations (and instantiations) of templates +/// beyond function overloading. +/// For now, assume that the candidates are non-matching specializations. +/// TODO: In the future, we may need to unify/generalize this with +/// OverloadCandidate. +struct TemplateSpecCandidate { + /// The declaration that was looked up, together with its access. + /// Might be a UsingShadowDecl, but usually a FunctionTemplateDecl. + DeclAccessPair FoundDecl; + + /// Specialization - The actual specialization that this candidate + /// represents. When NULL, this may be a built-in candidate. + Decl *Specialization; + + /// Template argument deduction info + DeductionFailureInfo DeductionFailure; + + void set(DeclAccessPair Found, Decl *Spec, DeductionFailureInfo Info) { + FoundDecl = Found; + Specialization = Spec; + DeductionFailure = Info; + } + + /// Diagnose a template argument deduction failure. + void NoteDeductionFailure(Sema &S, bool ForTakingAddress); +}; + +/// TemplateSpecCandidateSet - A set of generalized overload candidates, +/// used in template specializations. +/// TODO: In the future, we may need to unify/generalize this with +/// OverloadCandidateSet. +class TemplateSpecCandidateSet { + SmallVector<TemplateSpecCandidate, 16> Candidates; + SourceLocation Loc; + + // Stores whether we're taking the address of these candidates. This helps us + // produce better error messages when dealing with the pass_object_size + // attribute on parameters. + bool ForTakingAddress; + + void destroyCandidates(); + +public: + TemplateSpecCandidateSet(SourceLocation Loc, bool ForTakingAddress = false) + : Loc(Loc), ForTakingAddress(ForTakingAddress) {} + TemplateSpecCandidateSet(const TemplateSpecCandidateSet &) = delete; + TemplateSpecCandidateSet & + operator=(const TemplateSpecCandidateSet &) = delete; + ~TemplateSpecCandidateSet() { destroyCandidates(); } + + SourceLocation getLocation() const { return Loc; } + + /// Clear out all of the candidates. + /// TODO: This may be unnecessary. + void clear(); + + using iterator = SmallVector<TemplateSpecCandidate, 16>::iterator; + + iterator begin() { return Candidates.begin(); } + iterator end() { return Candidates.end(); } + + size_t size() const { return Candidates.size(); } + bool empty() const { return Candidates.empty(); } + + /// Add a new candidate with NumConversions conversion sequence slots + /// to the overload set. + TemplateSpecCandidate &addCandidate() { + Candidates.emplace_back(); + return Candidates.back(); + } + + void NoteCandidates(Sema &S, SourceLocation Loc); + + void NoteCandidates(Sema &S, SourceLocation Loc) const { + const_cast<TemplateSpecCandidateSet *>(this)->NoteCandidates(S, Loc); + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/TemplateInstCallback.h b/contrib/libs/clang16/include/clang/Sema/TemplateInstCallback.h new file mode 100644 index 0000000000..79ae05ba06 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/TemplateInstCallback.h @@ -0,0 +1,93 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- TemplateInstCallback.h - Template Instantiation Callback - 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 defines the TemplateInstantiationCallback class, which is the +// base class for callbacks that will be notified at template instantiations. +// +//===---------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_TEMPLATEINSTCALLBACK_H +#define LLVM_CLANG_SEMA_TEMPLATEINSTCALLBACK_H + +#include "clang/Sema/Sema.h" + +namespace clang { + +/// This is a base class for callbacks that will be notified at every +/// template instantiation. +class TemplateInstantiationCallback { +public: + virtual ~TemplateInstantiationCallback() = default; + + /// Called before doing AST-parsing. + virtual void initialize(const Sema &TheSema) = 0; + + /// Called after AST-parsing is completed. + virtual void finalize(const Sema &TheSema) = 0; + + /// Called when instantiation of a template just began. + virtual void atTemplateBegin(const Sema &TheSema, + const Sema::CodeSynthesisContext &Inst) = 0; + + /// Called when instantiation of a template is just about to end. + virtual void atTemplateEnd(const Sema &TheSema, + const Sema::CodeSynthesisContext &Inst) = 0; +}; + +template <class TemplateInstantiationCallbackPtrs> +void initialize(TemplateInstantiationCallbackPtrs &Callbacks, + const Sema &TheSema) { + for (auto &C : Callbacks) { + if (C) + C->initialize(TheSema); + } +} + +template <class TemplateInstantiationCallbackPtrs> +void finalize(TemplateInstantiationCallbackPtrs &Callbacks, + const Sema &TheSema) { + for (auto &C : Callbacks) { + if (C) + C->finalize(TheSema); + } +} + +template <class TemplateInstantiationCallbackPtrs> +void atTemplateBegin(TemplateInstantiationCallbackPtrs &Callbacks, + const Sema &TheSema, + const Sema::CodeSynthesisContext &Inst) { + for (auto &C : Callbacks) { + if (C) + C->atTemplateBegin(TheSema, Inst); + } +} + +template <class TemplateInstantiationCallbackPtrs> +void atTemplateEnd(TemplateInstantiationCallbackPtrs &Callbacks, + const Sema &TheSema, + const Sema::CodeSynthesisContext &Inst) { + for (auto &C : Callbacks) { + if (C) + C->atTemplateEnd(TheSema, Inst); + } +} + +} // namespace clang + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/TypoCorrection.h b/contrib/libs/clang16/include/clang/Sema/TypoCorrection.h new file mode 100644 index 0000000000..378d9c04f7 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/TypoCorrection.h @@ -0,0 +1,429 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- TypoCorrection.h - Class for typo correction results -----*- 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 defines the TypoCorrection class, which stores the results of +// Sema's typo correction (Sema::CorrectTypo). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_TYPOCORRECTION_H +#define LLVM_CLANG_SEMA_TYPOCORRECTION_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/DeclSpec.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" +#include <cstddef> +#include <limits> +#include <string> +#include <utility> +#include <vector> + +namespace clang { + +class DeclContext; +class IdentifierInfo; +class LangOptions; +class MemberExpr; +class NestedNameSpecifier; +class Sema; + +/// Simple class containing the result of Sema::CorrectTypo +class TypoCorrection { +public: + // "Distance" for unusable corrections + static const unsigned InvalidDistance = std::numeric_limits<unsigned>::max(); + + // The largest distance still considered valid (larger edit distances are + // mapped to InvalidDistance by getEditDistance). + static const unsigned MaximumDistance = 10000U; + + // Relative weightings of the "edit distance" components. The higher the + // weight, the more of a penalty to fitness the component will give (higher + // weights mean greater contribution to the total edit distance, with the + // best correction candidates having the lowest edit distance). + static const unsigned CharDistanceWeight = 100U; + static const unsigned QualifierDistanceWeight = 110U; + static const unsigned CallbackDistanceWeight = 150U; + + TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl, + NestedNameSpecifier *NNS = nullptr, unsigned CharDistance = 0, + unsigned QualifierDistance = 0) + : CorrectionName(Name), CorrectionNameSpec(NNS), + CharDistance(CharDistance), QualifierDistance(QualifierDistance) { + if (NameDecl) + CorrectionDecls.push_back(NameDecl); + } + + TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS = nullptr, + unsigned CharDistance = 0) + : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS), + CharDistance(CharDistance) { + if (Name) + CorrectionDecls.push_back(Name); + } + + TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS = nullptr, + unsigned CharDistance = 0) + : CorrectionName(Name), CorrectionNameSpec(NNS), + CharDistance(CharDistance) {} + + TypoCorrection() = default; + + /// Gets the DeclarationName of the typo correction + DeclarationName getCorrection() const { return CorrectionName; } + + IdentifierInfo *getCorrectionAsIdentifierInfo() const { + return CorrectionName.getAsIdentifierInfo(); + } + + /// Gets the NestedNameSpecifier needed to use the typo correction + NestedNameSpecifier *getCorrectionSpecifier() const { + return CorrectionNameSpec; + } + + void setCorrectionSpecifier(NestedNameSpecifier *NNS) { + CorrectionNameSpec = NNS; + ForceSpecifierReplacement = (NNS != nullptr); + } + + void WillReplaceSpecifier(bool ForceReplacement) { + ForceSpecifierReplacement = ForceReplacement; + } + + bool WillReplaceSpecifier() const { + return ForceSpecifierReplacement; + } + + void setQualifierDistance(unsigned ED) { + QualifierDistance = ED; + } + + void setCallbackDistance(unsigned ED) { + CallbackDistance = ED; + } + + // Convert the given weighted edit distance to a roughly equivalent number of + // single-character edits (typically for comparison to the length of the + // string being edited). + static unsigned NormalizeEditDistance(unsigned ED) { + if (ED > MaximumDistance) + return InvalidDistance; + return (ED + CharDistanceWeight / 2) / CharDistanceWeight; + } + + /// Gets the "edit distance" of the typo correction from the typo. + /// If Normalized is true, scale the distance down by the CharDistanceWeight + /// to return the edit distance in terms of single-character edits. + unsigned getEditDistance(bool Normalized = true) const { + if (CharDistance > MaximumDistance || QualifierDistance > MaximumDistance || + CallbackDistance > MaximumDistance) + return InvalidDistance; + unsigned ED = + CharDistance * CharDistanceWeight + + QualifierDistance * QualifierDistanceWeight + + CallbackDistance * CallbackDistanceWeight; + if (ED > MaximumDistance) + return InvalidDistance; + // Half the CharDistanceWeight is added to ED to simulate rounding since + // integer division truncates the value (i.e. round-to-nearest-int instead + // of round-to-zero). + return Normalized ? NormalizeEditDistance(ED) : ED; + } + + /// Get the correction declaration found by name lookup (before we + /// looked through using shadow declarations and the like). + NamedDecl *getFoundDecl() const { + return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : nullptr; + } + + /// Gets the pointer to the declaration of the typo correction + NamedDecl *getCorrectionDecl() const { + auto *D = getFoundDecl(); + return D ? D->getUnderlyingDecl() : nullptr; + } + template <class DeclClass> + DeclClass *getCorrectionDeclAs() const { + return dyn_cast_or_null<DeclClass>(getCorrectionDecl()); + } + + /// Clears the list of NamedDecls. + void ClearCorrectionDecls() { + CorrectionDecls.clear(); + } + + /// Clears the list of NamedDecls before adding the new one. + void setCorrectionDecl(NamedDecl *CDecl) { + CorrectionDecls.clear(); + addCorrectionDecl(CDecl); + } + + /// Clears the list of NamedDecls and adds the given set. + void setCorrectionDecls(ArrayRef<NamedDecl*> Decls) { + CorrectionDecls.clear(); + CorrectionDecls.insert(CorrectionDecls.begin(), Decls.begin(), Decls.end()); + } + + /// Add the given NamedDecl to the list of NamedDecls that are the + /// declarations associated with the DeclarationName of this TypoCorrection + void addCorrectionDecl(NamedDecl *CDecl); + + std::string getAsString(const LangOptions &LO) const; + + std::string getQuoted(const LangOptions &LO) const { + return "'" + getAsString(LO) + "'"; + } + + /// Returns whether this TypoCorrection has a non-empty DeclarationName + explicit operator bool() const { return bool(CorrectionName); } + + /// Mark this TypoCorrection as being a keyword. + /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be + /// added to the list of the correction's NamedDecl pointers, NULL is added + /// as the only element in the list to mark this TypoCorrection as a keyword. + void makeKeyword() { + CorrectionDecls.clear(); + CorrectionDecls.push_back(nullptr); + ForceSpecifierReplacement = true; + } + + // Check if this TypoCorrection is a keyword by checking if the first + // item in CorrectionDecls is NULL. + bool isKeyword() const { + return !CorrectionDecls.empty() && CorrectionDecls.front() == nullptr; + } + + // Check if this TypoCorrection is the given keyword. + template<std::size_t StrLen> + bool isKeyword(const char (&Str)[StrLen]) const { + return isKeyword() && getCorrectionAsIdentifierInfo()->isStr(Str); + } + + // Returns true if the correction either is a keyword or has a known decl. + bool isResolved() const { return !CorrectionDecls.empty(); } + + bool isOverloaded() const { + return CorrectionDecls.size() > 1; + } + + void setCorrectionRange(CXXScopeSpec *SS, + const DeclarationNameInfo &TypoName) { + CorrectionRange = TypoName.getSourceRange(); + if (ForceSpecifierReplacement && SS && !SS->isEmpty()) + CorrectionRange.setBegin(SS->getBeginLoc()); + } + + SourceRange getCorrectionRange() const { + return CorrectionRange; + } + + using decl_iterator = SmallVectorImpl<NamedDecl *>::iterator; + + decl_iterator begin() { + return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin(); + } + + decl_iterator end() { return CorrectionDecls.end(); } + + using const_decl_iterator = SmallVectorImpl<NamedDecl *>::const_iterator; + + const_decl_iterator begin() const { + return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin(); + } + + const_decl_iterator end() const { return CorrectionDecls.end(); } + + /// Returns whether this typo correction is correcting to a + /// declaration that was declared in a module that has not been imported. + bool requiresImport() const { return RequiresImport; } + void setRequiresImport(bool Req) { RequiresImport = Req; } + + /// Extra diagnostics are printed after the first diagnostic for the typo. + /// This can be used to attach external notes to the diag. + void addExtraDiagnostic(PartialDiagnostic PD) { + ExtraDiagnostics.push_back(std::move(PD)); + } + ArrayRef<PartialDiagnostic> getExtraDiagnostics() const { + return ExtraDiagnostics; + } + +private: + bool hasCorrectionDecl() const { + return (!isKeyword() && !CorrectionDecls.empty()); + } + + // Results. + DeclarationName CorrectionName; + NestedNameSpecifier *CorrectionNameSpec = nullptr; + SmallVector<NamedDecl *, 1> CorrectionDecls; + unsigned CharDistance = 0; + unsigned QualifierDistance = 0; + unsigned CallbackDistance = 0; + SourceRange CorrectionRange; + bool ForceSpecifierReplacement = false; + bool RequiresImport = false; + + std::vector<PartialDiagnostic> ExtraDiagnostics; +}; + +/// Base class for callback objects used by Sema::CorrectTypo to check +/// the validity of a potential typo correction. +class CorrectionCandidateCallback { +public: + static const unsigned InvalidDistance = TypoCorrection::InvalidDistance; + + explicit CorrectionCandidateCallback(IdentifierInfo *Typo = nullptr, + NestedNameSpecifier *TypoNNS = nullptr) + : Typo(Typo), TypoNNS(TypoNNS) {} + + virtual ~CorrectionCandidateCallback() = default; + + /// Simple predicate used by the default RankCandidate to + /// determine whether to return an edit distance of 0 or InvalidDistance. + /// This can be overridden by validators that only need to determine if a + /// candidate is viable, without ranking potentially viable candidates. + /// Only ValidateCandidate or RankCandidate need to be overridden by a + /// callback wishing to check the viability of correction candidates. + /// The default predicate always returns true if the candidate is not a type + /// name or keyword, true for types if WantTypeSpecifiers is true, and true + /// for keywords if WantTypeSpecifiers, WantExpressionKeywords, + /// WantCXXNamedCasts, WantRemainingKeywords, or WantObjCSuper is true. + virtual bool ValidateCandidate(const TypoCorrection &candidate); + + /// Method used by Sema::CorrectTypo to assign an "edit distance" rank + /// to a candidate (where a lower value represents a better candidate), or + /// returning InvalidDistance if the candidate is not at all viable. For + /// validation callbacks that only need to determine if a candidate is viable, + /// the default RankCandidate returns either 0 or InvalidDistance depending + /// whether ValidateCandidate returns true or false. + virtual unsigned RankCandidate(const TypoCorrection &candidate) { + return (!MatchesTypo(candidate) && ValidateCandidate(candidate)) + ? 0 + : InvalidDistance; + } + + /// Clone this CorrectionCandidateCallback. CorrectionCandidateCallbacks are + /// initially stack-allocated. However in case where delayed typo-correction + /// is done we need to move the callback to storage with a longer lifetime. + /// Every class deriving from CorrectionCandidateCallback must implement + /// this method. + virtual std::unique_ptr<CorrectionCandidateCallback> clone() = 0; + + void setTypoName(IdentifierInfo *II) { Typo = II; } + void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; } + + // Flags for context-dependent keywords. WantFunctionLikeCasts is only + // used/meaningful when WantCXXNamedCasts is false. + // TODO: Expand these to apply to non-keywords or possibly remove them. + bool WantTypeSpecifiers = true; + bool WantExpressionKeywords = true; + bool WantCXXNamedCasts = true; + bool WantFunctionLikeCasts = true; + bool WantRemainingKeywords = true; + bool WantObjCSuper = false; + // Temporary hack for the one case where a CorrectTypoContext enum is used + // when looking up results. + bool IsObjCIvarLookup = false; + bool IsAddressOfOperand = false; + +protected: + bool MatchesTypo(const TypoCorrection &candidate) { + return Typo && candidate.isResolved() && !candidate.requiresImport() && + candidate.getCorrectionAsIdentifierInfo() == Typo && + // FIXME: This probably does not return true when both + // NestedNameSpecifiers have the same textual representation. + candidate.getCorrectionSpecifier() == TypoNNS; + } + + IdentifierInfo *Typo; + NestedNameSpecifier *TypoNNS; +}; + +class DefaultFilterCCC final : public CorrectionCandidateCallback { +public: + explicit DefaultFilterCCC(IdentifierInfo *Typo = nullptr, + NestedNameSpecifier *TypoNNS = nullptr) + : CorrectionCandidateCallback(Typo, TypoNNS) {} + + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return std::make_unique<DefaultFilterCCC>(*this); + } +}; + +/// Simple template class for restricting typo correction candidates +/// to ones having a single Decl* of the given type. +template <class C> +class DeclFilterCCC final : public CorrectionCandidateCallback { +public: + bool ValidateCandidate(const TypoCorrection &candidate) override { + return candidate.getCorrectionDeclAs<C>(); + } + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return std::make_unique<DeclFilterCCC>(*this); + } +}; + +// Callback class to limit the allowed keywords and to only accept typo +// corrections that are keywords or whose decls refer to functions (or template +// functions) that accept the given number of arguments. +class FunctionCallFilterCCC : public CorrectionCandidateCallback { +public: + FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs, + bool HasExplicitTemplateArgs, + MemberExpr *ME = nullptr); + + bool ValidateCandidate(const TypoCorrection &candidate) override; + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return std::make_unique<FunctionCallFilterCCC>(*this); + } + +private: + unsigned NumArgs; + bool HasExplicitTemplateArgs; + DeclContext *CurContext; + MemberExpr *MemberFn; +}; + +// Callback class that effectively disabled typo correction +class NoTypoCorrectionCCC final : public CorrectionCandidateCallback { +public: + NoTypoCorrectionCCC() { + WantTypeSpecifiers = false; + WantExpressionKeywords = false; + WantCXXNamedCasts = false; + WantFunctionLikeCasts = false; + WantRemainingKeywords = false; + } + + bool ValidateCandidate(const TypoCorrection &candidate) override { + return false; + } + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return std::make_unique<NoTypoCorrectionCCC>(*this); + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_TYPOCORRECTION_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Sema/Weak.h b/contrib/libs/clang16/include/clang/Sema/Weak.h new file mode 100644 index 0000000000..b50c18e926 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Sema/Weak.h @@ -0,0 +1,67 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- UnresolvedSet.h - Unresolved sets of declarations ------*- 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 defines the WeakInfo class, which is used to store +// information about the target of a #pragma weak directive. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_WEAK_H +#define LLVM_CLANG_SEMA_WEAK_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMapInfo.h" + +namespace clang { + +class IdentifierInfo; + +/// Captures information about a \#pragma weak directive. +class WeakInfo { + const IdentifierInfo *alias = nullptr; // alias (optional) + SourceLocation loc; // for diagnostics +public: + WeakInfo() = default; + WeakInfo(const IdentifierInfo *Alias, SourceLocation Loc) + : alias(Alias), loc(Loc) {} + inline const IdentifierInfo *getAlias() const { return alias; } + inline SourceLocation getLocation() const { return loc; } + bool operator==(WeakInfo RHS) const = delete; + bool operator!=(WeakInfo RHS) const = delete; + + struct DenseMapInfoByAliasOnly + : private llvm::DenseMapInfo<const IdentifierInfo *> { + static inline WeakInfo getEmptyKey() { + return WeakInfo(DenseMapInfo::getEmptyKey(), SourceLocation()); + } + static inline WeakInfo getTombstoneKey() { + return WeakInfo(DenseMapInfo::getTombstoneKey(), SourceLocation()); + } + static unsigned getHashValue(const WeakInfo &W) { + return DenseMapInfo::getHashValue(W.getAlias()); + } + static bool isEqual(const WeakInfo &LHS, const WeakInfo &RHS) { + return DenseMapInfo::isEqual(LHS.getAlias(), RHS.getAlias()); + } + }; +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_WEAK_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif |