| //===--- 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/Optional.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 <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 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 funciton, 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. |
| ExternalSemaSource *ExternalSource; |
| |
| ///Whether Sema has generated a multiplexer and has to delete it. |
| bool isMultiplexExternalSource; |
| |
| static bool mightHaveNonExternalLinkage(const DeclaratorDecl *FD); |
| |
| bool isVisibleSlow(const NamedDecl *D); |
| |
| /// 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; |
| |
| // 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; |
| |
| /// 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; |
| |
| /// 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::makeArrayRef(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::makeArrayRef(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 |
| llvm::MapVector<IdentifierInfo *, WeakInfo> 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; |
| |
| /// 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; |
| |
| ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, |
| unsigned NumCleanupObjects, |
| CleanupInfo ParentCleanup, |
| Decl *ManglingContextDecl, |
| ExpressionKind ExprContext) |
| : Context(Context), ParentCleanup(ParentCleanup), |
| NumCleanupObjects(NumCleanupObjects), NumTypos(0), |
| ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext) {} |
| |
| 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; |
| } |
| }; |
| |
| /// 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() : Pair() {} |
| 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) : S(S), OldFPFeaturesState(S.CurFPFeatures) { |
| OldOverrides = S.FpPragmaStack.CurrentValue; |
| } |
| ~FPFeaturesStateRAII() { |
| S.CurFPFeatures = OldFPFeaturesState; |
| S.FpPragmaStack.CurrentValue = OldOverrides; |
| } |
| FPOptionsOverride getOverrides() { return OldOverrides; } |
| |
| private: |
| Sema& S; |
| FPOptions OldFPFeaturesState; |
| FPOptionsOverride OldOverrides; |
| }; |
| |
| 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; |
| |
| Optional<std::unique_ptr<DarwinSDKInfo>> CachedDarwinSDKInfo; |
| |
| 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; } |
| DarwinSDKInfo *getDarwinSDKInfoForAvailabilityChecking(SourceLocation Loc, |
| StringRef Platform); |
| |
| ///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 = typename std::enable_if< |
| !std::is_lvalue_reference<T>::value>::type> |
| 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.hasValue(); } |
| |
| /// 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.hasValue()) |
| *Diag.ImmediateDiag << Value; |
| else if (Diag.PartialDiagId.hasValue()) |
| 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 = typename std::enable_if< |
| !std::is_lvalue_reference<T>::value>::type> |
| const SemaDiagnosticBuilder &operator<<(T &&V) const { |
| if (ImmediateDiag.hasValue()) |
| *ImmediateDiag << std::move(V); |
| else if (PartialDiagId.hasValue()) |
| S.DeviceDeferredDiags[Fn][*PartialDiagId].second << std::move(V); |
| return *this; |
| } |
| |
| friend const SemaDiagnosticBuilder & |
| operator<<(const SemaDiagnosticBuilder &Diag, const PartialDiagnostic &PD) { |
| if (Diag.ImmediateDiag.hasValue()) |
| PD.Emit(*Diag.ImmediateDiag); |
| else if (Diag.PartialDiagId.hasValue()) |
| Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second = PD; |
| return Diag; |
| } |
| |
| void AddFixItHint(const FixItHint &Hint) const { |
| if (ImmediateDiag.hasValue()) |
| ImmediateDiag->AddFixItHint(Hint); |
| else if (PartialDiagId.hasValue()) |
| 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. |
| llvm::Optional<ImmediateDiagBuilder> ImmediateDiag; |
| llvm::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 BuildExtIntType(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 |
| }; |
| |
| 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 ImplicitGlobalModuleFragment = false; |
| VisibleModuleSet OuterVisibleModules; |
| }; |
| /// The modules we're currently parsing. |
| llvm::SmallVector<ModuleScope, 16> ModuleScopes; |
| |
| /// Namespace definitions that we will export when they finish. |
| llvm::SmallPtrSet<const NamespaceDecl*, 8> DeferredExportedNamespaces; |
| |
| /// Get the module whose scope we are currently within. |
| Module *getCurrentModule() const { |
| return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module; |
| } |
| |
| VisibleModuleSet VisibleModules; |
| |
| public: |
| /// Get the module owning an entity. |
| Module *getOwningModule(const Decl *Entity) { |
| return Entity->getOwningModule(); |
| } |
| |
| /// 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() || isVisibleSlow(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); |
| |
| 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 the template parameter \p D has a visible default argument. |
| bool |
| hasVisibleDefaultArgument(const NamedDecl *D, |
| llvm::SmallVectorImpl<Module *> *Modules = nullptr); |
| |
| /// 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 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 \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); |
| |
| 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); |
| /// 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); |
| QualType BuildUnaryTransformType(QualType BaseType, |
| UnaryTransformType::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, |
| 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 = None); |
| 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 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); |
| 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, |
| SourceLocation AttrEnd); |
| void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); |
| void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc); |
| void CheckStaticLocalForDllExport(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); |
| |
| 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); |
| Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D, |
| SkipBodyInfo *SkipBody = nullptr); |
| 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); |
| |
| 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 |