diff --git a/contrib/llvm-project/clang/include/clang/AST/ComputeDependence.h b/contrib/llvm-project/clang/include/clang/AST/ComputeDependence.h index cb545aff51f8..3360fd11ab1f 100644 --- a/contrib/llvm-project/clang/include/clang/AST/ComputeDependence.h +++ b/contrib/llvm-project/clang/include/clang/AST/ComputeDependence.h @@ -1,200 +1,204 @@ //===--- ComputeDependence.h -------------------------------------- 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 // //===----------------------------------------------------------------------===// // // Calculate various template dependency flags for the AST. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_COMPUTEDEPENDENCE_H #define LLVM_CLANG_AST_COMPUTEDEPENDENCE_H #include "clang/AST/DependenceFlags.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "llvm/ADT/ArrayRef.h" namespace clang { class ASTContext; class Expr; class FullExpr; class OpaqueValueExpr; class ParenExpr; class UnaryOperator; class UnaryExprOrTypeTraitExpr; class ArraySubscriptExpr; class MatrixSubscriptExpr; class CompoundLiteralExpr; -class CastExpr; +class ImplicitCastExpr; +class ExplicitCastExpr; class BinaryOperator; class ConditionalOperator; class BinaryConditionalOperator; class StmtExpr; class ConvertVectorExpr; class VAArgExpr; class ChooseExpr; class NoInitExpr; class ArrayInitLoopExpr; class ImplicitValueInitExpr; class InitListExpr; class ExtVectorElementExpr; class BlockExpr; class AsTypeExpr; class DeclRefExpr; class RecoveryExpr; class CXXRewrittenBinaryOperator; class CXXStdInitializerListExpr; class CXXTypeidExpr; class MSPropertyRefExpr; class MSPropertySubscriptExpr; class CXXUuidofExpr; class CXXThisExpr; class CXXThrowExpr; class CXXBindTemporaryExpr; class CXXScalarValueInitExpr; class CXXDeleteExpr; class ArrayTypeTraitExpr; class ExpressionTraitExpr; class CXXNoexceptExpr; class PackExpansionExpr; class SubstNonTypeTemplateParmExpr; class CoroutineSuspendExpr; class DependentCoawaitExpr; class CXXNewExpr; class CXXPseudoDestructorExpr; class OverloadExpr; class DependentScopeDeclRefExpr; class CXXConstructExpr; +class CXXTemporaryObjectExpr; class CXXDefaultInitExpr; class CXXDefaultArgExpr; class LambdaExpr; class CXXUnresolvedConstructExpr; class CXXDependentScopeMemberExpr; class MaterializeTemporaryExpr; class CXXFoldExpr; class TypeTraitExpr; class ConceptSpecializationExpr; class SYCLUniqueStableNameExpr; class PredefinedExpr; class CallExpr; class OffsetOfExpr; class MemberExpr; class ShuffleVectorExpr; class GenericSelectionExpr; class DesignatedInitExpr; class ParenListExpr; class PseudoObjectExpr; class AtomicExpr; class OMPArraySectionExpr; class OMPArrayShapingExpr; class OMPIteratorExpr; class ObjCArrayLiteral; class ObjCDictionaryLiteral; class ObjCBoxedExpr; class ObjCEncodeExpr; class ObjCIvarRefExpr; class ObjCPropertyRefExpr; class ObjCSubscriptRefExpr; class ObjCIsaExpr; class ObjCIndirectCopyRestoreExpr; class ObjCMessageExpr; // The following functions are called from constructors of `Expr`, so they // should not access anything beyond basic ExprDependence computeDependence(FullExpr *E); ExprDependence computeDependence(OpaqueValueExpr *E); ExprDependence computeDependence(ParenExpr *E); ExprDependence computeDependence(UnaryOperator *E, const ASTContext &Ctx); ExprDependence computeDependence(UnaryExprOrTypeTraitExpr *E); ExprDependence computeDependence(ArraySubscriptExpr *E); ExprDependence computeDependence(MatrixSubscriptExpr *E); ExprDependence computeDependence(CompoundLiteralExpr *E); -ExprDependence computeDependence(CastExpr *E); +ExprDependence computeDependence(ImplicitCastExpr *E); +ExprDependence computeDependence(ExplicitCastExpr *E); ExprDependence computeDependence(BinaryOperator *E); ExprDependence computeDependence(ConditionalOperator *E); ExprDependence computeDependence(BinaryConditionalOperator *E); ExprDependence computeDependence(StmtExpr *E, unsigned TemplateDepth); ExprDependence computeDependence(ConvertVectorExpr *E); ExprDependence computeDependence(VAArgExpr *E); ExprDependence computeDependence(ChooseExpr *E); ExprDependence computeDependence(NoInitExpr *E); ExprDependence computeDependence(ArrayInitLoopExpr *E); ExprDependence computeDependence(ImplicitValueInitExpr *E); ExprDependence computeDependence(InitListExpr *E); ExprDependence computeDependence(ExtVectorElementExpr *E); ExprDependence computeDependence(BlockExpr *E); ExprDependence computeDependence(AsTypeExpr *E); ExprDependence computeDependence(DeclRefExpr *E, const ASTContext &Ctx); ExprDependence computeDependence(RecoveryExpr *E); ExprDependence computeDependence(CXXRewrittenBinaryOperator *E); ExprDependence computeDependence(CXXStdInitializerListExpr *E); ExprDependence computeDependence(CXXTypeidExpr *E); ExprDependence computeDependence(MSPropertyRefExpr *E); ExprDependence computeDependence(MSPropertySubscriptExpr *E); ExprDependence computeDependence(CXXUuidofExpr *E); ExprDependence computeDependence(CXXThisExpr *E); ExprDependence computeDependence(CXXThrowExpr *E); ExprDependence computeDependence(CXXBindTemporaryExpr *E); ExprDependence computeDependence(CXXScalarValueInitExpr *E); ExprDependence computeDependence(CXXDeleteExpr *E); ExprDependence computeDependence(ArrayTypeTraitExpr *E); ExprDependence computeDependence(ExpressionTraitExpr *E); ExprDependence computeDependence(CXXNoexceptExpr *E, CanThrowResult CT); ExprDependence computeDependence(PackExpansionExpr *E); ExprDependence computeDependence(SubstNonTypeTemplateParmExpr *E); ExprDependence computeDependence(CoroutineSuspendExpr *E); ExprDependence computeDependence(DependentCoawaitExpr *E); ExprDependence computeDependence(CXXNewExpr *E); ExprDependence computeDependence(CXXPseudoDestructorExpr *E); ExprDependence computeDependence(OverloadExpr *E, bool KnownDependent, bool KnownInstantiationDependent, bool KnownContainsUnexpandedParameterPack); ExprDependence computeDependence(DependentScopeDeclRefExpr *E); ExprDependence computeDependence(CXXConstructExpr *E); +ExprDependence computeDependence(CXXTemporaryObjectExpr *E); ExprDependence computeDependence(CXXDefaultInitExpr *E); ExprDependence computeDependence(CXXDefaultArgExpr *E); ExprDependence computeDependence(LambdaExpr *E, bool ContainsUnexpandedParameterPack); ExprDependence computeDependence(CXXUnresolvedConstructExpr *E); ExprDependence computeDependence(CXXDependentScopeMemberExpr *E); ExprDependence computeDependence(MaterializeTemporaryExpr *E); ExprDependence computeDependence(CXXFoldExpr *E); ExprDependence computeDependence(TypeTraitExpr *E); ExprDependence computeDependence(ConceptSpecializationExpr *E, bool ValueDependent); ExprDependence computeDependence(SYCLUniqueStableNameExpr *E); ExprDependence computeDependence(PredefinedExpr *E); ExprDependence computeDependence(CallExpr *E, llvm::ArrayRef PreArgs); ExprDependence computeDependence(OffsetOfExpr *E); ExprDependence computeDependence(MemberExpr *E); ExprDependence computeDependence(ShuffleVectorExpr *E); ExprDependence computeDependence(GenericSelectionExpr *E, bool ContainsUnexpandedPack); ExprDependence computeDependence(DesignatedInitExpr *E); ExprDependence computeDependence(ParenListExpr *E); ExprDependence computeDependence(PseudoObjectExpr *E); ExprDependence computeDependence(AtomicExpr *E); ExprDependence computeDependence(OMPArraySectionExpr *E); ExprDependence computeDependence(OMPArrayShapingExpr *E); ExprDependence computeDependence(OMPIteratorExpr *E); ExprDependence computeDependence(ObjCArrayLiteral *E); ExprDependence computeDependence(ObjCDictionaryLiteral *E); ExprDependence computeDependence(ObjCBoxedExpr *E); ExprDependence computeDependence(ObjCEncodeExpr *E); ExprDependence computeDependence(ObjCIvarRefExpr *E); ExprDependence computeDependence(ObjCPropertyRefExpr *E); ExprDependence computeDependence(ObjCSubscriptRefExpr *E); ExprDependence computeDependence(ObjCIsaExpr *E); ExprDependence computeDependence(ObjCIndirectCopyRestoreExpr *E); ExprDependence computeDependence(ObjCMessageExpr *E); } // namespace clang #endif diff --git a/contrib/llvm-project/clang/include/clang/AST/DependenceFlags.h b/contrib/llvm-project/clang/include/clang/AST/DependenceFlags.h index 62efdb4ce6e4..3b3c1afb096a 100644 --- a/contrib/llvm-project/clang/include/clang/AST/DependenceFlags.h +++ b/contrib/llvm-project/clang/include/clang/AST/DependenceFlags.h @@ -1,299 +1,321 @@ //===--- DependenceFlags.h ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_DEPENDENCEFLAGS_H #define LLVM_CLANG_AST_DEPENDENCEFLAGS_H #include "clang/Basic/BitmaskEnum.h" #include "llvm/ADT/BitmaskEnum.h" #include namespace clang { struct ExprDependenceScope { enum ExprDependence : uint8_t { UnexpandedPack = 1, // This expr depends in any way on // - a template parameter, it implies that the resolution of this expr may // cause instantiation to fail // - or an error (often in a non-template context) // // Note that C++ standard doesn't define the instantiation-dependent term, // we follow the formal definition coming from the Itanium C++ ABI, and // extend it to errors. Instantiation = 2, // The type of this expr depends on a template parameter, or an error. Type = 4, // The value of this expr depends on a template parameter, or an error. Value = 8, // clang extension: this expr contains or references an error, and is // considered dependent on how that error is resolved. Error = 16, None = 0, All = 31, TypeValue = Type | Value, TypeInstantiation = Type | Instantiation, ValueInstantiation = Value | Instantiation, TypeValueInstantiation = Type | Value | Instantiation, ErrorDependent = Error | ValueInstantiation, LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Error) }; }; using ExprDependence = ExprDependenceScope::ExprDependence; struct TypeDependenceScope { enum TypeDependence : uint8_t { /// Whether this type contains an unexpanded parameter pack /// (for C++11 variadic templates) UnexpandedPack = 1, /// Whether this type somehow involves /// - a template parameter, even if the resolution of the type does not /// depend on a template parameter. /// - or an error. Instantiation = 2, /// Whether this type /// - is a dependent type (C++ [temp.dep.type]) /// - or it somehow involves an error, e.g. decltype(recovery-expr) Dependent = 4, /// Whether this type is a variably-modified type (C99 6.7.5). VariablyModified = 8, /// Whether this type references an error, e.g. decltype(err-expression) /// yields an error type. Error = 16, None = 0, All = 31, DependentInstantiation = Dependent | Instantiation, LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Error) }; }; using TypeDependence = TypeDependenceScope::TypeDependence; #define LLVM_COMMON_DEPENDENCE(NAME) \ struct NAME##Scope { \ enum NAME : uint8_t { \ UnexpandedPack = 1, \ Instantiation = 2, \ Dependent = 4, \ Error = 8, \ \ None = 0, \ DependentInstantiation = Dependent | Instantiation, \ All = 15, \ \ LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Error) \ }; \ }; \ using NAME = NAME##Scope::NAME; LLVM_COMMON_DEPENDENCE(NestedNameSpecifierDependence) LLVM_COMMON_DEPENDENCE(TemplateNameDependence) LLVM_COMMON_DEPENDENCE(TemplateArgumentDependence) #undef LLVM_COMMON_DEPENDENCE // A combined space of all dependence concepts for all node types. // Used when aggregating dependence of nodes of different types. class Dependence { public: enum Bits : uint8_t { None = 0, // Contains a template parameter pack that wasn't expanded. UnexpandedPack = 1, // Depends on a template parameter or an error in some way. // Validity depends on how the template is instantiated or the error is // resolved. Instantiation = 2, // Expression type depends on template context, or an error. // Value and Instantiation should also be set. Type = 4, // Expression value depends on template context, or an error. // Instantiation should also be set. Value = 8, // Depends on template context, or an error. // The type/value distinction is only meaningful for expressions. Dependent = Type | Value, // Includes an error, and depends on how it is resolved. Error = 16, // Type depends on a runtime value (variable-length array). VariablyModified = 32, // Dependence that is propagated syntactically, regardless of semantics. Syntactic = UnexpandedPack | Instantiation | Error, + // Dependence that is propagated semantically, even in cases where the + // type doesn't syntactically appear. This currently excludes only + // UnexpandedPack. Even though Instantiation dependence is also notionally + // syntactic, we also want to propagate it semantically because anything + // that semantically depends on an instantiation-dependent entity should + // always be instantiated when that instantiation-dependent entity is. + Semantic = + Instantiation | Type | Value | Dependent | Error | VariablyModified, LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/VariablyModified) }; Dependence() : V(None) {} Dependence(TypeDependence D) : V(translate(D, TypeDependence::UnexpandedPack, UnexpandedPack) | translate(D, TypeDependence::Instantiation, Instantiation) | translate(D, TypeDependence::Dependent, Dependent) | translate(D, TypeDependence::Error, Error) | translate(D, TypeDependence::VariablyModified, VariablyModified)) {} Dependence(ExprDependence D) : V(translate(D, ExprDependence::UnexpandedPack, UnexpandedPack) | translate(D, ExprDependence::Instantiation, Instantiation) | translate(D, ExprDependence::Type, Type) | translate(D, ExprDependence::Value, Value) | translate(D, ExprDependence::Error, Error)) {} Dependence(NestedNameSpecifierDependence D) : V ( translate(D, NNSDependence::UnexpandedPack, UnexpandedPack) | translate(D, NNSDependence::Instantiation, Instantiation) | translate(D, NNSDependence::Dependent, Dependent) | translate(D, NNSDependence::Error, Error)) {} Dependence(TemplateArgumentDependence D) : V(translate(D, TADependence::UnexpandedPack, UnexpandedPack) | translate(D, TADependence::Instantiation, Instantiation) | translate(D, TADependence::Dependent, Dependent) | translate(D, TADependence::Error, Error)) {} Dependence(TemplateNameDependence D) : V(translate(D, TNDependence::UnexpandedPack, UnexpandedPack) | translate(D, TNDependence::Instantiation, Instantiation) | translate(D, TNDependence::Dependent, Dependent) | translate(D, TNDependence::Error, Error)) {} /// Extract only the syntactic portions of this type's dependence. Dependence syntactic() { Dependence Result = *this; Result.V &= Syntactic; return Result; } + /// Extract the semantic portions of this type's dependence that apply even + /// to uses where the type does not appear syntactically. + Dependence semantic() { + Dependence Result = *this; + Result.V &= Semantic; + return Result; + } + TypeDependence type() const { return translate(V, UnexpandedPack, TypeDependence::UnexpandedPack) | translate(V, Instantiation, TypeDependence::Instantiation) | translate(V, Dependent, TypeDependence::Dependent) | translate(V, Error, TypeDependence::Error) | translate(V, VariablyModified, TypeDependence::VariablyModified); } ExprDependence expr() const { return translate(V, UnexpandedPack, ExprDependence::UnexpandedPack) | translate(V, Instantiation, ExprDependence::Instantiation) | translate(V, Type, ExprDependence::Type) | translate(V, Value, ExprDependence::Value) | translate(V, Error, ExprDependence::Error); } NestedNameSpecifierDependence nestedNameSpecifier() const { return translate(V, UnexpandedPack, NNSDependence::UnexpandedPack) | translate(V, Instantiation, NNSDependence::Instantiation) | translate(V, Dependent, NNSDependence::Dependent) | translate(V, Error, NNSDependence::Error); } TemplateArgumentDependence templateArgument() const { return translate(V, UnexpandedPack, TADependence::UnexpandedPack) | translate(V, Instantiation, TADependence::Instantiation) | translate(V, Dependent, TADependence::Dependent) | translate(V, Error, TADependence::Error); } TemplateNameDependence templateName() const { return translate(V, UnexpandedPack, TNDependence::UnexpandedPack) | translate(V, Instantiation, TNDependence::Instantiation) | translate(V, Dependent, TNDependence::Dependent) | translate(V, Error, TNDependence::Error); } private: Bits V; template static U translate(T Bits, T FromBit, U ToBit) { return (Bits & FromBit) ? ToBit : static_cast(0); } // Abbreviations to make conversions more readable. using NNSDependence = NestedNameSpecifierDependence; using TADependence = TemplateArgumentDependence; using TNDependence = TemplateNameDependence; }; /// Computes dependencies of a reference with the name having template arguments /// with \p TA dependencies. inline ExprDependence toExprDependence(TemplateArgumentDependence TA) { return Dependence(TA).expr(); } -inline ExprDependence toExprDependence(TypeDependence D) { +inline ExprDependence toExprDependenceForImpliedType(TypeDependence D) { + return Dependence(D).semantic().expr(); +} +inline ExprDependence toExprDependenceAsWritten(TypeDependence D) { return Dependence(D).expr(); } // Note: it's often necessary to strip `Dependent` from qualifiers. // If V:: refers to the current instantiation, NNS is considered dependent // but the containing V::foo likely isn't. inline ExprDependence toExprDependence(NestedNameSpecifierDependence D) { return Dependence(D).expr(); } inline ExprDependence turnTypeToValueDependence(ExprDependence D) { // Type-dependent expressions are always be value-dependent, so we simply drop // type dependency. return D & ~ExprDependence::Type; } inline ExprDependence turnValueToTypeDependence(ExprDependence D) { // Type-dependent expressions are always be value-dependent. if (D & ExprDependence::Value) D |= ExprDependence::Type; return D; } // Returned type-dependence will never have VariablyModified set. inline TypeDependence toTypeDependence(ExprDependence D) { return Dependence(D).type(); } inline TypeDependence toTypeDependence(NestedNameSpecifierDependence D) { return Dependence(D).type(); } inline TypeDependence toTypeDependence(TemplateNameDependence D) { return Dependence(D).type(); } inline TypeDependence toTypeDependence(TemplateArgumentDependence D) { return Dependence(D).type(); } inline TypeDependence toSyntacticDependence(TypeDependence D) { return Dependence(D).syntactic().type(); } +inline TypeDependence toSemanticDependence(TypeDependence D) { + return Dependence(D).semantic().type(); +} inline NestedNameSpecifierDependence toNestedNameSpecifierDependendence(TypeDependence D) { return Dependence(D).nestedNameSpecifier(); } inline TemplateArgumentDependence toTemplateArgumentDependence(TypeDependence D) { return Dependence(D).templateArgument(); } inline TemplateArgumentDependence toTemplateArgumentDependence(TemplateNameDependence D) { return Dependence(D).templateArgument(); } inline TemplateArgumentDependence toTemplateArgumentDependence(ExprDependence D) { return Dependence(D).templateArgument(); } inline TemplateNameDependence toTemplateNameDependence(NestedNameSpecifierDependence D) { return Dependence(D).templateName(); } LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); } // namespace clang #endif diff --git a/contrib/llvm-project/clang/include/clang/AST/Expr.h b/contrib/llvm-project/clang/include/clang/AST/Expr.h index ce5280d77c36..fcbc59cba90a 100644 --- a/contrib/llvm-project/clang/include/clang/AST/Expr.h +++ b/contrib/llvm-project/clang/include/clang/AST/Expr.h @@ -1,6467 +1,6469 @@ //===--- Expr.h - Classes for representing expressions ----------*- 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 Expr interface and subclasses. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_EXPR_H #define LLVM_CLANG_AST_EXPR_H #include "clang/AST/APValue.h" #include "clang/AST/ASTVector.h" #include "clang/AST/ComputeDependence.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclAccessPair.h" #include "clang/AST/DependenceFlags.h" #include "clang/AST/OperationKinds.h" #include "clang/AST/Stmt.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SyncScope.h" #include "clang/Basic/TypeTraits.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/TrailingObjects.h" namespace clang { class APValue; class ASTContext; class BlockDecl; class CXXBaseSpecifier; class CXXMemberCallExpr; class CXXOperatorCallExpr; class CastExpr; class Decl; class IdentifierInfo; class MaterializeTemporaryExpr; class NamedDecl; class ObjCPropertyRefExpr; class OpaqueValueExpr; class ParmVarDecl; class StringLiteral; class TargetInfo; class ValueDecl; /// A simple array of base specifiers. typedef SmallVector CXXCastPath; /// An adjustment to be made to the temporary created when emitting a /// reference binding, which accesses a particular subobject of that temporary. struct SubobjectAdjustment { enum { DerivedToBaseAdjustment, FieldAdjustment, MemberPointerAdjustment } Kind; struct DTB { const CastExpr *BasePath; const CXXRecordDecl *DerivedClass; }; struct P { const MemberPointerType *MPT; Expr *RHS; }; union { struct DTB DerivedToBase; FieldDecl *Field; struct P Ptr; }; SubobjectAdjustment(const CastExpr *BasePath, const CXXRecordDecl *DerivedClass) : Kind(DerivedToBaseAdjustment) { DerivedToBase.BasePath = BasePath; DerivedToBase.DerivedClass = DerivedClass; } SubobjectAdjustment(FieldDecl *Field) : Kind(FieldAdjustment) { this->Field = Field; } SubobjectAdjustment(const MemberPointerType *MPT, Expr *RHS) : Kind(MemberPointerAdjustment) { this->Ptr.MPT = MPT; this->Ptr.RHS = RHS; } }; /// This represents one expression. Note that Expr's are subclasses of Stmt. /// This allows an expression to be transparently used any place a Stmt is /// required. class Expr : public ValueStmt { QualType TR; public: Expr() = delete; Expr(const Expr&) = delete; Expr(Expr &&) = delete; Expr &operator=(const Expr&) = delete; Expr &operator=(Expr&&) = delete; protected: Expr(StmtClass SC, QualType T, ExprValueKind VK, ExprObjectKind OK) : ValueStmt(SC) { ExprBits.Dependent = 0; ExprBits.ValueKind = VK; ExprBits.ObjectKind = OK; assert(ExprBits.ObjectKind == OK && "truncated kind"); setType(T); } /// Construct an empty expression. explicit Expr(StmtClass SC, EmptyShell) : ValueStmt(SC) { } /// Each concrete expr subclass is expected to compute its dependence and call /// this in the constructor. void setDependence(ExprDependence Deps) { ExprBits.Dependent = static_cast(Deps); } friend class ASTImporter; // Sets dependence dircetly. friend class ASTStmtReader; // Sets dependence dircetly. public: QualType getType() const { return TR; } void setType(QualType t) { // In C++, the type of an expression is always adjusted so that it // will not have reference type (C++ [expr]p6). Use // QualType::getNonReferenceType() to retrieve the non-reference // type. Additionally, inspect Expr::isLvalue to determine whether // an expression that is adjusted in this manner should be // considered an lvalue. assert((t.isNull() || !t->isReferenceType()) && "Expressions can't have reference type"); TR = t; } ExprDependence getDependence() const { return static_cast(ExprBits.Dependent); } /// Determines whether the value of this expression depends on /// - a template parameter (C++ [temp.dep.constexpr]) /// - or an error, whose resolution is unknown /// /// For example, the array bound of "Chars" in the following example is /// value-dependent. /// @code /// template struct meta_string; /// @endcode bool isValueDependent() const { return static_cast(getDependence() & ExprDependence::Value); } /// Determines whether the type of this expression depends on /// - a template paramter (C++ [temp.dep.expr], which means that its type /// could change from one template instantiation to the next) /// - or an error /// /// For example, the expressions "x" and "x + y" are type-dependent in /// the following code, but "y" is not type-dependent: /// @code /// template /// void add(T x, int y) { /// x + y; /// } /// @endcode bool isTypeDependent() const { return static_cast(getDependence() & ExprDependence::Type); } /// Whether this expression is instantiation-dependent, meaning that /// it depends in some way on /// - a template parameter (even if neither its type nor (constant) value /// can change due to the template instantiation) /// - or an error /// /// In the following example, the expression \c sizeof(sizeof(T() + T())) is /// instantiation-dependent (since it involves a template parameter \c T), but /// is neither type- nor value-dependent, since the type of the inner /// \c sizeof is known (\c std::size_t) and therefore the size of the outer /// \c sizeof is known. /// /// \code /// template /// void f(T x, T y) { /// sizeof(sizeof(T() + T()); /// } /// \endcode /// /// \code /// void func(int) { /// func(); // the expression is instantiation-dependent, because it depends /// // on an error. /// } /// \endcode bool isInstantiationDependent() const { return static_cast(getDependence() & ExprDependence::Instantiation); } /// Whether this expression contains an unexpanded parameter /// pack (for C++11 variadic templates). /// /// Given the following function template: /// /// \code /// template /// void forward(const F &f, Types &&...args) { /// f(static_cast(args)...); /// } /// \endcode /// /// The expressions \c args and \c static_cast(args) both /// contain parameter packs. bool containsUnexpandedParameterPack() const { return static_cast(getDependence() & ExprDependence::UnexpandedPack); } /// Whether this expression contains subexpressions which had errors, e.g. a /// TypoExpr. bool containsErrors() const { return static_cast(getDependence() & ExprDependence::Error); } /// getExprLoc - Return the preferred location for the arrow when diagnosing /// a problem with a generic expression. SourceLocation getExprLoc() const LLVM_READONLY; /// Determine whether an lvalue-to-rvalue conversion should implicitly be /// applied to this expression if it appears as a discarded-value expression /// in C++11 onwards. This applies to certain forms of volatile glvalues. bool isReadIfDiscardedInCPlusPlus11() const; /// isUnusedResultAWarning - Return true if this immediate expression should /// be warned about if the result is unused. If so, fill in expr, location, /// and ranges with expr to warn on and source locations/ranges appropriate /// for a warning. bool isUnusedResultAWarning(const Expr *&WarnExpr, SourceLocation &Loc, SourceRange &R1, SourceRange &R2, ASTContext &Ctx) const; /// isLValue - True if this expression is an "l-value" according to /// the rules of the current language. C and C++ give somewhat /// different rules for this concept, but in general, the result of /// an l-value expression identifies a specific object whereas the /// result of an r-value expression is a value detached from any /// specific storage. /// /// C++11 divides the concept of "r-value" into pure r-values /// ("pr-values") and so-called expiring values ("x-values"), which /// identify specific objects that can be safely cannibalized for /// their resources. bool isLValue() const { return getValueKind() == VK_LValue; } bool isPRValue() const { return getValueKind() == VK_PRValue; } bool isXValue() const { return getValueKind() == VK_XValue; } bool isGLValue() const { return getValueKind() != VK_PRValue; } enum LValueClassification { LV_Valid, LV_NotObjectType, LV_IncompleteVoidType, LV_DuplicateVectorComponents, LV_InvalidExpression, LV_InvalidMessageExpression, LV_MemberFunction, LV_SubObjCPropertySetting, LV_ClassTemporary, LV_ArrayTemporary }; /// Reasons why an expression might not be an l-value. LValueClassification ClassifyLValue(ASTContext &Ctx) const; enum isModifiableLvalueResult { MLV_Valid, MLV_NotObjectType, MLV_IncompleteVoidType, MLV_DuplicateVectorComponents, MLV_InvalidExpression, MLV_LValueCast, // Specialized form of MLV_InvalidExpression. MLV_IncompleteType, MLV_ConstQualified, MLV_ConstQualifiedField, MLV_ConstAddrSpace, MLV_ArrayType, MLV_NoSetterProperty, MLV_MemberFunction, MLV_SubObjCPropertySetting, MLV_InvalidMessageExpression, MLV_ClassTemporary, MLV_ArrayTemporary }; /// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, /// does not have an incomplete type, does not have a const-qualified type, /// and if it is a structure or union, does not have any member (including, /// recursively, any member or element of all contained aggregates or unions) /// with a const-qualified type. /// /// \param Loc [in,out] - A source location which *may* be filled /// in with the location of the expression making this a /// non-modifiable lvalue, if specified. isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc = nullptr) const; /// The return type of classify(). Represents the C++11 expression /// taxonomy. class Classification { public: /// The various classification results. Most of these mean prvalue. enum Kinds { CL_LValue, CL_XValue, CL_Function, // Functions cannot be lvalues in C. CL_Void, // Void cannot be an lvalue in C. CL_AddressableVoid, // Void expression whose address can be taken in C. CL_DuplicateVectorComponents, // A vector shuffle with dupes. CL_MemberFunction, // An expression referring to a member function CL_SubObjCPropertySetting, CL_ClassTemporary, // A temporary of class type, or subobject thereof. CL_ArrayTemporary, // A temporary of array type. CL_ObjCMessageRValue, // ObjC message is an rvalue CL_PRValue // A prvalue for any other reason, of any other type }; /// The results of modification testing. enum ModifiableType { CM_Untested, // testModifiable was false. CM_Modifiable, CM_RValue, // Not modifiable because it's an rvalue CM_Function, // Not modifiable because it's a function; C++ only CM_LValueCast, // Same as CM_RValue, but indicates GCC cast-as-lvalue ext CM_NoSetterProperty,// Implicit assignment to ObjC property without setter CM_ConstQualified, CM_ConstQualifiedField, CM_ConstAddrSpace, CM_ArrayType, CM_IncompleteType }; private: friend class Expr; unsigned short Kind; unsigned short Modifiable; explicit Classification(Kinds k, ModifiableType m) : Kind(k), Modifiable(m) {} public: Classification() {} Kinds getKind() const { return static_cast(Kind); } ModifiableType getModifiable() const { assert(Modifiable != CM_Untested && "Did not test for modifiability."); return static_cast(Modifiable); } bool isLValue() const { return Kind == CL_LValue; } bool isXValue() const { return Kind == CL_XValue; } bool isGLValue() const { return Kind <= CL_XValue; } bool isPRValue() const { return Kind >= CL_Function; } bool isRValue() const { return Kind >= CL_XValue; } bool isModifiable() const { return getModifiable() == CM_Modifiable; } /// Create a simple, modifiably lvalue static Classification makeSimpleLValue() { return Classification(CL_LValue, CM_Modifiable); } }; /// Classify - Classify this expression according to the C++11 /// expression taxonomy. /// /// C++11 defines ([basic.lval]) a new taxonomy of expressions to replace the /// old lvalue vs rvalue. This function determines the type of expression this /// is. There are three expression types: /// - lvalues are classical lvalues as in C++03. /// - prvalues are equivalent to rvalues in C++03. /// - xvalues are expressions yielding unnamed rvalue references, e.g. a /// function returning an rvalue reference. /// lvalues and xvalues are collectively referred to as glvalues, while /// prvalues and xvalues together form rvalues. Classification Classify(ASTContext &Ctx) const { return ClassifyImpl(Ctx, nullptr); } /// ClassifyModifiable - Classify this expression according to the /// C++11 expression taxonomy, and see if it is valid on the left side /// of an assignment. /// /// This function extends classify in that it also tests whether the /// expression is modifiable (C99 6.3.2.1p1). /// \param Loc A source location that might be filled with a relevant location /// if the expression is not modifiable. Classification ClassifyModifiable(ASTContext &Ctx, SourceLocation &Loc) const{ return ClassifyImpl(Ctx, &Loc); } /// Returns the set of floating point options that apply to this expression. /// Only meaningful for operations on floating point values. FPOptions getFPFeaturesInEffect(const LangOptions &LO) const; /// getValueKindForType - Given a formal return or parameter type, /// give its value kind. static ExprValueKind getValueKindForType(QualType T) { if (const ReferenceType *RT = T->getAs()) return (isa(RT) ? VK_LValue : (RT->getPointeeType()->isFunctionType() ? VK_LValue : VK_XValue)); return VK_PRValue; } /// getValueKind - The value kind that this expression produces. ExprValueKind getValueKind() const { return static_cast(ExprBits.ValueKind); } /// getObjectKind - The object kind that this expression produces. /// Object kinds are meaningful only for expressions that yield an /// l-value or x-value. ExprObjectKind getObjectKind() const { return static_cast(ExprBits.ObjectKind); } bool isOrdinaryOrBitFieldObject() const { ExprObjectKind OK = getObjectKind(); return (OK == OK_Ordinary || OK == OK_BitField); } /// setValueKind - Set the value kind produced by this expression. void setValueKind(ExprValueKind Cat) { ExprBits.ValueKind = Cat; } /// setObjectKind - Set the object kind produced by this expression. void setObjectKind(ExprObjectKind Cat) { ExprBits.ObjectKind = Cat; } private: Classification ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const; public: /// Returns true if this expression is a gl-value that /// potentially refers to a bit-field. /// /// In C++, whether a gl-value refers to a bitfield is essentially /// an aspect of the value-kind type system. bool refersToBitField() const { return getObjectKind() == OK_BitField; } /// If this expression refers to a bit-field, retrieve the /// declaration of that bit-field. /// /// Note that this returns a non-null pointer in subtly different /// places than refersToBitField returns true. In particular, this can /// return a non-null pointer even for r-values loaded from /// bit-fields, but it will return null for a conditional bit-field. FieldDecl *getSourceBitField(); const FieldDecl *getSourceBitField() const { return const_cast(this)->getSourceBitField(); } Decl *getReferencedDeclOfCallee(); const Decl *getReferencedDeclOfCallee() const { return const_cast(this)->getReferencedDeclOfCallee(); } /// If this expression is an l-value for an Objective C /// property, find the underlying property reference expression. const ObjCPropertyRefExpr *getObjCProperty() const; /// Check if this expression is the ObjC 'self' implicit parameter. bool isObjCSelfExpr() const; /// Returns whether this expression refers to a vector element. bool refersToVectorElement() const; /// Returns whether this expression refers to a matrix element. bool refersToMatrixElement() const { return getObjectKind() == OK_MatrixComponent; } /// Returns whether this expression refers to a global register /// variable. bool refersToGlobalRegisterVar() const; /// Returns whether this expression has a placeholder type. bool hasPlaceholderType() const { return getType()->isPlaceholderType(); } /// Returns whether this expression has a specific placeholder type. bool hasPlaceholderType(BuiltinType::Kind K) const { assert(BuiltinType::isPlaceholderTypeKind(K)); if (const BuiltinType *BT = dyn_cast(getType())) return BT->getKind() == K; return false; } /// isKnownToHaveBooleanValue - Return true if this is an integer expression /// that is known to return 0 or 1. This happens for _Bool/bool expressions /// but also int expressions which are produced by things like comparisons in /// C. /// /// \param Semantic If true, only return true for expressions that are known /// to be semantically boolean, which might not be true even for expressions /// that are known to evaluate to 0/1. For instance, reading an unsigned /// bit-field with width '1' will evaluate to 0/1, but doesn't necessarily /// semantically correspond to a bool. bool isKnownToHaveBooleanValue(bool Semantic = true) const; /// isIntegerConstantExpr - Return the value if this expression is a valid /// integer constant expression. If not a valid i-c-e, return None and fill /// in Loc (if specified) with the location of the invalid expression. /// /// Note: This does not perform the implicit conversions required by C++11 /// [expr.const]p5. Optional getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc = nullptr, bool isEvaluated = true) const; bool isIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc = nullptr) const; /// isCXX98IntegralConstantExpr - Return true if this expression is an /// integral constant expression in C++98. Can only be used in C++. bool isCXX98IntegralConstantExpr(const ASTContext &Ctx) const; /// isCXX11ConstantExpr - Return true if this expression is a constant /// expression in C++11. Can only be used in C++. /// /// Note: This does not perform the implicit conversions required by C++11 /// [expr.const]p5. bool isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result = nullptr, SourceLocation *Loc = nullptr) const; /// isPotentialConstantExpr - Return true if this function's definition /// might be usable in a constant expression in C++11, if it were marked /// constexpr. Return false if the function can never produce a constant /// expression, along with diagnostics describing why not. static bool isPotentialConstantExpr(const FunctionDecl *FD, SmallVectorImpl< PartialDiagnosticAt> &Diags); /// isPotentialConstantExprUnevaluted - Return true if this expression might /// be usable in a constant expression in C++11 in an unevaluated context, if /// it were in function FD marked constexpr. Return false if the function can /// never produce a constant expression, along with diagnostics describing /// why not. static bool isPotentialConstantExprUnevaluated(Expr *E, const FunctionDecl *FD, SmallVectorImpl< PartialDiagnosticAt> &Diags); /// isConstantInitializer - Returns true if this expression can be emitted to /// IR as a constant, and thus can be used as a constant initializer in C. /// If this expression is not constant and Culprit is non-null, /// it is used to store the address of first non constant expr. bool isConstantInitializer(ASTContext &Ctx, bool ForRef, const Expr **Culprit = nullptr) const; /// If this expression is an unambiguous reference to a single declaration, /// in the style of __builtin_function_start, return that declaration. Note /// that this may return a non-static member function or field in C++ if this /// expression is a member pointer constant. const ValueDecl *getAsBuiltinConstantDeclRef(const ASTContext &Context) const; /// EvalStatus is a struct with detailed info about an evaluation in progress. struct EvalStatus { /// Whether the evaluated expression has side effects. /// For example, (f() && 0) can be folded, but it still has side effects. bool HasSideEffects; /// Whether the evaluation hit undefined behavior. /// For example, 1.0 / 0.0 can be folded to Inf, but has undefined behavior. /// Likewise, INT_MAX + 1 can be folded to INT_MIN, but has UB. bool HasUndefinedBehavior; /// Diag - If this is non-null, it will be filled in with a stack of notes /// indicating why evaluation failed (or why it failed to produce a constant /// expression). /// If the expression is unfoldable, the notes will indicate why it's not /// foldable. If the expression is foldable, but not a constant expression, /// the notes will describes why it isn't a constant expression. If the /// expression *is* a constant expression, no notes will be produced. SmallVectorImpl *Diag; EvalStatus() : HasSideEffects(false), HasUndefinedBehavior(false), Diag(nullptr) {} // hasSideEffects - Return true if the evaluated expression has // side effects. bool hasSideEffects() const { return HasSideEffects; } }; /// EvalResult is a struct with detailed info about an evaluated expression. struct EvalResult : EvalStatus { /// Val - This is the value the expression can be folded to. APValue Val; // isGlobalLValue - Return true if the evaluated lvalue expression // is global. bool isGlobalLValue() const; }; /// EvaluateAsRValue - Return true if this is a constant which we can fold to /// an rvalue using any crazy technique (that has nothing to do with language /// standards) that we want to, even if the expression has side-effects. If /// this function returns true, it returns the folded constant in Result. If /// the expression is a glvalue, an lvalue-to-rvalue conversion will be /// applied. bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx, bool InConstantContext = false) const; /// EvaluateAsBooleanCondition - Return true if this is a constant /// which we can fold and convert to a boolean condition using /// any crazy technique that we want to, even if the expression has /// side-effects. bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, bool InConstantContext = false) const; enum SideEffectsKind { SE_NoSideEffects, ///< Strictly evaluate the expression. SE_AllowUndefinedBehavior, ///< Allow UB that we can give a value, but not ///< arbitrary unmodeled side effects. SE_AllowSideEffects ///< Allow any unmodeled side effect. }; /// EvaluateAsInt - Return true if this is a constant which we can fold and /// convert to an integer, using any crazy technique that we want to. bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects = SE_NoSideEffects, bool InConstantContext = false) const; /// EvaluateAsFloat - Return true if this is a constant which we can fold and /// convert to a floating point value, using any crazy technique that we /// want to. bool EvaluateAsFloat(llvm::APFloat &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects = SE_NoSideEffects, bool InConstantContext = false) const; /// EvaluateAsFloat - Return true if this is a constant which we can fold and /// convert to a fixed point value. bool EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects = SE_NoSideEffects, bool InConstantContext = false) const; /// isEvaluatable - Call EvaluateAsRValue to see if this expression can be /// constant folded without side-effects, but discard the result. bool isEvaluatable(const ASTContext &Ctx, SideEffectsKind AllowSideEffects = SE_NoSideEffects) const; /// HasSideEffects - This routine returns true for all those expressions /// which have any effect other than producing a value. Example is a function /// call, volatile variable read, or throwing an exception. If /// IncludePossibleEffects is false, this call treats certain expressions with /// potential side effects (such as function call-like expressions, /// instantiation-dependent expressions, or invocations from a macro) as not /// having side effects. bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects = true) const; /// Determine whether this expression involves a call to any function /// that is not trivial. bool hasNonTrivialCall(const ASTContext &Ctx) const; /// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded /// integer. This must be called on an expression that constant folds to an /// integer. llvm::APSInt EvaluateKnownConstInt( const ASTContext &Ctx, SmallVectorImpl *Diag = nullptr) const; llvm::APSInt EvaluateKnownConstIntCheckOverflow( const ASTContext &Ctx, SmallVectorImpl *Diag = nullptr) const; void EvaluateForOverflow(const ASTContext &Ctx) const; /// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an /// lvalue with link time known address, with no side-effects. bool EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx, bool InConstantContext = false) const; /// EvaluateAsInitializer - Evaluate an expression as if it were the /// initializer of the given declaration. Returns true if the initializer /// can be folded to a constant, and produces any relevant notes. In C++11, /// notes will be produced if the expression is not a constant expression. bool EvaluateAsInitializer(APValue &Result, const ASTContext &Ctx, const VarDecl *VD, SmallVectorImpl &Notes) const; /// EvaluateWithSubstitution - Evaluate an expression as if from the context /// of a call to the given function with the given arguments, inside an /// unevaluated context. Returns true if the expression could be folded to a /// constant. bool EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx, const FunctionDecl *Callee, ArrayRef Args, const Expr *This = nullptr) const; enum class ConstantExprKind { /// An integer constant expression (an array bound, enumerator, case value, /// bit-field width, or similar) or similar. Normal, /// A non-class template argument. Such a value is only used for mangling, /// not for code generation, so can refer to dllimported functions. NonClassTemplateArgument, /// A class template argument. Such a value is used for code generation. ClassTemplateArgument, /// An immediate invocation. The destruction of the end result of this /// evaluation is not part of the evaluation, but all other temporaries /// are destroyed. ImmediateInvocation, }; /// Evaluate an expression that is required to be a constant expression. Does /// not check the syntactic constraints for C and C++98 constant expressions. bool EvaluateAsConstantExpr( EvalResult &Result, const ASTContext &Ctx, ConstantExprKind Kind = ConstantExprKind::Normal) const; /// If the current Expr is a pointer, this will try to statically /// determine the number of bytes available where the pointer is pointing. /// Returns true if all of the above holds and we were able to figure out the /// size, false otherwise. /// /// \param Type - How to evaluate the size of the Expr, as defined by the /// "type" parameter of __builtin_object_size bool tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx, unsigned Type) const; /// If the current Expr is a pointer, this will try to statically /// determine the strlen of the string pointed to. /// Returns true if all of the above holds and we were able to figure out the /// strlen, false otherwise. bool tryEvaluateStrLen(uint64_t &Result, ASTContext &Ctx) const; /// Enumeration used to describe the kind of Null pointer constant /// returned from \c isNullPointerConstant(). enum NullPointerConstantKind { /// Expression is not a Null pointer constant. NPCK_NotNull = 0, /// Expression is a Null pointer constant built from a zero integer /// expression that is not a simple, possibly parenthesized, zero literal. /// C++ Core Issue 903 will classify these expressions as "not pointers" /// once it is adopted. /// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#903 NPCK_ZeroExpression, /// Expression is a Null pointer constant built from a literal zero. NPCK_ZeroLiteral, /// Expression is a C++11 nullptr. NPCK_CXX11_nullptr, /// Expression is a GNU-style __null constant. NPCK_GNUNull }; /// Enumeration used to describe how \c isNullPointerConstant() /// should cope with value-dependent expressions. enum NullPointerConstantValueDependence { /// Specifies that the expression should never be value-dependent. NPC_NeverValueDependent = 0, /// Specifies that a value-dependent expression of integral or /// dependent type should be considered a null pointer constant. NPC_ValueDependentIsNull, /// Specifies that a value-dependent expression should be considered /// to never be a null pointer constant. NPC_ValueDependentIsNotNull }; /// isNullPointerConstant - C99 6.3.2.3p3 - Test if this reduces down to /// a Null pointer constant. The return value can further distinguish the /// kind of NULL pointer constant that was detected. NullPointerConstantKind isNullPointerConstant( ASTContext &Ctx, NullPointerConstantValueDependence NPC) const; /// isOBJCGCCandidate - Return true if this expression may be used in a read/ /// write barrier. bool isOBJCGCCandidate(ASTContext &Ctx) const; /// Returns true if this expression is a bound member function. bool isBoundMemberFunction(ASTContext &Ctx) const; /// Given an expression of bound-member type, find the type /// of the member. Returns null if this is an *overloaded* bound /// member expression. static QualType findBoundMemberType(const Expr *expr); /// Skip past any invisble AST nodes which might surround this /// statement, such as ExprWithCleanups or ImplicitCastExpr nodes, /// but also injected CXXMemberExpr and CXXConstructExpr which represent /// implicit conversions. Expr *IgnoreUnlessSpelledInSource(); const Expr *IgnoreUnlessSpelledInSource() const { return const_cast(this)->IgnoreUnlessSpelledInSource(); } /// Skip past any implicit casts which might surround this expression until /// reaching a fixed point. Skips: /// * ImplicitCastExpr /// * FullExpr Expr *IgnoreImpCasts() LLVM_READONLY; const Expr *IgnoreImpCasts() const { return const_cast(this)->IgnoreImpCasts(); } /// Skip past any casts which might surround this expression until reaching /// a fixed point. Skips: /// * CastExpr /// * FullExpr /// * MaterializeTemporaryExpr /// * SubstNonTypeTemplateParmExpr Expr *IgnoreCasts() LLVM_READONLY; const Expr *IgnoreCasts() const { return const_cast(this)->IgnoreCasts(); } /// Skip past any implicit AST nodes which might surround this expression /// until reaching a fixed point. Skips: /// * What IgnoreImpCasts() skips /// * MaterializeTemporaryExpr /// * CXXBindTemporaryExpr Expr *IgnoreImplicit() LLVM_READONLY; const Expr *IgnoreImplicit() const { return const_cast(this)->IgnoreImplicit(); } /// Skip past any implicit AST nodes which might surround this expression /// until reaching a fixed point. Same as IgnoreImplicit, except that it /// also skips over implicit calls to constructors and conversion functions. /// /// FIXME: Should IgnoreImplicit do this? Expr *IgnoreImplicitAsWritten() LLVM_READONLY; const Expr *IgnoreImplicitAsWritten() const { return const_cast(this)->IgnoreImplicitAsWritten(); } /// Skip past any parentheses which might surround this expression until /// reaching a fixed point. Skips: /// * ParenExpr /// * UnaryOperator if `UO_Extension` /// * GenericSelectionExpr if `!isResultDependent()` /// * ChooseExpr if `!isConditionDependent()` /// * ConstantExpr Expr *IgnoreParens() LLVM_READONLY; const Expr *IgnoreParens() const { return const_cast(this)->IgnoreParens(); } /// Skip past any parentheses and implicit casts which might surround this /// expression until reaching a fixed point. /// FIXME: IgnoreParenImpCasts really ought to be equivalent to /// IgnoreParens() + IgnoreImpCasts() until reaching a fixed point. However /// this is currently not the case. Instead IgnoreParenImpCasts() skips: /// * What IgnoreParens() skips /// * What IgnoreImpCasts() skips /// * MaterializeTemporaryExpr /// * SubstNonTypeTemplateParmExpr Expr *IgnoreParenImpCasts() LLVM_READONLY; const Expr *IgnoreParenImpCasts() const { return const_cast(this)->IgnoreParenImpCasts(); } /// Skip past any parentheses and casts which might surround this expression /// until reaching a fixed point. Skips: /// * What IgnoreParens() skips /// * What IgnoreCasts() skips Expr *IgnoreParenCasts() LLVM_READONLY; const Expr *IgnoreParenCasts() const { return const_cast(this)->IgnoreParenCasts(); } /// Skip conversion operators. If this Expr is a call to a conversion /// operator, return the argument. Expr *IgnoreConversionOperatorSingleStep() LLVM_READONLY; const Expr *IgnoreConversionOperatorSingleStep() const { return const_cast(this)->IgnoreConversionOperatorSingleStep(); } /// Skip past any parentheses and lvalue casts which might surround this /// expression until reaching a fixed point. Skips: /// * What IgnoreParens() skips /// * What IgnoreCasts() skips, except that only lvalue-to-rvalue /// casts are skipped /// FIXME: This is intended purely as a temporary workaround for code /// that hasn't yet been rewritten to do the right thing about those /// casts, and may disappear along with the last internal use. Expr *IgnoreParenLValueCasts() LLVM_READONLY; const Expr *IgnoreParenLValueCasts() const { return const_cast(this)->IgnoreParenLValueCasts(); } /// Skip past any parenthese and casts which do not change the value /// (including ptr->int casts of the same size) until reaching a fixed point. /// Skips: /// * What IgnoreParens() skips /// * CastExpr which do not change the value /// * SubstNonTypeTemplateParmExpr Expr *IgnoreParenNoopCasts(const ASTContext &Ctx) LLVM_READONLY; const Expr *IgnoreParenNoopCasts(const ASTContext &Ctx) const { return const_cast(this)->IgnoreParenNoopCasts(Ctx); } /// Skip past any parentheses and derived-to-base casts until reaching a /// fixed point. Skips: /// * What IgnoreParens() skips /// * CastExpr which represent a derived-to-base cast (CK_DerivedToBase, /// CK_UncheckedDerivedToBase and CK_NoOp) Expr *IgnoreParenBaseCasts() LLVM_READONLY; const Expr *IgnoreParenBaseCasts() const { return const_cast(this)->IgnoreParenBaseCasts(); } /// Determine whether this expression is a default function argument. /// /// Default arguments are implicitly generated in the abstract syntax tree /// by semantic analysis for function calls, object constructions, etc. in /// C++. Default arguments are represented by \c CXXDefaultArgExpr nodes; /// this routine also looks through any implicit casts to determine whether /// the expression is a default argument. bool isDefaultArgument() const; /// Determine whether the result of this expression is a /// temporary object of the given class type. bool isTemporaryObject(ASTContext &Ctx, const CXXRecordDecl *TempTy) const; /// Whether this expression is an implicit reference to 'this' in C++. bool isImplicitCXXThis() const; static bool hasAnyTypeDependentArguments(ArrayRef Exprs); /// For an expression of class type or pointer to class type, /// return the most derived class decl the expression is known to refer to. /// /// If this expression is a cast, this method looks through it to find the /// most derived decl that can be inferred from the expression. /// This is valid because derived-to-base conversions have undefined /// behavior if the object isn't dynamically of the derived type. const CXXRecordDecl *getBestDynamicClassType() const; /// Get the inner expression that determines the best dynamic class. /// If this is a prvalue, we guarantee that it is of the most-derived type /// for the object itself. const Expr *getBestDynamicClassTypeExpr() const; /// Walk outwards from an expression we want to bind a reference to and /// find the expression whose lifetime needs to be extended. Record /// the LHSs of comma expressions and adjustments needed along the path. const Expr *skipRValueSubobjectAdjustments( SmallVectorImpl &CommaLHS, SmallVectorImpl &Adjustments) const; const Expr *skipRValueSubobjectAdjustments() const { SmallVector CommaLHSs; SmallVector Adjustments; return skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); } /// Checks that the two Expr's will refer to the same value as a comparison /// operand. The caller must ensure that the values referenced by the Expr's /// are not modified between E1 and E2 or the result my be invalid. static bool isSameComparisonOperand(const Expr* E1, const Expr* E2); static bool classof(const Stmt *T) { return T->getStmtClass() >= firstExprConstant && T->getStmtClass() <= lastExprConstant; } }; // PointerLikeTypeTraits is specialized so it can be used with a forward-decl of // Expr. Verify that we got it right. static_assert(llvm::PointerLikeTypeTraits::NumLowBitsAvailable <= llvm::detail::ConstantLog2::value, "PointerLikeTypeTraits assumes too much alignment."); using ConstantExprKind = Expr::ConstantExprKind; //===----------------------------------------------------------------------===// // Wrapper Expressions. //===----------------------------------------------------------------------===// /// FullExpr - Represents a "full-expression" node. class FullExpr : public Expr { protected: Stmt *SubExpr; FullExpr(StmtClass SC, Expr *subexpr) : Expr(SC, subexpr->getType(), subexpr->getValueKind(), subexpr->getObjectKind()), SubExpr(subexpr) { setDependence(computeDependence(this)); } FullExpr(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) {} public: const Expr *getSubExpr() const { return cast(SubExpr); } Expr *getSubExpr() { return cast(SubExpr); } /// As with any mutator of the AST, be very careful when modifying an /// existing AST to preserve its invariants. void setSubExpr(Expr *E) { SubExpr = E; } static bool classof(const Stmt *T) { return T->getStmtClass() >= firstFullExprConstant && T->getStmtClass() <= lastFullExprConstant; } }; /// ConstantExpr - An expression that occurs in a constant context and /// optionally the result of evaluating the expression. class ConstantExpr final : public FullExpr, private llvm::TrailingObjects { static_assert(std::is_same::value, "ConstantExpr assumes that llvm::APInt::WordType is uint64_t " "for tail-allocated storage"); friend TrailingObjects; friend class ASTStmtReader; friend class ASTStmtWriter; public: /// Describes the kind of result that can be tail-allocated. enum ResultStorageKind { RSK_None, RSK_Int64, RSK_APValue }; private: size_t numTrailingObjects(OverloadToken) const { return ConstantExprBits.ResultKind == ConstantExpr::RSK_APValue; } size_t numTrailingObjects(OverloadToken) const { return ConstantExprBits.ResultKind == ConstantExpr::RSK_Int64; } uint64_t &Int64Result() { assert(ConstantExprBits.ResultKind == ConstantExpr::RSK_Int64 && "invalid accessor"); return *getTrailingObjects(); } const uint64_t &Int64Result() const { return const_cast(this)->Int64Result(); } APValue &APValueResult() { assert(ConstantExprBits.ResultKind == ConstantExpr::RSK_APValue && "invalid accessor"); return *getTrailingObjects(); } APValue &APValueResult() const { return const_cast(this)->APValueResult(); } ConstantExpr(Expr *SubExpr, ResultStorageKind StorageKind, bool IsImmediateInvocation); ConstantExpr(EmptyShell Empty, ResultStorageKind StorageKind); public: static ConstantExpr *Create(const ASTContext &Context, Expr *E, const APValue &Result); static ConstantExpr *Create(const ASTContext &Context, Expr *E, ResultStorageKind Storage = RSK_None, bool IsImmediateInvocation = false); static ConstantExpr *CreateEmpty(const ASTContext &Context, ResultStorageKind StorageKind); static ResultStorageKind getStorageKind(const APValue &Value); static ResultStorageKind getStorageKind(const Type *T, const ASTContext &Context); SourceLocation getBeginLoc() const LLVM_READONLY { return SubExpr->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return SubExpr->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ConstantExprClass; } void SetResult(APValue Value, const ASTContext &Context) { MoveIntoResult(Value, Context); } void MoveIntoResult(APValue &Value, const ASTContext &Context); APValue::ValueKind getResultAPValueKind() const { return static_cast(ConstantExprBits.APValueKind); } ResultStorageKind getResultStorageKind() const { return static_cast(ConstantExprBits.ResultKind); } bool isImmediateInvocation() const { return ConstantExprBits.IsImmediateInvocation; } bool hasAPValueResult() const { return ConstantExprBits.APValueKind != APValue::None; } APValue getAPValueResult() const; APValue &getResultAsAPValue() const { return APValueResult(); } llvm::APSInt getResultAsAPSInt() const; // Iterators child_range children() { return child_range(&SubExpr, &SubExpr+1); } const_child_range children() const { return const_child_range(&SubExpr, &SubExpr + 1); } }; //===----------------------------------------------------------------------===// // Primary Expressions. //===----------------------------------------------------------------------===// /// OpaqueValueExpr - An expression referring to an opaque object of a /// fixed type and value class. These don't correspond to concrete /// syntax; instead they're used to express operations (usually copy /// operations) on values whose source is generally obvious from /// context. class OpaqueValueExpr : public Expr { friend class ASTStmtReader; Expr *SourceExpr; public: OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK, ExprObjectKind OK = OK_Ordinary, Expr *SourceExpr = nullptr) : Expr(OpaqueValueExprClass, T, VK, OK), SourceExpr(SourceExpr) { setIsUnique(false); OpaqueValueExprBits.Loc = Loc; setDependence(computeDependence(this)); } /// Given an expression which invokes a copy constructor --- i.e. a /// CXXConstructExpr, possibly wrapped in an ExprWithCleanups --- /// find the OpaqueValueExpr that's the source of the construction. static const OpaqueValueExpr *findInCopyConstruct(const Expr *expr); explicit OpaqueValueExpr(EmptyShell Empty) : Expr(OpaqueValueExprClass, Empty) {} /// Retrieve the location of this expression. SourceLocation getLocation() const { return OpaqueValueExprBits.Loc; } SourceLocation getBeginLoc() const LLVM_READONLY { return SourceExpr ? SourceExpr->getBeginLoc() : getLocation(); } SourceLocation getEndLoc() const LLVM_READONLY { return SourceExpr ? SourceExpr->getEndLoc() : getLocation(); } SourceLocation getExprLoc() const LLVM_READONLY { return SourceExpr ? SourceExpr->getExprLoc() : getLocation(); } child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } /// The source expression of an opaque value expression is the /// expression which originally generated the value. This is /// provided as a convenience for analyses that don't wish to /// precisely model the execution behavior of the program. /// /// The source expression is typically set when building the /// expression which binds the opaque value expression in the first /// place. Expr *getSourceExpr() const { return SourceExpr; } void setIsUnique(bool V) { assert((!V || SourceExpr) && "unique OVEs are expected to have source expressions"); OpaqueValueExprBits.IsUnique = V; } bool isUnique() const { return OpaqueValueExprBits.IsUnique; } static bool classof(const Stmt *T) { return T->getStmtClass() == OpaqueValueExprClass; } }; /// A reference to a declared variable, function, enum, etc. /// [C99 6.5.1p2] /// /// This encodes all the information about how a declaration is referenced /// within an expression. /// /// There are several optional constructs attached to DeclRefExprs only when /// they apply in order to conserve memory. These are laid out past the end of /// the object, and flags in the DeclRefExprBitfield track whether they exist: /// /// DeclRefExprBits.HasQualifier: /// Specifies when this declaration reference expression has a C++ /// nested-name-specifier. /// DeclRefExprBits.HasFoundDecl: /// Specifies when this declaration reference expression has a record of /// a NamedDecl (different from the referenced ValueDecl) which was found /// during name lookup and/or overload resolution. /// DeclRefExprBits.HasTemplateKWAndArgsInfo: /// Specifies when this declaration reference expression has an explicit /// C++ template keyword and/or template argument list. /// DeclRefExprBits.RefersToEnclosingVariableOrCapture /// Specifies when this declaration reference expression (validly) /// refers to an enclosed local or a captured variable. class DeclRefExpr final : public Expr, private llvm::TrailingObjects { friend class ASTStmtReader; friend class ASTStmtWriter; friend TrailingObjects; /// The declaration that we are referencing. ValueDecl *D; /// Provides source/type location info for the declaration name /// embedded in D. DeclarationNameLoc DNLoc; size_t numTrailingObjects(OverloadToken) const { return hasQualifier(); } size_t numTrailingObjects(OverloadToken) const { return hasFoundDecl(); } size_t numTrailingObjects(OverloadToken) const { return hasTemplateKWAndArgsInfo(); } /// Test whether there is a distinct FoundDecl attached to the end of /// this DRE. bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; } DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnlosingVariableOrCapture, const DeclarationNameInfo &NameInfo, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, QualType T, ExprValueKind VK, NonOdrUseReason NOUR); /// Construct an empty declaration reference expression. explicit DeclRefExpr(EmptyShell Empty) : Expr(DeclRefExprClass, Empty) {} public: DeclRefExpr(const ASTContext &Ctx, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, QualType T, ExprValueKind VK, SourceLocation L, const DeclarationNameLoc &LocInfo = DeclarationNameLoc(), NonOdrUseReason NOUR = NOUR_None); static DeclRefExpr * Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc, QualType T, ExprValueKind VK, NamedDecl *FoundD = nullptr, const TemplateArgumentListInfo *TemplateArgs = nullptr, NonOdrUseReason NOUR = NOUR_None); static DeclRefExpr * Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK, NamedDecl *FoundD = nullptr, const TemplateArgumentListInfo *TemplateArgs = nullptr, NonOdrUseReason NOUR = NOUR_None); /// Construct an empty declaration reference expression. static DeclRefExpr *CreateEmpty(const ASTContext &Context, bool HasQualifier, bool HasFoundDecl, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs); ValueDecl *getDecl() { return D; } const ValueDecl *getDecl() const { return D; } void setDecl(ValueDecl *NewD); DeclarationNameInfo getNameInfo() const { return DeclarationNameInfo(getDecl()->getDeclName(), getLocation(), DNLoc); } SourceLocation getLocation() const { return DeclRefExprBits.Loc; } void setLocation(SourceLocation L) { DeclRefExprBits.Loc = L; } SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; /// Determine whether this declaration reference was preceded by a /// C++ nested-name-specifier, e.g., \c N::foo. bool hasQualifier() const { return DeclRefExprBits.HasQualifier; } /// If the name was qualified, retrieves the nested-name-specifier /// that precedes the name, with source-location information. NestedNameSpecifierLoc getQualifierLoc() const { if (!hasQualifier()) return NestedNameSpecifierLoc(); return *getTrailingObjects(); } /// If the name was qualified, retrieves the nested-name-specifier /// that precedes the name. Otherwise, returns NULL. NestedNameSpecifier *getQualifier() const { return getQualifierLoc().getNestedNameSpecifier(); } /// Get the NamedDecl through which this reference occurred. /// /// This Decl may be different from the ValueDecl actually referred to in the /// presence of using declarations, etc. It always returns non-NULL, and may /// simple return the ValueDecl when appropriate. NamedDecl *getFoundDecl() { return hasFoundDecl() ? *getTrailingObjects() : D; } /// Get the NamedDecl through which this reference occurred. /// See non-const variant. const NamedDecl *getFoundDecl() const { return hasFoundDecl() ? *getTrailingObjects() : D; } bool hasTemplateKWAndArgsInfo() const { return DeclRefExprBits.HasTemplateKWAndArgsInfo; } /// Retrieve the location of the template keyword preceding /// this name, if any. SourceLocation getTemplateKeywordLoc() const { if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); return getTrailingObjects()->TemplateKWLoc; } /// Retrieve the location of the left angle bracket starting the /// explicit template argument list following the name, if any. SourceLocation getLAngleLoc() const { if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); return getTrailingObjects()->LAngleLoc; } /// Retrieve the location of the right angle bracket ending the /// explicit template argument list following the name, if any. SourceLocation getRAngleLoc() const { if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); return getTrailingObjects()->RAngleLoc; } /// Determines whether the name in this declaration reference /// was preceded by the template keyword. bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } /// Determines whether this declaration reference was followed by an /// explicit template argument list. bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } /// Copies the template arguments (if present) into the given /// structure. void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { if (hasExplicitTemplateArgs()) getTrailingObjects()->copyInto( getTrailingObjects(), List); } /// Retrieve the template arguments provided as part of this /// template-id. const TemplateArgumentLoc *getTemplateArgs() const { if (!hasExplicitTemplateArgs()) return nullptr; return getTrailingObjects(); } /// Retrieve the number of template arguments provided as part of this /// template-id. unsigned getNumTemplateArgs() const { if (!hasExplicitTemplateArgs()) return 0; return getTrailingObjects()->NumTemplateArgs; } ArrayRef template_arguments() const { return {getTemplateArgs(), getNumTemplateArgs()}; } /// Returns true if this expression refers to a function that /// was resolved from an overloaded set having size greater than 1. bool hadMultipleCandidates() const { return DeclRefExprBits.HadMultipleCandidates; } /// Sets the flag telling whether this expression refers to /// a function that was resolved from an overloaded set having size /// greater than 1. void setHadMultipleCandidates(bool V = true) { DeclRefExprBits.HadMultipleCandidates = V; } /// Is this expression a non-odr-use reference, and if so, why? NonOdrUseReason isNonOdrUse() const { return static_cast(DeclRefExprBits.NonOdrUseReason); } /// Does this DeclRefExpr refer to an enclosing local or a captured /// variable? bool refersToEnclosingVariableOrCapture() const { return DeclRefExprBits.RefersToEnclosingVariableOrCapture; } static bool classof(const Stmt *T) { return T->getStmtClass() == DeclRefExprClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// Used by IntegerLiteral/FloatingLiteral to store the numeric without /// leaking memory. /// /// For large floats/integers, APFloat/APInt will allocate memory from the heap /// to represent these numbers. Unfortunately, when we use a BumpPtrAllocator /// to allocate IntegerLiteral/FloatingLiteral nodes the memory associated with /// the APFloat/APInt values will never get freed. APNumericStorage uses /// ASTContext's allocator for memory allocation. class APNumericStorage { union { uint64_t VAL; ///< Used to store the <= 64 bits integer value. uint64_t *pVal; ///< Used to store the >64 bits integer value. }; unsigned BitWidth; bool hasAllocation() const { return llvm::APInt::getNumWords(BitWidth) > 1; } APNumericStorage(const APNumericStorage &) = delete; void operator=(const APNumericStorage &) = delete; protected: APNumericStorage() : VAL(0), BitWidth(0) { } llvm::APInt getIntValue() const { unsigned NumWords = llvm::APInt::getNumWords(BitWidth); if (NumWords > 1) return llvm::APInt(BitWidth, NumWords, pVal); else return llvm::APInt(BitWidth, VAL); } void setIntValue(const ASTContext &C, const llvm::APInt &Val); }; class APIntStorage : private APNumericStorage { public: llvm::APInt getValue() const { return getIntValue(); } void setValue(const ASTContext &C, const llvm::APInt &Val) { setIntValue(C, Val); } }; class APFloatStorage : private APNumericStorage { public: llvm::APFloat getValue(const llvm::fltSemantics &Semantics) const { return llvm::APFloat(Semantics, getIntValue()); } void setValue(const ASTContext &C, const llvm::APFloat &Val) { setIntValue(C, Val.bitcastToAPInt()); } }; class IntegerLiteral : public Expr, public APIntStorage { SourceLocation Loc; /// Construct an empty integer literal. explicit IntegerLiteral(EmptyShell Empty) : Expr(IntegerLiteralClass, Empty) { } public: // type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy, // or UnsignedLongLongTy IntegerLiteral(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l); /// Returns a new integer literal with value 'V' and type 'type'. /// \param type - either IntTy, LongTy, LongLongTy, UnsignedIntTy, /// UnsignedLongTy, or UnsignedLongLongTy which should match the size of V /// \param V - the value that the returned integer literal contains. static IntegerLiteral *Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l); /// Returns a new empty integer literal. static IntegerLiteral *Create(const ASTContext &C, EmptyShell Empty); SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } /// Retrieve the location of the literal. SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation Location) { Loc = Location; } static bool classof(const Stmt *T) { return T->getStmtClass() == IntegerLiteralClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; class FixedPointLiteral : public Expr, public APIntStorage { SourceLocation Loc; unsigned Scale; /// \brief Construct an empty fixed-point literal. explicit FixedPointLiteral(EmptyShell Empty) : Expr(FixedPointLiteralClass, Empty) {} public: FixedPointLiteral(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l, unsigned Scale); // Store the int as is without any bit shifting. static FixedPointLiteral *CreateFromRawInt(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l, unsigned Scale); /// Returns an empty fixed-point literal. static FixedPointLiteral *Create(const ASTContext &C, EmptyShell Empty); SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } /// \brief Retrieve the location of the literal. SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation Location) { Loc = Location; } unsigned getScale() const { return Scale; } void setScale(unsigned S) { Scale = S; } static bool classof(const Stmt *T) { return T->getStmtClass() == FixedPointLiteralClass; } std::string getValueAsString(unsigned Radix) const; // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; class CharacterLiteral : public Expr { public: enum CharacterKind { Ascii, Wide, UTF8, UTF16, UTF32 }; private: unsigned Value; SourceLocation Loc; public: // type should be IntTy CharacterLiteral(unsigned value, CharacterKind kind, QualType type, SourceLocation l) : Expr(CharacterLiteralClass, type, VK_PRValue, OK_Ordinary), Value(value), Loc(l) { CharacterLiteralBits.Kind = kind; setDependence(ExprDependence::None); } /// Construct an empty character literal. CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { } SourceLocation getLocation() const { return Loc; } CharacterKind getKind() const { return static_cast(CharacterLiteralBits.Kind); } SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } unsigned getValue() const { return Value; } void setLocation(SourceLocation Location) { Loc = Location; } void setKind(CharacterKind kind) { CharacterLiteralBits.Kind = kind; } void setValue(unsigned Val) { Value = Val; } static bool classof(const Stmt *T) { return T->getStmtClass() == CharacterLiteralClass; } static void print(unsigned val, CharacterKind Kind, raw_ostream &OS); // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; class FloatingLiteral : public Expr, private APFloatStorage { SourceLocation Loc; FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L); /// Construct an empty floating-point literal. explicit FloatingLiteral(const ASTContext &C, EmptyShell Empty); public: static FloatingLiteral *Create(const ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L); static FloatingLiteral *Create(const ASTContext &C, EmptyShell Empty); llvm::APFloat getValue() const { return APFloatStorage::getValue(getSemantics()); } void setValue(const ASTContext &C, const llvm::APFloat &Val) { assert(&getSemantics() == &Val.getSemantics() && "Inconsistent semantics"); APFloatStorage::setValue(C, Val); } /// Get a raw enumeration value representing the floating-point semantics of /// this literal (32-bit IEEE, x87, ...), suitable for serialisation. llvm::APFloatBase::Semantics getRawSemantics() const { return static_cast( FloatingLiteralBits.Semantics); } /// Set the raw enumeration value representing the floating-point semantics of /// this literal (32-bit IEEE, x87, ...), suitable for serialisation. void setRawSemantics(llvm::APFloatBase::Semantics Sem) { FloatingLiteralBits.Semantics = Sem; } /// Return the APFloat semantics this literal uses. const llvm::fltSemantics &getSemantics() const { return llvm::APFloatBase::EnumToSemantics( static_cast( FloatingLiteralBits.Semantics)); } /// Set the APFloat semantics this literal uses. void setSemantics(const llvm::fltSemantics &Sem) { FloatingLiteralBits.Semantics = llvm::APFloatBase::SemanticsToEnum(Sem); } bool isExact() const { return FloatingLiteralBits.IsExact; } void setExact(bool E) { FloatingLiteralBits.IsExact = E; } /// getValueAsApproximateDouble - This returns the value as an inaccurate /// double. Note that this may cause loss of precision, but is useful for /// debugging dumps, etc. double getValueAsApproximateDouble() const; SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } static bool classof(const Stmt *T) { return T->getStmtClass() == FloatingLiteralClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// ImaginaryLiteral - We support imaginary integer and floating point literals, /// like "1.0i". We represent these as a wrapper around FloatingLiteral and /// IntegerLiteral classes. Instances of this class always have a Complex type /// whose element type matches the subexpression. /// class ImaginaryLiteral : public Expr { Stmt *Val; public: ImaginaryLiteral(Expr *val, QualType Ty) : Expr(ImaginaryLiteralClass, Ty, VK_PRValue, OK_Ordinary), Val(val) { setDependence(ExprDependence::None); } /// Build an empty imaginary literal. explicit ImaginaryLiteral(EmptyShell Empty) : Expr(ImaginaryLiteralClass, Empty) { } const Expr *getSubExpr() const { return cast(Val); } Expr *getSubExpr() { return cast(Val); } void setSubExpr(Expr *E) { Val = E; } SourceLocation getBeginLoc() const LLVM_READONLY { return Val->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return Val->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ImaginaryLiteralClass; } // Iterators child_range children() { return child_range(&Val, &Val+1); } const_child_range children() const { return const_child_range(&Val, &Val + 1); } }; /// StringLiteral - This represents a string literal expression, e.g. "foo" /// or L"bar" (wide strings). The actual string data can be obtained with /// getBytes() and is NOT null-terminated. The length of the string data is /// determined by calling getByteLength(). /// /// The C type for a string is always a ConstantArrayType. In C++, the char /// type is const qualified, in C it is not. /// /// Note that strings in C can be formed by concatenation of multiple string /// literal pptokens in translation phase #6. This keeps track of the locations /// of each of these pieces. /// /// Strings in C can also be truncated and extended by assigning into arrays, /// e.g. with constructs like: /// char X[2] = "foobar"; /// In this case, getByteLength() will return 6, but the string literal will /// have type "char[2]". class StringLiteral final : public Expr, private llvm::TrailingObjects { friend class ASTStmtReader; friend TrailingObjects; /// StringLiteral is followed by several trailing objects. They are in order: /// /// * A single unsigned storing the length in characters of this string. The /// length in bytes is this length times the width of a single character. /// Always present and stored as a trailing objects because storing it in /// StringLiteral would increase the size of StringLiteral by sizeof(void *) /// due to alignment requirements. If you add some data to StringLiteral, /// consider moving it inside StringLiteral. /// /// * An array of getNumConcatenated() SourceLocation, one for each of the /// token this string is made of. /// /// * An array of getByteLength() char used to store the string data. public: enum StringKind { Ascii, Wide, UTF8, UTF16, UTF32 }; private: unsigned numTrailingObjects(OverloadToken) const { return 1; } unsigned numTrailingObjects(OverloadToken) const { return getNumConcatenated(); } unsigned numTrailingObjects(OverloadToken) const { return getByteLength(); } char *getStrDataAsChar() { return getTrailingObjects(); } const char *getStrDataAsChar() const { return getTrailingObjects(); } const uint16_t *getStrDataAsUInt16() const { return reinterpret_cast(getTrailingObjects()); } const uint32_t *getStrDataAsUInt32() const { return reinterpret_cast(getTrailingObjects()); } /// Build a string literal. StringLiteral(const ASTContext &Ctx, StringRef Str, StringKind Kind, bool Pascal, QualType Ty, const SourceLocation *Loc, unsigned NumConcatenated); /// Build an empty string literal. StringLiteral(EmptyShell Empty, unsigned NumConcatenated, unsigned Length, unsigned CharByteWidth); /// Map a target and string kind to the appropriate character width. static unsigned mapCharByteWidth(TargetInfo const &Target, StringKind SK); /// Set one of the string literal token. void setStrTokenLoc(unsigned TokNum, SourceLocation L) { assert(TokNum < getNumConcatenated() && "Invalid tok number"); getTrailingObjects()[TokNum] = L; } public: /// This is the "fully general" constructor that allows representation of /// strings formed from multiple concatenated tokens. static StringLiteral *Create(const ASTContext &Ctx, StringRef Str, StringKind Kind, bool Pascal, QualType Ty, const SourceLocation *Loc, unsigned NumConcatenated); /// Simple constructor for string literals made from one token. static StringLiteral *Create(const ASTContext &Ctx, StringRef Str, StringKind Kind, bool Pascal, QualType Ty, SourceLocation Loc) { return Create(Ctx, Str, Kind, Pascal, Ty, &Loc, 1); } /// Construct an empty string literal. static StringLiteral *CreateEmpty(const ASTContext &Ctx, unsigned NumConcatenated, unsigned Length, unsigned CharByteWidth); StringRef getString() const { assert(getCharByteWidth() == 1 && "This function is used in places that assume strings use char"); return StringRef(getStrDataAsChar(), getByteLength()); } /// Allow access to clients that need the byte representation, such as /// ASTWriterStmt::VisitStringLiteral(). StringRef getBytes() const { // FIXME: StringRef may not be the right type to use as a result for this. return StringRef(getStrDataAsChar(), getByteLength()); } void outputString(raw_ostream &OS) const; uint32_t getCodeUnit(size_t i) const { assert(i < getLength() && "out of bounds access"); switch (getCharByteWidth()) { case 1: return static_cast(getStrDataAsChar()[i]); case 2: return getStrDataAsUInt16()[i]; case 4: return getStrDataAsUInt32()[i]; } llvm_unreachable("Unsupported character width!"); } unsigned getByteLength() const { return getCharByteWidth() * getLength(); } unsigned getLength() const { return *getTrailingObjects(); } unsigned getCharByteWidth() const { return StringLiteralBits.CharByteWidth; } StringKind getKind() const { return static_cast(StringLiteralBits.Kind); } bool isAscii() const { return getKind() == Ascii; } bool isWide() const { return getKind() == Wide; } bool isUTF8() const { return getKind() == UTF8; } bool isUTF16() const { return getKind() == UTF16; } bool isUTF32() const { return getKind() == UTF32; } bool isPascal() const { return StringLiteralBits.IsPascal; } bool containsNonAscii() const { for (auto c : getString()) if (!isASCII(c)) return true; return false; } bool containsNonAsciiOrNull() const { for (auto c : getString()) if (!isASCII(c) || !c) return true; return false; } /// getNumConcatenated - Get the number of string literal tokens that were /// concatenated in translation phase #6 to form this string literal. unsigned getNumConcatenated() const { return StringLiteralBits.NumConcatenated; } /// Get one of the string literal token. SourceLocation getStrTokenLoc(unsigned TokNum) const { assert(TokNum < getNumConcatenated() && "Invalid tok number"); return getTrailingObjects()[TokNum]; } /// getLocationOfByte - Return a source location that points to the specified /// byte of this string literal. /// /// Strings are amazingly complex. They can be formed from multiple tokens /// and can have escape sequences in them in addition to the usual trigraph /// and escaped newline business. This routine handles this complexity. /// SourceLocation getLocationOfByte(unsigned ByteNo, const SourceManager &SM, const LangOptions &Features, const TargetInfo &Target, unsigned *StartToken = nullptr, unsigned *StartTokenByteOffset = nullptr) const; typedef const SourceLocation *tokloc_iterator; tokloc_iterator tokloc_begin() const { return getTrailingObjects(); } tokloc_iterator tokloc_end() const { return getTrailingObjects() + getNumConcatenated(); } SourceLocation getBeginLoc() const LLVM_READONLY { return *tokloc_begin(); } SourceLocation getEndLoc() const LLVM_READONLY { return *(tokloc_end() - 1); } static bool classof(const Stmt *T) { return T->getStmtClass() == StringLiteralClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// [C99 6.4.2.2] - A predefined identifier such as __func__. class PredefinedExpr final : public Expr, private llvm::TrailingObjects { friend class ASTStmtReader; friend TrailingObjects; // PredefinedExpr is optionally followed by a single trailing // "Stmt *" for the predefined identifier. It is present if and only if // hasFunctionName() is true and is always a "StringLiteral *". public: enum IdentKind { Func, Function, LFunction, // Same as Function, but as wide string. FuncDName, FuncSig, LFuncSig, // Same as FuncSig, but as as wide string PrettyFunction, /// The same as PrettyFunction, except that the /// 'virtual' keyword is omitted for virtual member functions. PrettyFunctionNoVirtual }; private: PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, StringLiteral *SL); explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName); /// True if this PredefinedExpr has storage for a function name. bool hasFunctionName() const { return PredefinedExprBits.HasFunctionName; } void setFunctionName(StringLiteral *SL) { assert(hasFunctionName() && "This PredefinedExpr has no storage for a function name!"); *getTrailingObjects() = SL; } public: /// Create a PredefinedExpr. static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L, QualType FNTy, IdentKind IK, StringLiteral *SL); /// Create an empty PredefinedExpr. static PredefinedExpr *CreateEmpty(const ASTContext &Ctx, bool HasFunctionName); IdentKind getIdentKind() const { return static_cast(PredefinedExprBits.Kind); } SourceLocation getLocation() const { return PredefinedExprBits.Loc; } void setLocation(SourceLocation L) { PredefinedExprBits.Loc = L; } StringLiteral *getFunctionName() { return hasFunctionName() ? static_cast(*getTrailingObjects()) : nullptr; } const StringLiteral *getFunctionName() const { return hasFunctionName() ? static_cast(*getTrailingObjects()) : nullptr; } static StringRef getIdentKindName(IdentKind IK); StringRef getIdentKindName() const { return getIdentKindName(getIdentKind()); } static std::string ComputeName(IdentKind IK, const Decl *CurrentDecl); SourceLocation getBeginLoc() const { return getLocation(); } SourceLocation getEndLoc() const { return getLocation(); } static bool classof(const Stmt *T) { return T->getStmtClass() == PredefinedExprClass; } // Iterators child_range children() { return child_range(getTrailingObjects(), getTrailingObjects() + hasFunctionName()); } const_child_range children() const { return const_child_range(getTrailingObjects(), getTrailingObjects() + hasFunctionName()); } }; // This represents a use of the __builtin_sycl_unique_stable_name, which takes a // type-id, and at CodeGen time emits a unique string representation of the // type in a way that permits us to properly encode information about the SYCL // kernels. class SYCLUniqueStableNameExpr final : public Expr { friend class ASTStmtReader; SourceLocation OpLoc, LParen, RParen; TypeSourceInfo *TypeInfo; SYCLUniqueStableNameExpr(EmptyShell Empty, QualType ResultTy); SYCLUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen, SourceLocation RParen, QualType ResultTy, TypeSourceInfo *TSI); void setTypeSourceInfo(TypeSourceInfo *Ty) { TypeInfo = Ty; } void setLocation(SourceLocation L) { OpLoc = L; } void setLParenLocation(SourceLocation L) { LParen = L; } void setRParenLocation(SourceLocation L) { RParen = L; } public: TypeSourceInfo *getTypeSourceInfo() { return TypeInfo; } const TypeSourceInfo *getTypeSourceInfo() const { return TypeInfo; } static SYCLUniqueStableNameExpr * Create(const ASTContext &Ctx, SourceLocation OpLoc, SourceLocation LParen, SourceLocation RParen, TypeSourceInfo *TSI); static SYCLUniqueStableNameExpr *CreateEmpty(const ASTContext &Ctx); SourceLocation getBeginLoc() const { return getLocation(); } SourceLocation getEndLoc() const { return RParen; } SourceLocation getLocation() const { return OpLoc; } SourceLocation getLParenLocation() const { return LParen; } SourceLocation getRParenLocation() const { return RParen; } static bool classof(const Stmt *T) { return T->getStmtClass() == SYCLUniqueStableNameExprClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } // Convenience function to generate the name of the currently stored type. std::string ComputeName(ASTContext &Context) const; // Get the generated name of the type. Note that this only works after all // kernels have been instantiated. static std::string ComputeName(ASTContext &Context, QualType Ty); }; /// ParenExpr - This represents a parethesized expression, e.g. "(1)". This /// AST node is only formed if full location information is requested. class ParenExpr : public Expr { SourceLocation L, R; Stmt *Val; public: ParenExpr(SourceLocation l, SourceLocation r, Expr *val) : Expr(ParenExprClass, val->getType(), val->getValueKind(), val->getObjectKind()), L(l), R(r), Val(val) { setDependence(computeDependence(this)); } /// Construct an empty parenthesized expression. explicit ParenExpr(EmptyShell Empty) : Expr(ParenExprClass, Empty) { } const Expr *getSubExpr() const { return cast(Val); } Expr *getSubExpr() { return cast(Val); } void setSubExpr(Expr *E) { Val = E; } SourceLocation getBeginLoc() const LLVM_READONLY { return L; } SourceLocation getEndLoc() const LLVM_READONLY { return R; } /// Get the location of the left parentheses '('. SourceLocation getLParen() const { return L; } void setLParen(SourceLocation Loc) { L = Loc; } /// Get the location of the right parentheses ')'. SourceLocation getRParen() const { return R; } void setRParen(SourceLocation Loc) { R = Loc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ParenExprClass; } // Iterators child_range children() { return child_range(&Val, &Val+1); } const_child_range children() const { return const_child_range(&Val, &Val + 1); } }; /// UnaryOperator - This represents the unary-expression's (except sizeof and /// alignof), the postinc/postdec operators from postfix-expression, and various /// extensions. /// /// Notes on various nodes: /// /// Real/Imag - These return the real/imag part of a complex operand. If /// applied to a non-complex value, the former returns its operand and the /// later returns zero in the type of the operand. /// class UnaryOperator final : public Expr, private llvm::TrailingObjects { Stmt *Val; size_t numTrailingObjects(OverloadToken) const { return UnaryOperatorBits.HasFPFeatures ? 1 : 0; } FPOptionsOverride &getTrailingFPFeatures() { assert(UnaryOperatorBits.HasFPFeatures); return *getTrailingObjects(); } const FPOptionsOverride &getTrailingFPFeatures() const { assert(UnaryOperatorBits.HasFPFeatures); return *getTrailingObjects(); } public: typedef UnaryOperatorKind Opcode; protected: UnaryOperator(const ASTContext &Ctx, Expr *input, Opcode opc, QualType type, ExprValueKind VK, ExprObjectKind OK, SourceLocation l, bool CanOverflow, FPOptionsOverride FPFeatures); /// Build an empty unary operator. explicit UnaryOperator(bool HasFPFeatures, EmptyShell Empty) : Expr(UnaryOperatorClass, Empty) { UnaryOperatorBits.Opc = UO_AddrOf; UnaryOperatorBits.HasFPFeatures = HasFPFeatures; } public: static UnaryOperator *CreateEmpty(const ASTContext &C, bool hasFPFeatures); static UnaryOperator *Create(const ASTContext &C, Expr *input, Opcode opc, QualType type, ExprValueKind VK, ExprObjectKind OK, SourceLocation l, bool CanOverflow, FPOptionsOverride FPFeatures); Opcode getOpcode() const { return static_cast(UnaryOperatorBits.Opc); } void setOpcode(Opcode Opc) { UnaryOperatorBits.Opc = Opc; } Expr *getSubExpr() const { return cast(Val); } void setSubExpr(Expr *E) { Val = E; } /// getOperatorLoc - Return the location of the operator. SourceLocation getOperatorLoc() const { return UnaryOperatorBits.Loc; } void setOperatorLoc(SourceLocation L) { UnaryOperatorBits.Loc = L; } /// Returns true if the unary operator can cause an overflow. For instance, /// signed int i = INT_MAX; i++; /// signed char c = CHAR_MAX; c++; /// Due to integer promotions, c++ is promoted to an int before the postfix /// increment, and the result is an int that cannot overflow. However, i++ /// can overflow. bool canOverflow() const { return UnaryOperatorBits.CanOverflow; } void setCanOverflow(bool C) { UnaryOperatorBits.CanOverflow = C; } // Get the FP contractability status of this operator. Only meaningful for // operations on floating point types. bool isFPContractableWithinStatement(const LangOptions &LO) const { return getFPFeaturesInEffect(LO).allowFPContractWithinStatement(); } // Get the FENV_ACCESS status of this operator. Only meaningful for // operations on floating point types. bool isFEnvAccessOn(const LangOptions &LO) const { return getFPFeaturesInEffect(LO).getAllowFEnvAccess(); } /// isPostfix - Return true if this is a postfix operation, like x++. static bool isPostfix(Opcode Op) { return Op == UO_PostInc || Op == UO_PostDec; } /// isPrefix - Return true if this is a prefix operation, like --x. static bool isPrefix(Opcode Op) { return Op == UO_PreInc || Op == UO_PreDec; } bool isPrefix() const { return isPrefix(getOpcode()); } bool isPostfix() const { return isPostfix(getOpcode()); } static bool isIncrementOp(Opcode Op) { return Op == UO_PreInc || Op == UO_PostInc; } bool isIncrementOp() const { return isIncrementOp(getOpcode()); } static bool isDecrementOp(Opcode Op) { return Op == UO_PreDec || Op == UO_PostDec; } bool isDecrementOp() const { return isDecrementOp(getOpcode()); } static bool isIncrementDecrementOp(Opcode Op) { return Op <= UO_PreDec; } bool isIncrementDecrementOp() const { return isIncrementDecrementOp(getOpcode()); } static bool isArithmeticOp(Opcode Op) { return Op >= UO_Plus && Op <= UO_LNot; } bool isArithmeticOp() const { return isArithmeticOp(getOpcode()); } /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "sizeof" or "[pre]++" static StringRef getOpcodeStr(Opcode Op); /// Retrieve the unary opcode that corresponds to the given /// overloaded operator. static Opcode getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix); /// Retrieve the overloaded operator kind that corresponds to /// the given unary opcode. static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); SourceLocation getBeginLoc() const LLVM_READONLY { return isPostfix() ? Val->getBeginLoc() : getOperatorLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return isPostfix() ? getOperatorLoc() : Val->getEndLoc(); } SourceLocation getExprLoc() const { return getOperatorLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == UnaryOperatorClass; } // Iterators child_range children() { return child_range(&Val, &Val+1); } const_child_range children() const { return const_child_range(&Val, &Val + 1); } /// Is FPFeatures in Trailing Storage? bool hasStoredFPFeatures() const { return UnaryOperatorBits.HasFPFeatures; } /// Get FPFeatures from trailing storage. FPOptionsOverride getStoredFPFeatures() const { return getTrailingFPFeatures(); } protected: /// Set FPFeatures in trailing storage, used only by Serialization void setStoredFPFeatures(FPOptionsOverride F) { getTrailingFPFeatures() = F; } public: // Get the FP features status of this operator. Only meaningful for // operations on floating point types. FPOptions getFPFeaturesInEffect(const LangOptions &LO) const { if (UnaryOperatorBits.HasFPFeatures) return getStoredFPFeatures().applyOverrides(LO); return FPOptions::defaultWithoutTrailingStorage(LO); } FPOptionsOverride getFPOptionsOverride() const { if (UnaryOperatorBits.HasFPFeatures) return getStoredFPFeatures(); return FPOptionsOverride(); } friend TrailingObjects; friend class ASTReader; friend class ASTStmtReader; friend class ASTStmtWriter; }; /// Helper class for OffsetOfExpr. // __builtin_offsetof(type, identifier(.identifier|[expr])*) class OffsetOfNode { public: /// The kind of offsetof node we have. enum Kind { /// An index into an array. Array = 0x00, /// A field. Field = 0x01, /// A field in a dependent type, known only by its name. Identifier = 0x02, /// An implicit indirection through a C++ base class, when the /// field found is in a base class. Base = 0x03 }; private: enum { MaskBits = 2, Mask = 0x03 }; /// The source range that covers this part of the designator. SourceRange Range; /// The data describing the designator, which comes in three /// different forms, depending on the lower two bits. /// - An unsigned index into the array of Expr*'s stored after this node /// in memory, for [constant-expression] designators. /// - A FieldDecl*, for references to a known field. /// - An IdentifierInfo*, for references to a field with a given name /// when the class type is dependent. /// - A CXXBaseSpecifier*, for references that look at a field in a /// base class. uintptr_t Data; public: /// Create an offsetof node that refers to an array element. OffsetOfNode(SourceLocation LBracketLoc, unsigned Index, SourceLocation RBracketLoc) : Range(LBracketLoc, RBracketLoc), Data((Index << 2) | Array) {} /// Create an offsetof node that refers to a field. OffsetOfNode(SourceLocation DotLoc, FieldDecl *Field, SourceLocation NameLoc) : Range(DotLoc.isValid() ? DotLoc : NameLoc, NameLoc), Data(reinterpret_cast(Field) | OffsetOfNode::Field) {} /// Create an offsetof node that refers to an identifier. OffsetOfNode(SourceLocation DotLoc, IdentifierInfo *Name, SourceLocation NameLoc) : Range(DotLoc.isValid() ? DotLoc : NameLoc, NameLoc), Data(reinterpret_cast(Name) | Identifier) {} /// Create an offsetof node that refers into a C++ base class. explicit OffsetOfNode(const CXXBaseSpecifier *Base) : Data(reinterpret_cast(Base) | OffsetOfNode::Base) {} /// Determine what kind of offsetof node this is. Kind getKind() const { return static_cast(Data & Mask); } /// For an array element node, returns the index into the array /// of expressions. unsigned getArrayExprIndex() const { assert(getKind() == Array); return Data >> 2; } /// For a field offsetof node, returns the field. FieldDecl *getField() const { assert(getKind() == Field); return reinterpret_cast(Data & ~(uintptr_t)Mask); } /// For a field or identifier offsetof node, returns the name of /// the field. IdentifierInfo *getFieldName() const; /// For a base class node, returns the base specifier. CXXBaseSpecifier *getBase() const { assert(getKind() == Base); return reinterpret_cast(Data & ~(uintptr_t)Mask); } /// Retrieve the source range that covers this offsetof node. /// /// For an array element node, the source range contains the locations of /// the square brackets. For a field or identifier node, the source range /// contains the location of the period (if there is one) and the /// identifier. SourceRange getSourceRange() const LLVM_READONLY { return Range; } SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } }; /// OffsetOfExpr - [C99 7.17] - This represents an expression of the form /// offsetof(record-type, member-designator). For example, given: /// @code /// struct S { /// float f; /// double d; /// }; /// struct T { /// int i; /// struct S s[10]; /// }; /// @endcode /// we can represent and evaluate the expression @c offsetof(struct T, s[2].d). class OffsetOfExpr final : public Expr, private llvm::TrailingObjects { SourceLocation OperatorLoc, RParenLoc; // Base type; TypeSourceInfo *TSInfo; // Number of sub-components (i.e. instances of OffsetOfNode). unsigned NumComps; // Number of sub-expressions (i.e. array subscript expressions). unsigned NumExprs; size_t numTrailingObjects(OverloadToken) const { return NumComps; } OffsetOfExpr(const ASTContext &C, QualType type, SourceLocation OperatorLoc, TypeSourceInfo *tsi, ArrayRef comps, ArrayRef exprs, SourceLocation RParenLoc); explicit OffsetOfExpr(unsigned numComps, unsigned numExprs) : Expr(OffsetOfExprClass, EmptyShell()), TSInfo(nullptr), NumComps(numComps), NumExprs(numExprs) {} public: static OffsetOfExpr *Create(const ASTContext &C, QualType type, SourceLocation OperatorLoc, TypeSourceInfo *tsi, ArrayRef comps, ArrayRef exprs, SourceLocation RParenLoc); static OffsetOfExpr *CreateEmpty(const ASTContext &C, unsigned NumComps, unsigned NumExprs); /// getOperatorLoc - Return the location of the operator. SourceLocation getOperatorLoc() const { return OperatorLoc; } void setOperatorLoc(SourceLocation L) { OperatorLoc = L; } /// Return the location of the right parentheses. SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation R) { RParenLoc = R; } TypeSourceInfo *getTypeSourceInfo() const { return TSInfo; } void setTypeSourceInfo(TypeSourceInfo *tsi) { TSInfo = tsi; } const OffsetOfNode &getComponent(unsigned Idx) const { assert(Idx < NumComps && "Subscript out of range"); return getTrailingObjects()[Idx]; } void setComponent(unsigned Idx, OffsetOfNode ON) { assert(Idx < NumComps && "Subscript out of range"); getTrailingObjects()[Idx] = ON; } unsigned getNumComponents() const { return NumComps; } Expr* getIndexExpr(unsigned Idx) { assert(Idx < NumExprs && "Subscript out of range"); return getTrailingObjects()[Idx]; } const Expr *getIndexExpr(unsigned Idx) const { assert(Idx < NumExprs && "Subscript out of range"); return getTrailingObjects()[Idx]; } void setIndexExpr(unsigned Idx, Expr* E) { assert(Idx < NumComps && "Subscript out of range"); getTrailingObjects()[Idx] = E; } unsigned getNumExpressions() const { return NumExprs; } SourceLocation getBeginLoc() const LLVM_READONLY { return OperatorLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == OffsetOfExprClass; } // Iterators child_range children() { Stmt **begin = reinterpret_cast(getTrailingObjects()); return child_range(begin, begin + NumExprs); } const_child_range children() const { Stmt *const *begin = reinterpret_cast(getTrailingObjects()); return const_child_range(begin, begin + NumExprs); } friend TrailingObjects; }; /// UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) /// expression operand. Used for sizeof/alignof (C99 6.5.3.4) and /// vec_step (OpenCL 1.1 6.11.12). class UnaryExprOrTypeTraitExpr : public Expr { union { TypeSourceInfo *Ty; Stmt *Ex; } Argument; SourceLocation OpLoc, RParenLoc; public: UnaryExprOrTypeTraitExpr(UnaryExprOrTypeTrait ExprKind, TypeSourceInfo *TInfo, QualType resultType, SourceLocation op, SourceLocation rp) : Expr(UnaryExprOrTypeTraitExprClass, resultType, VK_PRValue, OK_Ordinary), OpLoc(op), RParenLoc(rp) { assert(ExprKind <= UETT_Last && "invalid enum value!"); UnaryExprOrTypeTraitExprBits.Kind = ExprKind; assert(static_cast(ExprKind) == UnaryExprOrTypeTraitExprBits.Kind && "UnaryExprOrTypeTraitExprBits.Kind overflow!"); UnaryExprOrTypeTraitExprBits.IsType = true; Argument.Ty = TInfo; setDependence(computeDependence(this)); } UnaryExprOrTypeTraitExpr(UnaryExprOrTypeTrait ExprKind, Expr *E, QualType resultType, SourceLocation op, SourceLocation rp); /// Construct an empty sizeof/alignof expression. explicit UnaryExprOrTypeTraitExpr(EmptyShell Empty) : Expr(UnaryExprOrTypeTraitExprClass, Empty) { } UnaryExprOrTypeTrait getKind() const { return static_cast(UnaryExprOrTypeTraitExprBits.Kind); } void setKind(UnaryExprOrTypeTrait K) { assert(K <= UETT_Last && "invalid enum value!"); UnaryExprOrTypeTraitExprBits.Kind = K; assert(static_cast(K) == UnaryExprOrTypeTraitExprBits.Kind && "UnaryExprOrTypeTraitExprBits.Kind overflow!"); } bool isArgumentType() const { return UnaryExprOrTypeTraitExprBits.IsType; } QualType getArgumentType() const { return getArgumentTypeInfo()->getType(); } TypeSourceInfo *getArgumentTypeInfo() const { assert(isArgumentType() && "calling getArgumentType() when arg is expr"); return Argument.Ty; } Expr *getArgumentExpr() { assert(!isArgumentType() && "calling getArgumentExpr() when arg is type"); return static_cast(Argument.Ex); } const Expr *getArgumentExpr() const { return const_cast(this)->getArgumentExpr(); } void setArgument(Expr *E) { Argument.Ex = E; UnaryExprOrTypeTraitExprBits.IsType = false; } void setArgument(TypeSourceInfo *TInfo) { Argument.Ty = TInfo; UnaryExprOrTypeTraitExprBits.IsType = true; } /// Gets the argument type, or the type of the argument expression, whichever /// is appropriate. QualType getTypeOfArgument() const { return isArgumentType() ? getArgumentType() : getArgumentExpr()->getType(); } SourceLocation getOperatorLoc() const { return OpLoc; } void setOperatorLoc(SourceLocation L) { OpLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return OpLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == UnaryExprOrTypeTraitExprClass; } // Iterators child_range children(); const_child_range children() const; }; //===----------------------------------------------------------------------===// // Postfix Operators. //===----------------------------------------------------------------------===// /// ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting. class ArraySubscriptExpr : public Expr { enum { LHS, RHS, END_EXPR }; Stmt *SubExprs[END_EXPR]; bool lhsIsBase() const { return getRHS()->getType()->isIntegerType(); } public: ArraySubscriptExpr(Expr *lhs, Expr *rhs, QualType t, ExprValueKind VK, ExprObjectKind OK, SourceLocation rbracketloc) : Expr(ArraySubscriptExprClass, t, VK, OK) { SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; ArrayOrMatrixSubscriptExprBits.RBracketLoc = rbracketloc; setDependence(computeDependence(this)); } /// Create an empty array subscript expression. explicit ArraySubscriptExpr(EmptyShell Shell) : Expr(ArraySubscriptExprClass, Shell) { } /// An array access can be written A[4] or 4[A] (both are equivalent). /// - getBase() and getIdx() always present the normalized view: A[4]. /// In this case getBase() returns "A" and getIdx() returns "4". /// - getLHS() and getRHS() present the syntactic view. e.g. for /// 4[A] getLHS() returns "4". /// Note: Because vector element access is also written A[4] we must /// predicate the format conversion in getBase and getIdx only on the /// the type of the RHS, as it is possible for the LHS to be a vector of /// integer type Expr *getLHS() { return cast(SubExprs[LHS]); } const Expr *getLHS() const { return cast(SubExprs[LHS]); } void setLHS(Expr *E) { SubExprs[LHS] = E; } Expr *getRHS() { return cast(SubExprs[RHS]); } const Expr *getRHS() const { return cast(SubExprs[RHS]); } void setRHS(Expr *E) { SubExprs[RHS] = E; } Expr *getBase() { return lhsIsBase() ? getLHS() : getRHS(); } const Expr *getBase() const { return lhsIsBase() ? getLHS() : getRHS(); } Expr *getIdx() { return lhsIsBase() ? getRHS() : getLHS(); } const Expr *getIdx() const { return lhsIsBase() ? getRHS() : getLHS(); } SourceLocation getBeginLoc() const LLVM_READONLY { return getLHS()->getBeginLoc(); } SourceLocation getEndLoc() const { return getRBracketLoc(); } SourceLocation getRBracketLoc() const { return ArrayOrMatrixSubscriptExprBits.RBracketLoc; } void setRBracketLoc(SourceLocation L) { ArrayOrMatrixSubscriptExprBits.RBracketLoc = L; } SourceLocation getExprLoc() const LLVM_READONLY { return getBase()->getExprLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ArraySubscriptExprClass; } // Iterators child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); } const_child_range children() const { return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } }; /// MatrixSubscriptExpr - Matrix subscript expression for the MatrixType /// extension. /// MatrixSubscriptExpr can be either incomplete (only Base and RowIdx are set /// so far, the type is IncompleteMatrixIdx) or complete (Base, RowIdx and /// ColumnIdx refer to valid expressions). Incomplete matrix expressions only /// exist during the initial construction of the AST. class MatrixSubscriptExpr : public Expr { enum { BASE, ROW_IDX, COLUMN_IDX, END_EXPR }; Stmt *SubExprs[END_EXPR]; public: MatrixSubscriptExpr(Expr *Base, Expr *RowIdx, Expr *ColumnIdx, QualType T, SourceLocation RBracketLoc) : Expr(MatrixSubscriptExprClass, T, Base->getValueKind(), OK_MatrixComponent) { SubExprs[BASE] = Base; SubExprs[ROW_IDX] = RowIdx; SubExprs[COLUMN_IDX] = ColumnIdx; ArrayOrMatrixSubscriptExprBits.RBracketLoc = RBracketLoc; setDependence(computeDependence(this)); } /// Create an empty matrix subscript expression. explicit MatrixSubscriptExpr(EmptyShell Shell) : Expr(MatrixSubscriptExprClass, Shell) {} bool isIncomplete() const { bool IsIncomplete = hasPlaceholderType(BuiltinType::IncompleteMatrixIdx); assert((SubExprs[COLUMN_IDX] || IsIncomplete) && "expressions without column index must be marked as incomplete"); return IsIncomplete; } Expr *getBase() { return cast(SubExprs[BASE]); } const Expr *getBase() const { return cast(SubExprs[BASE]); } void setBase(Expr *E) { SubExprs[BASE] = E; } Expr *getRowIdx() { return cast(SubExprs[ROW_IDX]); } const Expr *getRowIdx() const { return cast(SubExprs[ROW_IDX]); } void setRowIdx(Expr *E) { SubExprs[ROW_IDX] = E; } Expr *getColumnIdx() { return cast_or_null(SubExprs[COLUMN_IDX]); } const Expr *getColumnIdx() const { assert(!isIncomplete() && "cannot get the column index of an incomplete expression"); return cast(SubExprs[COLUMN_IDX]); } void setColumnIdx(Expr *E) { SubExprs[COLUMN_IDX] = E; } SourceLocation getBeginLoc() const LLVM_READONLY { return getBase()->getBeginLoc(); } SourceLocation getEndLoc() const { return getRBracketLoc(); } SourceLocation getExprLoc() const LLVM_READONLY { return getBase()->getExprLoc(); } SourceLocation getRBracketLoc() const { return ArrayOrMatrixSubscriptExprBits.RBracketLoc; } void setRBracketLoc(SourceLocation L) { ArrayOrMatrixSubscriptExprBits.RBracketLoc = L; } static bool classof(const Stmt *T) { return T->getStmtClass() == MatrixSubscriptExprClass; } // Iterators child_range children() { return child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } const_child_range children() const { return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } }; /// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]). /// CallExpr itself represents a normal function call, e.g., "f(x, 2)", /// while its subclasses may represent alternative syntax that (semantically) /// results in a function call. For example, CXXOperatorCallExpr is /// a subclass for overloaded operator calls that use operator syntax, e.g., /// "str1 + str2" to resolve to a function call. class CallExpr : public Expr { enum { FN = 0, PREARGS_START = 1 }; /// The number of arguments in the call expression. unsigned NumArgs; /// The location of the right parenthese. This has a different meaning for /// the derived classes of CallExpr. SourceLocation RParenLoc; // CallExpr store some data in trailing objects. However since CallExpr // is used a base of other expression classes we cannot use // llvm::TrailingObjects. Instead we manually perform the pointer arithmetic // and casts. // // The trailing objects are in order: // // * A single "Stmt *" for the callee expression. // // * An array of getNumPreArgs() "Stmt *" for the pre-argument expressions. // // * An array of getNumArgs() "Stmt *" for the argument expressions. // // * An optional of type FPOptionsOverride. // // Note that we store the offset in bytes from the this pointer to the start // of the trailing objects. It would be perfectly possible to compute it // based on the dynamic kind of the CallExpr. However 1.) we have plenty of // space in the bit-fields of Stmt. 2.) It was benchmarked to be faster to // compute this once and then load the offset from the bit-fields of Stmt, // instead of re-computing the offset each time the trailing objects are // accessed. /// Return a pointer to the start of the trailing array of "Stmt *". Stmt **getTrailingStmts() { return reinterpret_cast(reinterpret_cast(this) + CallExprBits.OffsetToTrailingObjects); } Stmt *const *getTrailingStmts() const { return const_cast(this)->getTrailingStmts(); } /// Map a statement class to the appropriate offset in bytes from the /// this pointer to the trailing objects. static unsigned offsetToTrailingObjects(StmtClass SC); unsigned getSizeOfTrailingStmts() const { return (1 + getNumPreArgs() + getNumArgs()) * sizeof(Stmt *); } size_t getOffsetOfTrailingFPFeatures() const { assert(hasStoredFPFeatures()); return CallExprBits.OffsetToTrailingObjects + getSizeOfTrailingStmts(); } public: enum class ADLCallKind : bool { NotADL, UsesADL }; static constexpr ADLCallKind NotADL = ADLCallKind::NotADL; static constexpr ADLCallKind UsesADL = ADLCallKind::UsesADL; protected: /// Build a call expression, assuming that appropriate storage has been /// allocated for the trailing objects. CallExpr(StmtClass SC, Expr *Fn, ArrayRef PreArgs, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation RParenLoc, FPOptionsOverride FPFeatures, unsigned MinNumArgs, ADLCallKind UsesADL); /// Build an empty call expression, for deserialization. CallExpr(StmtClass SC, unsigned NumPreArgs, unsigned NumArgs, bool hasFPFeatures, EmptyShell Empty); /// Return the size in bytes needed for the trailing objects. /// Used by the derived classes to allocate the right amount of storage. static unsigned sizeOfTrailingObjects(unsigned NumPreArgs, unsigned NumArgs, bool HasFPFeatures) { return (1 + NumPreArgs + NumArgs) * sizeof(Stmt *) + HasFPFeatures * sizeof(FPOptionsOverride); } Stmt *getPreArg(unsigned I) { assert(I < getNumPreArgs() && "Prearg access out of range!"); return getTrailingStmts()[PREARGS_START + I]; } const Stmt *getPreArg(unsigned I) const { assert(I < getNumPreArgs() && "Prearg access out of range!"); return getTrailingStmts()[PREARGS_START + I]; } void setPreArg(unsigned I, Stmt *PreArg) { assert(I < getNumPreArgs() && "Prearg access out of range!"); getTrailingStmts()[PREARGS_START + I] = PreArg; } unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; } /// Return a pointer to the trailing FPOptions FPOptionsOverride *getTrailingFPFeatures() { assert(hasStoredFPFeatures()); return reinterpret_cast( reinterpret_cast(this) + CallExprBits.OffsetToTrailingObjects + getSizeOfTrailingStmts()); } const FPOptionsOverride *getTrailingFPFeatures() const { assert(hasStoredFPFeatures()); return reinterpret_cast( reinterpret_cast(this) + CallExprBits.OffsetToTrailingObjects + getSizeOfTrailingStmts()); } public: /// Create a call expression. /// \param Fn The callee expression, /// \param Args The argument array, /// \param Ty The type of the call expression (which is *not* the return /// type in general), /// \param VK The value kind of the call expression (lvalue, rvalue, ...), /// \param RParenLoc The location of the right parenthesis in the call /// expression. /// \param FPFeatures Floating-point features associated with the call, /// \param MinNumArgs Specifies the minimum number of arguments. The actual /// number of arguments will be the greater of Args.size() /// and MinNumArgs. This is used in a few places to allocate /// enough storage for the default arguments. /// \param UsesADL Specifies whether the callee was found through /// argument-dependent lookup. /// /// Note that you can use CreateTemporary if you need a temporary call /// expression on the stack. static CallExpr *Create(const ASTContext &Ctx, Expr *Fn, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation RParenLoc, FPOptionsOverride FPFeatures, unsigned MinNumArgs = 0, ADLCallKind UsesADL = NotADL); /// Create a temporary call expression with no arguments in the memory /// pointed to by Mem. Mem must points to at least sizeof(CallExpr) /// + sizeof(Stmt *) bytes of storage, aligned to alignof(CallExpr): /// /// \code{.cpp} /// alignas(CallExpr) char Buffer[sizeof(CallExpr) + sizeof(Stmt *)]; /// CallExpr *TheCall = CallExpr::CreateTemporary(Buffer, etc); /// \endcode static CallExpr *CreateTemporary(void *Mem, Expr *Fn, QualType Ty, ExprValueKind VK, SourceLocation RParenLoc, ADLCallKind UsesADL = NotADL); /// Create an empty call expression, for deserialization. static CallExpr *CreateEmpty(const ASTContext &Ctx, unsigned NumArgs, bool HasFPFeatures, EmptyShell Empty); Expr *getCallee() { return cast(getTrailingStmts()[FN]); } const Expr *getCallee() const { return cast(getTrailingStmts()[FN]); } void setCallee(Expr *F) { getTrailingStmts()[FN] = F; } ADLCallKind getADLCallKind() const { return static_cast(CallExprBits.UsesADL); } void setADLCallKind(ADLCallKind V = UsesADL) { CallExprBits.UsesADL = static_cast(V); } bool usesADL() const { return getADLCallKind() == UsesADL; } bool hasStoredFPFeatures() const { return CallExprBits.HasFPFeatures; } Decl *getCalleeDecl() { return getCallee()->getReferencedDeclOfCallee(); } const Decl *getCalleeDecl() const { return getCallee()->getReferencedDeclOfCallee(); } /// If the callee is a FunctionDecl, return it. Otherwise return null. FunctionDecl *getDirectCallee() { return dyn_cast_or_null(getCalleeDecl()); } const FunctionDecl *getDirectCallee() const { return dyn_cast_or_null(getCalleeDecl()); } /// getNumArgs - Return the number of actual arguments to this call. unsigned getNumArgs() const { return NumArgs; } /// Retrieve the call arguments. Expr **getArgs() { return reinterpret_cast(getTrailingStmts() + PREARGS_START + getNumPreArgs()); } const Expr *const *getArgs() const { return reinterpret_cast( getTrailingStmts() + PREARGS_START + getNumPreArgs()); } /// getArg - Return the specified argument. Expr *getArg(unsigned Arg) { assert(Arg < getNumArgs() && "Arg access out of range!"); return getArgs()[Arg]; } const Expr *getArg(unsigned Arg) const { assert(Arg < getNumArgs() && "Arg access out of range!"); return getArgs()[Arg]; } /// setArg - Set the specified argument. /// ! the dependence bits might be stale after calling this setter, it is /// *caller*'s responsibility to recompute them by calling /// computeDependence(). void setArg(unsigned Arg, Expr *ArgExpr) { assert(Arg < getNumArgs() && "Arg access out of range!"); getArgs()[Arg] = ArgExpr; } /// Compute and set dependence bits. void computeDependence() { setDependence(clang::computeDependence( this, llvm::makeArrayRef( reinterpret_cast(getTrailingStmts() + PREARGS_START), getNumPreArgs()))); } /// Reduce the number of arguments in this call expression. This is used for /// example during error recovery to drop extra arguments. There is no way /// to perform the opposite because: 1.) We don't track how much storage /// we have for the argument array 2.) This would potentially require growing /// the argument array, something we cannot support since the arguments are /// stored in a trailing array. void shrinkNumArgs(unsigned NewNumArgs) { assert((NewNumArgs <= getNumArgs()) && "shrinkNumArgs cannot increase the number of arguments!"); NumArgs = NewNumArgs; } /// Bluntly set a new number of arguments without doing any checks whatsoever. /// Only used during construction of a CallExpr in a few places in Sema. /// FIXME: Find a way to remove it. void setNumArgsUnsafe(unsigned NewNumArgs) { NumArgs = NewNumArgs; } typedef ExprIterator arg_iterator; typedef ConstExprIterator const_arg_iterator; typedef llvm::iterator_range arg_range; typedef llvm::iterator_range const_arg_range; arg_range arguments() { return arg_range(arg_begin(), arg_end()); } const_arg_range arguments() const { return const_arg_range(arg_begin(), arg_end()); } arg_iterator arg_begin() { return getTrailingStmts() + PREARGS_START + getNumPreArgs(); } arg_iterator arg_end() { return arg_begin() + getNumArgs(); } const_arg_iterator arg_begin() const { return getTrailingStmts() + PREARGS_START + getNumPreArgs(); } const_arg_iterator arg_end() const { return arg_begin() + getNumArgs(); } /// This method provides fast access to all the subexpressions of /// a CallExpr without going through the slower virtual child_iterator /// interface. This provides efficient reverse iteration of the /// subexpressions. This is currently used for CFG construction. ArrayRef getRawSubExprs() { return llvm::makeArrayRef(getTrailingStmts(), PREARGS_START + getNumPreArgs() + getNumArgs()); } /// getNumCommas - Return the number of commas that must have been present in /// this function call. unsigned getNumCommas() const { return getNumArgs() ? getNumArgs() - 1 : 0; } /// Get FPOptionsOverride from trailing storage. FPOptionsOverride getStoredFPFeatures() const { assert(hasStoredFPFeatures()); return *getTrailingFPFeatures(); } /// Set FPOptionsOverride in trailing storage. Used only by Serialization. void setStoredFPFeatures(FPOptionsOverride F) { assert(hasStoredFPFeatures()); *getTrailingFPFeatures() = F; } // Get the FP features status of this operator. Only meaningful for // operations on floating point types. FPOptions getFPFeaturesInEffect(const LangOptions &LO) const { if (hasStoredFPFeatures()) return getStoredFPFeatures().applyOverrides(LO); return FPOptions::defaultWithoutTrailingStorage(LO); } FPOptionsOverride getFPFeatures() const { if (hasStoredFPFeatures()) return getStoredFPFeatures(); return FPOptionsOverride(); } /// getBuiltinCallee - If this is a call to a builtin, return the builtin ID /// of the callee. If not, return 0. unsigned getBuiltinCallee() const; /// Returns \c true if this is a call to a builtin which does not /// evaluate side-effects within its arguments. bool isUnevaluatedBuiltinCall(const ASTContext &Ctx) const; /// getCallReturnType - Get the return type of the call expr. This is not /// always the type of the expr itself, if the return type is a reference /// type. QualType getCallReturnType(const ASTContext &Ctx) const; /// Returns the WarnUnusedResultAttr that is either declared on the called /// function, or its return type declaration. const Attr *getUnusedResultAttr(const ASTContext &Ctx) const; /// Returns true if this call expression should warn on unused results. bool hasUnusedResultAttr(const ASTContext &Ctx) const { return getUnusedResultAttr(Ctx) != nullptr; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; /// Return true if this is a call to __assume() or __builtin_assume() with /// a non-value-dependent constant parameter evaluating as false. bool isBuiltinAssumeFalse(const ASTContext &Ctx) const; /// Used by Sema to implement MSVC-compatible delayed name lookup. /// (Usually Exprs themselves should set dependence). void markDependentForPostponedNameLookup() { setDependence(getDependence() | ExprDependence::TypeValueInstantiation); } bool isCallToStdMove() const { const FunctionDecl *FD = getDirectCallee(); return getNumArgs() == 1 && FD && FD->isInStdNamespace() && FD->getIdentifier() && FD->getIdentifier()->isStr("move"); } static bool classof(const Stmt *T) { return T->getStmtClass() >= firstCallExprConstant && T->getStmtClass() <= lastCallExprConstant; } // Iterators child_range children() { return child_range(getTrailingStmts(), getTrailingStmts() + PREARGS_START + getNumPreArgs() + getNumArgs()); } const_child_range children() const { return const_child_range(getTrailingStmts(), getTrailingStmts() + PREARGS_START + getNumPreArgs() + getNumArgs()); } }; /// Extra data stored in some MemberExpr objects. struct MemberExprNameQualifier { /// The nested-name-specifier that qualifies the name, including /// source-location information. NestedNameSpecifierLoc QualifierLoc; /// The DeclAccessPair through which the MemberDecl was found due to /// name qualifiers. DeclAccessPair FoundDecl; }; /// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F. /// class MemberExpr final : public Expr, private llvm::TrailingObjects { friend class ASTReader; friend class ASTStmtReader; friend class ASTStmtWriter; friend TrailingObjects; /// Base - the expression for the base pointer or structure references. In /// X.F, this is "X". Stmt *Base; /// MemberDecl - This is the decl being referenced by the field/member name. /// In X.F, this is the decl referenced by F. ValueDecl *MemberDecl; /// MemberDNLoc - Provides source/type location info for the /// declaration name embedded in MemberDecl. DeclarationNameLoc MemberDNLoc; /// MemberLoc - This is the location of the member name. SourceLocation MemberLoc; size_t numTrailingObjects(OverloadToken) const { return hasQualifierOrFoundDecl(); } size_t numTrailingObjects(OverloadToken) const { return hasTemplateKWAndArgsInfo(); } bool hasQualifierOrFoundDecl() const { return MemberExprBits.HasQualifierOrFoundDecl; } bool hasTemplateKWAndArgsInfo() const { return MemberExprBits.HasTemplateKWAndArgsInfo; } MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc, ValueDecl *MemberDecl, const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR); MemberExpr(EmptyShell Empty) : Expr(MemberExprClass, Empty), Base(), MemberDecl() {} public: static MemberExpr *Create(const ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *MemberDecl, DeclAccessPair FoundDecl, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs, QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR); /// Create an implicit MemberExpr, with no location, qualifier, template /// arguments, and so on. Suitable only for non-static member access. static MemberExpr *CreateImplicit(const ASTContext &C, Expr *Base, bool IsArrow, ValueDecl *MemberDecl, QualType T, ExprValueKind VK, ExprObjectKind OK) { return Create(C, Base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), MemberDecl, DeclAccessPair::make(MemberDecl, MemberDecl->getAccess()), DeclarationNameInfo(), nullptr, T, VK, OK, NOUR_None); } static MemberExpr *CreateEmpty(const ASTContext &Context, bool HasQualifier, bool HasFoundDecl, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs); void setBase(Expr *E) { Base = E; } Expr *getBase() const { return cast(Base); } /// Retrieve the member declaration to which this expression refers. /// /// The returned declaration will be a FieldDecl or (in C++) a VarDecl (for /// static data members), a CXXMethodDecl, or an EnumConstantDecl. ValueDecl *getMemberDecl() const { return MemberDecl; } void setMemberDecl(ValueDecl *D); /// Retrieves the declaration found by lookup. DeclAccessPair getFoundDecl() const { if (!hasQualifierOrFoundDecl()) return DeclAccessPair::make(getMemberDecl(), getMemberDecl()->getAccess()); return getTrailingObjects()->FoundDecl; } /// Determines whether this member expression actually had /// a C++ nested-name-specifier prior to the name of the member, e.g., /// x->Base::foo. bool hasQualifier() const { return getQualifier() != nullptr; } /// If the member name was qualified, retrieves the /// nested-name-specifier that precedes the member name, with source-location /// information. NestedNameSpecifierLoc getQualifierLoc() const { if (!hasQualifierOrFoundDecl()) return NestedNameSpecifierLoc(); return getTrailingObjects()->QualifierLoc; } /// If the member name was qualified, retrieves the /// nested-name-specifier that precedes the member name. Otherwise, returns /// NULL. NestedNameSpecifier *getQualifier() const { return getQualifierLoc().getNestedNameSpecifier(); } /// Retrieve the location of the template keyword preceding /// the member name, if any. SourceLocation getTemplateKeywordLoc() const { if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); return getTrailingObjects()->TemplateKWLoc; } /// Retrieve the location of the left angle bracket starting the /// explicit template argument list following the member name, if any. SourceLocation getLAngleLoc() const { if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); return getTrailingObjects()->LAngleLoc; } /// Retrieve the location of the right angle bracket ending the /// explicit template argument list following the member name, if any. SourceLocation getRAngleLoc() const { if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); return getTrailingObjects()->RAngleLoc; } /// Determines whether the member name was preceded by the template keyword. bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } /// Determines whether the member name was followed by an /// explicit template argument list. bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } /// Copies the template arguments (if present) into the given /// structure. void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { if (hasExplicitTemplateArgs()) getTrailingObjects()->copyInto( getTrailingObjects(), List); } /// Retrieve the template arguments provided as part of this /// template-id. const TemplateArgumentLoc *getTemplateArgs() const { if (!hasExplicitTemplateArgs()) return nullptr; return getTrailingObjects(); } /// Retrieve the number of template arguments provided as part of this /// template-id. unsigned getNumTemplateArgs() const { if (!hasExplicitTemplateArgs()) return 0; return getTrailingObjects()->NumTemplateArgs; } ArrayRef template_arguments() const { return {getTemplateArgs(), getNumTemplateArgs()}; } /// Retrieve the member declaration name info. DeclarationNameInfo getMemberNameInfo() const { return DeclarationNameInfo(MemberDecl->getDeclName(), MemberLoc, MemberDNLoc); } SourceLocation getOperatorLoc() const { return MemberExprBits.OperatorLoc; } bool isArrow() const { return MemberExprBits.IsArrow; } void setArrow(bool A) { MemberExprBits.IsArrow = A; } /// getMemberLoc - Return the location of the "member", in X->F, it is the /// location of 'F'. SourceLocation getMemberLoc() const { return MemberLoc; } void setMemberLoc(SourceLocation L) { MemberLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; SourceLocation getExprLoc() const LLVM_READONLY { return MemberLoc; } /// Determine whether the base of this explicit is implicit. bool isImplicitAccess() const { return getBase() && getBase()->isImplicitCXXThis(); } /// Returns true if this member expression refers to a method that /// was resolved from an overloaded set having size greater than 1. bool hadMultipleCandidates() const { return MemberExprBits.HadMultipleCandidates; } /// Sets the flag telling whether this expression refers to /// a method that was resolved from an overloaded set having size /// greater than 1. void setHadMultipleCandidates(bool V = true) { MemberExprBits.HadMultipleCandidates = V; } /// Returns true if virtual dispatch is performed. /// If the member access is fully qualified, (i.e. X::f()), virtual /// dispatching is not performed. In -fapple-kext mode qualified /// calls to virtual method will still go through the vtable. bool performsVirtualDispatch(const LangOptions &LO) const { return LO.AppleKext || !hasQualifier(); } /// Is this expression a non-odr-use reference, and if so, why? /// This is only meaningful if the named member is a static member. NonOdrUseReason isNonOdrUse() const { return static_cast(MemberExprBits.NonOdrUseReason); } static bool classof(const Stmt *T) { return T->getStmtClass() == MemberExprClass; } // Iterators child_range children() { return child_range(&Base, &Base+1); } const_child_range children() const { return const_child_range(&Base, &Base + 1); } }; /// CompoundLiteralExpr - [C99 6.5.2.5] /// class CompoundLiteralExpr : public Expr { /// LParenLoc - If non-null, this is the location of the left paren in a /// compound literal like "(int){4}". This can be null if this is a /// synthesized compound expression. SourceLocation LParenLoc; /// The type as written. This can be an incomplete array type, in /// which case the actual expression type will be different. /// The int part of the pair stores whether this expr is file scope. llvm::PointerIntPair TInfoAndScope; Stmt *Init; public: CompoundLiteralExpr(SourceLocation lparenloc, TypeSourceInfo *tinfo, QualType T, ExprValueKind VK, Expr *init, bool fileScope) : Expr(CompoundLiteralExprClass, T, VK, OK_Ordinary), LParenLoc(lparenloc), TInfoAndScope(tinfo, fileScope), Init(init) { setDependence(computeDependence(this)); } /// Construct an empty compound literal. explicit CompoundLiteralExpr(EmptyShell Empty) : Expr(CompoundLiteralExprClass, Empty) { } const Expr *getInitializer() const { return cast(Init); } Expr *getInitializer() { return cast(Init); } void setInitializer(Expr *E) { Init = E; } bool isFileScope() const { return TInfoAndScope.getInt(); } void setFileScope(bool FS) { TInfoAndScope.setInt(FS); } SourceLocation getLParenLoc() const { return LParenLoc; } void setLParenLoc(SourceLocation L) { LParenLoc = L; } TypeSourceInfo *getTypeSourceInfo() const { return TInfoAndScope.getPointer(); } void setTypeSourceInfo(TypeSourceInfo *tinfo) { TInfoAndScope.setPointer(tinfo); } SourceLocation getBeginLoc() const LLVM_READONLY { // FIXME: Init should never be null. if (!Init) return SourceLocation(); if (LParenLoc.isInvalid()) return Init->getBeginLoc(); return LParenLoc; } SourceLocation getEndLoc() const LLVM_READONLY { // FIXME: Init should never be null. if (!Init) return SourceLocation(); return Init->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == CompoundLiteralExprClass; } // Iterators child_range children() { return child_range(&Init, &Init+1); } const_child_range children() const { return const_child_range(&Init, &Init + 1); } }; /// CastExpr - Base class for type casts, including both implicit /// casts (ImplicitCastExpr) and explicit casts that have some /// representation in the source code (ExplicitCastExpr's derived /// classes). class CastExpr : public Expr { Stmt *Op; bool CastConsistency() const; const CXXBaseSpecifier * const *path_buffer() const { return const_cast(this)->path_buffer(); } CXXBaseSpecifier **path_buffer(); friend class ASTStmtReader; protected: CastExpr(StmtClass SC, QualType ty, ExprValueKind VK, const CastKind kind, Expr *op, unsigned BasePathSize, bool HasFPFeatures) : Expr(SC, ty, VK, OK_Ordinary), Op(op) { CastExprBits.Kind = kind; CastExprBits.PartOfExplicitCast = false; CastExprBits.BasePathSize = BasePathSize; assert((CastExprBits.BasePathSize == BasePathSize) && "BasePathSize overflow!"); - setDependence(computeDependence(this)); assert(CastConsistency()); CastExprBits.HasFPFeatures = HasFPFeatures; } /// Construct an empty cast. CastExpr(StmtClass SC, EmptyShell Empty, unsigned BasePathSize, bool HasFPFeatures) : Expr(SC, Empty) { CastExprBits.PartOfExplicitCast = false; CastExprBits.BasePathSize = BasePathSize; CastExprBits.HasFPFeatures = HasFPFeatures; assert((CastExprBits.BasePathSize == BasePathSize) && "BasePathSize overflow!"); } /// Return a pointer to the trailing FPOptions. /// \pre hasStoredFPFeatures() == true FPOptionsOverride *getTrailingFPFeatures(); const FPOptionsOverride *getTrailingFPFeatures() const { return const_cast(this)->getTrailingFPFeatures(); } public: CastKind getCastKind() const { return (CastKind) CastExprBits.Kind; } void setCastKind(CastKind K) { CastExprBits.Kind = K; } static const char *getCastKindName(CastKind CK); const char *getCastKindName() const { return getCastKindName(getCastKind()); } Expr *getSubExpr() { return cast(Op); } const Expr *getSubExpr() const { return cast(Op); } void setSubExpr(Expr *E) { Op = E; } /// Retrieve the cast subexpression as it was written in the source /// code, looking through any implicit casts or other intermediate nodes /// introduced by semantic analysis. Expr *getSubExprAsWritten(); const Expr *getSubExprAsWritten() const { return const_cast(this)->getSubExprAsWritten(); } /// If this cast applies a user-defined conversion, retrieve the conversion /// function that it invokes. NamedDecl *getConversionFunction() const; typedef CXXBaseSpecifier **path_iterator; typedef const CXXBaseSpecifier *const *path_const_iterator; bool path_empty() const { return path_size() == 0; } unsigned path_size() const { return CastExprBits.BasePathSize; } path_iterator path_begin() { return path_buffer(); } path_iterator path_end() { return path_buffer() + path_size(); } path_const_iterator path_begin() const { return path_buffer(); } path_const_iterator path_end() const { return path_buffer() + path_size(); } llvm::iterator_range path() { return llvm::make_range(path_begin(), path_end()); } llvm::iterator_range path() const { return llvm::make_range(path_begin(), path_end()); } const FieldDecl *getTargetUnionField() const { assert(getCastKind() == CK_ToUnion); return getTargetFieldForToUnionCast(getType(), getSubExpr()->getType()); } bool hasStoredFPFeatures() const { return CastExprBits.HasFPFeatures; } /// Get FPOptionsOverride from trailing storage. FPOptionsOverride getStoredFPFeatures() const { assert(hasStoredFPFeatures()); return *getTrailingFPFeatures(); } // Get the FP features status of this operation. Only meaningful for // operations on floating point types. FPOptions getFPFeaturesInEffect(const LangOptions &LO) const { if (hasStoredFPFeatures()) return getStoredFPFeatures().applyOverrides(LO); return FPOptions::defaultWithoutTrailingStorage(LO); } FPOptionsOverride getFPFeatures() const { if (hasStoredFPFeatures()) return getStoredFPFeatures(); return FPOptionsOverride(); } static const FieldDecl *getTargetFieldForToUnionCast(QualType unionType, QualType opType); static const FieldDecl *getTargetFieldForToUnionCast(const RecordDecl *RD, QualType opType); static bool classof(const Stmt *T) { return T->getStmtClass() >= firstCastExprConstant && T->getStmtClass() <= lastCastExprConstant; } // Iterators child_range children() { return child_range(&Op, &Op+1); } const_child_range children() const { return const_child_range(&Op, &Op + 1); } }; /// ImplicitCastExpr - Allows us to explicitly represent implicit type /// conversions, which have no direct representation in the original /// source code. For example: converting T[]->T*, void f()->void /// (*f)(), float->double, short->int, etc. /// /// In C, implicit casts always produce rvalues. However, in C++, an /// implicit cast whose result is being bound to a reference will be /// an lvalue or xvalue. For example: /// /// @code /// class Base { }; /// class Derived : public Base { }; /// Derived &&ref(); /// void f(Derived d) { /// Base& b = d; // initializer is an ImplicitCastExpr /// // to an lvalue of type Base /// Base&& r = ref(); // initializer is an ImplicitCastExpr /// // to an xvalue of type Base /// } /// @endcode class ImplicitCastExpr final : public CastExpr, private llvm::TrailingObjects { ImplicitCastExpr(QualType ty, CastKind kind, Expr *op, unsigned BasePathLength, FPOptionsOverride FPO, ExprValueKind VK) : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, BasePathLength, FPO.requiresTrailingStorage()) { + setDependence(computeDependence(this)); if (hasStoredFPFeatures()) *getTrailingFPFeatures() = FPO; } /// Construct an empty implicit cast. explicit ImplicitCastExpr(EmptyShell Shell, unsigned PathSize, bool HasFPFeatures) : CastExpr(ImplicitCastExprClass, Shell, PathSize, HasFPFeatures) {} unsigned numTrailingObjects(OverloadToken) const { return path_size(); } public: enum OnStack_t { OnStack }; ImplicitCastExpr(OnStack_t _, QualType ty, CastKind kind, Expr *op, ExprValueKind VK, FPOptionsOverride FPO) : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, 0, FPO.requiresTrailingStorage()) { if (hasStoredFPFeatures()) *getTrailingFPFeatures() = FPO; } bool isPartOfExplicitCast() const { return CastExprBits.PartOfExplicitCast; } void setIsPartOfExplicitCast(bool PartOfExplicitCast) { CastExprBits.PartOfExplicitCast = PartOfExplicitCast; } static ImplicitCastExpr *Create(const ASTContext &Context, QualType T, CastKind Kind, Expr *Operand, const CXXCastPath *BasePath, ExprValueKind Cat, FPOptionsOverride FPO); static ImplicitCastExpr *CreateEmpty(const ASTContext &Context, unsigned PathSize, bool HasFPFeatures); SourceLocation getBeginLoc() const LLVM_READONLY { return getSubExpr()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getSubExpr()->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ImplicitCastExprClass; } friend TrailingObjects; friend class CastExpr; }; /// ExplicitCastExpr - An explicit cast written in the source /// code. /// /// This class is effectively an abstract class, because it provides /// the basic representation of an explicitly-written cast without /// specifying which kind of cast (C cast, functional cast, static /// cast, etc.) was written; specific derived classes represent the /// particular style of cast and its location information. /// /// Unlike implicit casts, explicit cast nodes have two different /// types: the type that was written into the source code, and the /// actual type of the expression as determined by semantic /// analysis. These types may differ slightly. For example, in C++ one /// can cast to a reference type, which indicates that the resulting /// expression will be an lvalue or xvalue. The reference type, however, /// will not be used as the type of the expression. class ExplicitCastExpr : public CastExpr { /// TInfo - Source type info for the (written) type /// this expression is casting to. TypeSourceInfo *TInfo; protected: ExplicitCastExpr(StmtClass SC, QualType exprTy, ExprValueKind VK, CastKind kind, Expr *op, unsigned PathSize, bool HasFPFeatures, TypeSourceInfo *writtenTy) : CastExpr(SC, exprTy, VK, kind, op, PathSize, HasFPFeatures), - TInfo(writtenTy) {} + TInfo(writtenTy) { + setDependence(computeDependence(this)); + } /// Construct an empty explicit cast. ExplicitCastExpr(StmtClass SC, EmptyShell Shell, unsigned PathSize, bool HasFPFeatures) : CastExpr(SC, Shell, PathSize, HasFPFeatures) {} public: /// getTypeInfoAsWritten - Returns the type source info for the type /// that this expression is casting to. TypeSourceInfo *getTypeInfoAsWritten() const { return TInfo; } void setTypeInfoAsWritten(TypeSourceInfo *writtenTy) { TInfo = writtenTy; } /// getTypeAsWritten - Returns the type that this expression is /// casting to, as written in the source code. QualType getTypeAsWritten() const { return TInfo->getType(); } static bool classof(const Stmt *T) { return T->getStmtClass() >= firstExplicitCastExprConstant && T->getStmtClass() <= lastExplicitCastExprConstant; } }; /// CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style /// cast in C++ (C++ [expr.cast]), which uses the syntax /// (Type)expr. For example: @c (int)f. class CStyleCastExpr final : public ExplicitCastExpr, private llvm::TrailingObjects { SourceLocation LPLoc; // the location of the left paren SourceLocation RPLoc; // the location of the right paren CStyleCastExpr(QualType exprTy, ExprValueKind vk, CastKind kind, Expr *op, unsigned PathSize, FPOptionsOverride FPO, TypeSourceInfo *writtenTy, SourceLocation l, SourceLocation r) : ExplicitCastExpr(CStyleCastExprClass, exprTy, vk, kind, op, PathSize, FPO.requiresTrailingStorage(), writtenTy), LPLoc(l), RPLoc(r) { if (hasStoredFPFeatures()) *getTrailingFPFeatures() = FPO; } /// Construct an empty C-style explicit cast. explicit CStyleCastExpr(EmptyShell Shell, unsigned PathSize, bool HasFPFeatures) : ExplicitCastExpr(CStyleCastExprClass, Shell, PathSize, HasFPFeatures) {} unsigned numTrailingObjects(OverloadToken) const { return path_size(); } public: static CStyleCastExpr * Create(const ASTContext &Context, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, FPOptionsOverride FPO, TypeSourceInfo *WrittenTy, SourceLocation L, SourceLocation R); static CStyleCastExpr *CreateEmpty(const ASTContext &Context, unsigned PathSize, bool HasFPFeatures); SourceLocation getLParenLoc() const { return LPLoc; } void setLParenLoc(SourceLocation L) { LPLoc = L; } SourceLocation getRParenLoc() const { return RPLoc; } void setRParenLoc(SourceLocation L) { RPLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return LPLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return getSubExpr()->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == CStyleCastExprClass; } friend TrailingObjects; friend class CastExpr; }; /// A builtin binary operation expression such as "x + y" or "x <= y". /// /// This expression node kind describes a builtin binary operation, /// such as "x + y" for integer values "x" and "y". The operands will /// already have been converted to appropriate types (e.g., by /// performing promotions or conversions). /// /// In C++, where operators may be overloaded, a different kind of /// expression node (CXXOperatorCallExpr) is used to express the /// invocation of an overloaded operator with operator syntax. Within /// a C++ template, whether BinaryOperator or CXXOperatorCallExpr is /// used to store an expression "x + y" depends on the subexpressions /// for x and y. If neither x or y is type-dependent, and the "+" /// operator resolves to a built-in operation, BinaryOperator will be /// used to express the computation (x and y may still be /// value-dependent). If either x or y is type-dependent, or if the /// "+" resolves to an overloaded operator, CXXOperatorCallExpr will /// be used to express the computation. class BinaryOperator : public Expr { enum { LHS, RHS, END_EXPR }; Stmt *SubExprs[END_EXPR]; public: typedef BinaryOperatorKind Opcode; protected: size_t offsetOfTrailingStorage() const; /// Return a pointer to the trailing FPOptions FPOptionsOverride *getTrailingFPFeatures() { assert(BinaryOperatorBits.HasFPFeatures); return reinterpret_cast( reinterpret_cast(this) + offsetOfTrailingStorage()); } const FPOptionsOverride *getTrailingFPFeatures() const { assert(BinaryOperatorBits.HasFPFeatures); return reinterpret_cast( reinterpret_cast(this) + offsetOfTrailingStorage()); } /// Build a binary operator, assuming that appropriate storage has been /// allocated for the trailing objects when needed. BinaryOperator(const ASTContext &Ctx, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, FPOptionsOverride FPFeatures); /// Construct an empty binary operator. explicit BinaryOperator(EmptyShell Empty) : Expr(BinaryOperatorClass, Empty) { BinaryOperatorBits.Opc = BO_Comma; } public: static BinaryOperator *CreateEmpty(const ASTContext &C, bool hasFPFeatures); static BinaryOperator *Create(const ASTContext &C, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, FPOptionsOverride FPFeatures); SourceLocation getExprLoc() const { return getOperatorLoc(); } SourceLocation getOperatorLoc() const { return BinaryOperatorBits.OpLoc; } void setOperatorLoc(SourceLocation L) { BinaryOperatorBits.OpLoc = L; } Opcode getOpcode() const { return static_cast(BinaryOperatorBits.Opc); } void setOpcode(Opcode Opc) { BinaryOperatorBits.Opc = Opc; } Expr *getLHS() const { return cast(SubExprs[LHS]); } void setLHS(Expr *E) { SubExprs[LHS] = E; } Expr *getRHS() const { return cast(SubExprs[RHS]); } void setRHS(Expr *E) { SubExprs[RHS] = E; } SourceLocation getBeginLoc() const LLVM_READONLY { return getLHS()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getRHS()->getEndLoc(); } /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "<<=". static StringRef getOpcodeStr(Opcode Op); StringRef getOpcodeStr() const { return getOpcodeStr(getOpcode()); } /// Retrieve the binary opcode that corresponds to the given /// overloaded operator. static Opcode getOverloadedOpcode(OverloadedOperatorKind OO); /// Retrieve the overloaded operator kind that corresponds to /// the given binary opcode. static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); /// predicates to categorize the respective opcodes. static bool isPtrMemOp(Opcode Opc) { return Opc == BO_PtrMemD || Opc == BO_PtrMemI; } bool isPtrMemOp() const { return isPtrMemOp(getOpcode()); } static bool isMultiplicativeOp(Opcode Opc) { return Opc >= BO_Mul && Opc <= BO_Rem; } bool isMultiplicativeOp() const { return isMultiplicativeOp(getOpcode()); } static bool isAdditiveOp(Opcode Opc) { return Opc == BO_Add || Opc==BO_Sub; } bool isAdditiveOp() const { return isAdditiveOp(getOpcode()); } static bool isShiftOp(Opcode Opc) { return Opc == BO_Shl || Opc == BO_Shr; } bool isShiftOp() const { return isShiftOp(getOpcode()); } static bool isBitwiseOp(Opcode Opc) { return Opc >= BO_And && Opc <= BO_Or; } bool isBitwiseOp() const { return isBitwiseOp(getOpcode()); } static bool isRelationalOp(Opcode Opc) { return Opc >= BO_LT && Opc<=BO_GE; } bool isRelationalOp() const { return isRelationalOp(getOpcode()); } static bool isEqualityOp(Opcode Opc) { return Opc == BO_EQ || Opc == BO_NE; } bool isEqualityOp() const { return isEqualityOp(getOpcode()); } static bool isComparisonOp(Opcode Opc) { return Opc >= BO_Cmp && Opc<=BO_NE; } bool isComparisonOp() const { return isComparisonOp(getOpcode()); } static bool isCommaOp(Opcode Opc) { return Opc == BO_Comma; } bool isCommaOp() const { return isCommaOp(getOpcode()); } static Opcode negateComparisonOp(Opcode Opc) { switch (Opc) { default: llvm_unreachable("Not a comparison operator."); case BO_LT: return BO_GE; case BO_GT: return BO_LE; case BO_LE: return BO_GT; case BO_GE: return BO_LT; case BO_EQ: return BO_NE; case BO_NE: return BO_EQ; } } static Opcode reverseComparisonOp(Opcode Opc) { switch (Opc) { default: llvm_unreachable("Not a comparison operator."); case BO_LT: return BO_GT; case BO_GT: return BO_LT; case BO_LE: return BO_GE; case BO_GE: return BO_LE; case BO_EQ: case BO_NE: return Opc; } } static bool isLogicalOp(Opcode Opc) { return Opc == BO_LAnd || Opc==BO_LOr; } bool isLogicalOp() const { return isLogicalOp(getOpcode()); } static bool isAssignmentOp(Opcode Opc) { return Opc >= BO_Assign && Opc <= BO_OrAssign; } bool isAssignmentOp() const { return isAssignmentOp(getOpcode()); } static bool isCompoundAssignmentOp(Opcode Opc) { return Opc > BO_Assign && Opc <= BO_OrAssign; } bool isCompoundAssignmentOp() const { return isCompoundAssignmentOp(getOpcode()); } static Opcode getOpForCompoundAssignment(Opcode Opc) { assert(isCompoundAssignmentOp(Opc)); if (Opc >= BO_AndAssign) return Opcode(unsigned(Opc) - BO_AndAssign + BO_And); else return Opcode(unsigned(Opc) - BO_MulAssign + BO_Mul); } static bool isShiftAssignOp(Opcode Opc) { return Opc == BO_ShlAssign || Opc == BO_ShrAssign; } bool isShiftAssignOp() const { return isShiftAssignOp(getOpcode()); } // Return true if a binary operator using the specified opcode and operands // would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized // integer to a pointer. static bool isNullPointerArithmeticExtension(ASTContext &Ctx, Opcode Opc, Expr *LHS, Expr *RHS); static bool classof(const Stmt *S) { return S->getStmtClass() >= firstBinaryOperatorConstant && S->getStmtClass() <= lastBinaryOperatorConstant; } // Iterators child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); } const_child_range children() const { return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } /// Set and fetch the bit that shows whether FPFeatures needs to be /// allocated in Trailing Storage void setHasStoredFPFeatures(bool B) { BinaryOperatorBits.HasFPFeatures = B; } bool hasStoredFPFeatures() const { return BinaryOperatorBits.HasFPFeatures; } /// Get FPFeatures from trailing storage FPOptionsOverride getStoredFPFeatures() const { assert(hasStoredFPFeatures()); return *getTrailingFPFeatures(); } /// Set FPFeatures in trailing storage, used only by Serialization void setStoredFPFeatures(FPOptionsOverride F) { assert(BinaryOperatorBits.HasFPFeatures); *getTrailingFPFeatures() = F; } // Get the FP features status of this operator. Only meaningful for // operations on floating point types. FPOptions getFPFeaturesInEffect(const LangOptions &LO) const { if (BinaryOperatorBits.HasFPFeatures) return getStoredFPFeatures().applyOverrides(LO); return FPOptions::defaultWithoutTrailingStorage(LO); } // This is used in ASTImporter FPOptionsOverride getFPFeatures(const LangOptions &LO) const { if (BinaryOperatorBits.HasFPFeatures) return getStoredFPFeatures(); return FPOptionsOverride(); } // Get the FP contractability status of this operator. Only meaningful for // operations on floating point types. bool isFPContractableWithinStatement(const LangOptions &LO) const { return getFPFeaturesInEffect(LO).allowFPContractWithinStatement(); } // Get the FENV_ACCESS status of this operator. Only meaningful for // operations on floating point types. bool isFEnvAccessOn(const LangOptions &LO) const { return getFPFeaturesInEffect(LO).getAllowFEnvAccess(); } protected: BinaryOperator(const ASTContext &Ctx, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, FPOptionsOverride FPFeatures, bool dead2); /// Construct an empty BinaryOperator, SC is CompoundAssignOperator. BinaryOperator(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) { BinaryOperatorBits.Opc = BO_MulAssign; } /// Return the size in bytes needed for the trailing objects. /// Used to allocate the right amount of storage. static unsigned sizeOfTrailingObjects(bool HasFPFeatures) { return HasFPFeatures * sizeof(FPOptionsOverride); } }; /// CompoundAssignOperator - For compound assignments (e.g. +=), we keep /// track of the type the operation is performed in. Due to the semantics of /// these operators, the operands are promoted, the arithmetic performed, an /// implicit conversion back to the result type done, then the assignment takes /// place. This captures the intermediate type which the computation is done /// in. class CompoundAssignOperator : public BinaryOperator { QualType ComputationLHSType; QualType ComputationResultType; /// Construct an empty CompoundAssignOperator. explicit CompoundAssignOperator(const ASTContext &C, EmptyShell Empty, bool hasFPFeatures) : BinaryOperator(CompoundAssignOperatorClass, Empty) {} protected: CompoundAssignOperator(const ASTContext &C, Expr *lhs, Expr *rhs, Opcode opc, QualType ResType, ExprValueKind VK, ExprObjectKind OK, SourceLocation OpLoc, FPOptionsOverride FPFeatures, QualType CompLHSType, QualType CompResultType) : BinaryOperator(C, lhs, rhs, opc, ResType, VK, OK, OpLoc, FPFeatures, true), ComputationLHSType(CompLHSType), ComputationResultType(CompResultType) { assert(isCompoundAssignmentOp() && "Only should be used for compound assignments"); } public: static CompoundAssignOperator *CreateEmpty(const ASTContext &C, bool hasFPFeatures); static CompoundAssignOperator * Create(const ASTContext &C, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, FPOptionsOverride FPFeatures, QualType CompLHSType = QualType(), QualType CompResultType = QualType()); // The two computation types are the type the LHS is converted // to for the computation and the type of the result; the two are // distinct in a few cases (specifically, int+=ptr and ptr-=ptr). QualType getComputationLHSType() const { return ComputationLHSType; } void setComputationLHSType(QualType T) { ComputationLHSType = T; } QualType getComputationResultType() const { return ComputationResultType; } void setComputationResultType(QualType T) { ComputationResultType = T; } static bool classof(const Stmt *S) { return S->getStmtClass() == CompoundAssignOperatorClass; } }; inline size_t BinaryOperator::offsetOfTrailingStorage() const { assert(BinaryOperatorBits.HasFPFeatures); return isa(this) ? sizeof(CompoundAssignOperator) : sizeof(BinaryOperator); } /// AbstractConditionalOperator - An abstract base class for /// ConditionalOperator and BinaryConditionalOperator. class AbstractConditionalOperator : public Expr { SourceLocation QuestionLoc, ColonLoc; friend class ASTStmtReader; protected: AbstractConditionalOperator(StmtClass SC, QualType T, ExprValueKind VK, ExprObjectKind OK, SourceLocation qloc, SourceLocation cloc) : Expr(SC, T, VK, OK), QuestionLoc(qloc), ColonLoc(cloc) {} AbstractConditionalOperator(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) { } public: // getCond - Return the expression representing the condition for // the ?: operator. Expr *getCond() const; // getTrueExpr - Return the subexpression representing the value of // the expression if the condition evaluates to true. Expr *getTrueExpr() const; // getFalseExpr - Return the subexpression representing the value of // the expression if the condition evaluates to false. This is // the same as getRHS. Expr *getFalseExpr() const; SourceLocation getQuestionLoc() const { return QuestionLoc; } SourceLocation getColonLoc() const { return ColonLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ConditionalOperatorClass || T->getStmtClass() == BinaryConditionalOperatorClass; } }; /// ConditionalOperator - The ?: ternary operator. The GNU "missing /// middle" extension is a BinaryConditionalOperator. class ConditionalOperator : public AbstractConditionalOperator { enum { COND, LHS, RHS, END_EXPR }; Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides. friend class ASTStmtReader; public: ConditionalOperator(Expr *cond, SourceLocation QLoc, Expr *lhs, SourceLocation CLoc, Expr *rhs, QualType t, ExprValueKind VK, ExprObjectKind OK) : AbstractConditionalOperator(ConditionalOperatorClass, t, VK, OK, QLoc, CLoc) { SubExprs[COND] = cond; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; setDependence(computeDependence(this)); } /// Build an empty conditional operator. explicit ConditionalOperator(EmptyShell Empty) : AbstractConditionalOperator(ConditionalOperatorClass, Empty) { } // getCond - Return the expression representing the condition for // the ?: operator. Expr *getCond() const { return cast(SubExprs[COND]); } // getTrueExpr - Return the subexpression representing the value of // the expression if the condition evaluates to true. Expr *getTrueExpr() const { return cast(SubExprs[LHS]); } // getFalseExpr - Return the subexpression representing the value of // the expression if the condition evaluates to false. This is // the same as getRHS. Expr *getFalseExpr() const { return cast(SubExprs[RHS]); } Expr *getLHS() const { return cast(SubExprs[LHS]); } Expr *getRHS() const { return cast(SubExprs[RHS]); } SourceLocation getBeginLoc() const LLVM_READONLY { return getCond()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getRHS()->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ConditionalOperatorClass; } // Iterators child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); } const_child_range children() const { return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } }; /// BinaryConditionalOperator - The GNU extension to the conditional /// operator which allows the middle operand to be omitted. /// /// This is a different expression kind on the assumption that almost /// every client ends up needing to know that these are different. class BinaryConditionalOperator : public AbstractConditionalOperator { enum { COMMON, COND, LHS, RHS, NUM_SUBEXPRS }; /// - the common condition/left-hand-side expression, which will be /// evaluated as the opaque value /// - the condition, expressed in terms of the opaque value /// - the left-hand-side, expressed in terms of the opaque value /// - the right-hand-side Stmt *SubExprs[NUM_SUBEXPRS]; OpaqueValueExpr *OpaqueValue; friend class ASTStmtReader; public: BinaryConditionalOperator(Expr *common, OpaqueValueExpr *opaqueValue, Expr *cond, Expr *lhs, Expr *rhs, SourceLocation qloc, SourceLocation cloc, QualType t, ExprValueKind VK, ExprObjectKind OK) : AbstractConditionalOperator(BinaryConditionalOperatorClass, t, VK, OK, qloc, cloc), OpaqueValue(opaqueValue) { SubExprs[COMMON] = common; SubExprs[COND] = cond; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; assert(OpaqueValue->getSourceExpr() == common && "Wrong opaque value"); setDependence(computeDependence(this)); } /// Build an empty conditional operator. explicit BinaryConditionalOperator(EmptyShell Empty) : AbstractConditionalOperator(BinaryConditionalOperatorClass, Empty) { } /// getCommon - Return the common expression, written to the /// left of the condition. The opaque value will be bound to the /// result of this expression. Expr *getCommon() const { return cast(SubExprs[COMMON]); } /// getOpaqueValue - Return the opaque value placeholder. OpaqueValueExpr *getOpaqueValue() const { return OpaqueValue; } /// getCond - Return the condition expression; this is defined /// in terms of the opaque value. Expr *getCond() const { return cast(SubExprs[COND]); } /// getTrueExpr - Return the subexpression which will be /// evaluated if the condition evaluates to true; this is defined /// in terms of the opaque value. Expr *getTrueExpr() const { return cast(SubExprs[LHS]); } /// getFalseExpr - Return the subexpression which will be /// evaluated if the condnition evaluates to false; this is /// defined in terms of the opaque value. Expr *getFalseExpr() const { return cast(SubExprs[RHS]); } SourceLocation getBeginLoc() const LLVM_READONLY { return getCommon()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getFalseExpr()->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == BinaryConditionalOperatorClass; } // Iterators child_range children() { return child_range(SubExprs, SubExprs + NUM_SUBEXPRS); } const_child_range children() const { return const_child_range(SubExprs, SubExprs + NUM_SUBEXPRS); } }; inline Expr *AbstractConditionalOperator::getCond() const { if (const ConditionalOperator *co = dyn_cast(this)) return co->getCond(); return cast(this)->getCond(); } inline Expr *AbstractConditionalOperator::getTrueExpr() const { if (const ConditionalOperator *co = dyn_cast(this)) return co->getTrueExpr(); return cast(this)->getTrueExpr(); } inline Expr *AbstractConditionalOperator::getFalseExpr() const { if (const ConditionalOperator *co = dyn_cast(this)) return co->getFalseExpr(); return cast(this)->getFalseExpr(); } /// AddrLabelExpr - The GNU address of label extension, representing &&label. class AddrLabelExpr : public Expr { SourceLocation AmpAmpLoc, LabelLoc; LabelDecl *Label; public: AddrLabelExpr(SourceLocation AALoc, SourceLocation LLoc, LabelDecl *L, QualType t) : Expr(AddrLabelExprClass, t, VK_PRValue, OK_Ordinary), AmpAmpLoc(AALoc), LabelLoc(LLoc), Label(L) { setDependence(ExprDependence::None); } /// Build an empty address of a label expression. explicit AddrLabelExpr(EmptyShell Empty) : Expr(AddrLabelExprClass, Empty) { } SourceLocation getAmpAmpLoc() const { return AmpAmpLoc; } void setAmpAmpLoc(SourceLocation L) { AmpAmpLoc = L; } SourceLocation getLabelLoc() const { return LabelLoc; } void setLabelLoc(SourceLocation L) { LabelLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return AmpAmpLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return LabelLoc; } LabelDecl *getLabel() const { return Label; } void setLabel(LabelDecl *L) { Label = L; } static bool classof(const Stmt *T) { return T->getStmtClass() == AddrLabelExprClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}). /// The StmtExpr contains a single CompoundStmt node, which it evaluates and /// takes the value of the last subexpression. /// /// A StmtExpr is always an r-value; values "returned" out of a /// StmtExpr will be copied. class StmtExpr : public Expr { Stmt *SubStmt; SourceLocation LParenLoc, RParenLoc; public: StmtExpr(CompoundStmt *SubStmt, QualType T, SourceLocation LParenLoc, SourceLocation RParenLoc, unsigned TemplateDepth) : Expr(StmtExprClass, T, VK_PRValue, OK_Ordinary), SubStmt(SubStmt), LParenLoc(LParenLoc), RParenLoc(RParenLoc) { setDependence(computeDependence(this, TemplateDepth)); // FIXME: A templated statement expression should have an associated // DeclContext so that nested declarations always have a dependent context. StmtExprBits.TemplateDepth = TemplateDepth; } /// Build an empty statement expression. explicit StmtExpr(EmptyShell Empty) : Expr(StmtExprClass, Empty) { } CompoundStmt *getSubStmt() { return cast(SubStmt); } const CompoundStmt *getSubStmt() const { return cast(SubStmt); } void setSubStmt(CompoundStmt *S) { SubStmt = S; } SourceLocation getBeginLoc() const LLVM_READONLY { return LParenLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } SourceLocation getLParenLoc() const { return LParenLoc; } void setLParenLoc(SourceLocation L) { LParenLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } unsigned getTemplateDepth() const { return StmtExprBits.TemplateDepth; } static bool classof(const Stmt *T) { return T->getStmtClass() == StmtExprClass; } // Iterators child_range children() { return child_range(&SubStmt, &SubStmt+1); } const_child_range children() const { return const_child_range(&SubStmt, &SubStmt + 1); } }; /// ShuffleVectorExpr - clang-specific builtin-in function /// __builtin_shufflevector. /// This AST node represents a operator that does a constant /// shuffle, similar to LLVM's shufflevector instruction. It takes /// two vectors and a variable number of constant indices, /// and returns the appropriately shuffled vector. class ShuffleVectorExpr : public Expr { SourceLocation BuiltinLoc, RParenLoc; // SubExprs - the list of values passed to the __builtin_shufflevector // function. The first two are vectors, and the rest are constant // indices. The number of values in this list is always // 2+the number of indices in the vector type. Stmt **SubExprs; unsigned NumExprs; public: ShuffleVectorExpr(const ASTContext &C, ArrayRef args, QualType Type, SourceLocation BLoc, SourceLocation RP); /// Build an empty vector-shuffle expression. explicit ShuffleVectorExpr(EmptyShell Empty) : Expr(ShuffleVectorExprClass, Empty), SubExprs(nullptr) { } SourceLocation getBuiltinLoc() const { return BuiltinLoc; } void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ShuffleVectorExprClass; } /// getNumSubExprs - Return the size of the SubExprs array. This includes the /// constant expression, the actual arguments passed in, and the function /// pointers. unsigned getNumSubExprs() const { return NumExprs; } /// Retrieve the array of expressions. Expr **getSubExprs() { return reinterpret_cast(SubExprs); } /// getExpr - Return the Expr at the specified index. Expr *getExpr(unsigned Index) { assert((Index < NumExprs) && "Arg access out of range!"); return cast(SubExprs[Index]); } const Expr *getExpr(unsigned Index) const { assert((Index < NumExprs) && "Arg access out of range!"); return cast(SubExprs[Index]); } void setExprs(const ASTContext &C, ArrayRef Exprs); llvm::APSInt getShuffleMaskIdx(const ASTContext &Ctx, unsigned N) const { assert((N < NumExprs - 2) && "Shuffle idx out of range!"); return getExpr(N+2)->EvaluateKnownConstInt(Ctx); } // Iterators child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+NumExprs); } const_child_range children() const { return const_child_range(&SubExprs[0], &SubExprs[0] + NumExprs); } }; /// ConvertVectorExpr - Clang builtin function __builtin_convertvector /// This AST node provides support for converting a vector type to another /// vector type of the same arity. class ConvertVectorExpr : public Expr { private: Stmt *SrcExpr; TypeSourceInfo *TInfo; SourceLocation BuiltinLoc, RParenLoc; friend class ASTReader; friend class ASTStmtReader; explicit ConvertVectorExpr(EmptyShell Empty) : Expr(ConvertVectorExprClass, Empty) {} public: ConvertVectorExpr(Expr *SrcExpr, TypeSourceInfo *TI, QualType DstType, ExprValueKind VK, ExprObjectKind OK, SourceLocation BuiltinLoc, SourceLocation RParenLoc) : Expr(ConvertVectorExprClass, DstType, VK, OK), SrcExpr(SrcExpr), TInfo(TI), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) { setDependence(computeDependence(this)); } /// getSrcExpr - Return the Expr to be converted. Expr *getSrcExpr() const { return cast(SrcExpr); } /// getTypeSourceInfo - Return the destination type. TypeSourceInfo *getTypeSourceInfo() const { return TInfo; } void setTypeSourceInfo(TypeSourceInfo *ti) { TInfo = ti; } /// getBuiltinLoc - Return the location of the __builtin_convertvector token. SourceLocation getBuiltinLoc() const { return BuiltinLoc; } /// getRParenLoc - Return the location of final right parenthesis. SourceLocation getRParenLoc() const { return RParenLoc; } SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ConvertVectorExprClass; } // Iterators child_range children() { return child_range(&SrcExpr, &SrcExpr+1); } const_child_range children() const { return const_child_range(&SrcExpr, &SrcExpr + 1); } }; /// ChooseExpr - GNU builtin-in function __builtin_choose_expr. /// This AST node is similar to the conditional operator (?:) in C, with /// the following exceptions: /// - the test expression must be a integer constant expression. /// - the expression returned acts like the chosen subexpression in every /// visible way: the type is the same as that of the chosen subexpression, /// and all predicates (whether it's an l-value, whether it's an integer /// constant expression, etc.) return the same result as for the chosen /// sub-expression. class ChooseExpr : public Expr { enum { COND, LHS, RHS, END_EXPR }; Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides. SourceLocation BuiltinLoc, RParenLoc; bool CondIsTrue; public: ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs, QualType t, ExprValueKind VK, ExprObjectKind OK, SourceLocation RP, bool condIsTrue) : Expr(ChooseExprClass, t, VK, OK), BuiltinLoc(BLoc), RParenLoc(RP), CondIsTrue(condIsTrue) { SubExprs[COND] = cond; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; setDependence(computeDependence(this)); } /// Build an empty __builtin_choose_expr. explicit ChooseExpr(EmptyShell Empty) : Expr(ChooseExprClass, Empty) { } /// isConditionTrue - Return whether the condition is true (i.e. not /// equal to zero). bool isConditionTrue() const { assert(!isConditionDependent() && "Dependent condition isn't true or false"); return CondIsTrue; } void setIsConditionTrue(bool isTrue) { CondIsTrue = isTrue; } bool isConditionDependent() const { return getCond()->isTypeDependent() || getCond()->isValueDependent(); } /// getChosenSubExpr - Return the subexpression chosen according to the /// condition. Expr *getChosenSubExpr() const { return isConditionTrue() ? getLHS() : getRHS(); } Expr *getCond() const { return cast(SubExprs[COND]); } void setCond(Expr *E) { SubExprs[COND] = E; } Expr *getLHS() const { return cast(SubExprs[LHS]); } void setLHS(Expr *E) { SubExprs[LHS] = E; } Expr *getRHS() const { return cast(SubExprs[RHS]); } void setRHS(Expr *E) { SubExprs[RHS] = E; } SourceLocation getBuiltinLoc() const { return BuiltinLoc; } void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ChooseExprClass; } // Iterators child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); } const_child_range children() const { return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } }; /// GNUNullExpr - Implements the GNU __null extension, which is a name /// for a null pointer constant that has integral type (e.g., int or /// long) and is the same size and alignment as a pointer. The __null /// extension is typically only used by system headers, which define /// NULL as __null in C++ rather than using 0 (which is an integer /// that may not match the size of a pointer). class GNUNullExpr : public Expr { /// TokenLoc - The location of the __null keyword. SourceLocation TokenLoc; public: GNUNullExpr(QualType Ty, SourceLocation Loc) : Expr(GNUNullExprClass, Ty, VK_PRValue, OK_Ordinary), TokenLoc(Loc) { setDependence(ExprDependence::None); } /// Build an empty GNU __null expression. explicit GNUNullExpr(EmptyShell Empty) : Expr(GNUNullExprClass, Empty) { } /// getTokenLocation - The location of the __null token. SourceLocation getTokenLocation() const { return TokenLoc; } void setTokenLocation(SourceLocation L) { TokenLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return TokenLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return TokenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == GNUNullExprClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// Represents a call to the builtin function \c __builtin_va_arg. class VAArgExpr : public Expr { Stmt *Val; llvm::PointerIntPair TInfo; SourceLocation BuiltinLoc, RParenLoc; public: VAArgExpr(SourceLocation BLoc, Expr *e, TypeSourceInfo *TInfo, SourceLocation RPLoc, QualType t, bool IsMS) : Expr(VAArgExprClass, t, VK_PRValue, OK_Ordinary), Val(e), TInfo(TInfo, IsMS), BuiltinLoc(BLoc), RParenLoc(RPLoc) { setDependence(computeDependence(this)); } /// Create an empty __builtin_va_arg expression. explicit VAArgExpr(EmptyShell Empty) : Expr(VAArgExprClass, Empty), Val(nullptr), TInfo(nullptr, false) {} const Expr *getSubExpr() const { return cast(Val); } Expr *getSubExpr() { return cast(Val); } void setSubExpr(Expr *E) { Val = E; } /// Returns whether this is really a Win64 ABI va_arg expression. bool isMicrosoftABI() const { return TInfo.getInt(); } void setIsMicrosoftABI(bool IsMS) { TInfo.setInt(IsMS); } TypeSourceInfo *getWrittenTypeInfo() const { return TInfo.getPointer(); } void setWrittenTypeInfo(TypeSourceInfo *TI) { TInfo.setPointer(TI); } SourceLocation getBuiltinLoc() const { return BuiltinLoc; } void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == VAArgExprClass; } // Iterators child_range children() { return child_range(&Val, &Val+1); } const_child_range children() const { return const_child_range(&Val, &Val + 1); } }; /// Represents a function call to one of __builtin_LINE(), __builtin_COLUMN(), /// __builtin_FUNCTION(), or __builtin_FILE(). class SourceLocExpr final : public Expr { SourceLocation BuiltinLoc, RParenLoc; DeclContext *ParentContext; public: enum IdentKind { Function, File, Line, Column }; SourceLocExpr(const ASTContext &Ctx, IdentKind Type, SourceLocation BLoc, SourceLocation RParenLoc, DeclContext *Context); /// Build an empty call expression. explicit SourceLocExpr(EmptyShell Empty) : Expr(SourceLocExprClass, Empty) {} /// Return the result of evaluating this SourceLocExpr in the specified /// (and possibly null) default argument or initialization context. APValue EvaluateInContext(const ASTContext &Ctx, const Expr *DefaultExpr) const; /// Return a string representing the name of the specific builtin function. StringRef getBuiltinStr() const; IdentKind getIdentKind() const { return static_cast(SourceLocExprBits.Kind); } bool isStringType() const { switch (getIdentKind()) { case File: case Function: return true; case Line: case Column: return false; } llvm_unreachable("unknown source location expression kind"); } bool isIntType() const LLVM_READONLY { return !isStringType(); } /// If the SourceLocExpr has been resolved return the subexpression /// representing the resolved value. Otherwise return null. const DeclContext *getParentContext() const { return ParentContext; } DeclContext *getParentContext() { return ParentContext; } SourceLocation getLocation() const { return BuiltinLoc; } SourceLocation getBeginLoc() const { return BuiltinLoc; } SourceLocation getEndLoc() const { return RParenLoc; } child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(child_iterator(), child_iterator()); } static bool classof(const Stmt *T) { return T->getStmtClass() == SourceLocExprClass; } private: friend class ASTStmtReader; }; /// Describes an C or C++ initializer list. /// /// InitListExpr describes an initializer list, which can be used to /// initialize objects of different types, including /// struct/class/union types, arrays, and vectors. For example: /// /// @code /// struct foo x = { 1, { 2, 3 } }; /// @endcode /// /// Prior to semantic analysis, an initializer list will represent the /// initializer list as written by the user, but will have the /// placeholder type "void". This initializer list is called the /// syntactic form of the initializer, and may contain C99 designated /// initializers (represented as DesignatedInitExprs), initializations /// of subobject members without explicit braces, and so on. Clients /// interested in the original syntax of the initializer list should /// use the syntactic form of the initializer list. /// /// After semantic analysis, the initializer list will represent the /// semantic form of the initializer, where the initializations of all /// subobjects are made explicit with nested InitListExpr nodes and /// C99 designators have been eliminated by placing the designated /// initializations into the subobject they initialize. Additionally, /// any "holes" in the initialization, where no initializer has been /// specified for a particular subobject, will be replaced with /// implicitly-generated ImplicitValueInitExpr expressions that /// value-initialize the subobjects. Note, however, that the /// initializer lists may still have fewer initializers than there are /// elements to initialize within the object. /// /// After semantic analysis has completed, given an initializer list, /// method isSemanticForm() returns true if and only if this is the /// semantic form of the initializer list (note: the same AST node /// may at the same time be the syntactic form). /// Given the semantic form of the initializer list, one can retrieve /// the syntactic form of that initializer list (when different) /// using method getSyntacticForm(); the method returns null if applied /// to a initializer list which is already in syntactic form. /// Similarly, given the syntactic form (i.e., an initializer list such /// that isSemanticForm() returns false), one can retrieve the semantic /// form using method getSemanticForm(). /// Since many initializer lists have the same syntactic and semantic forms, /// getSyntacticForm() may return NULL, indicating that the current /// semantic initializer list also serves as its syntactic form. class InitListExpr : public Expr { // FIXME: Eliminate this vector in favor of ASTContext allocation typedef ASTVector InitExprsTy; InitExprsTy InitExprs; SourceLocation LBraceLoc, RBraceLoc; /// The alternative form of the initializer list (if it exists). /// The int part of the pair stores whether this initializer list is /// in semantic form. If not null, the pointer points to: /// - the syntactic form, if this is in semantic form; /// - the semantic form, if this is in syntactic form. llvm::PointerIntPair AltForm; /// Either: /// If this initializer list initializes an array with more elements than /// there are initializers in the list, specifies an expression to be used /// for value initialization of the rest of the elements. /// Or /// If this initializer list initializes a union, specifies which /// field within the union will be initialized. llvm::PointerUnion ArrayFillerOrUnionFieldInit; public: InitListExpr(const ASTContext &C, SourceLocation lbraceloc, ArrayRef initExprs, SourceLocation rbraceloc); /// Build an empty initializer list. explicit InitListExpr(EmptyShell Empty) : Expr(InitListExprClass, Empty), AltForm(nullptr, true) { } unsigned getNumInits() const { return InitExprs.size(); } /// Retrieve the set of initializers. Expr **getInits() { return reinterpret_cast(InitExprs.data()); } /// Retrieve the set of initializers. Expr * const *getInits() const { return reinterpret_cast(InitExprs.data()); } ArrayRef inits() { return llvm::makeArrayRef(getInits(), getNumInits()); } ArrayRef inits() const { return llvm::makeArrayRef(getInits(), getNumInits()); } const Expr *getInit(unsigned Init) const { assert(Init < getNumInits() && "Initializer access out of range!"); return cast_or_null(InitExprs[Init]); } Expr *getInit(unsigned Init) { assert(Init < getNumInits() && "Initializer access out of range!"); return cast_or_null(InitExprs[Init]); } void setInit(unsigned Init, Expr *expr) { assert(Init < getNumInits() && "Initializer access out of range!"); InitExprs[Init] = expr; if (expr) setDependence(getDependence() | expr->getDependence()); } /// Mark the semantic form of the InitListExpr as error when the semantic /// analysis fails. void markError() { assert(isSemanticForm()); setDependence(getDependence() | ExprDependence::ErrorDependent); } /// Reserve space for some number of initializers. void reserveInits(const ASTContext &C, unsigned NumInits); /// Specify the number of initializers /// /// If there are more than @p NumInits initializers, the remaining /// initializers will be destroyed. If there are fewer than @p /// NumInits initializers, NULL expressions will be added for the /// unknown initializers. void resizeInits(const ASTContext &Context, unsigned NumInits); /// Updates the initializer at index @p Init with the new /// expression @p expr, and returns the old expression at that /// location. /// /// When @p Init is out of range for this initializer list, the /// initializer list will be extended with NULL expressions to /// accommodate the new entry. Expr *updateInit(const ASTContext &C, unsigned Init, Expr *expr); /// If this initializer list initializes an array with more elements /// than there are initializers in the list, specifies an expression to be /// used for value initialization of the rest of the elements. Expr *getArrayFiller() { return ArrayFillerOrUnionFieldInit.dyn_cast(); } const Expr *getArrayFiller() const { return const_cast(this)->getArrayFiller(); } void setArrayFiller(Expr *filler); /// Return true if this is an array initializer and its array "filler" /// has been set. bool hasArrayFiller() const { return getArrayFiller(); } /// If this initializes a union, specifies which field in the /// union to initialize. /// /// Typically, this field is the first named field within the /// union. However, a designated initializer can specify the /// initialization of a different field within the union. FieldDecl *getInitializedFieldInUnion() { return ArrayFillerOrUnionFieldInit.dyn_cast(); } const FieldDecl *getInitializedFieldInUnion() const { return const_cast(this)->getInitializedFieldInUnion(); } void setInitializedFieldInUnion(FieldDecl *FD) { assert((FD == nullptr || getInitializedFieldInUnion() == nullptr || getInitializedFieldInUnion() == FD) && "Only one field of a union may be initialized at a time!"); ArrayFillerOrUnionFieldInit = FD; } // Explicit InitListExpr's originate from source code (and have valid source // locations). Implicit InitListExpr's are created by the semantic analyzer. // FIXME: This is wrong; InitListExprs created by semantic analysis have // valid source locations too! bool isExplicit() const { return LBraceLoc.isValid() && RBraceLoc.isValid(); } // Is this an initializer for an array of characters, initialized by a string // literal or an @encode? bool isStringLiteralInit() const; /// Is this a transparent initializer list (that is, an InitListExpr that is /// purely syntactic, and whose semantics are that of the sole contained /// initializer)? bool isTransparent() const; /// Is this the zero initializer {0} in a language which considers it /// idiomatic? bool isIdiomaticZeroInitializer(const LangOptions &LangOpts) const; SourceLocation getLBraceLoc() const { return LBraceLoc; } void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; } SourceLocation getRBraceLoc() const { return RBraceLoc; } void setRBraceLoc(SourceLocation Loc) { RBraceLoc = Loc; } bool isSemanticForm() const { return AltForm.getInt(); } InitListExpr *getSemanticForm() const { return isSemanticForm() ? nullptr : AltForm.getPointer(); } bool isSyntacticForm() const { return !AltForm.getInt() || !AltForm.getPointer(); } InitListExpr *getSyntacticForm() const { return isSemanticForm() ? AltForm.getPointer() : nullptr; } void setSyntacticForm(InitListExpr *Init) { AltForm.setPointer(Init); AltForm.setInt(true); Init->AltForm.setPointer(this); Init->AltForm.setInt(false); } bool hadArrayRangeDesignator() const { return InitListExprBits.HadArrayRangeDesignator != 0; } void sawArrayRangeDesignator(bool ARD = true) { InitListExprBits.HadArrayRangeDesignator = ARD; } SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == InitListExprClass; } // Iterators child_range children() { const_child_range CCR = const_cast(this)->children(); return child_range(cast_away_const(CCR.begin()), cast_away_const(CCR.end())); } const_child_range children() const { // FIXME: This does not include the array filler expression. if (InitExprs.empty()) return const_child_range(const_child_iterator(), const_child_iterator()); return const_child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size()); } typedef InitExprsTy::iterator iterator; typedef InitExprsTy::const_iterator const_iterator; typedef InitExprsTy::reverse_iterator reverse_iterator; typedef InitExprsTy::const_reverse_iterator const_reverse_iterator; iterator begin() { return InitExprs.begin(); } const_iterator begin() const { return InitExprs.begin(); } iterator end() { return InitExprs.end(); } const_iterator end() const { return InitExprs.end(); } reverse_iterator rbegin() { return InitExprs.rbegin(); } const_reverse_iterator rbegin() const { return InitExprs.rbegin(); } reverse_iterator rend() { return InitExprs.rend(); } const_reverse_iterator rend() const { return InitExprs.rend(); } friend class ASTStmtReader; friend class ASTStmtWriter; }; /// Represents a C99 designated initializer expression. /// /// A designated initializer expression (C99 6.7.8) contains one or /// more designators (which can be field designators, array /// designators, or GNU array-range designators) followed by an /// expression that initializes the field or element(s) that the /// designators refer to. For example, given: /// /// @code /// struct point { /// double x; /// double y; /// }; /// struct point ptarray[10] = { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; /// @endcode /// /// The InitListExpr contains three DesignatedInitExprs, the first of /// which covers @c [2].y=1.0. This DesignatedInitExpr will have two /// designators, one array designator for @c [2] followed by one field /// designator for @c .y. The initialization expression will be 1.0. class DesignatedInitExpr final : public Expr, private llvm::TrailingObjects { public: /// Forward declaration of the Designator class. class Designator; private: /// The location of the '=' or ':' prior to the actual initializer /// expression. SourceLocation EqualOrColonLoc; /// Whether this designated initializer used the GNU deprecated /// syntax rather than the C99 '=' syntax. unsigned GNUSyntax : 1; /// The number of designators in this initializer expression. unsigned NumDesignators : 15; /// The number of subexpressions of this initializer expression, /// which contains both the initializer and any additional /// expressions used by array and array-range designators. unsigned NumSubExprs : 16; /// The designators in this designated initialization /// expression. Designator *Designators; DesignatedInitExpr(const ASTContext &C, QualType Ty, llvm::ArrayRef Designators, SourceLocation EqualOrColonLoc, bool GNUSyntax, ArrayRef IndexExprs, Expr *Init); explicit DesignatedInitExpr(unsigned NumSubExprs) : Expr(DesignatedInitExprClass, EmptyShell()), NumDesignators(0), NumSubExprs(NumSubExprs), Designators(nullptr) { } public: /// A field designator, e.g., ".x". struct FieldDesignator { /// Refers to the field that is being initialized. The low bit /// of this field determines whether this is actually a pointer /// to an IdentifierInfo (if 1) or a FieldDecl (if 0). When /// initially constructed, a field designator will store an /// IdentifierInfo*. After semantic analysis has resolved that /// name, the field designator will instead store a FieldDecl*. uintptr_t NameOrField; /// The location of the '.' in the designated initializer. SourceLocation DotLoc; /// The location of the field name in the designated initializer. SourceLocation FieldLoc; }; /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]". struct ArrayOrRangeDesignator { /// Location of the first index expression within the designated /// initializer expression's list of subexpressions. unsigned Index; /// The location of the '[' starting the array range designator. SourceLocation LBracketLoc; /// The location of the ellipsis separating the start and end /// indices. Only valid for GNU array-range designators. SourceLocation EllipsisLoc; /// The location of the ']' terminating the array range designator. SourceLocation RBracketLoc; }; /// Represents a single C99 designator. /// /// @todo This class is infuriatingly similar to clang::Designator, /// but minor differences (storing indices vs. storing pointers) /// keep us from reusing it. Try harder, later, to rectify these /// differences. class Designator { /// The kind of designator this describes. enum { FieldDesignator, ArrayDesignator, ArrayRangeDesignator } Kind; union { /// A field designator, e.g., ".x". struct FieldDesignator Field; /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]". struct ArrayOrRangeDesignator ArrayOrRange; }; friend class DesignatedInitExpr; public: Designator() {} /// Initializes a field designator. Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc, SourceLocation FieldLoc) : Kind(FieldDesignator) { new (&Field) DesignatedInitExpr::FieldDesignator; Field.NameOrField = reinterpret_cast(FieldName) | 0x01; Field.DotLoc = DotLoc; Field.FieldLoc = FieldLoc; } /// Initializes an array designator. Designator(unsigned Index, SourceLocation LBracketLoc, SourceLocation RBracketLoc) : Kind(ArrayDesignator) { new (&ArrayOrRange) DesignatedInitExpr::ArrayOrRangeDesignator; ArrayOrRange.Index = Index; ArrayOrRange.LBracketLoc = LBracketLoc; ArrayOrRange.EllipsisLoc = SourceLocation(); ArrayOrRange.RBracketLoc = RBracketLoc; } /// Initializes a GNU array-range designator. Designator(unsigned Index, SourceLocation LBracketLoc, SourceLocation EllipsisLoc, SourceLocation RBracketLoc) : Kind(ArrayRangeDesignator) { new (&ArrayOrRange) DesignatedInitExpr::ArrayOrRangeDesignator; ArrayOrRange.Index = Index; ArrayOrRange.LBracketLoc = LBracketLoc; ArrayOrRange.EllipsisLoc = EllipsisLoc; ArrayOrRange.RBracketLoc = RBracketLoc; } bool isFieldDesignator() const { return Kind == FieldDesignator; } bool isArrayDesignator() const { return Kind == ArrayDesignator; } bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; } IdentifierInfo *getFieldName() const; FieldDecl *getField() const { assert(Kind == FieldDesignator && "Only valid on a field designator"); if (Field.NameOrField & 0x01) return nullptr; else return reinterpret_cast(Field.NameOrField); } void setField(FieldDecl *FD) { assert(Kind == FieldDesignator && "Only valid on a field designator"); Field.NameOrField = reinterpret_cast(FD); } SourceLocation getDotLoc() const { assert(Kind == FieldDesignator && "Only valid on a field designator"); return Field.DotLoc; } SourceLocation getFieldLoc() const { assert(Kind == FieldDesignator && "Only valid on a field designator"); return Field.FieldLoc; } SourceLocation getLBracketLoc() const { assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && "Only valid on an array or array-range designator"); return ArrayOrRange.LBracketLoc; } SourceLocation getRBracketLoc() const { assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && "Only valid on an array or array-range designator"); return ArrayOrRange.RBracketLoc; } SourceLocation getEllipsisLoc() const { assert(Kind == ArrayRangeDesignator && "Only valid on an array-range designator"); return ArrayOrRange.EllipsisLoc; } unsigned getFirstExprIndex() const { assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && "Only valid on an array or array-range designator"); return ArrayOrRange.Index; } SourceLocation getBeginLoc() const LLVM_READONLY { if (Kind == FieldDesignator) return getDotLoc().isInvalid()? getFieldLoc() : getDotLoc(); else return getLBracketLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return Kind == FieldDesignator ? getFieldLoc() : getRBracketLoc(); } SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(getBeginLoc(), getEndLoc()); } }; static DesignatedInitExpr *Create(const ASTContext &C, llvm::ArrayRef Designators, ArrayRef IndexExprs, SourceLocation EqualOrColonLoc, bool GNUSyntax, Expr *Init); static DesignatedInitExpr *CreateEmpty(const ASTContext &C, unsigned NumIndexExprs); /// Returns the number of designators in this initializer. unsigned size() const { return NumDesignators; } // Iterator access to the designators. llvm::MutableArrayRef designators() { return {Designators, NumDesignators}; } llvm::ArrayRef designators() const { return {Designators, NumDesignators}; } Designator *getDesignator(unsigned Idx) { return &designators()[Idx]; } const Designator *getDesignator(unsigned Idx) const { return &designators()[Idx]; } void setDesignators(const ASTContext &C, const Designator *Desigs, unsigned NumDesigs); Expr *getArrayIndex(const Designator &D) const; Expr *getArrayRangeStart(const Designator &D) const; Expr *getArrayRangeEnd(const Designator &D) const; /// Retrieve the location of the '=' that precedes the /// initializer value itself, if present. SourceLocation getEqualOrColonLoc() const { return EqualOrColonLoc; } void setEqualOrColonLoc(SourceLocation L) { EqualOrColonLoc = L; } /// Whether this designated initializer should result in direct-initialization /// of the designated subobject (eg, '{.foo{1, 2, 3}}'). bool isDirectInit() const { return EqualOrColonLoc.isInvalid(); } /// Determines whether this designated initializer used the /// deprecated GNU syntax for designated initializers. bool usesGNUSyntax() const { return GNUSyntax; } void setGNUSyntax(bool GNU) { GNUSyntax = GNU; } /// Retrieve the initializer value. Expr *getInit() const { return cast(*const_cast(this)->child_begin()); } void setInit(Expr *init) { *child_begin() = init; } /// Retrieve the total number of subexpressions in this /// designated initializer expression, including the actual /// initialized value and any expressions that occur within array /// and array-range designators. unsigned getNumSubExprs() const { return NumSubExprs; } Expr *getSubExpr(unsigned Idx) const { assert(Idx < NumSubExprs && "Subscript out of range"); return cast(getTrailingObjects()[Idx]); } void setSubExpr(unsigned Idx, Expr *E) { assert(Idx < NumSubExprs && "Subscript out of range"); getTrailingObjects()[Idx] = E; } /// Replaces the designator at index @p Idx with the series /// of designators in [First, Last). void ExpandDesignator(const ASTContext &C, unsigned Idx, const Designator *First, const Designator *Last); SourceRange getDesignatorsSourceRange() const; SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == DesignatedInitExprClass; } // Iterators child_range children() { Stmt **begin = getTrailingObjects(); return child_range(begin, begin + NumSubExprs); } const_child_range children() const { Stmt * const *begin = getTrailingObjects(); return const_child_range(begin, begin + NumSubExprs); } friend TrailingObjects; }; /// Represents a place-holder for an object not to be initialized by /// anything. /// /// This only makes sense when it appears as part of an updater of a /// DesignatedInitUpdateExpr (see below). The base expression of a DIUE /// initializes a big object, and the NoInitExpr's mark the spots within the /// big object not to be overwritten by the updater. /// /// \see DesignatedInitUpdateExpr class NoInitExpr : public Expr { public: explicit NoInitExpr(QualType ty) : Expr(NoInitExprClass, ty, VK_PRValue, OK_Ordinary) { setDependence(computeDependence(this)); } explicit NoInitExpr(EmptyShell Empty) : Expr(NoInitExprClass, Empty) { } static bool classof(const Stmt *T) { return T->getStmtClass() == NoInitExprClass; } SourceLocation getBeginLoc() const LLVM_READONLY { return SourceLocation(); } SourceLocation getEndLoc() const LLVM_READONLY { return SourceLocation(); } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; // In cases like: // struct Q { int a, b, c; }; // Q *getQ(); // void foo() { // struct A { Q q; } a = { *getQ(), .q.b = 3 }; // } // // We will have an InitListExpr for a, with type A, and then a // DesignatedInitUpdateExpr for "a.q" with type Q. The "base" for this DIUE // is the call expression *getQ(); the "updater" for the DIUE is ".q.b = 3" // class DesignatedInitUpdateExpr : public Expr { // BaseAndUpdaterExprs[0] is the base expression; // BaseAndUpdaterExprs[1] is an InitListExpr overwriting part of the base. Stmt *BaseAndUpdaterExprs[2]; public: DesignatedInitUpdateExpr(const ASTContext &C, SourceLocation lBraceLoc, Expr *baseExprs, SourceLocation rBraceLoc); explicit DesignatedInitUpdateExpr(EmptyShell Empty) : Expr(DesignatedInitUpdateExprClass, Empty) { } SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == DesignatedInitUpdateExprClass; } Expr *getBase() const { return cast(BaseAndUpdaterExprs[0]); } void setBase(Expr *Base) { BaseAndUpdaterExprs[0] = Base; } InitListExpr *getUpdater() const { return cast(BaseAndUpdaterExprs[1]); } void setUpdater(Expr *Updater) { BaseAndUpdaterExprs[1] = Updater; } // Iterators // children = the base and the updater child_range children() { return child_range(&BaseAndUpdaterExprs[0], &BaseAndUpdaterExprs[0] + 2); } const_child_range children() const { return const_child_range(&BaseAndUpdaterExprs[0], &BaseAndUpdaterExprs[0] + 2); } }; /// Represents a loop initializing the elements of an array. /// /// The need to initialize the elements of an array occurs in a number of /// contexts: /// /// * in the implicit copy/move constructor for a class with an array member /// * when a lambda-expression captures an array by value /// * when a decomposition declaration decomposes an array /// /// There are two subexpressions: a common expression (the source array) /// that is evaluated once up-front, and a per-element initializer that /// runs once for each array element. /// /// Within the per-element initializer, the common expression may be referenced /// via an OpaqueValueExpr, and the current index may be obtained via an /// ArrayInitIndexExpr. class ArrayInitLoopExpr : public Expr { Stmt *SubExprs[2]; explicit ArrayInitLoopExpr(EmptyShell Empty) : Expr(ArrayInitLoopExprClass, Empty), SubExprs{} {} public: explicit ArrayInitLoopExpr(QualType T, Expr *CommonInit, Expr *ElementInit) : Expr(ArrayInitLoopExprClass, T, VK_PRValue, OK_Ordinary), SubExprs{CommonInit, ElementInit} { setDependence(computeDependence(this)); } /// Get the common subexpression shared by all initializations (the source /// array). OpaqueValueExpr *getCommonExpr() const { return cast(SubExprs[0]); } /// Get the initializer to use for each array element. Expr *getSubExpr() const { return cast(SubExprs[1]); } llvm::APInt getArraySize() const { return cast(getType()->castAsArrayTypeUnsafe()) ->getSize(); } static bool classof(const Stmt *S) { return S->getStmtClass() == ArrayInitLoopExprClass; } SourceLocation getBeginLoc() const LLVM_READONLY { return getCommonExpr()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getCommonExpr()->getEndLoc(); } child_range children() { return child_range(SubExprs, SubExprs + 2); } const_child_range children() const { return const_child_range(SubExprs, SubExprs + 2); } friend class ASTReader; friend class ASTStmtReader; friend class ASTStmtWriter; }; /// Represents the index of the current element of an array being /// initialized by an ArrayInitLoopExpr. This can only appear within the /// subexpression of an ArrayInitLoopExpr. class ArrayInitIndexExpr : public Expr { explicit ArrayInitIndexExpr(EmptyShell Empty) : Expr(ArrayInitIndexExprClass, Empty) {} public: explicit ArrayInitIndexExpr(QualType T) : Expr(ArrayInitIndexExprClass, T, VK_PRValue, OK_Ordinary) { setDependence(ExprDependence::None); } static bool classof(const Stmt *S) { return S->getStmtClass() == ArrayInitIndexExprClass; } SourceLocation getBeginLoc() const LLVM_READONLY { return SourceLocation(); } SourceLocation getEndLoc() const LLVM_READONLY { return SourceLocation(); } child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } friend class ASTReader; friend class ASTStmtReader; }; /// Represents an implicitly-generated value initialization of /// an object of a given type. /// /// Implicit value initializations occur within semantic initializer /// list expressions (InitListExpr) as placeholders for subobject /// initializations not explicitly specified by the user. /// /// \see InitListExpr class ImplicitValueInitExpr : public Expr { public: explicit ImplicitValueInitExpr(QualType ty) : Expr(ImplicitValueInitExprClass, ty, VK_PRValue, OK_Ordinary) { setDependence(computeDependence(this)); } /// Construct an empty implicit value initialization. explicit ImplicitValueInitExpr(EmptyShell Empty) : Expr(ImplicitValueInitExprClass, Empty) { } static bool classof(const Stmt *T) { return T->getStmtClass() == ImplicitValueInitExprClass; } SourceLocation getBeginLoc() const LLVM_READONLY { return SourceLocation(); } SourceLocation getEndLoc() const LLVM_READONLY { return SourceLocation(); } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; class ParenListExpr final : public Expr, private llvm::TrailingObjects { friend class ASTStmtReader; friend TrailingObjects; /// The location of the left and right parentheses. SourceLocation LParenLoc, RParenLoc; /// Build a paren list. ParenListExpr(SourceLocation LParenLoc, ArrayRef Exprs, SourceLocation RParenLoc); /// Build an empty paren list. ParenListExpr(EmptyShell Empty, unsigned NumExprs); public: /// Create a paren list. static ParenListExpr *Create(const ASTContext &Ctx, SourceLocation LParenLoc, ArrayRef Exprs, SourceLocation RParenLoc); /// Create an empty paren list. static ParenListExpr *CreateEmpty(const ASTContext &Ctx, unsigned NumExprs); /// Return the number of expressions in this paren list. unsigned getNumExprs() const { return ParenListExprBits.NumExprs; } Expr *getExpr(unsigned Init) { assert(Init < getNumExprs() && "Initializer access out of range!"); return getExprs()[Init]; } const Expr *getExpr(unsigned Init) const { return const_cast(this)->getExpr(Init); } Expr **getExprs() { return reinterpret_cast(getTrailingObjects()); } ArrayRef exprs() { return llvm::makeArrayRef(getExprs(), getNumExprs()); } SourceLocation getLParenLoc() const { return LParenLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } SourceLocation getBeginLoc() const { return getLParenLoc(); } SourceLocation getEndLoc() const { return getRParenLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ParenListExprClass; } // Iterators child_range children() { return child_range(getTrailingObjects(), getTrailingObjects() + getNumExprs()); } const_child_range children() const { return const_child_range(getTrailingObjects(), getTrailingObjects() + getNumExprs()); } }; /// Represents a C11 generic selection. /// /// A generic selection (C11 6.5.1.1) contains an unevaluated controlling /// expression, followed by one or more generic associations. Each generic /// association specifies a type name and an expression, or "default" and an /// expression (in which case it is known as a default generic association). /// The type and value of the generic selection are identical to those of its /// result expression, which is defined as the expression in the generic /// association with a type name that is compatible with the type of the /// controlling expression, or the expression in the default generic association /// if no types are compatible. For example: /// /// @code /// _Generic(X, double: 1, float: 2, default: 3) /// @endcode /// /// The above expression evaluates to 1 if 1.0 is substituted for X, 2 if 1.0f /// or 3 if "hello". /// /// As an extension, generic selections are allowed in C++, where the following /// additional semantics apply: /// /// Any generic selection whose controlling expression is type-dependent or /// which names a dependent type in its association list is result-dependent, /// which means that the choice of result expression is dependent. /// Result-dependent generic associations are both type- and value-dependent. class GenericSelectionExpr final : public Expr, private llvm::TrailingObjects { friend class ASTStmtReader; friend class ASTStmtWriter; friend TrailingObjects; /// The number of association expressions and the index of the result /// expression in the case where the generic selection expression is not /// result-dependent. The result index is equal to ResultDependentIndex /// if and only if the generic selection expression is result-dependent. unsigned NumAssocs, ResultIndex; enum : unsigned { ResultDependentIndex = std::numeric_limits::max(), ControllingIndex = 0, AssocExprStartIndex = 1 }; /// The location of the "default" and of the right parenthesis. SourceLocation DefaultLoc, RParenLoc; // GenericSelectionExpr is followed by several trailing objects. // They are (in order): // // * A single Stmt * for the controlling expression. // * An array of getNumAssocs() Stmt * for the association expressions. // * An array of getNumAssocs() TypeSourceInfo *, one for each of the // association expressions. unsigned numTrailingObjects(OverloadToken) const { // Add one to account for the controlling expression; the remainder // are the associated expressions. return 1 + getNumAssocs(); } unsigned numTrailingObjects(OverloadToken) const { return getNumAssocs(); } template class AssociationIteratorTy; /// Bundle together an association expression and its TypeSourceInfo. /// The Const template parameter is for the const and non-const versions /// of AssociationTy. template class AssociationTy { friend class GenericSelectionExpr; template friend class AssociationIteratorTy; using ExprPtrTy = std::conditional_t; using TSIPtrTy = std::conditional_t; ExprPtrTy E; TSIPtrTy TSI; bool Selected; AssociationTy(ExprPtrTy E, TSIPtrTy TSI, bool Selected) : E(E), TSI(TSI), Selected(Selected) {} public: ExprPtrTy getAssociationExpr() const { return E; } TSIPtrTy getTypeSourceInfo() const { return TSI; } QualType getType() const { return TSI ? TSI->getType() : QualType(); } bool isSelected() const { return Selected; } AssociationTy *operator->() { return this; } const AssociationTy *operator->() const { return this; } }; // class AssociationTy /// Iterator over const and non-const Association objects. The Association /// objects are created on the fly when the iterator is dereferenced. /// This abstract over how exactly the association expressions and the /// corresponding TypeSourceInfo * are stored. template class AssociationIteratorTy : public llvm::iterator_facade_base< AssociationIteratorTy, std::input_iterator_tag, AssociationTy, std::ptrdiff_t, AssociationTy, AssociationTy> { friend class GenericSelectionExpr; // FIXME: This iterator could conceptually be a random access iterator, and // it would be nice if we could strengthen the iterator category someday. // However this iterator does not satisfy two requirements of forward // iterators: // a) reference = T& or reference = const T& // b) If It1 and It2 are both dereferenceable, then It1 == It2 if and only // if *It1 and *It2 are bound to the same objects. // An alternative design approach was discussed during review; // store an Association object inside the iterator, and return a reference // to it when dereferenced. This idea was discarded beacuse of nasty // lifetime issues: // AssociationIterator It = ...; // const Association &Assoc = *It++; // Oops, Assoc is dangling. using BaseTy = typename AssociationIteratorTy::iterator_facade_base; using StmtPtrPtrTy = std::conditional_t; using TSIPtrPtrTy = std::conditional_t; StmtPtrPtrTy E; // = nullptr; FIXME: Once support for gcc 4.8 is dropped. TSIPtrPtrTy TSI; // Kept in sync with E. unsigned Offset = 0, SelectedOffset = 0; AssociationIteratorTy(StmtPtrPtrTy E, TSIPtrPtrTy TSI, unsigned Offset, unsigned SelectedOffset) : E(E), TSI(TSI), Offset(Offset), SelectedOffset(SelectedOffset) {} public: AssociationIteratorTy() : E(nullptr), TSI(nullptr) {} typename BaseTy::reference operator*() const { return AssociationTy(cast(*E), *TSI, Offset == SelectedOffset); } typename BaseTy::pointer operator->() const { return **this; } using BaseTy::operator++; AssociationIteratorTy &operator++() { ++E; ++TSI; ++Offset; return *this; } bool operator==(AssociationIteratorTy Other) const { return E == Other.E; } }; // class AssociationIterator /// Build a non-result-dependent generic selection expression. GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef AssocTypes, ArrayRef AssocExprs, SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack, unsigned ResultIndex); /// Build a result-dependent generic selection expression. GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef AssocTypes, ArrayRef AssocExprs, SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack); /// Build an empty generic selection expression for deserialization. explicit GenericSelectionExpr(EmptyShell Empty, unsigned NumAssocs); public: /// Create a non-result-dependent generic selection expression. static GenericSelectionExpr * Create(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef AssocTypes, ArrayRef AssocExprs, SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack, unsigned ResultIndex); /// Create a result-dependent generic selection expression. static GenericSelectionExpr * Create(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef AssocTypes, ArrayRef AssocExprs, SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack); /// Create an empty generic selection expression for deserialization. static GenericSelectionExpr *CreateEmpty(const ASTContext &Context, unsigned NumAssocs); using Association = AssociationTy; using ConstAssociation = AssociationTy; using AssociationIterator = AssociationIteratorTy; using ConstAssociationIterator = AssociationIteratorTy; using association_range = llvm::iterator_range; using const_association_range = llvm::iterator_range; /// The number of association expressions. unsigned getNumAssocs() const { return NumAssocs; } /// The zero-based index of the result expression's generic association in /// the generic selection's association list. Defined only if the /// generic selection is not result-dependent. unsigned getResultIndex() const { assert(!isResultDependent() && "Generic selection is result-dependent but getResultIndex called!"); return ResultIndex; } /// Whether this generic selection is result-dependent. bool isResultDependent() const { return ResultIndex == ResultDependentIndex; } /// Return the controlling expression of this generic selection expression. Expr *getControllingExpr() { return cast(getTrailingObjects()[ControllingIndex]); } const Expr *getControllingExpr() const { return cast(getTrailingObjects()[ControllingIndex]); } /// Return the result expression of this controlling expression. Defined if /// and only if the generic selection expression is not result-dependent. Expr *getResultExpr() { return cast( getTrailingObjects()[AssocExprStartIndex + getResultIndex()]); } const Expr *getResultExpr() const { return cast( getTrailingObjects()[AssocExprStartIndex + getResultIndex()]); } ArrayRef getAssocExprs() const { return {reinterpret_cast(getTrailingObjects() + AssocExprStartIndex), NumAssocs}; } ArrayRef getAssocTypeSourceInfos() const { return {getTrailingObjects(), NumAssocs}; } /// Return the Ith association expression with its TypeSourceInfo, /// bundled together in GenericSelectionExpr::(Const)Association. Association getAssociation(unsigned I) { assert(I < getNumAssocs() && "Out-of-range index in GenericSelectionExpr::getAssociation!"); return Association( cast(getTrailingObjects()[AssocExprStartIndex + I]), getTrailingObjects()[I], !isResultDependent() && (getResultIndex() == I)); } ConstAssociation getAssociation(unsigned I) const { assert(I < getNumAssocs() && "Out-of-range index in GenericSelectionExpr::getAssociation!"); return ConstAssociation( cast(getTrailingObjects()[AssocExprStartIndex + I]), getTrailingObjects()[I], !isResultDependent() && (getResultIndex() == I)); } association_range associations() { AssociationIterator Begin(getTrailingObjects() + AssocExprStartIndex, getTrailingObjects(), /*Offset=*/0, ResultIndex); AssociationIterator End(Begin.E + NumAssocs, Begin.TSI + NumAssocs, /*Offset=*/NumAssocs, ResultIndex); return llvm::make_range(Begin, End); } const_association_range associations() const { ConstAssociationIterator Begin(getTrailingObjects() + AssocExprStartIndex, getTrailingObjects(), /*Offset=*/0, ResultIndex); ConstAssociationIterator End(Begin.E + NumAssocs, Begin.TSI + NumAssocs, /*Offset=*/NumAssocs, ResultIndex); return llvm::make_range(Begin, End); } SourceLocation getGenericLoc() const { return GenericSelectionExprBits.GenericLoc; } SourceLocation getDefaultLoc() const { return DefaultLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } SourceLocation getBeginLoc() const { return getGenericLoc(); } SourceLocation getEndLoc() const { return getRParenLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == GenericSelectionExprClass; } child_range children() { return child_range(getTrailingObjects(), getTrailingObjects() + numTrailingObjects(OverloadToken())); } const_child_range children() const { return const_child_range(getTrailingObjects(), getTrailingObjects() + numTrailingObjects(OverloadToken())); } }; //===----------------------------------------------------------------------===// // Clang Extensions //===----------------------------------------------------------------------===// /// ExtVectorElementExpr - This represents access to specific elements of a /// vector, and may occur on the left hand side or right hand side. For example /// the following is legal: "V.xy = V.zw" if V is a 4 element extended vector. /// /// Note that the base may have either vector or pointer to vector type, just /// like a struct field reference. /// class ExtVectorElementExpr : public Expr { Stmt *Base; IdentifierInfo *Accessor; SourceLocation AccessorLoc; public: ExtVectorElementExpr(QualType ty, ExprValueKind VK, Expr *base, IdentifierInfo &accessor, SourceLocation loc) : Expr(ExtVectorElementExprClass, ty, VK, (VK == VK_PRValue ? OK_Ordinary : OK_VectorComponent)), Base(base), Accessor(&accessor), AccessorLoc(loc) { setDependence(computeDependence(this)); } /// Build an empty vector element expression. explicit ExtVectorElementExpr(EmptyShell Empty) : Expr(ExtVectorElementExprClass, Empty) { } const Expr *getBase() const { return cast(Base); } Expr *getBase() { return cast(Base); } void setBase(Expr *E) { Base = E; } IdentifierInfo &getAccessor() const { return *Accessor; } void setAccessor(IdentifierInfo *II) { Accessor = II; } SourceLocation getAccessorLoc() const { return AccessorLoc; } void setAccessorLoc(SourceLocation L) { AccessorLoc = L; } /// getNumElements - Get the number of components being selected. unsigned getNumElements() const; /// containsDuplicateElements - Return true if any element access is /// repeated. bool containsDuplicateElements() const; /// getEncodedElementAccess - Encode the elements accessed into an llvm /// aggregate Constant of ConstantInt(s). void getEncodedElementAccess(SmallVectorImpl &Elts) const; SourceLocation getBeginLoc() const LLVM_READONLY { return getBase()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return AccessorLoc; } /// isArrow - Return true if the base expression is a pointer to vector, /// return false if the base expression is a vector. bool isArrow() const; static bool classof(const Stmt *T) { return T->getStmtClass() == ExtVectorElementExprClass; } // Iterators child_range children() { return child_range(&Base, &Base+1); } const_child_range children() const { return const_child_range(&Base, &Base + 1); } }; /// BlockExpr - Adaptor class for mixing a BlockDecl with expressions. /// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } class BlockExpr : public Expr { protected: BlockDecl *TheBlock; public: BlockExpr(BlockDecl *BD, QualType ty) : Expr(BlockExprClass, ty, VK_PRValue, OK_Ordinary), TheBlock(BD) { setDependence(computeDependence(this)); } /// Build an empty block expression. explicit BlockExpr(EmptyShell Empty) : Expr(BlockExprClass, Empty) { } const BlockDecl *getBlockDecl() const { return TheBlock; } BlockDecl *getBlockDecl() { return TheBlock; } void setBlockDecl(BlockDecl *BD) { TheBlock = BD; } // Convenience functions for probing the underlying BlockDecl. SourceLocation getCaretLocation() const; const Stmt *getBody() const; Stmt *getBody(); SourceLocation getBeginLoc() const LLVM_READONLY { return getCaretLocation(); } SourceLocation getEndLoc() const LLVM_READONLY { return getBody()->getEndLoc(); } /// getFunctionType - Return the underlying function type for this block. const FunctionProtoType *getFunctionType() const; static bool classof(const Stmt *T) { return T->getStmtClass() == BlockExprClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// Copy initialization expr of a __block variable and a boolean flag that /// indicates whether the expression can throw. struct BlockVarCopyInit { BlockVarCopyInit() = default; BlockVarCopyInit(Expr *CopyExpr, bool CanThrow) : ExprAndFlag(CopyExpr, CanThrow) {} void setExprAndFlag(Expr *CopyExpr, bool CanThrow) { ExprAndFlag.setPointerAndInt(CopyExpr, CanThrow); } Expr *getCopyExpr() const { return ExprAndFlag.getPointer(); } bool canThrow() const { return ExprAndFlag.getInt(); } llvm::PointerIntPair ExprAndFlag; }; /// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2] /// This AST node provides support for reinterpreting a type to another /// type of the same size. class AsTypeExpr : public Expr { private: Stmt *SrcExpr; SourceLocation BuiltinLoc, RParenLoc; friend class ASTReader; friend class ASTStmtReader; explicit AsTypeExpr(EmptyShell Empty) : Expr(AsTypeExprClass, Empty) {} public: AsTypeExpr(Expr *SrcExpr, QualType DstType, ExprValueKind VK, ExprObjectKind OK, SourceLocation BuiltinLoc, SourceLocation RParenLoc) : Expr(AsTypeExprClass, DstType, VK, OK), SrcExpr(SrcExpr), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) { setDependence(computeDependence(this)); } /// getSrcExpr - Return the Expr to be converted. Expr *getSrcExpr() const { return cast(SrcExpr); } /// getBuiltinLoc - Return the location of the __builtin_astype token. SourceLocation getBuiltinLoc() const { return BuiltinLoc; } /// getRParenLoc - Return the location of final right parenthesis. SourceLocation getRParenLoc() const { return RParenLoc; } SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == AsTypeExprClass; } // Iterators child_range children() { return child_range(&SrcExpr, &SrcExpr+1); } const_child_range children() const { return const_child_range(&SrcExpr, &SrcExpr + 1); } }; /// PseudoObjectExpr - An expression which accesses a pseudo-object /// l-value. A pseudo-object is an abstract object, accesses to which /// are translated to calls. The pseudo-object expression has a /// syntactic form, which shows how the expression was actually /// written in the source code, and a semantic form, which is a series /// of expressions to be executed in order which detail how the /// operation is actually evaluated. Optionally, one of the semantic /// forms may also provide a result value for the expression. /// /// If any of the semantic-form expressions is an OpaqueValueExpr, /// that OVE is required to have a source expression, and it is bound /// to the result of that source expression. Such OVEs may appear /// only in subsequent semantic-form expressions and as /// sub-expressions of the syntactic form. /// /// PseudoObjectExpr should be used only when an operation can be /// usefully described in terms of fairly simple rewrite rules on /// objects and functions that are meant to be used by end-developers. /// For example, under the Itanium ABI, dynamic casts are implemented /// as a call to a runtime function called __dynamic_cast; using this /// class to describe that would be inappropriate because that call is /// not really part of the user-visible semantics, and instead the /// cast is properly reflected in the AST and IR-generation has been /// taught to generate the call as necessary. In contrast, an /// Objective-C property access is semantically defined to be /// equivalent to a particular message send, and this is very much /// part of the user model. The name of this class encourages this /// modelling design. class PseudoObjectExpr final : public Expr, private llvm::TrailingObjects { // PseudoObjectExprBits.NumSubExprs - The number of sub-expressions. // Always at least two, because the first sub-expression is the // syntactic form. // PseudoObjectExprBits.ResultIndex - The index of the // sub-expression holding the result. 0 means the result is void, // which is unambiguous because it's the index of the syntactic // form. Note that this is therefore 1 higher than the value passed // in to Create, which is an index within the semantic forms. // Note also that ASTStmtWriter assumes this encoding. Expr **getSubExprsBuffer() { return getTrailingObjects(); } const Expr * const *getSubExprsBuffer() const { return getTrailingObjects(); } PseudoObjectExpr(QualType type, ExprValueKind VK, Expr *syntactic, ArrayRef semantic, unsigned resultIndex); PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs); unsigned getNumSubExprs() const { return PseudoObjectExprBits.NumSubExprs; } public: /// NoResult - A value for the result index indicating that there is /// no semantic result. enum : unsigned { NoResult = ~0U }; static PseudoObjectExpr *Create(const ASTContext &Context, Expr *syntactic, ArrayRef semantic, unsigned resultIndex); static PseudoObjectExpr *Create(const ASTContext &Context, EmptyShell shell, unsigned numSemanticExprs); /// Return the syntactic form of this expression, i.e. the /// expression it actually looks like. Likely to be expressed in /// terms of OpaqueValueExprs bound in the semantic form. Expr *getSyntacticForm() { return getSubExprsBuffer()[0]; } const Expr *getSyntacticForm() const { return getSubExprsBuffer()[0]; } /// Return the index of the result-bearing expression into the semantics /// expressions, or PseudoObjectExpr::NoResult if there is none. unsigned getResultExprIndex() const { if (PseudoObjectExprBits.ResultIndex == 0) return NoResult; return PseudoObjectExprBits.ResultIndex - 1; } /// Return the result-bearing expression, or null if there is none. Expr *getResultExpr() { if (PseudoObjectExprBits.ResultIndex == 0) return nullptr; return getSubExprsBuffer()[PseudoObjectExprBits.ResultIndex]; } const Expr *getResultExpr() const { return const_cast(this)->getResultExpr(); } unsigned getNumSemanticExprs() const { return getNumSubExprs() - 1; } typedef Expr * const *semantics_iterator; typedef const Expr * const *const_semantics_iterator; semantics_iterator semantics_begin() { return getSubExprsBuffer() + 1; } const_semantics_iterator semantics_begin() const { return getSubExprsBuffer() + 1; } semantics_iterator semantics_end() { return getSubExprsBuffer() + getNumSubExprs(); } const_semantics_iterator semantics_end() const { return getSubExprsBuffer() + getNumSubExprs(); } llvm::iterator_range semantics() { return llvm::make_range(semantics_begin(), semantics_end()); } llvm::iterator_range semantics() const { return llvm::make_range(semantics_begin(), semantics_end()); } Expr *getSemanticExpr(unsigned index) { assert(index + 1 < getNumSubExprs()); return getSubExprsBuffer()[index + 1]; } const Expr *getSemanticExpr(unsigned index) const { return const_cast(this)->getSemanticExpr(index); } SourceLocation getExprLoc() const LLVM_READONLY { return getSyntacticForm()->getExprLoc(); } SourceLocation getBeginLoc() const LLVM_READONLY { return getSyntacticForm()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getSyntacticForm()->getEndLoc(); } child_range children() { const_child_range CCR = const_cast(this)->children(); return child_range(cast_away_const(CCR.begin()), cast_away_const(CCR.end())); } const_child_range children() const { Stmt *const *cs = const_cast( reinterpret_cast(getSubExprsBuffer())); return const_child_range(cs, cs + getNumSubExprs()); } static bool classof(const Stmt *T) { return T->getStmtClass() == PseudoObjectExprClass; } friend TrailingObjects; friend class ASTStmtReader; }; /// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*, /// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the /// similarly-named C++11 instructions, and __c11 variants for , /// and corresponding __opencl_atomic_* for OpenCL 2.0. /// All of these instructions take one primary pointer, at least one memory /// order. The instructions for which getScopeModel returns non-null value /// take one synch scope. class AtomicExpr : public Expr { public: enum AtomicOp { #define BUILTIN(ID, TYPE, ATTRS) #define ATOMIC_BUILTIN(ID, TYPE, ATTRS) AO ## ID, #include "clang/Basic/Builtins.def" // Avoid trailing comma BI_First = 0 }; private: /// Location of sub-expressions. /// The location of Scope sub-expression is NumSubExprs - 1, which is /// not fixed, therefore is not defined in enum. enum { PTR, ORDER, VAL1, ORDER_FAIL, VAL2, WEAK, END_EXPR }; Stmt *SubExprs[END_EXPR + 1]; unsigned NumSubExprs; SourceLocation BuiltinLoc, RParenLoc; AtomicOp Op; friend class ASTStmtReader; public: AtomicExpr(SourceLocation BLoc, ArrayRef args, QualType t, AtomicOp op, SourceLocation RP); /// Determine the number of arguments the specified atomic builtin /// should have. static unsigned getNumSubExprs(AtomicOp Op); /// Build an empty AtomicExpr. explicit AtomicExpr(EmptyShell Empty) : Expr(AtomicExprClass, Empty) { } Expr *getPtr() const { return cast(SubExprs[PTR]); } Expr *getOrder() const { return cast(SubExprs[ORDER]); } Expr *getScope() const { assert(getScopeModel() && "No scope"); return cast(SubExprs[NumSubExprs - 1]); } Expr *getVal1() const { if (Op == AO__c11_atomic_init || Op == AO__opencl_atomic_init) return cast(SubExprs[ORDER]); assert(NumSubExprs > VAL1); return cast(SubExprs[VAL1]); } Expr *getOrderFail() const { assert(NumSubExprs > ORDER_FAIL); return cast(SubExprs[ORDER_FAIL]); } Expr *getVal2() const { if (Op == AO__atomic_exchange) return cast(SubExprs[ORDER_FAIL]); assert(NumSubExprs > VAL2); return cast(SubExprs[VAL2]); } Expr *getWeak() const { assert(NumSubExprs > WEAK); return cast(SubExprs[WEAK]); } QualType getValueType() const; AtomicOp getOp() const { return Op; } unsigned getNumSubExprs() const { return NumSubExprs; } Expr **getSubExprs() { return reinterpret_cast(SubExprs); } const Expr * const *getSubExprs() const { return reinterpret_cast(SubExprs); } bool isVolatile() const { return getPtr()->getType()->getPointeeType().isVolatileQualified(); } bool isCmpXChg() const { return getOp() == AO__c11_atomic_compare_exchange_strong || getOp() == AO__c11_atomic_compare_exchange_weak || getOp() == AO__hip_atomic_compare_exchange_strong || getOp() == AO__opencl_atomic_compare_exchange_strong || getOp() == AO__opencl_atomic_compare_exchange_weak || getOp() == AO__hip_atomic_compare_exchange_weak || getOp() == AO__atomic_compare_exchange || getOp() == AO__atomic_compare_exchange_n; } bool isOpenCL() const { return getOp() >= AO__opencl_atomic_init && getOp() <= AO__opencl_atomic_fetch_max; } SourceLocation getBuiltinLoc() const { return BuiltinLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == AtomicExprClass; } // Iterators child_range children() { return child_range(SubExprs, SubExprs+NumSubExprs); } const_child_range children() const { return const_child_range(SubExprs, SubExprs + NumSubExprs); } /// Get atomic scope model for the atomic op code. /// \return empty atomic scope model if the atomic op code does not have /// scope operand. static std::unique_ptr getScopeModel(AtomicOp Op) { auto Kind = (Op >= AO__opencl_atomic_load && Op <= AO__opencl_atomic_fetch_max) ? AtomicScopeModelKind::OpenCL : (Op >= AO__hip_atomic_load && Op <= AO__hip_atomic_fetch_max) ? AtomicScopeModelKind::HIP : AtomicScopeModelKind::None; return AtomicScopeModel::create(Kind); } /// Get atomic scope model. /// \return empty atomic scope model if this atomic expression does not have /// scope operand. std::unique_ptr getScopeModel() const { return getScopeModel(getOp()); } }; /// TypoExpr - Internal placeholder for expressions where typo correction /// still needs to be performed and/or an error diagnostic emitted. class TypoExpr : public Expr { // The location for the typo name. SourceLocation TypoLoc; public: TypoExpr(QualType T, SourceLocation TypoLoc) : Expr(TypoExprClass, T, VK_LValue, OK_Ordinary), TypoLoc(TypoLoc) { assert(T->isDependentType() && "TypoExpr given a non-dependent type"); setDependence(ExprDependence::TypeValueInstantiation | ExprDependence::Error); } child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } SourceLocation getBeginLoc() const LLVM_READONLY { return TypoLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return TypoLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == TypoExprClass; } }; /// Frontend produces RecoveryExprs on semantic errors that prevent creating /// other well-formed expressions. E.g. when type-checking of a binary operator /// fails, we cannot produce a BinaryOperator expression. Instead, we can choose /// to produce a recovery expression storing left and right operands. /// /// RecoveryExpr does not have any semantic meaning in C++, it is only useful to /// preserve expressions in AST that would otherwise be dropped. It captures /// subexpressions of some expression that we could not construct and source /// range covered by the expression. /// /// By default, RecoveryExpr uses dependence-bits to take advantage of existing /// machinery to deal with dependent code in C++, e.g. RecoveryExpr is preserved /// in `decltype()` as part of the `DependentDecltypeType`. In /// addition to that, clang does not report most errors on dependent /// expressions, so we get rid of bogus errors for free. However, note that /// unlike other dependent expressions, RecoveryExpr can be produced in /// non-template contexts. /// /// We will preserve the type in RecoveryExpr when the type is known, e.g. /// preserving the return type for a broken non-overloaded function call, a /// overloaded call where all candidates have the same return type. In this /// case, the expression is not type-dependent (unless the known type is itself /// dependent) /// /// One can also reliably suppress all bogus errors on expressions containing /// recovery expressions by examining results of Expr::containsErrors(). class RecoveryExpr final : public Expr, private llvm::TrailingObjects { public: static RecoveryExpr *Create(ASTContext &Ctx, QualType T, SourceLocation BeginLoc, SourceLocation EndLoc, ArrayRef SubExprs); static RecoveryExpr *CreateEmpty(ASTContext &Ctx, unsigned NumSubExprs); ArrayRef subExpressions() { auto *B = getTrailingObjects(); return llvm::makeArrayRef(B, B + NumExprs); } ArrayRef subExpressions() const { return const_cast(this)->subExpressions(); } child_range children() { Stmt **B = reinterpret_cast(getTrailingObjects()); return child_range(B, B + NumExprs); } SourceLocation getBeginLoc() const { return BeginLoc; } SourceLocation getEndLoc() const { return EndLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == RecoveryExprClass; } private: RecoveryExpr(ASTContext &Ctx, QualType T, SourceLocation BeginLoc, SourceLocation EndLoc, ArrayRef SubExprs); RecoveryExpr(EmptyShell Empty, unsigned NumSubExprs) : Expr(RecoveryExprClass, Empty), NumExprs(NumSubExprs) {} size_t numTrailingObjects(OverloadToken) const { return NumExprs; } SourceLocation BeginLoc, EndLoc; unsigned NumExprs; friend TrailingObjects; friend class ASTStmtReader; friend class ASTStmtWriter; }; } // end namespace clang #endif // LLVM_CLANG_AST_EXPR_H diff --git a/contrib/llvm-project/clang/lib/AST/ComputeDependence.cpp b/contrib/llvm-project/clang/lib/AST/ComputeDependence.cpp index 5648cf2103d6..2a2b98776e65 100644 --- a/contrib/llvm-project/clang/lib/AST/ComputeDependence.cpp +++ b/contrib/llvm-project/clang/lib/AST/ComputeDependence.cpp @@ -1,852 +1,889 @@ //===- ComputeDependence.cpp ----------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// #include "clang/AST/ComputeDependence.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/DependenceFlags.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/Basic/ExceptionSpecificationType.h" #include "llvm/ADT/ArrayRef.h" using namespace clang; ExprDependence clang::computeDependence(FullExpr *E) { return E->getSubExpr()->getDependence(); } ExprDependence clang::computeDependence(OpaqueValueExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); if (auto *S = E->getSourceExpr()) D |= S->getDependence(); assert(!(D & ExprDependence::UnexpandedPack)); return D; } ExprDependence clang::computeDependence(ParenExpr *E) { return E->getSubExpr()->getDependence(); } ExprDependence clang::computeDependence(UnaryOperator *E, const ASTContext &Ctx) { - ExprDependence Dep = toExprDependence(E->getType()->getDependence()) | - E->getSubExpr()->getDependence(); + ExprDependence Dep = + // FIXME: Do we need to look at the type? + toExprDependenceForImpliedType(E->getType()->getDependence()) | + E->getSubExpr()->getDependence(); // C++ [temp.dep.constexpr]p5: // An expression of the form & qualified-id where the qualified-id names a // dependent member of the current instantiation is value-dependent. An // expression of the form & cast-expression is also value-dependent if // evaluating cast-expression as a core constant expression succeeds and // the result of the evaluation refers to a templated entity that is an // object with static or thread storage duration or a member function. // // What this amounts to is: constant-evaluate the operand and check whether it // refers to a templated entity other than a variable with local storage. if (Ctx.getLangOpts().CPlusPlus && E->getOpcode() == UO_AddrOf && !(Dep & ExprDependence::Value)) { Expr::EvalResult Result; SmallVector Diag; Result.Diag = &Diag; // FIXME: This doesn't enforce the C++98 constant expression rules. if (E->getSubExpr()->EvaluateAsConstantExpr(Result, Ctx) && Diag.empty() && Result.Val.isLValue()) { auto *VD = Result.Val.getLValueBase().dyn_cast(); if (VD && VD->isTemplated()) { auto *VarD = dyn_cast(VD); if (!VarD || !VarD->hasLocalStorage()) Dep |= ExprDependence::Value; } } } return Dep; } ExprDependence clang::computeDependence(UnaryExprOrTypeTraitExpr *E) { // Never type-dependent (C++ [temp.dep.expr]p3). // Value-dependent if the argument is type-dependent. if (E->isArgumentType()) return turnTypeToValueDependence( - toExprDependence(E->getArgumentType()->getDependence())); + toExprDependenceAsWritten(E->getArgumentType()->getDependence())); auto ArgDeps = E->getArgumentExpr()->getDependence(); auto Deps = ArgDeps & ~ExprDependence::TypeValue; // Value-dependent if the argument is type-dependent. if (ArgDeps & ExprDependence::Type) Deps |= ExprDependence::Value; // Check to see if we are in the situation where alignof(decl) should be // dependent because decl's alignment is dependent. auto ExprKind = E->getKind(); if (ExprKind != UETT_AlignOf && ExprKind != UETT_PreferredAlignOf) return Deps; if ((Deps & ExprDependence::Value) && (Deps & ExprDependence::Instantiation)) return Deps; auto *NoParens = E->getArgumentExpr()->IgnoreParens(); const ValueDecl *D = nullptr; if (const auto *DRE = dyn_cast(NoParens)) D = DRE->getDecl(); else if (const auto *ME = dyn_cast(NoParens)) D = ME->getMemberDecl(); if (!D) return Deps; for (const auto *I : D->specific_attrs()) { if (I->isAlignmentErrorDependent()) Deps |= ExprDependence::Error; if (I->isAlignmentDependent()) Deps |= ExprDependence::ValueInstantiation; } return Deps; } ExprDependence clang::computeDependence(ArraySubscriptExpr *E) { return E->getLHS()->getDependence() | E->getRHS()->getDependence(); } ExprDependence clang::computeDependence(MatrixSubscriptExpr *E) { return E->getBase()->getDependence() | E->getRowIdx()->getDependence() | (E->getColumnIdx() ? E->getColumnIdx()->getDependence() : ExprDependence::None); } ExprDependence clang::computeDependence(CompoundLiteralExpr *E) { - return toExprDependence(E->getTypeSourceInfo()->getType()->getDependence()) | + return toExprDependenceAsWritten( + E->getTypeSourceInfo()->getType()->getDependence()) | + toExprDependenceForImpliedType(E->getType()->getDependence()) | turnTypeToValueDependence(E->getInitializer()->getDependence()); } -ExprDependence clang::computeDependence(CastExpr *E) { +ExprDependence clang::computeDependence(ImplicitCastExpr *E) { + // We model implicit conversions as combining the dependence of their + // subexpression, apart from its type, with the semantic portion of the + // target type. + ExprDependence D = + toExprDependenceForImpliedType(E->getType()->getDependence()); + if (auto *S = E->getSubExpr()) + D |= S->getDependence() & ~ExprDependence::Type; + return D; +} + +ExprDependence clang::computeDependence(ExplicitCastExpr *E) { // Cast expressions are type-dependent if the type is // dependent (C++ [temp.dep.expr]p3). // Cast expressions are value-dependent if the type is // dependent or if the subexpression is value-dependent. - auto D = toExprDependence(E->getType()->getDependence()); - if (E->getStmtClass() == Stmt::ImplicitCastExprClass) { - // An implicit cast expression doesn't (lexically) contain an - // unexpanded pack, even if its target type does. - D &= ~ExprDependence::UnexpandedPack; - } + // + // Note that we also need to consider the dependence of the actual type here, + // because when the type as written is a deduced type, that type is not + // dependent, but it may be deduced as a dependent type. + ExprDependence D = + toExprDependenceAsWritten( + cast(E)->getTypeAsWritten()->getDependence()) | + toExprDependenceForImpliedType(E->getType()->getDependence()); if (auto *S = E->getSubExpr()) D |= S->getDependence() & ~ExprDependence::Type; return D; } ExprDependence clang::computeDependence(BinaryOperator *E) { return E->getLHS()->getDependence() | E->getRHS()->getDependence(); } ExprDependence clang::computeDependence(ConditionalOperator *E) { // The type of the conditional operator depends on the type of the conditional // to support the GCC vector conditional extension. Additionally, // [temp.dep.expr] does specify state that this should be dependent on ALL sub // expressions. return E->getCond()->getDependence() | E->getLHS()->getDependence() | E->getRHS()->getDependence(); } ExprDependence clang::computeDependence(BinaryConditionalOperator *E) { return E->getCommon()->getDependence() | E->getFalseExpr()->getDependence(); } ExprDependence clang::computeDependence(StmtExpr *E, unsigned TemplateDepth) { - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); // Propagate dependence of the result. if (const auto *CompoundExprResult = dyn_cast_or_null(E->getSubStmt()->getStmtExprResult())) if (const Expr *ResultExpr = CompoundExprResult->getExprStmt()) D |= ResultExpr->getDependence(); // Note: we treat a statement-expression in a dependent context as always // being value- and instantiation-dependent. This matches the behavior of // lambda-expressions and GCC. if (TemplateDepth) D |= ExprDependence::ValueInstantiation; // A param pack cannot be expanded over stmtexpr boundaries. return D & ~ExprDependence::UnexpandedPack; } ExprDependence clang::computeDependence(ConvertVectorExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()) | + auto D = toExprDependenceAsWritten( + E->getTypeSourceInfo()->getType()->getDependence()) | E->getSrcExpr()->getDependence(); if (!E->getType()->isDependentType()) D &= ~ExprDependence::Type; return D; } ExprDependence clang::computeDependence(ChooseExpr *E) { if (E->isConditionDependent()) return ExprDependence::TypeValueInstantiation | E->getCond()->getDependence() | E->getLHS()->getDependence() | E->getRHS()->getDependence(); auto Cond = E->getCond()->getDependence(); auto Active = E->getLHS()->getDependence(); auto Inactive = E->getRHS()->getDependence(); if (!E->isConditionTrue()) std::swap(Active, Inactive); // Take type- and value- dependency from the active branch. Propagate all // other flags from all branches. return (Active & ExprDependence::TypeValue) | ((Cond | Active | Inactive) & ~ExprDependence::TypeValue); } ExprDependence clang::computeDependence(ParenListExpr *P) { auto D = ExprDependence::None; for (auto *E : P->exprs()) D |= E->getDependence(); return D; } ExprDependence clang::computeDependence(VAArgExpr *E) { - auto D = - toExprDependence(E->getWrittenTypeInfo()->getType()->getDependence()) | - (E->getSubExpr()->getDependence() & ~ExprDependence::Type); + auto D = toExprDependenceAsWritten( + E->getWrittenTypeInfo()->getType()->getDependence()) | + (E->getSubExpr()->getDependence() & ~ExprDependence::Type); return D & ~ExprDependence::Value; } ExprDependence clang::computeDependence(NoInitExpr *E) { - return toExprDependence(E->getType()->getDependence()) & + return toExprDependenceForImpliedType(E->getType()->getDependence()) & (ExprDependence::Instantiation | ExprDependence::Error); } ExprDependence clang::computeDependence(ArrayInitLoopExpr *E) { auto D = E->getCommonExpr()->getDependence() | E->getSubExpr()->getDependence() | ExprDependence::Instantiation; if (!E->getType()->isInstantiationDependentType()) D &= ~ExprDependence::Instantiation; return turnTypeToValueDependence(D); } ExprDependence clang::computeDependence(ImplicitValueInitExpr *E) { - return toExprDependence(E->getType()->getDependence()) & + return toExprDependenceForImpliedType(E->getType()->getDependence()) & ExprDependence::Instantiation; } ExprDependence clang::computeDependence(ExtVectorElementExpr *E) { return E->getBase()->getDependence(); } ExprDependence clang::computeDependence(BlockExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); if (E->getBlockDecl()->isDependentContext()) D |= ExprDependence::Instantiation; - return D & ~ExprDependence::UnexpandedPack; + return D; } ExprDependence clang::computeDependence(AsTypeExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()) | + // FIXME: AsTypeExpr doesn't store the type as written. Assume the expression + // type has identical sugar for now, so is a type-as-written. + auto D = toExprDependenceAsWritten(E->getType()->getDependence()) | E->getSrcExpr()->getDependence(); if (!E->getType()->isDependentType()) D &= ~ExprDependence::Type; return D; } ExprDependence clang::computeDependence(CXXRewrittenBinaryOperator *E) { return E->getSemanticForm()->getDependence(); } ExprDependence clang::computeDependence(CXXStdInitializerListExpr *E) { auto D = turnTypeToValueDependence(E->getSubExpr()->getDependence()); - D |= toExprDependence(E->getType()->getDependence()) & - (ExprDependence::Type | ExprDependence::Error); + D |= toExprDependenceForImpliedType(E->getType()->getDependence()); return D; } ExprDependence clang::computeDependence(CXXTypeidExpr *E) { auto D = ExprDependence::None; if (E->isTypeOperand()) - D = toExprDependence( + D = toExprDependenceAsWritten( E->getTypeOperandSourceInfo()->getType()->getDependence()); else D = turnTypeToValueDependence(E->getExprOperand()->getDependence()); // typeid is never type-dependent (C++ [temp.dep.expr]p4) return D & ~ExprDependence::Type; } ExprDependence clang::computeDependence(MSPropertyRefExpr *E) { return E->getBaseExpr()->getDependence() & ~ExprDependence::Type; } ExprDependence clang::computeDependence(MSPropertySubscriptExpr *E) { return E->getIdx()->getDependence(); } ExprDependence clang::computeDependence(CXXUuidofExpr *E) { if (E->isTypeOperand()) - return turnTypeToValueDependence(toExprDependence( + return turnTypeToValueDependence(toExprDependenceAsWritten( E->getTypeOperandSourceInfo()->getType()->getDependence())); return turnTypeToValueDependence(E->getExprOperand()->getDependence()); } ExprDependence clang::computeDependence(CXXThisExpr *E) { // 'this' is type-dependent if the class type of the enclosing // member function is dependent (C++ [temp.dep.expr]p2) - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); assert(!(D & ExprDependence::UnexpandedPack)); return D; } ExprDependence clang::computeDependence(CXXThrowExpr *E) { auto *Op = E->getSubExpr(); if (!Op) return ExprDependence::None; return Op->getDependence() & ~ExprDependence::TypeValue; } ExprDependence clang::computeDependence(CXXBindTemporaryExpr *E) { return E->getSubExpr()->getDependence(); } ExprDependence clang::computeDependence(CXXScalarValueInitExpr *E) { - return toExprDependence(E->getType()->getDependence()) & - ~ExprDependence::TypeValue; + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); + if (auto *TSI = E->getTypeSourceInfo()) + D |= toExprDependenceAsWritten(TSI->getType()->getDependence()); + return D; } ExprDependence clang::computeDependence(CXXDeleteExpr *E) { return turnTypeToValueDependence(E->getArgument()->getDependence()); } ExprDependence clang::computeDependence(ArrayTypeTraitExpr *E) { - auto D = toExprDependence(E->getQueriedType()->getDependence()); + auto D = toExprDependenceAsWritten(E->getQueriedType()->getDependence()); if (auto *Dim = E->getDimensionExpression()) D |= Dim->getDependence(); return turnTypeToValueDependence(D); } ExprDependence clang::computeDependence(ExpressionTraitExpr *E) { // Never type-dependent. auto D = E->getQueriedExpression()->getDependence() & ~ExprDependence::Type; // Value-dependent if the argument is type-dependent. if (E->getQueriedExpression()->isTypeDependent()) D |= ExprDependence::Value; return D; } ExprDependence clang::computeDependence(CXXNoexceptExpr *E, CanThrowResult CT) { auto D = E->getOperand()->getDependence() & ~ExprDependence::TypeValue; if (CT == CT_Dependent) D |= ExprDependence::ValueInstantiation; return D; } ExprDependence clang::computeDependence(PackExpansionExpr *E) { return (E->getPattern()->getDependence() & ~ExprDependence::UnexpandedPack) | ExprDependence::TypeValueInstantiation; } ExprDependence clang::computeDependence(SubstNonTypeTemplateParmExpr *E) { return E->getReplacement()->getDependence(); } ExprDependence clang::computeDependence(CoroutineSuspendExpr *E) { if (auto *Resume = E->getResumeExpr()) return (Resume->getDependence() & (ExprDependence::TypeValue | ExprDependence::Error)) | (E->getCommonExpr()->getDependence() & ~ExprDependence::TypeValue); return E->getCommonExpr()->getDependence() | ExprDependence::TypeValueInstantiation; } ExprDependence clang::computeDependence(DependentCoawaitExpr *E) { return E->getOperand()->getDependence() | ExprDependence::TypeValueInstantiation; } ExprDependence clang::computeDependence(ObjCBoxedExpr *E) { return E->getSubExpr()->getDependence(); } ExprDependence clang::computeDependence(ObjCEncodeExpr *E) { - return toExprDependence(E->getEncodedType()->getDependence()); + return toExprDependenceAsWritten(E->getEncodedType()->getDependence()); } ExprDependence clang::computeDependence(ObjCIvarRefExpr *E) { return turnTypeToValueDependence(E->getBase()->getDependence()); } ExprDependence clang::computeDependence(ObjCPropertyRefExpr *E) { if (E->isObjectReceiver()) return E->getBase()->getDependence() & ~ExprDependence::Type; if (E->isSuperReceiver()) - return toExprDependence(E->getSuperReceiverType()->getDependence()) & + return toExprDependenceForImpliedType( + E->getSuperReceiverType()->getDependence()) & ~ExprDependence::TypeValue; assert(E->isClassReceiver()); return ExprDependence::None; } ExprDependence clang::computeDependence(ObjCSubscriptRefExpr *E) { return E->getBaseExpr()->getDependence() | E->getKeyExpr()->getDependence(); } ExprDependence clang::computeDependence(ObjCIsaExpr *E) { return E->getBase()->getDependence() & ~ExprDependence::Type & ~ExprDependence::UnexpandedPack; } ExprDependence clang::computeDependence(ObjCIndirectCopyRestoreExpr *E) { return E->getSubExpr()->getDependence(); } ExprDependence clang::computeDependence(OMPArraySectionExpr *E) { auto D = E->getBase()->getDependence(); if (auto *LB = E->getLowerBound()) D |= LB->getDependence(); if (auto *Len = E->getLength()) D |= Len->getDependence(); return D; } ExprDependence clang::computeDependence(OMPArrayShapingExpr *E) { - auto D = E->getBase()->getDependence() | - toExprDependence(E->getType()->getDependence()); + auto D = E->getBase()->getDependence(); for (Expr *Dim: E->getDimensions()) if (Dim) - D |= Dim->getDependence(); + D |= turnValueToTypeDependence(Dim->getDependence()); return D; } ExprDependence clang::computeDependence(OMPIteratorExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); for (unsigned I = 0, End = E->numOfIterators(); I < End; ++I) { - if (auto *VD = cast_or_null(E->getIteratorDecl(I))) - D |= toExprDependence(VD->getType()->getDependence()); + if (auto *DD = cast_or_null(E->getIteratorDecl(I))) { + // If the type is omitted, it's 'int', and is not dependent in any way. + if (auto *TSI = DD->getTypeSourceInfo()) { + D |= toExprDependenceAsWritten(TSI->getType()->getDependence()); + } + } OMPIteratorExpr::IteratorRange IR = E->getIteratorRange(I); if (Expr *BE = IR.Begin) D |= BE->getDependence(); if (Expr *EE = IR.End) D |= EE->getDependence(); if (Expr *SE = IR.Step) D |= SE->getDependence(); } return D; } /// Compute the type-, value-, and instantiation-dependence of a /// declaration reference /// based on the declaration being referenced. ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) { auto Deps = ExprDependence::None; if (auto *NNS = E->getQualifier()) Deps |= toExprDependence(NNS->getDependence() & ~NestedNameSpecifierDependence::Dependent); if (auto *FirstArg = E->getTemplateArgs()) { unsigned NumArgs = E->getNumTemplateArgs(); for (auto *Arg = FirstArg, *End = FirstArg + NumArgs; Arg < End; ++Arg) Deps |= toExprDependence(Arg->getArgument().getDependence()); } auto *Decl = E->getDecl(); auto Type = E->getType(); if (Decl->isParameterPack()) Deps |= ExprDependence::UnexpandedPack; - Deps |= toExprDependence(Type->getDependence()) & ExprDependence::Error; + Deps |= toExprDependenceForImpliedType(Type->getDependence()) & + ExprDependence::Error; // C++ [temp.dep.expr]p3: // An id-expression is type-dependent if it contains: // - an identifier associated by name lookup with one or more declarations // declared with a dependent type // // [The "or more" case is not modeled as a DeclRefExpr. There are a bunch // more bullets here that we handle by treating the declaration as having a // dependent type if they involve a placeholder type that can't be deduced.] if (Type->isDependentType()) return Deps | ExprDependence::TypeValueInstantiation; else if (Type->isInstantiationDependentType()) Deps |= ExprDependence::Instantiation; // - a conversion-function-id that specifies a dependent type if (Decl->getDeclName().getNameKind() == DeclarationName::CXXConversionFunctionName) { QualType T = Decl->getDeclName().getCXXNameType(); if (T->isDependentType()) return Deps | ExprDependence::TypeValueInstantiation; if (T->isInstantiationDependentType()) Deps |= ExprDependence::Instantiation; } // - a template-id that is dependent, // - a nested-name-specifier or a qualified-id that names a member of an // unknown specialization // [These are not modeled as DeclRefExprs.] // or if it names a dependent member of the current instantiation that is a // static data member of type "array of unknown bound of T" for some T // [handled below]. // C++ [temp.dep.constexpr]p2: // An id-expression is value-dependent if: // - it is type-dependent [handled above] // - it is the name of a non-type template parameter, if (isa(Decl)) return Deps | ExprDependence::ValueInstantiation; // - it names a potentially-constant variable that is initialized with an // expression that is value-dependent if (const auto *Var = dyn_cast(Decl)) { if (Var->mightBeUsableInConstantExpressions(Ctx)) { if (const Expr *Init = Var->getAnyInitializer()) { if (Init->isValueDependent()) Deps |= ExprDependence::ValueInstantiation; if (Init->containsErrors()) Deps |= ExprDependence::Error; } } // - it names a static data member that is a dependent member of the // current instantiation and is not initialized in a member-declarator, if (Var->isStaticDataMember() && Var->getDeclContext()->isDependentContext() && !Var->getFirstDecl()->hasInit()) { const VarDecl *First = Var->getFirstDecl(); TypeSourceInfo *TInfo = First->getTypeSourceInfo(); if (TInfo->getType()->isIncompleteArrayType()) { Deps |= ExprDependence::TypeValueInstantiation; } else if (!First->hasInit()) { Deps |= ExprDependence::ValueInstantiation; } } return Deps; } // - it names a static member function that is a dependent member of the // current instantiation // // FIXME: It's unclear that the restriction to static members here has any // effect: any use of a non-static member function name requires either // forming a pointer-to-member or providing an object parameter, either of // which makes the overall expression value-dependent. if (auto *MD = dyn_cast(Decl)) { if (MD->isStatic() && Decl->getDeclContext()->isDependentContext()) Deps |= ExprDependence::ValueInstantiation; } return Deps; } ExprDependence clang::computeDependence(RecoveryExpr *E) { // RecoveryExpr is // - always value-dependent, and therefore instantiation dependent // - contains errors (ExprDependence::Error), by definition // - type-dependent if we don't know the type (fallback to an opaque // dependent type), or the type is known and dependent, or it has // type-dependent subexpressions. - auto D = toExprDependence(E->getType()->getDependence()) | + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()) | ExprDependence::ErrorDependent; // FIXME: remove the type-dependent bit from subexpressions, if the // RecoveryExpr has a non-dependent type. for (auto *S : E->subExpressions()) D |= S->getDependence(); return D; } ExprDependence clang::computeDependence(SYCLUniqueStableNameExpr *E) { - return toExprDependence(E->getTypeSourceInfo()->getType()->getDependence()); + return toExprDependenceAsWritten( + E->getTypeSourceInfo()->getType()->getDependence()); } ExprDependence clang::computeDependence(PredefinedExpr *E) { - return toExprDependence(E->getType()->getDependence()) & - ~ExprDependence::UnexpandedPack; + return toExprDependenceForImpliedType(E->getType()->getDependence()); } ExprDependence clang::computeDependence(CallExpr *E, llvm::ArrayRef PreArgs) { auto D = E->getCallee()->getDependence(); for (auto *A : llvm::makeArrayRef(E->getArgs(), E->getNumArgs())) { if (A) D |= A->getDependence(); } for (auto *A : PreArgs) D |= A->getDependence(); return D; } ExprDependence clang::computeDependence(OffsetOfExpr *E) { - auto D = turnTypeToValueDependence( - toExprDependence(E->getTypeSourceInfo()->getType()->getDependence())); + auto D = turnTypeToValueDependence(toExprDependenceAsWritten( + E->getTypeSourceInfo()->getType()->getDependence())); for (unsigned I = 0, N = E->getNumExpressions(); I < N; ++I) D |= turnTypeToValueDependence(E->getIndexExpr(I)->getDependence()); return D; } ExprDependence clang::computeDependence(MemberExpr *E) { auto *MemberDecl = E->getMemberDecl(); auto D = E->getBase()->getDependence(); if (FieldDecl *FD = dyn_cast(MemberDecl)) { DeclContext *DC = MemberDecl->getDeclContext(); // dyn_cast_or_null is used to handle objC variables which do not // have a declaration context. CXXRecordDecl *RD = dyn_cast_or_null(DC); if (RD && RD->isDependentContext() && RD->isCurrentInstantiation(DC)) { if (!E->getType()->isDependentType()) D &= ~ExprDependence::Type; } // Bitfield with value-dependent width is type-dependent. if (FD && FD->isBitField() && FD->getBitWidth()->isValueDependent()) { D |= ExprDependence::Type; } } // FIXME: move remaining dependence computation from MemberExpr::Create() return D; } ExprDependence clang::computeDependence(InitListExpr *E) { auto D = ExprDependence::None; for (auto *A : E->inits()) D |= A->getDependence(); return D; } ExprDependence clang::computeDependence(ShuffleVectorExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); for (auto *C : llvm::makeArrayRef(E->getSubExprs(), E->getNumSubExprs())) D |= C->getDependence(); return D; } ExprDependence clang::computeDependence(GenericSelectionExpr *E, bool ContainsUnexpandedPack) { auto D = ContainsUnexpandedPack ? ExprDependence::UnexpandedPack : ExprDependence::None; for (auto *AE : E->getAssocExprs()) D |= AE->getDependence() & ExprDependence::Error; D |= E->getControllingExpr()->getDependence() & ExprDependence::Error; if (E->isResultDependent()) return D | ExprDependence::TypeValueInstantiation; return D | (E->getResultExpr()->getDependence() & ~ExprDependence::UnexpandedPack); } ExprDependence clang::computeDependence(DesignatedInitExpr *E) { auto Deps = E->getInit()->getDependence(); for (auto D : E->designators()) { auto DesignatorDeps = ExprDependence::None; if (D.isArrayDesignator()) DesignatorDeps |= E->getArrayIndex(D)->getDependence(); else if (D.isArrayRangeDesignator()) DesignatorDeps |= E->getArrayRangeStart(D)->getDependence() | E->getArrayRangeEnd(D)->getDependence(); Deps |= DesignatorDeps; if (DesignatorDeps & ExprDependence::TypeValue) Deps |= ExprDependence::TypeValueInstantiation; } return Deps; } ExprDependence clang::computeDependence(PseudoObjectExpr *O) { auto D = O->getSyntacticForm()->getDependence(); for (auto *E : O->semantics()) D |= E->getDependence(); return D; } ExprDependence clang::computeDependence(AtomicExpr *A) { auto D = ExprDependence::None; for (auto *E : llvm::makeArrayRef(A->getSubExprs(), A->getNumSubExprs())) D |= E->getDependence(); return D; } ExprDependence clang::computeDependence(CXXNewExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceAsWritten( + E->getAllocatedTypeSourceInfo()->getType()->getDependence()); + D |= toExprDependenceForImpliedType(E->getAllocatedType()->getDependence()); auto Size = E->getArraySize(); if (Size.hasValue() && *Size) D |= turnTypeToValueDependence((*Size)->getDependence()); if (auto *I = E->getInitializer()) D |= turnTypeToValueDependence(I->getDependence()); for (auto *A : E->placement_arguments()) D |= turnTypeToValueDependence(A->getDependence()); return D; } ExprDependence clang::computeDependence(CXXPseudoDestructorExpr *E) { auto D = E->getBase()->getDependence(); - if (!E->getDestroyedType().isNull()) - D |= toExprDependence(E->getDestroyedType()->getDependence()); + if (auto *TSI = E->getDestroyedTypeInfo()) + D |= toExprDependenceAsWritten(TSI->getType()->getDependence()); if (auto *ST = E->getScopeTypeInfo()) D |= turnTypeToValueDependence( - toExprDependence(ST->getType()->getDependence())); + toExprDependenceAsWritten(ST->getType()->getDependence())); if (auto *Q = E->getQualifier()) D |= toExprDependence(Q->getDependence() & ~NestedNameSpecifierDependence::Dependent); return D; } static inline ExprDependence getDependenceInExpr(DeclarationNameInfo Name) { auto D = ExprDependence::None; if (Name.isInstantiationDependent()) D |= ExprDependence::Instantiation; if (Name.containsUnexpandedParameterPack()) D |= ExprDependence::UnexpandedPack; return D; } ExprDependence clang::computeDependence(OverloadExpr *E, bool KnownDependent, bool KnownInstantiationDependent, bool KnownContainsUnexpandedParameterPack) { auto Deps = ExprDependence::None; if (KnownDependent) Deps |= ExprDependence::TypeValue; if (KnownInstantiationDependent) Deps |= ExprDependence::Instantiation; if (KnownContainsUnexpandedParameterPack) Deps |= ExprDependence::UnexpandedPack; Deps |= getDependenceInExpr(E->getNameInfo()); if (auto *Q = E->getQualifier()) Deps |= toExprDependence(Q->getDependence() & ~NestedNameSpecifierDependence::Dependent); for (auto *D : E->decls()) { if (D->getDeclContext()->isDependentContext() || isa(D)) Deps |= ExprDependence::TypeValueInstantiation; } // If we have explicit template arguments, check for dependent // template arguments and whether they contain any unexpanded pack // expansions. for (auto A : E->template_arguments()) Deps |= toExprDependence(A.getArgument().getDependence()); return Deps; } ExprDependence clang::computeDependence(DependentScopeDeclRefExpr *E) { auto D = ExprDependence::TypeValue; D |= getDependenceInExpr(E->getNameInfo()); if (auto *Q = E->getQualifier()) D |= toExprDependence(Q->getDependence()); for (auto A : E->template_arguments()) D |= toExprDependence(A.getArgument().getDependence()); return D; } ExprDependence clang::computeDependence(CXXConstructExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()); + ExprDependence D = + toExprDependenceForImpliedType(E->getType()->getDependence()); for (auto *A : E->arguments()) D |= A->getDependence() & ~ExprDependence::Type; return D; } +ExprDependence clang::computeDependence(CXXTemporaryObjectExpr *E) { + CXXConstructExpr *BaseE = E; + return toExprDependenceAsWritten( + E->getTypeSourceInfo()->getType()->getDependence()) | + computeDependence(BaseE); +} + ExprDependence clang::computeDependence(CXXDefaultInitExpr *E) { return E->getExpr()->getDependence(); } ExprDependence clang::computeDependence(CXXDefaultArgExpr *E) { return E->getExpr()->getDependence(); } ExprDependence clang::computeDependence(LambdaExpr *E, bool ContainsUnexpandedParameterPack) { - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); if (ContainsUnexpandedParameterPack) D |= ExprDependence::UnexpandedPack; return D; } ExprDependence clang::computeDependence(CXXUnresolvedConstructExpr *E) { auto D = ExprDependence::ValueInstantiation; - D |= toExprDependence(E->getType()->getDependence()); + D |= toExprDependenceAsWritten(E->getTypeAsWritten()->getDependence()); + D |= toExprDependenceForImpliedType(E->getType()->getDependence()); for (auto *A : E->arguments()) D |= A->getDependence() & (ExprDependence::UnexpandedPack | ExprDependence::Error); return D; } ExprDependence clang::computeDependence(CXXDependentScopeMemberExpr *E) { auto D = ExprDependence::TypeValueInstantiation; if (!E->isImplicitAccess()) D |= E->getBase()->getDependence(); if (auto *Q = E->getQualifier()) D |= toExprDependence(Q->getDependence()); D |= getDependenceInExpr(E->getMemberNameInfo()); for (auto A : E->template_arguments()) D |= toExprDependence(A.getArgument().getDependence()); return D; } ExprDependence clang::computeDependence(MaterializeTemporaryExpr *E) { return E->getSubExpr()->getDependence(); } ExprDependence clang::computeDependence(CXXFoldExpr *E) { auto D = ExprDependence::TypeValueInstantiation; for (const auto *C : {E->getLHS(), E->getRHS()}) { if (C) D |= C->getDependence() & ~ExprDependence::UnexpandedPack; } return D; } ExprDependence clang::computeDependence(TypeTraitExpr *E) { auto D = ExprDependence::None; for (const auto *A : E->getArgs()) - D |= - toExprDependence(A->getType()->getDependence()) & ~ExprDependence::Type; + D |= toExprDependenceAsWritten(A->getType()->getDependence()) & + ~ExprDependence::Type; return D; } ExprDependence clang::computeDependence(ConceptSpecializationExpr *E, bool ValueDependent) { auto TA = TemplateArgumentDependence::None; const auto InterestingDeps = TemplateArgumentDependence::Instantiation | TemplateArgumentDependence::UnexpandedPack; for (const TemplateArgumentLoc &ArgLoc : E->getTemplateArgsAsWritten()->arguments()) { TA |= ArgLoc.getArgument().getDependence() & InterestingDeps; if (TA == InterestingDeps) break; } ExprDependence D = ValueDependent ? ExprDependence::Value : ExprDependence::None; return D | toExprDependence(TA); } ExprDependence clang::computeDependence(ObjCArrayLiteral *E) { auto D = ExprDependence::None; Expr **Elements = E->getElements(); for (unsigned I = 0, N = E->getNumElements(); I != N; ++I) D |= turnTypeToValueDependence(Elements[I]->getDependence()); return D; } ExprDependence clang::computeDependence(ObjCDictionaryLiteral *E) { auto Deps = ExprDependence::None; for (unsigned I = 0, N = E->getNumElements(); I < N; ++I) { auto KV = E->getKeyValueElement(I); auto KVDeps = turnTypeToValueDependence(KV.Key->getDependence() | KV.Value->getDependence()); if (KV.EllipsisLoc.isValid()) KVDeps &= ~ExprDependence::UnexpandedPack; Deps |= KVDeps; } return Deps; } ExprDependence clang::computeDependence(ObjCMessageExpr *E) { auto D = ExprDependence::None; if (auto *R = E->getInstanceReceiver()) D |= R->getDependence(); else - D |= toExprDependence(E->getType()->getDependence()); + D |= toExprDependenceForImpliedType(E->getType()->getDependence()); for (auto *A : E->arguments()) D |= A->getDependence(); return D; } diff --git a/contrib/llvm-project/clang/lib/AST/ExprCXX.cpp b/contrib/llvm-project/clang/lib/AST/ExprCXX.cpp index c98cfd74dab0..55f3c3541b7f 100644 --- a/contrib/llvm-project/clang/lib/AST/ExprCXX.cpp +++ b/contrib/llvm-project/clang/lib/AST/ExprCXX.cpp @@ -1,1744 +1,1748 @@ //===- ExprCXX.cpp - (C++) Expression AST Node Implementation -------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements the subclesses of Expr class declared in ExprCXX.h // //===----------------------------------------------------------------------===// #include "clang/AST/ExprCXX.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/ComputeDependence.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclAccessPair.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/DependenceFlags.h" #include "clang/AST/Expr.h" #include "clang/AST/LambdaCapture.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include #include #include #include using namespace clang; //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// bool CXXOperatorCallExpr::isInfixBinaryOp() const { // An infix binary operator is any operator with two arguments other than // operator() and operator[]. Note that none of these operators can have // default arguments, so it suffices to check the number of argument // expressions. if (getNumArgs() != 2) return false; switch (getOperator()) { case OO_Call: case OO_Subscript: return false; default: return true; } } CXXRewrittenBinaryOperator::DecomposedForm CXXRewrittenBinaryOperator::getDecomposedForm() const { DecomposedForm Result = {}; const Expr *E = getSemanticForm()->IgnoreImplicit(); // Remove an outer '!' if it exists (only happens for a '!=' rewrite). bool SkippedNot = false; if (auto *NotEq = dyn_cast(E)) { assert(NotEq->getOpcode() == UO_LNot); E = NotEq->getSubExpr()->IgnoreImplicit(); SkippedNot = true; } // Decompose the outer binary operator. if (auto *BO = dyn_cast(E)) { assert(!SkippedNot || BO->getOpcode() == BO_EQ); Result.Opcode = SkippedNot ? BO_NE : BO->getOpcode(); Result.LHS = BO->getLHS(); Result.RHS = BO->getRHS(); Result.InnerBinOp = BO; } else if (auto *BO = dyn_cast(E)) { assert(!SkippedNot || BO->getOperator() == OO_EqualEqual); assert(BO->isInfixBinaryOp()); switch (BO->getOperator()) { case OO_Less: Result.Opcode = BO_LT; break; case OO_LessEqual: Result.Opcode = BO_LE; break; case OO_Greater: Result.Opcode = BO_GT; break; case OO_GreaterEqual: Result.Opcode = BO_GE; break; case OO_Spaceship: Result.Opcode = BO_Cmp; break; case OO_EqualEqual: Result.Opcode = SkippedNot ? BO_NE : BO_EQ; break; default: llvm_unreachable("unexpected binop in rewritten operator expr"); } Result.LHS = BO->getArg(0); Result.RHS = BO->getArg(1); Result.InnerBinOp = BO; } else { llvm_unreachable("unexpected rewritten operator form"); } // Put the operands in the right order for == and !=, and canonicalize the // <=> subexpression onto the LHS for all other forms. if (isReversed()) std::swap(Result.LHS, Result.RHS); // If this isn't a spaceship rewrite, we're done. if (Result.Opcode == BO_EQ || Result.Opcode == BO_NE) return Result; // Otherwise, we expect a <=> to now be on the LHS. E = Result.LHS->IgnoreImplicitAsWritten(); if (auto *BO = dyn_cast(E)) { assert(BO->getOpcode() == BO_Cmp); Result.LHS = BO->getLHS(); Result.RHS = BO->getRHS(); Result.InnerBinOp = BO; } else if (auto *BO = dyn_cast(E)) { assert(BO->getOperator() == OO_Spaceship); Result.LHS = BO->getArg(0); Result.RHS = BO->getArg(1); Result.InnerBinOp = BO; } else { llvm_unreachable("unexpected rewritten operator form"); } // Put the comparison operands in the right order. if (isReversed()) std::swap(Result.LHS, Result.RHS); return Result; } bool CXXTypeidExpr::isPotentiallyEvaluated() const { if (isTypeOperand()) return false; // C++11 [expr.typeid]p3: // When typeid is applied to an expression other than a glvalue of // polymorphic class type, [...] the expression is an unevaluated operand. const Expr *E = getExprOperand(); if (const CXXRecordDecl *RD = E->getType()->getAsCXXRecordDecl()) if (RD->isPolymorphic() && E->isGLValue()) return true; return false; } bool CXXTypeidExpr::isMostDerived(ASTContext &Context) const { assert(!isTypeOperand() && "Cannot call isMostDerived for typeid(type)"); const Expr *E = getExprOperand()->IgnoreParenNoopCasts(Context); if (const auto *DRE = dyn_cast(E)) { QualType Ty = DRE->getDecl()->getType(); if (!Ty->isPointerType() && !Ty->isReferenceType()) return true; } return false; } QualType CXXTypeidExpr::getTypeOperand(ASTContext &Context) const { assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); Qualifiers Quals; return Context.getUnqualifiedArrayType( Operand.get()->getType().getNonReferenceType(), Quals); } QualType CXXUuidofExpr::getTypeOperand(ASTContext &Context) const { assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); Qualifiers Quals; return Context.getUnqualifiedArrayType( Operand.get()->getType().getNonReferenceType(), Quals); } // CXXScalarValueInitExpr SourceLocation CXXScalarValueInitExpr::getBeginLoc() const { return TypeInfo ? TypeInfo->getTypeLoc().getBeginLoc() : getRParenLoc(); } // CXXNewExpr CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew, FunctionDecl *OperatorDelete, bool ShouldPassAlignment, bool UsualArrayDeleteWantsSize, ArrayRef PlacementArgs, SourceRange TypeIdParens, Optional ArraySize, InitializationStyle InitializationStyle, Expr *Initializer, QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range, SourceRange DirectInitRange) : Expr(CXXNewExprClass, Ty, VK_PRValue, OK_Ordinary), OperatorNew(OperatorNew), OperatorDelete(OperatorDelete), AllocatedTypeInfo(AllocatedTypeInfo), Range(Range), DirectInitRange(DirectInitRange) { assert((Initializer != nullptr || InitializationStyle == NoInit) && "Only NoInit can have no initializer!"); CXXNewExprBits.IsGlobalNew = IsGlobalNew; CXXNewExprBits.IsArray = ArraySize.hasValue(); CXXNewExprBits.ShouldPassAlignment = ShouldPassAlignment; CXXNewExprBits.UsualArrayDeleteWantsSize = UsualArrayDeleteWantsSize; CXXNewExprBits.StoredInitializationStyle = Initializer ? InitializationStyle + 1 : 0; bool IsParenTypeId = TypeIdParens.isValid(); CXXNewExprBits.IsParenTypeId = IsParenTypeId; CXXNewExprBits.NumPlacementArgs = PlacementArgs.size(); if (ArraySize) getTrailingObjects()[arraySizeOffset()] = *ArraySize; if (Initializer) getTrailingObjects()[initExprOffset()] = Initializer; for (unsigned I = 0; I != PlacementArgs.size(); ++I) getTrailingObjects()[placementNewArgsOffset() + I] = PlacementArgs[I]; if (IsParenTypeId) getTrailingObjects()[0] = TypeIdParens; switch (getInitializationStyle()) { case CallInit: this->Range.setEnd(DirectInitRange.getEnd()); break; case ListInit: this->Range.setEnd(getInitializer()->getSourceRange().getEnd()); break; default: if (IsParenTypeId) this->Range.setEnd(TypeIdParens.getEnd()); break; } setDependence(computeDependence(this)); } CXXNewExpr::CXXNewExpr(EmptyShell Empty, bool IsArray, unsigned NumPlacementArgs, bool IsParenTypeId) : Expr(CXXNewExprClass, Empty) { CXXNewExprBits.IsArray = IsArray; CXXNewExprBits.NumPlacementArgs = NumPlacementArgs; CXXNewExprBits.IsParenTypeId = IsParenTypeId; } CXXNewExpr * CXXNewExpr::Create(const ASTContext &Ctx, bool IsGlobalNew, FunctionDecl *OperatorNew, FunctionDecl *OperatorDelete, bool ShouldPassAlignment, bool UsualArrayDeleteWantsSize, ArrayRef PlacementArgs, SourceRange TypeIdParens, Optional ArraySize, InitializationStyle InitializationStyle, Expr *Initializer, QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range, SourceRange DirectInitRange) { bool IsArray = ArraySize.hasValue(); bool HasInit = Initializer != nullptr; unsigned NumPlacementArgs = PlacementArgs.size(); bool IsParenTypeId = TypeIdParens.isValid(); void *Mem = Ctx.Allocate(totalSizeToAlloc( IsArray + HasInit + NumPlacementArgs, IsParenTypeId), alignof(CXXNewExpr)); return new (Mem) CXXNewExpr(IsGlobalNew, OperatorNew, OperatorDelete, ShouldPassAlignment, UsualArrayDeleteWantsSize, PlacementArgs, TypeIdParens, ArraySize, InitializationStyle, Initializer, Ty, AllocatedTypeInfo, Range, DirectInitRange); } CXXNewExpr *CXXNewExpr::CreateEmpty(const ASTContext &Ctx, bool IsArray, bool HasInit, unsigned NumPlacementArgs, bool IsParenTypeId) { void *Mem = Ctx.Allocate(totalSizeToAlloc( IsArray + HasInit + NumPlacementArgs, IsParenTypeId), alignof(CXXNewExpr)); return new (Mem) CXXNewExpr(EmptyShell(), IsArray, NumPlacementArgs, IsParenTypeId); } bool CXXNewExpr::shouldNullCheckAllocation() const { return !getOperatorNew()->hasAttr() && getOperatorNew() ->getType() ->castAs() ->isNothrow() && !getOperatorNew()->isReservedGlobalPlacementOperator(); } // CXXDeleteExpr QualType CXXDeleteExpr::getDestroyedType() const { const Expr *Arg = getArgument(); // For a destroying operator delete, we may have implicitly converted the // pointer type to the type of the parameter of the 'operator delete' // function. while (const auto *ICE = dyn_cast(Arg)) { if (ICE->getCastKind() == CK_DerivedToBase || ICE->getCastKind() == CK_UncheckedDerivedToBase || ICE->getCastKind() == CK_NoOp) { assert((ICE->getCastKind() == CK_NoOp || getOperatorDelete()->isDestroyingOperatorDelete()) && "only a destroying operator delete can have a converted arg"); Arg = ICE->getSubExpr(); } else break; } // The type-to-delete may not be a pointer if it's a dependent type. const QualType ArgType = Arg->getType(); if (ArgType->isDependentType() && !ArgType->isPointerType()) return QualType(); return ArgType->castAs()->getPointeeType(); } // CXXPseudoDestructorExpr PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info) : Type(Info) { Location = Info->getTypeLoc().getLocalSourceRange().getBegin(); } CXXPseudoDestructorExpr::CXXPseudoDestructorExpr( const ASTContext &Context, Expr *Base, bool isArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, TypeSourceInfo *ScopeType, SourceLocation ColonColonLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType) : Expr(CXXPseudoDestructorExprClass, Context.BoundMemberTy, VK_PRValue, OK_Ordinary), Base(static_cast(Base)), IsArrow(isArrow), OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc), ScopeType(ScopeType), ColonColonLoc(ColonColonLoc), TildeLoc(TildeLoc), DestroyedType(DestroyedType) { setDependence(computeDependence(this)); } QualType CXXPseudoDestructorExpr::getDestroyedType() const { if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo()) return TInfo->getType(); return QualType(); } SourceLocation CXXPseudoDestructorExpr::getEndLoc() const { SourceLocation End = DestroyedType.getLocation(); if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo()) End = TInfo->getTypeLoc().getLocalSourceRange().getEnd(); return End; } // UnresolvedLookupExpr UnresolvedLookupExpr::UnresolvedLookupExpr( const ASTContext &Context, CXXRecordDecl *NamingClass, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, bool RequiresADL, bool Overloaded, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End) : OverloadExpr(UnresolvedLookupExprClass, Context, QualifierLoc, TemplateKWLoc, NameInfo, TemplateArgs, Begin, End, false, false, false), NamingClass(NamingClass) { UnresolvedLookupExprBits.RequiresADL = RequiresADL; UnresolvedLookupExprBits.Overloaded = Overloaded; } UnresolvedLookupExpr::UnresolvedLookupExpr(EmptyShell Empty, unsigned NumResults, bool HasTemplateKWAndArgsInfo) : OverloadExpr(UnresolvedLookupExprClass, Empty, NumResults, HasTemplateKWAndArgsInfo) {} UnresolvedLookupExpr *UnresolvedLookupExpr::Create( const ASTContext &Context, CXXRecordDecl *NamingClass, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, bool RequiresADL, bool Overloaded, UnresolvedSetIterator Begin, UnresolvedSetIterator End) { unsigned NumResults = End - Begin; unsigned Size = totalSizeToAlloc(NumResults, 0, 0); void *Mem = Context.Allocate(Size, alignof(UnresolvedLookupExpr)); return new (Mem) UnresolvedLookupExpr(Context, NamingClass, QualifierLoc, SourceLocation(), NameInfo, RequiresADL, Overloaded, nullptr, Begin, End); } UnresolvedLookupExpr *UnresolvedLookupExpr::Create( const ASTContext &Context, CXXRecordDecl *NamingClass, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, bool RequiresADL, const TemplateArgumentListInfo *Args, UnresolvedSetIterator Begin, UnresolvedSetIterator End) { assert(Args || TemplateKWLoc.isValid()); unsigned NumResults = End - Begin; unsigned NumTemplateArgs = Args ? Args->size() : 0; unsigned Size = totalSizeToAlloc(NumResults, 1, NumTemplateArgs); void *Mem = Context.Allocate(Size, alignof(UnresolvedLookupExpr)); return new (Mem) UnresolvedLookupExpr(Context, NamingClass, QualifierLoc, TemplateKWLoc, NameInfo, RequiresADL, /*Overloaded*/ true, Args, Begin, End); } UnresolvedLookupExpr *UnresolvedLookupExpr::CreateEmpty( const ASTContext &Context, unsigned NumResults, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) { assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo); unsigned Size = totalSizeToAlloc( NumResults, HasTemplateKWAndArgsInfo, NumTemplateArgs); void *Mem = Context.Allocate(Size, alignof(UnresolvedLookupExpr)); return new (Mem) UnresolvedLookupExpr(EmptyShell(), NumResults, HasTemplateKWAndArgsInfo); } OverloadExpr::OverloadExpr(StmtClass SC, const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End, bool KnownDependent, bool KnownInstantiationDependent, bool KnownContainsUnexpandedParameterPack) : Expr(SC, Context.OverloadTy, VK_LValue, OK_Ordinary), NameInfo(NameInfo), QualifierLoc(QualifierLoc) { unsigned NumResults = End - Begin; OverloadExprBits.NumResults = NumResults; OverloadExprBits.HasTemplateKWAndArgsInfo = (TemplateArgs != nullptr ) || TemplateKWLoc.isValid(); if (NumResults) { // Copy the results to the trailing array past UnresolvedLookupExpr // or UnresolvedMemberExpr. DeclAccessPair *Results = getTrailingResults(); memcpy(Results, Begin.I, NumResults * sizeof(DeclAccessPair)); } if (TemplateArgs) { auto Deps = TemplateArgumentDependence::None; getTrailingASTTemplateKWAndArgsInfo()->initializeFrom( TemplateKWLoc, *TemplateArgs, getTrailingTemplateArgumentLoc(), Deps); } else if (TemplateKWLoc.isValid()) { getTrailingASTTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc); } setDependence(computeDependence(this, KnownDependent, KnownInstantiationDependent, KnownContainsUnexpandedParameterPack)); if (isTypeDependent()) setType(Context.DependentTy); } OverloadExpr::OverloadExpr(StmtClass SC, EmptyShell Empty, unsigned NumResults, bool HasTemplateKWAndArgsInfo) : Expr(SC, Empty) { OverloadExprBits.NumResults = NumResults; OverloadExprBits.HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo; } // DependentScopeDeclRefExpr DependentScopeDeclRefExpr::DependentScopeDeclRefExpr( QualType Ty, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *Args) : Expr(DependentScopeDeclRefExprClass, Ty, VK_LValue, OK_Ordinary), QualifierLoc(QualifierLoc), NameInfo(NameInfo) { DependentScopeDeclRefExprBits.HasTemplateKWAndArgsInfo = (Args != nullptr) || TemplateKWLoc.isValid(); if (Args) { auto Deps = TemplateArgumentDependence::None; getTrailingObjects()->initializeFrom( TemplateKWLoc, *Args, getTrailingObjects(), Deps); } else if (TemplateKWLoc.isValid()) { getTrailingObjects()->initializeFrom( TemplateKWLoc); } setDependence(computeDependence(this)); } DependentScopeDeclRefExpr *DependentScopeDeclRefExpr::Create( const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *Args) { assert(QualifierLoc && "should be created for dependent qualifiers"); bool HasTemplateKWAndArgsInfo = Args || TemplateKWLoc.isValid(); std::size_t Size = totalSizeToAlloc( HasTemplateKWAndArgsInfo, Args ? Args->size() : 0); void *Mem = Context.Allocate(Size); return new (Mem) DependentScopeDeclRefExpr(Context.DependentTy, QualifierLoc, TemplateKWLoc, NameInfo, Args); } DependentScopeDeclRefExpr * DependentScopeDeclRefExpr::CreateEmpty(const ASTContext &Context, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) { assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo); std::size_t Size = totalSizeToAlloc( HasTemplateKWAndArgsInfo, NumTemplateArgs); void *Mem = Context.Allocate(Size); auto *E = new (Mem) DependentScopeDeclRefExpr( QualType(), NestedNameSpecifierLoc(), SourceLocation(), DeclarationNameInfo(), nullptr); E->DependentScopeDeclRefExprBits.HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo; return E; } SourceLocation CXXConstructExpr::getBeginLoc() const { if (isa(this)) return cast(this)->getBeginLoc(); return getLocation(); } SourceLocation CXXConstructExpr::getEndLoc() const { if (isa(this)) return cast(this)->getEndLoc(); if (ParenOrBraceRange.isValid()) return ParenOrBraceRange.getEnd(); SourceLocation End = getLocation(); for (unsigned I = getNumArgs(); I > 0; --I) { const Expr *Arg = getArg(I-1); if (!Arg->isDefaultArgument()) { SourceLocation NewEnd = Arg->getEndLoc(); if (NewEnd.isValid()) { End = NewEnd; break; } } } return End; } CXXOperatorCallExpr::CXXOperatorCallExpr(OverloadedOperatorKind OpKind, Expr *Fn, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation OperatorLoc, FPOptionsOverride FPFeatures, ADLCallKind UsesADL) : CallExpr(CXXOperatorCallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK, OperatorLoc, FPFeatures, /*MinNumArgs=*/0, UsesADL) { CXXOperatorCallExprBits.OperatorKind = OpKind; assert( (CXXOperatorCallExprBits.OperatorKind == static_cast(OpKind)) && "OperatorKind overflow!"); Range = getSourceRangeImpl(); } CXXOperatorCallExpr::CXXOperatorCallExpr(unsigned NumArgs, bool HasFPFeatures, EmptyShell Empty) : CallExpr(CXXOperatorCallExprClass, /*NumPreArgs=*/0, NumArgs, HasFPFeatures, Empty) {} CXXOperatorCallExpr * CXXOperatorCallExpr::Create(const ASTContext &Ctx, OverloadedOperatorKind OpKind, Expr *Fn, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation OperatorLoc, FPOptionsOverride FPFeatures, ADLCallKind UsesADL) { // Allocate storage for the trailing objects of CallExpr. unsigned NumArgs = Args.size(); unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects( /*NumPreArgs=*/0, NumArgs, FPFeatures.requiresTrailingStorage()); void *Mem = Ctx.Allocate(sizeof(CXXOperatorCallExpr) + SizeOfTrailingObjects, alignof(CXXOperatorCallExpr)); return new (Mem) CXXOperatorCallExpr(OpKind, Fn, Args, Ty, VK, OperatorLoc, FPFeatures, UsesADL); } CXXOperatorCallExpr *CXXOperatorCallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs, bool HasFPFeatures, EmptyShell Empty) { // Allocate storage for the trailing objects of CallExpr. unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects(/*NumPreArgs=*/0, NumArgs, HasFPFeatures); void *Mem = Ctx.Allocate(sizeof(CXXOperatorCallExpr) + SizeOfTrailingObjects, alignof(CXXOperatorCallExpr)); return new (Mem) CXXOperatorCallExpr(NumArgs, HasFPFeatures, Empty); } SourceRange CXXOperatorCallExpr::getSourceRangeImpl() const { OverloadedOperatorKind Kind = getOperator(); if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) { if (getNumArgs() == 1) // Prefix operator return SourceRange(getOperatorLoc(), getArg(0)->getEndLoc()); else // Postfix operator return SourceRange(getArg(0)->getBeginLoc(), getOperatorLoc()); } else if (Kind == OO_Arrow) { return SourceRange(getArg(0)->getBeginLoc(), getOperatorLoc()); } else if (Kind == OO_Call) { return SourceRange(getArg(0)->getBeginLoc(), getRParenLoc()); } else if (Kind == OO_Subscript) { return SourceRange(getArg(0)->getBeginLoc(), getRParenLoc()); } else if (getNumArgs() == 1) { return SourceRange(getOperatorLoc(), getArg(0)->getEndLoc()); } else if (getNumArgs() == 2) { return SourceRange(getArg(0)->getBeginLoc(), getArg(1)->getEndLoc()); } else { return getOperatorLoc(); } } CXXMemberCallExpr::CXXMemberCallExpr(Expr *Fn, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation RP, FPOptionsOverride FPOptions, unsigned MinNumArgs) : CallExpr(CXXMemberCallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK, RP, FPOptions, MinNumArgs, NotADL) {} CXXMemberCallExpr::CXXMemberCallExpr(unsigned NumArgs, bool HasFPFeatures, EmptyShell Empty) : CallExpr(CXXMemberCallExprClass, /*NumPreArgs=*/0, NumArgs, HasFPFeatures, Empty) {} CXXMemberCallExpr *CXXMemberCallExpr::Create(const ASTContext &Ctx, Expr *Fn, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation RP, FPOptionsOverride FPFeatures, unsigned MinNumArgs) { // Allocate storage for the trailing objects of CallExpr. unsigned NumArgs = std::max(Args.size(), MinNumArgs); unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects( /*NumPreArgs=*/0, NumArgs, FPFeatures.requiresTrailingStorage()); void *Mem = Ctx.Allocate(sizeof(CXXMemberCallExpr) + SizeOfTrailingObjects, alignof(CXXMemberCallExpr)); return new (Mem) CXXMemberCallExpr(Fn, Args, Ty, VK, RP, FPFeatures, MinNumArgs); } CXXMemberCallExpr *CXXMemberCallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs, bool HasFPFeatures, EmptyShell Empty) { // Allocate storage for the trailing objects of CallExpr. unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects(/*NumPreArgs=*/0, NumArgs, HasFPFeatures); void *Mem = Ctx.Allocate(sizeof(CXXMemberCallExpr) + SizeOfTrailingObjects, alignof(CXXMemberCallExpr)); return new (Mem) CXXMemberCallExpr(NumArgs, HasFPFeatures, Empty); } Expr *CXXMemberCallExpr::getImplicitObjectArgument() const { const Expr *Callee = getCallee()->IgnoreParens(); if (const auto *MemExpr = dyn_cast(Callee)) return MemExpr->getBase(); if (const auto *BO = dyn_cast(Callee)) if (BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI) return BO->getLHS(); // FIXME: Will eventually need to cope with member pointers. return nullptr; } QualType CXXMemberCallExpr::getObjectType() const { QualType Ty = getImplicitObjectArgument()->getType(); if (Ty->isPointerType()) Ty = Ty->getPointeeType(); return Ty; } CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const { if (const auto *MemExpr = dyn_cast(getCallee()->IgnoreParens())) return cast(MemExpr->getMemberDecl()); // FIXME: Will eventually need to cope with member pointers. // NOTE: Update makeTailCallIfSwiftAsync on fixing this. return nullptr; } CXXRecordDecl *CXXMemberCallExpr::getRecordDecl() const { Expr* ThisArg = getImplicitObjectArgument(); if (!ThisArg) return nullptr; if (ThisArg->getType()->isAnyPointerType()) return ThisArg->getType()->getPointeeType()->getAsCXXRecordDecl(); return ThisArg->getType()->getAsCXXRecordDecl(); } //===----------------------------------------------------------------------===// // Named casts //===----------------------------------------------------------------------===// /// getCastName - Get the name of the C++ cast being used, e.g., /// "static_cast", "dynamic_cast", "reinterpret_cast", or /// "const_cast". The returned pointer must not be freed. const char *CXXNamedCastExpr::getCastName() const { switch (getStmtClass()) { case CXXStaticCastExprClass: return "static_cast"; case CXXDynamicCastExprClass: return "dynamic_cast"; case CXXReinterpretCastExprClass: return "reinterpret_cast"; case CXXConstCastExprClass: return "const_cast"; case CXXAddrspaceCastExprClass: return "addrspace_cast"; default: return ""; } } CXXStaticCastExpr * CXXStaticCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, FPOptionsOverride FPO, SourceLocation L, SourceLocation RParenLoc, SourceRange AngleBrackets) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(totalSizeToAlloc( PathSize, FPO.requiresTrailingStorage())); auto *E = new (Buffer) CXXStaticCastExpr(T, VK, K, Op, PathSize, WrittenTy, FPO, L, RParenLoc, AngleBrackets); if (PathSize) std::uninitialized_copy_n(BasePath->data(), BasePath->size(), E->getTrailingObjects()); return E; } CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize, bool HasFPFeatures) { void *Buffer = C.Allocate(totalSizeToAlloc( PathSize, HasFPFeatures)); return new (Buffer) CXXStaticCastExpr(EmptyShell(), PathSize, HasFPFeatures); } CXXDynamicCastExpr *CXXDynamicCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, SourceLocation L, SourceLocation RParenLoc, SourceRange AngleBrackets) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(totalSizeToAlloc(PathSize)); auto *E = new (Buffer) CXXDynamicCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, RParenLoc, AngleBrackets); if (PathSize) std::uninitialized_copy_n(BasePath->data(), BasePath->size(), E->getTrailingObjects()); return E; } CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) { void *Buffer = C.Allocate(totalSizeToAlloc(PathSize)); return new (Buffer) CXXDynamicCastExpr(EmptyShell(), PathSize); } /// isAlwaysNull - Return whether the result of the dynamic_cast is proven /// to always be null. For example: /// /// struct A { }; /// struct B final : A { }; /// struct C { }; /// /// C *f(B* b) { return dynamic_cast(b); } bool CXXDynamicCastExpr::isAlwaysNull() const { QualType SrcType = getSubExpr()->getType(); QualType DestType = getType(); if (const auto *SrcPTy = SrcType->getAs()) { SrcType = SrcPTy->getPointeeType(); DestType = DestType->castAs()->getPointeeType(); } if (DestType->isVoidType()) return false; const auto *SrcRD = cast(SrcType->castAs()->getDecl()); if (!SrcRD->hasAttr()) return false; const auto *DestRD = cast(DestType->castAs()->getDecl()); return !DestRD->isDerivedFrom(SrcRD); } CXXReinterpretCastExpr * CXXReinterpretCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, SourceLocation L, SourceLocation RParenLoc, SourceRange AngleBrackets) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(totalSizeToAlloc(PathSize)); auto *E = new (Buffer) CXXReinterpretCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, RParenLoc, AngleBrackets); if (PathSize) std::uninitialized_copy_n(BasePath->data(), BasePath->size(), E->getTrailingObjects()); return E; } CXXReinterpretCastExpr * CXXReinterpretCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) { void *Buffer = C.Allocate(totalSizeToAlloc(PathSize)); return new (Buffer) CXXReinterpretCastExpr(EmptyShell(), PathSize); } CXXConstCastExpr *CXXConstCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, Expr *Op, TypeSourceInfo *WrittenTy, SourceLocation L, SourceLocation RParenLoc, SourceRange AngleBrackets) { return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc, AngleBrackets); } CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(const ASTContext &C) { return new (C) CXXConstCastExpr(EmptyShell()); } CXXAddrspaceCastExpr * CXXAddrspaceCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, CastKind K, Expr *Op, TypeSourceInfo *WrittenTy, SourceLocation L, SourceLocation RParenLoc, SourceRange AngleBrackets) { return new (C) CXXAddrspaceCastExpr(T, VK, K, Op, WrittenTy, L, RParenLoc, AngleBrackets); } CXXAddrspaceCastExpr *CXXAddrspaceCastExpr::CreateEmpty(const ASTContext &C) { return new (C) CXXAddrspaceCastExpr(EmptyShell()); } CXXFunctionalCastExpr *CXXFunctionalCastExpr::Create( const ASTContext &C, QualType T, ExprValueKind VK, TypeSourceInfo *Written, CastKind K, Expr *Op, const CXXCastPath *BasePath, FPOptionsOverride FPO, SourceLocation L, SourceLocation R) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(totalSizeToAlloc( PathSize, FPO.requiresTrailingStorage())); auto *E = new (Buffer) CXXFunctionalCastExpr(T, VK, Written, K, Op, PathSize, FPO, L, R); if (PathSize) std::uninitialized_copy_n(BasePath->data(), BasePath->size(), E->getTrailingObjects()); return E; } CXXFunctionalCastExpr *CXXFunctionalCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize, bool HasFPFeatures) { void *Buffer = C.Allocate(totalSizeToAlloc( PathSize, HasFPFeatures)); return new (Buffer) CXXFunctionalCastExpr(EmptyShell(), PathSize, HasFPFeatures); } SourceLocation CXXFunctionalCastExpr::getBeginLoc() const { return getTypeInfoAsWritten()->getTypeLoc().getBeginLoc(); } SourceLocation CXXFunctionalCastExpr::getEndLoc() const { return RParenLoc.isValid() ? RParenLoc : getSubExpr()->getEndLoc(); } UserDefinedLiteral::UserDefinedLiteral(Expr *Fn, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation LitEndLoc, SourceLocation SuffixLoc, FPOptionsOverride FPFeatures) : CallExpr(UserDefinedLiteralClass, Fn, /*PreArgs=*/{}, Args, Ty, VK, LitEndLoc, FPFeatures, /*MinNumArgs=*/0, NotADL), UDSuffixLoc(SuffixLoc) {} UserDefinedLiteral::UserDefinedLiteral(unsigned NumArgs, bool HasFPFeatures, EmptyShell Empty) : CallExpr(UserDefinedLiteralClass, /*NumPreArgs=*/0, NumArgs, HasFPFeatures, Empty) {} UserDefinedLiteral *UserDefinedLiteral::Create(const ASTContext &Ctx, Expr *Fn, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation LitEndLoc, SourceLocation SuffixLoc, FPOptionsOverride FPFeatures) { // Allocate storage for the trailing objects of CallExpr. unsigned NumArgs = Args.size(); unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects( /*NumPreArgs=*/0, NumArgs, FPFeatures.requiresTrailingStorage()); void *Mem = Ctx.Allocate(sizeof(UserDefinedLiteral) + SizeOfTrailingObjects, alignof(UserDefinedLiteral)); return new (Mem) UserDefinedLiteral(Fn, Args, Ty, VK, LitEndLoc, SuffixLoc, FPFeatures); } UserDefinedLiteral *UserDefinedLiteral::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs, bool HasFPOptions, EmptyShell Empty) { // Allocate storage for the trailing objects of CallExpr. unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects(/*NumPreArgs=*/0, NumArgs, HasFPOptions); void *Mem = Ctx.Allocate(sizeof(UserDefinedLiteral) + SizeOfTrailingObjects, alignof(UserDefinedLiteral)); return new (Mem) UserDefinedLiteral(NumArgs, HasFPOptions, Empty); } UserDefinedLiteral::LiteralOperatorKind UserDefinedLiteral::getLiteralOperatorKind() const { if (getNumArgs() == 0) return LOK_Template; if (getNumArgs() == 2) return LOK_String; assert(getNumArgs() == 1 && "unexpected #args in literal operator call"); QualType ParamTy = cast(getCalleeDecl())->getParamDecl(0)->getType(); if (ParamTy->isPointerType()) return LOK_Raw; if (ParamTy->isAnyCharacterType()) return LOK_Character; if (ParamTy->isIntegerType()) return LOK_Integer; if (ParamTy->isFloatingType()) return LOK_Floating; llvm_unreachable("unknown kind of literal operator"); } Expr *UserDefinedLiteral::getCookedLiteral() { #ifndef NDEBUG LiteralOperatorKind LOK = getLiteralOperatorKind(); assert(LOK != LOK_Template && LOK != LOK_Raw && "not a cooked literal"); #endif return getArg(0); } const IdentifierInfo *UserDefinedLiteral::getUDSuffix() const { return cast(getCalleeDecl())->getLiteralIdentifier(); } CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &Ctx, SourceLocation Loc, FieldDecl *Field, QualType Ty, DeclContext *UsedContext) : Expr(CXXDefaultInitExprClass, Ty.getNonLValueExprType(Ctx), Ty->isLValueReferenceType() ? VK_LValue : Ty->isRValueReferenceType() ? VK_XValue : VK_PRValue, /*FIXME*/ OK_Ordinary), Field(Field), UsedContext(UsedContext) { CXXDefaultInitExprBits.Loc = Loc; assert(Field->hasInClassInitializer()); setDependence(computeDependence(this)); } CXXTemporary *CXXTemporary::Create(const ASTContext &C, const CXXDestructorDecl *Destructor) { return new (C) CXXTemporary(Destructor); } CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(const ASTContext &C, CXXTemporary *Temp, Expr* SubExpr) { assert((SubExpr->getType()->isRecordType() || SubExpr->getType()->isArrayType()) && "Expression bound to a temporary must have record or array type!"); return new (C) CXXBindTemporaryExpr(Temp, SubExpr); } CXXTemporaryObjectExpr::CXXTemporaryObjectExpr( CXXConstructorDecl *Cons, QualType Ty, TypeSourceInfo *TSI, ArrayRef Args, SourceRange ParenOrBraceRange, bool HadMultipleCandidates, bool ListInitialization, bool StdInitListInitialization, bool ZeroInitialization) : CXXConstructExpr( CXXTemporaryObjectExprClass, Ty, TSI->getTypeLoc().getBeginLoc(), Cons, /* Elidable=*/false, Args, HadMultipleCandidates, ListInitialization, StdInitListInitialization, ZeroInitialization, CXXConstructExpr::CK_Complete, ParenOrBraceRange), - TSI(TSI) {} + TSI(TSI) { + setDependence(computeDependence(this)); +} CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(EmptyShell Empty, unsigned NumArgs) : CXXConstructExpr(CXXTemporaryObjectExprClass, Empty, NumArgs) {} CXXTemporaryObjectExpr *CXXTemporaryObjectExpr::Create( const ASTContext &Ctx, CXXConstructorDecl *Cons, QualType Ty, TypeSourceInfo *TSI, ArrayRef Args, SourceRange ParenOrBraceRange, bool HadMultipleCandidates, bool ListInitialization, bool StdInitListInitialization, bool ZeroInitialization) { unsigned SizeOfTrailingObjects = sizeOfTrailingObjects(Args.size()); void *Mem = Ctx.Allocate(sizeof(CXXTemporaryObjectExpr) + SizeOfTrailingObjects, alignof(CXXTemporaryObjectExpr)); return new (Mem) CXXTemporaryObjectExpr( Cons, Ty, TSI, Args, ParenOrBraceRange, HadMultipleCandidates, ListInitialization, StdInitListInitialization, ZeroInitialization); } CXXTemporaryObjectExpr * CXXTemporaryObjectExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs) { unsigned SizeOfTrailingObjects = sizeOfTrailingObjects(NumArgs); void *Mem = Ctx.Allocate(sizeof(CXXTemporaryObjectExpr) + SizeOfTrailingObjects, alignof(CXXTemporaryObjectExpr)); return new (Mem) CXXTemporaryObjectExpr(EmptyShell(), NumArgs); } SourceLocation CXXTemporaryObjectExpr::getBeginLoc() const { return getTypeSourceInfo()->getTypeLoc().getBeginLoc(); } SourceLocation CXXTemporaryObjectExpr::getEndLoc() const { SourceLocation Loc = getParenOrBraceRange().getEnd(); if (Loc.isInvalid() && getNumArgs()) Loc = getArg(getNumArgs() - 1)->getEndLoc(); return Loc; } CXXConstructExpr *CXXConstructExpr::Create( const ASTContext &Ctx, QualType Ty, SourceLocation Loc, CXXConstructorDecl *Ctor, bool Elidable, ArrayRef Args, bool HadMultipleCandidates, bool ListInitialization, bool StdInitListInitialization, bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenOrBraceRange) { unsigned SizeOfTrailingObjects = sizeOfTrailingObjects(Args.size()); void *Mem = Ctx.Allocate(sizeof(CXXConstructExpr) + SizeOfTrailingObjects, alignof(CXXConstructExpr)); return new (Mem) CXXConstructExpr( CXXConstructExprClass, Ty, Loc, Ctor, Elidable, Args, HadMultipleCandidates, ListInitialization, StdInitListInitialization, ZeroInitialization, ConstructKind, ParenOrBraceRange); } CXXConstructExpr *CXXConstructExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs) { unsigned SizeOfTrailingObjects = sizeOfTrailingObjects(NumArgs); void *Mem = Ctx.Allocate(sizeof(CXXConstructExpr) + SizeOfTrailingObjects, alignof(CXXConstructExpr)); return new (Mem) CXXConstructExpr(CXXConstructExprClass, EmptyShell(), NumArgs); } CXXConstructExpr::CXXConstructExpr( StmtClass SC, QualType Ty, SourceLocation Loc, CXXConstructorDecl *Ctor, bool Elidable, ArrayRef Args, bool HadMultipleCandidates, bool ListInitialization, bool StdInitListInitialization, bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenOrBraceRange) : Expr(SC, Ty, VK_PRValue, OK_Ordinary), Constructor(Ctor), ParenOrBraceRange(ParenOrBraceRange), NumArgs(Args.size()) { CXXConstructExprBits.Elidable = Elidable; CXXConstructExprBits.HadMultipleCandidates = HadMultipleCandidates; CXXConstructExprBits.ListInitialization = ListInitialization; CXXConstructExprBits.StdInitListInitialization = StdInitListInitialization; CXXConstructExprBits.ZeroInitialization = ZeroInitialization; CXXConstructExprBits.ConstructionKind = ConstructKind; CXXConstructExprBits.Loc = Loc; Stmt **TrailingArgs = getTrailingArgs(); for (unsigned I = 0, N = Args.size(); I != N; ++I) { assert(Args[I] && "NULL argument in CXXConstructExpr!"); TrailingArgs[I] = Args[I]; } - setDependence(computeDependence(this)); + // CXXTemporaryObjectExpr does this itself after setting its TypeSourceInfo. + if (SC == CXXConstructExprClass) + setDependence(computeDependence(this)); } CXXConstructExpr::CXXConstructExpr(StmtClass SC, EmptyShell Empty, unsigned NumArgs) : Expr(SC, Empty), NumArgs(NumArgs) {} LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit, LambdaCaptureKind Kind, VarDecl *Var, SourceLocation EllipsisLoc) : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) { unsigned Bits = 0; if (Implicit) Bits |= Capture_Implicit; switch (Kind) { case LCK_StarThis: Bits |= Capture_ByCopy; LLVM_FALLTHROUGH; case LCK_This: assert(!Var && "'this' capture cannot have a variable!"); Bits |= Capture_This; break; case LCK_ByCopy: Bits |= Capture_ByCopy; LLVM_FALLTHROUGH; case LCK_ByRef: assert(Var && "capture must have a variable!"); break; case LCK_VLAType: assert(!Var && "VLA type capture cannot have a variable!"); break; } DeclAndBits.setInt(Bits); } LambdaCaptureKind LambdaCapture::getCaptureKind() const { if (capturesVLAType()) return LCK_VLAType; bool CapByCopy = DeclAndBits.getInt() & Capture_ByCopy; if (capturesThis()) return CapByCopy ? LCK_StarThis : LCK_This; return CapByCopy ? LCK_ByCopy : LCK_ByRef; } LambdaExpr::LambdaExpr(QualType T, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, SourceLocation CaptureDefaultLoc, bool ExplicitParams, bool ExplicitResultType, ArrayRef CaptureInits, SourceLocation ClosingBrace, bool ContainsUnexpandedParameterPack) : Expr(LambdaExprClass, T, VK_PRValue, OK_Ordinary), IntroducerRange(IntroducerRange), CaptureDefaultLoc(CaptureDefaultLoc), ClosingBrace(ClosingBrace) { LambdaExprBits.NumCaptures = CaptureInits.size(); LambdaExprBits.CaptureDefault = CaptureDefault; LambdaExprBits.ExplicitParams = ExplicitParams; LambdaExprBits.ExplicitResultType = ExplicitResultType; CXXRecordDecl *Class = getLambdaClass(); (void)Class; assert(capture_size() == Class->capture_size() && "Wrong number of captures"); assert(getCaptureDefault() == Class->getLambdaCaptureDefault()); // Copy initialization expressions for the non-static data members. Stmt **Stored = getStoredStmts(); for (unsigned I = 0, N = CaptureInits.size(); I != N; ++I) *Stored++ = CaptureInits[I]; // Copy the body of the lambda. *Stored++ = getCallOperator()->getBody(); setDependence(computeDependence(this, ContainsUnexpandedParameterPack)); } LambdaExpr::LambdaExpr(EmptyShell Empty, unsigned NumCaptures) : Expr(LambdaExprClass, Empty) { LambdaExprBits.NumCaptures = NumCaptures; // Initially don't initialize the body of the LambdaExpr. The body will // be lazily deserialized when needed. getStoredStmts()[NumCaptures] = nullptr; // Not one past the end. } LambdaExpr *LambdaExpr::Create(const ASTContext &Context, CXXRecordDecl *Class, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, SourceLocation CaptureDefaultLoc, bool ExplicitParams, bool ExplicitResultType, ArrayRef CaptureInits, SourceLocation ClosingBrace, bool ContainsUnexpandedParameterPack) { // Determine the type of the expression (i.e., the type of the // function object we're creating). QualType T = Context.getTypeDeclType(Class); unsigned Size = totalSizeToAlloc(CaptureInits.size() + 1); void *Mem = Context.Allocate(Size); return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault, CaptureDefaultLoc, ExplicitParams, ExplicitResultType, CaptureInits, ClosingBrace, ContainsUnexpandedParameterPack); } LambdaExpr *LambdaExpr::CreateDeserialized(const ASTContext &C, unsigned NumCaptures) { unsigned Size = totalSizeToAlloc(NumCaptures + 1); void *Mem = C.Allocate(Size); return new (Mem) LambdaExpr(EmptyShell(), NumCaptures); } void LambdaExpr::initBodyIfNeeded() const { if (!getStoredStmts()[capture_size()]) { auto *This = const_cast(this); This->getStoredStmts()[capture_size()] = getCallOperator()->getBody(); } } Stmt *LambdaExpr::getBody() const { initBodyIfNeeded(); return getStoredStmts()[capture_size()]; } const CompoundStmt *LambdaExpr::getCompoundStmtBody() const { Stmt *Body = getBody(); if (const auto *CoroBody = dyn_cast(Body)) return cast(CoroBody->getBody()); return cast(Body); } bool LambdaExpr::isInitCapture(const LambdaCapture *C) const { return (C->capturesVariable() && C->getCapturedVar()->isInitCapture() && (getCallOperator() == C->getCapturedVar()->getDeclContext())); } LambdaExpr::capture_iterator LambdaExpr::capture_begin() const { return getLambdaClass()->getLambdaData().Captures; } LambdaExpr::capture_iterator LambdaExpr::capture_end() const { return capture_begin() + capture_size(); } LambdaExpr::capture_range LambdaExpr::captures() const { return capture_range(capture_begin(), capture_end()); } LambdaExpr::capture_iterator LambdaExpr::explicit_capture_begin() const { return capture_begin(); } LambdaExpr::capture_iterator LambdaExpr::explicit_capture_end() const { struct CXXRecordDecl::LambdaDefinitionData &Data = getLambdaClass()->getLambdaData(); return Data.Captures + Data.NumExplicitCaptures; } LambdaExpr::capture_range LambdaExpr::explicit_captures() const { return capture_range(explicit_capture_begin(), explicit_capture_end()); } LambdaExpr::capture_iterator LambdaExpr::implicit_capture_begin() const { return explicit_capture_end(); } LambdaExpr::capture_iterator LambdaExpr::implicit_capture_end() const { return capture_end(); } LambdaExpr::capture_range LambdaExpr::implicit_captures() const { return capture_range(implicit_capture_begin(), implicit_capture_end()); } CXXRecordDecl *LambdaExpr::getLambdaClass() const { return getType()->getAsCXXRecordDecl(); } CXXMethodDecl *LambdaExpr::getCallOperator() const { CXXRecordDecl *Record = getLambdaClass(); return Record->getLambdaCallOperator(); } FunctionTemplateDecl *LambdaExpr::getDependentCallOperator() const { CXXRecordDecl *Record = getLambdaClass(); return Record->getDependentLambdaCallOperator(); } TemplateParameterList *LambdaExpr::getTemplateParameterList() const { CXXRecordDecl *Record = getLambdaClass(); return Record->getGenericLambdaTemplateParameterList(); } ArrayRef LambdaExpr::getExplicitTemplateParameters() const { const CXXRecordDecl *Record = getLambdaClass(); return Record->getLambdaExplicitTemplateParameters(); } Expr *LambdaExpr::getTrailingRequiresClause() const { return getCallOperator()->getTrailingRequiresClause(); } bool LambdaExpr::isMutable() const { return !getCallOperator()->isConst(); } LambdaExpr::child_range LambdaExpr::children() { initBodyIfNeeded(); return child_range(getStoredStmts(), getStoredStmts() + capture_size() + 1); } LambdaExpr::const_child_range LambdaExpr::children() const { initBodyIfNeeded(); return const_child_range(getStoredStmts(), getStoredStmts() + capture_size() + 1); } ExprWithCleanups::ExprWithCleanups(Expr *subexpr, bool CleanupsHaveSideEffects, ArrayRef objects) : FullExpr(ExprWithCleanupsClass, subexpr) { ExprWithCleanupsBits.CleanupsHaveSideEffects = CleanupsHaveSideEffects; ExprWithCleanupsBits.NumObjects = objects.size(); for (unsigned i = 0, e = objects.size(); i != e; ++i) getTrailingObjects()[i] = objects[i]; } ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C, Expr *subexpr, bool CleanupsHaveSideEffects, ArrayRef objects) { void *buffer = C.Allocate(totalSizeToAlloc(objects.size()), alignof(ExprWithCleanups)); return new (buffer) ExprWithCleanups(subexpr, CleanupsHaveSideEffects, objects); } ExprWithCleanups::ExprWithCleanups(EmptyShell empty, unsigned numObjects) : FullExpr(ExprWithCleanupsClass, empty) { ExprWithCleanupsBits.NumObjects = numObjects; } ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C, EmptyShell empty, unsigned numObjects) { void *buffer = C.Allocate(totalSizeToAlloc(numObjects), alignof(ExprWithCleanups)); return new (buffer) ExprWithCleanups(empty, numObjects); } CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(QualType T, TypeSourceInfo *TSI, SourceLocation LParenLoc, ArrayRef Args, SourceLocation RParenLoc) : Expr(CXXUnresolvedConstructExprClass, T, (TSI->getType()->isLValueReferenceType() ? VK_LValue : TSI->getType()->isRValueReferenceType() ? VK_XValue : VK_PRValue), OK_Ordinary), TSI(TSI), LParenLoc(LParenLoc), RParenLoc(RParenLoc) { CXXUnresolvedConstructExprBits.NumArgs = Args.size(); auto **StoredArgs = getTrailingObjects(); for (unsigned I = 0; I != Args.size(); ++I) StoredArgs[I] = Args[I]; setDependence(computeDependence(this)); } CXXUnresolvedConstructExpr *CXXUnresolvedConstructExpr::Create( const ASTContext &Context, QualType T, TypeSourceInfo *TSI, SourceLocation LParenLoc, ArrayRef Args, SourceLocation RParenLoc) { void *Mem = Context.Allocate(totalSizeToAlloc(Args.size())); return new (Mem) CXXUnresolvedConstructExpr(T, TSI, LParenLoc, Args, RParenLoc); } CXXUnresolvedConstructExpr * CXXUnresolvedConstructExpr::CreateEmpty(const ASTContext &Context, unsigned NumArgs) { void *Mem = Context.Allocate(totalSizeToAlloc(NumArgs)); return new (Mem) CXXUnresolvedConstructExpr(EmptyShell(), NumArgs); } SourceLocation CXXUnresolvedConstructExpr::getBeginLoc() const { return TSI->getTypeLoc().getBeginLoc(); } CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr( const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs) : Expr(CXXDependentScopeMemberExprClass, Ctx.DependentTy, VK_LValue, OK_Ordinary), Base(Base), BaseType(BaseType), QualifierLoc(QualifierLoc), MemberNameInfo(MemberNameInfo) { CXXDependentScopeMemberExprBits.IsArrow = IsArrow; CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo = (TemplateArgs != nullptr) || TemplateKWLoc.isValid(); CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope = FirstQualifierFoundInScope != nullptr; CXXDependentScopeMemberExprBits.OperatorLoc = OperatorLoc; if (TemplateArgs) { auto Deps = TemplateArgumentDependence::None; getTrailingObjects()->initializeFrom( TemplateKWLoc, *TemplateArgs, getTrailingObjects(), Deps); } else if (TemplateKWLoc.isValid()) { getTrailingObjects()->initializeFrom( TemplateKWLoc); } if (hasFirstQualifierFoundInScope()) *getTrailingObjects() = FirstQualifierFoundInScope; setDependence(computeDependence(this)); } CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr( EmptyShell Empty, bool HasTemplateKWAndArgsInfo, bool HasFirstQualifierFoundInScope) : Expr(CXXDependentScopeMemberExprClass, Empty) { CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo; CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope = HasFirstQualifierFoundInScope; } CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::Create( const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs) { bool HasTemplateKWAndArgsInfo = (TemplateArgs != nullptr) || TemplateKWLoc.isValid(); unsigned NumTemplateArgs = TemplateArgs ? TemplateArgs->size() : 0; bool HasFirstQualifierFoundInScope = FirstQualifierFoundInScope != nullptr; unsigned Size = totalSizeToAlloc( HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope); void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr)); return new (Mem) CXXDependentScopeMemberExpr( Ctx, Base, BaseType, IsArrow, OperatorLoc, QualifierLoc, TemplateKWLoc, FirstQualifierFoundInScope, MemberNameInfo, TemplateArgs); } CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::CreateEmpty( const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope) { assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo); unsigned Size = totalSizeToAlloc( HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope); void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr)); return new (Mem) CXXDependentScopeMemberExpr( EmptyShell(), HasTemplateKWAndArgsInfo, HasFirstQualifierFoundInScope); } static bool hasOnlyNonStaticMemberFunctions(UnresolvedSetIterator begin, UnresolvedSetIterator end) { do { NamedDecl *decl = *begin; if (isa(decl)) return false; // Unresolved member expressions should only contain methods and // method templates. if (cast(decl->getUnderlyingDecl()->getAsFunction()) ->isStatic()) return false; } while (++begin != end); return true; } UnresolvedMemberExpr::UnresolvedMemberExpr( const ASTContext &Context, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End) : OverloadExpr( UnresolvedMemberExprClass, Context, QualifierLoc, TemplateKWLoc, MemberNameInfo, TemplateArgs, Begin, End, // Dependent ((Base && Base->isTypeDependent()) || BaseType->isDependentType()), ((Base && Base->isInstantiationDependent()) || BaseType->isInstantiationDependentType()), // Contains unexpanded parameter pack ((Base && Base->containsUnexpandedParameterPack()) || BaseType->containsUnexpandedParameterPack())), Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) { UnresolvedMemberExprBits.IsArrow = IsArrow; UnresolvedMemberExprBits.HasUnresolvedUsing = HasUnresolvedUsing; // Check whether all of the members are non-static member functions, // and if so, mark give this bound-member type instead of overload type. if (hasOnlyNonStaticMemberFunctions(Begin, End)) setType(Context.BoundMemberTy); } UnresolvedMemberExpr::UnresolvedMemberExpr(EmptyShell Empty, unsigned NumResults, bool HasTemplateKWAndArgsInfo) : OverloadExpr(UnresolvedMemberExprClass, Empty, NumResults, HasTemplateKWAndArgsInfo) {} bool UnresolvedMemberExpr::isImplicitAccess() const { if (!Base) return true; return cast(Base)->isImplicitCXXThis(); } UnresolvedMemberExpr *UnresolvedMemberExpr::Create( const ASTContext &Context, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End) { unsigned NumResults = End - Begin; bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid(); unsigned NumTemplateArgs = TemplateArgs ? TemplateArgs->size() : 0; unsigned Size = totalSizeToAlloc( NumResults, HasTemplateKWAndArgsInfo, NumTemplateArgs); void *Mem = Context.Allocate(Size, alignof(UnresolvedMemberExpr)); return new (Mem) UnresolvedMemberExpr( Context, HasUnresolvedUsing, Base, BaseType, IsArrow, OperatorLoc, QualifierLoc, TemplateKWLoc, MemberNameInfo, TemplateArgs, Begin, End); } UnresolvedMemberExpr *UnresolvedMemberExpr::CreateEmpty( const ASTContext &Context, unsigned NumResults, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) { assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo); unsigned Size = totalSizeToAlloc( NumResults, HasTemplateKWAndArgsInfo, NumTemplateArgs); void *Mem = Context.Allocate(Size, alignof(UnresolvedMemberExpr)); return new (Mem) UnresolvedMemberExpr(EmptyShell(), NumResults, HasTemplateKWAndArgsInfo); } CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() { // Unlike for UnresolvedLookupExpr, it is very easy to re-derive this. // If there was a nested name specifier, it names the naming class. // It can't be dependent: after all, we were actually able to do the // lookup. CXXRecordDecl *Record = nullptr; auto *NNS = getQualifier(); if (NNS && NNS->getKind() != NestedNameSpecifier::Super) { const Type *T = getQualifier()->getAsType(); assert(T && "qualifier in member expression does not name type"); Record = T->getAsCXXRecordDecl(); assert(Record && "qualifier in member expression does not name record"); } // Otherwise the naming class must have been the base class. else { QualType BaseType = getBaseType().getNonReferenceType(); if (isArrow()) BaseType = BaseType->castAs()->getPointeeType(); Record = BaseType->getAsCXXRecordDecl(); assert(Record && "base of member expression does not name record"); } return Record; } SizeOfPackExpr * SizeOfPackExpr::Create(ASTContext &Context, SourceLocation OperatorLoc, NamedDecl *Pack, SourceLocation PackLoc, SourceLocation RParenLoc, Optional Length, ArrayRef PartialArgs) { void *Storage = Context.Allocate(totalSizeToAlloc(PartialArgs.size())); return new (Storage) SizeOfPackExpr(Context.getSizeType(), OperatorLoc, Pack, PackLoc, RParenLoc, Length, PartialArgs); } SizeOfPackExpr *SizeOfPackExpr::CreateDeserialized(ASTContext &Context, unsigned NumPartialArgs) { void *Storage = Context.Allocate(totalSizeToAlloc(NumPartialArgs)); return new (Storage) SizeOfPackExpr(EmptyShell(), NumPartialArgs); } QualType SubstNonTypeTemplateParmExpr::getParameterType( const ASTContext &Context) const { // Note that, for a class type NTTP, we will have an lvalue of type 'const // T', so we can't just compute this from the type and value category. if (isReferenceParameter()) return Context.getLValueReferenceType(getType()); return getType().getUnqualifiedType(); } SubstNonTypeTemplateParmPackExpr::SubstNonTypeTemplateParmPackExpr( QualType T, ExprValueKind ValueKind, NonTypeTemplateParmDecl *Param, SourceLocation NameLoc, const TemplateArgument &ArgPack) : Expr(SubstNonTypeTemplateParmPackExprClass, T, ValueKind, OK_Ordinary), Param(Param), Arguments(ArgPack.pack_begin()), NumArguments(ArgPack.pack_size()), NameLoc(NameLoc) { setDependence(ExprDependence::TypeValueInstantiation | ExprDependence::UnexpandedPack); } TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const { return TemplateArgument(llvm::makeArrayRef(Arguments, NumArguments)); } FunctionParmPackExpr::FunctionParmPackExpr(QualType T, VarDecl *ParamPack, SourceLocation NameLoc, unsigned NumParams, VarDecl *const *Params) : Expr(FunctionParmPackExprClass, T, VK_LValue, OK_Ordinary), ParamPack(ParamPack), NameLoc(NameLoc), NumParameters(NumParams) { if (Params) std::uninitialized_copy(Params, Params + NumParams, getTrailingObjects()); setDependence(ExprDependence::TypeValueInstantiation | ExprDependence::UnexpandedPack); } FunctionParmPackExpr * FunctionParmPackExpr::Create(const ASTContext &Context, QualType T, VarDecl *ParamPack, SourceLocation NameLoc, ArrayRef Params) { return new (Context.Allocate(totalSizeToAlloc(Params.size()))) FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data()); } FunctionParmPackExpr * FunctionParmPackExpr::CreateEmpty(const ASTContext &Context, unsigned NumParams) { return new (Context.Allocate(totalSizeToAlloc(NumParams))) FunctionParmPackExpr(QualType(), nullptr, SourceLocation(), 0, nullptr); } MaterializeTemporaryExpr::MaterializeTemporaryExpr( QualType T, Expr *Temporary, bool BoundToLvalueReference, LifetimeExtendedTemporaryDecl *MTD) : Expr(MaterializeTemporaryExprClass, T, BoundToLvalueReference ? VK_LValue : VK_XValue, OK_Ordinary) { if (MTD) { State = MTD; MTD->ExprWithTemporary = Temporary; return; } State = Temporary; setDependence(computeDependence(this)); } void MaterializeTemporaryExpr::setExtendingDecl(ValueDecl *ExtendedBy, unsigned ManglingNumber) { // We only need extra state if we have to remember more than just the Stmt. if (!ExtendedBy) return; // We may need to allocate extra storage for the mangling number and the // extended-by ValueDecl. if (!State.is()) State = LifetimeExtendedTemporaryDecl::Create( cast(State.get()), ExtendedBy, ManglingNumber); auto ES = State.get(); ES->ExtendingDecl = ExtendedBy; ES->ManglingNumber = ManglingNumber; } bool MaterializeTemporaryExpr::isUsableInConstantExpressions( const ASTContext &Context) const { // C++20 [expr.const]p4: // An object or reference is usable in constant expressions if it is [...] // a temporary object of non-volatile const-qualified literal type // whose lifetime is extended to that of a variable that is usable // in constant expressions auto *VD = dyn_cast_or_null(getExtendingDecl()); return VD && getType().isConstant(Context) && !getType().isVolatileQualified() && getType()->isLiteralType(Context) && VD->isUsableInConstantExpressions(Context); } TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind, ArrayRef Args, SourceLocation RParenLoc, bool Value) : Expr(TypeTraitExprClass, T, VK_PRValue, OK_Ordinary), Loc(Loc), RParenLoc(RParenLoc) { assert(Kind <= TT_Last && "invalid enum value!"); TypeTraitExprBits.Kind = Kind; assert(static_cast(Kind) == TypeTraitExprBits.Kind && "TypeTraitExprBits.Kind overflow!"); TypeTraitExprBits.Value = Value; TypeTraitExprBits.NumArgs = Args.size(); assert(Args.size() == TypeTraitExprBits.NumArgs && "TypeTraitExprBits.NumArgs overflow!"); auto **ToArgs = getTrailingObjects(); for (unsigned I = 0, N = Args.size(); I != N; ++I) ToArgs[I] = Args[I]; setDependence(computeDependence(this)); } TypeTraitExpr *TypeTraitExpr::Create(const ASTContext &C, QualType T, SourceLocation Loc, TypeTrait Kind, ArrayRef Args, SourceLocation RParenLoc, bool Value) { void *Mem = C.Allocate(totalSizeToAlloc(Args.size())); return new (Mem) TypeTraitExpr(T, Loc, Kind, Args, RParenLoc, Value); } TypeTraitExpr *TypeTraitExpr::CreateDeserialized(const ASTContext &C, unsigned NumArgs) { void *Mem = C.Allocate(totalSizeToAlloc(NumArgs)); return new (Mem) TypeTraitExpr(EmptyShell()); } CUDAKernelCallExpr::CUDAKernelCallExpr(Expr *Fn, CallExpr *Config, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation RP, FPOptionsOverride FPFeatures, unsigned MinNumArgs) : CallExpr(CUDAKernelCallExprClass, Fn, /*PreArgs=*/Config, Args, Ty, VK, RP, FPFeatures, MinNumArgs, NotADL) {} CUDAKernelCallExpr::CUDAKernelCallExpr(unsigned NumArgs, bool HasFPFeatures, EmptyShell Empty) : CallExpr(CUDAKernelCallExprClass, /*NumPreArgs=*/END_PREARG, NumArgs, HasFPFeatures, Empty) {} CUDAKernelCallExpr * CUDAKernelCallExpr::Create(const ASTContext &Ctx, Expr *Fn, CallExpr *Config, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation RP, FPOptionsOverride FPFeatures, unsigned MinNumArgs) { // Allocate storage for the trailing objects of CallExpr. unsigned NumArgs = std::max(Args.size(), MinNumArgs); unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects( /*NumPreArgs=*/END_PREARG, NumArgs, FPFeatures.requiresTrailingStorage()); void *Mem = Ctx.Allocate(sizeof(CUDAKernelCallExpr) + SizeOfTrailingObjects, alignof(CUDAKernelCallExpr)); return new (Mem) CUDAKernelCallExpr(Fn, Config, Args, Ty, VK, RP, FPFeatures, MinNumArgs); } CUDAKernelCallExpr *CUDAKernelCallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs, bool HasFPFeatures, EmptyShell Empty) { // Allocate storage for the trailing objects of CallExpr. unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects( /*NumPreArgs=*/END_PREARG, NumArgs, HasFPFeatures); void *Mem = Ctx.Allocate(sizeof(CUDAKernelCallExpr) + SizeOfTrailingObjects, alignof(CUDAKernelCallExpr)); return new (Mem) CUDAKernelCallExpr(NumArgs, HasFPFeatures, Empty); } diff --git a/contrib/llvm-project/clang/lib/AST/Type.cpp b/contrib/llvm-project/clang/lib/AST/Type.cpp index 774b3e94159d..adfe8a9462b3 100644 --- a/contrib/llvm-project/clang/lib/AST/Type.cpp +++ b/contrib/llvm-project/clang/lib/AST/Type.cpp @@ -1,4449 +1,4447 @@ //===- Type.cpp - Type representation and manipulation --------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements type-related functionality. // //===----------------------------------------------------------------------===// #include "clang/AST/Type.h" #include "Linkage.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DependenceFlags.h" #include "clang/AST/Expr.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/NonTrivialTypeVisitor.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Linkage.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetCXXABI.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Visibility.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/None.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include #include #include #include #include using namespace clang; bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const { return (*this != Other) && // CVR qualifiers superset (((Mask & CVRMask) | (Other.Mask & CVRMask)) == (Mask & CVRMask)) && // ObjC GC qualifiers superset ((getObjCGCAttr() == Other.getObjCGCAttr()) || (hasObjCGCAttr() && !Other.hasObjCGCAttr())) && // Address space superset. ((getAddressSpace() == Other.getAddressSpace()) || (hasAddressSpace()&& !Other.hasAddressSpace())) && // Lifetime qualifier superset. ((getObjCLifetime() == Other.getObjCLifetime()) || (hasObjCLifetime() && !Other.hasObjCLifetime())); } const IdentifierInfo* QualType::getBaseTypeIdentifier() const { const Type* ty = getTypePtr(); NamedDecl *ND = nullptr; if (ty->isPointerType() || ty->isReferenceType()) return ty->getPointeeType().getBaseTypeIdentifier(); else if (ty->isRecordType()) ND = ty->castAs()->getDecl(); else if (ty->isEnumeralType()) ND = ty->castAs()->getDecl(); else if (ty->getTypeClass() == Type::Typedef) ND = ty->castAs()->getDecl(); else if (ty->isArrayType()) return ty->castAsArrayTypeUnsafe()-> getElementType().getBaseTypeIdentifier(); if (ND) return ND->getIdentifier(); return nullptr; } bool QualType::mayBeDynamicClass() const { const auto *ClassDecl = getTypePtr()->getPointeeCXXRecordDecl(); return ClassDecl && ClassDecl->mayBeDynamicClass(); } bool QualType::mayBeNotDynamicClass() const { const auto *ClassDecl = getTypePtr()->getPointeeCXXRecordDecl(); return !ClassDecl || ClassDecl->mayBeNonDynamicClass(); } bool QualType::isConstant(QualType T, const ASTContext &Ctx) { if (T.isConstQualified()) return true; if (const ArrayType *AT = Ctx.getAsArrayType(T)) return AT->getElementType().isConstant(Ctx); return T.getAddressSpace() == LangAS::opencl_constant; } // C++ [temp.dep.type]p1: // A type is dependent if it is... // - an array type constructed from any dependent type or whose // size is specified by a constant expression that is // value-dependent, ArrayType::ArrayType(TypeClass tc, QualType et, QualType can, ArraySizeModifier sm, unsigned tq, const Expr *sz) // Note, we need to check for DependentSizedArrayType explicitly here // because we use a DependentSizedArrayType with no size expression as the // type of a dependent array of unknown bound with a dependent braced // initializer: // // template int arr[] = {N...}; : Type(tc, can, et->getDependence() | (sz ? toTypeDependence( turnValueToTypeDependence(sz->getDependence())) : TypeDependence::None) | (tc == VariableArray ? TypeDependence::VariablyModified : TypeDependence::None) | (tc == DependentSizedArray ? TypeDependence::DependentInstantiation : TypeDependence::None)), ElementType(et) { ArrayTypeBits.IndexTypeQuals = tq; ArrayTypeBits.SizeModifier = sm; } unsigned ConstantArrayType::getNumAddressingBits(const ASTContext &Context, QualType ElementType, const llvm::APInt &NumElements) { uint64_t ElementSize = Context.getTypeSizeInChars(ElementType).getQuantity(); // Fast path the common cases so we can avoid the conservative computation // below, which in common cases allocates "large" APSInt values, which are // slow. // If the element size is a power of 2, we can directly compute the additional // number of addressing bits beyond those required for the element count. if (llvm::isPowerOf2_64(ElementSize)) { return NumElements.getActiveBits() + llvm::Log2_64(ElementSize); } // If both the element count and element size fit in 32-bits, we can do the // computation directly in 64-bits. if ((ElementSize >> 32) == 0 && NumElements.getBitWidth() <= 64 && (NumElements.getZExtValue() >> 32) == 0) { uint64_t TotalSize = NumElements.getZExtValue() * ElementSize; return 64 - llvm::countLeadingZeros(TotalSize); } // Otherwise, use APSInt to handle arbitrary sized values. llvm::APSInt SizeExtended(NumElements, true); unsigned SizeTypeBits = Context.getTypeSize(Context.getSizeType()); SizeExtended = SizeExtended.extend(std::max(SizeTypeBits, SizeExtended.getBitWidth()) * 2); llvm::APSInt TotalSize(llvm::APInt(SizeExtended.getBitWidth(), ElementSize)); TotalSize *= SizeExtended; return TotalSize.getActiveBits(); } unsigned ConstantArrayType::getMaxSizeBits(const ASTContext &Context) { unsigned Bits = Context.getTypeSize(Context.getSizeType()); // Limit the number of bits in size_t so that maximal bit size fits 64 bit // integer (see PR8256). We can do this as currently there is no hardware // that supports full 64-bit virtual space. if (Bits > 61) Bits = 61; return Bits; } void ConstantArrayType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ET, const llvm::APInt &ArraySize, const Expr *SizeExpr, ArraySizeModifier SizeMod, unsigned TypeQuals) { ID.AddPointer(ET.getAsOpaquePtr()); ID.AddInteger(ArraySize.getZExtValue()); ID.AddInteger(SizeMod); ID.AddInteger(TypeQuals); ID.AddBoolean(SizeExpr != nullptr); if (SizeExpr) SizeExpr->Profile(ID, Context, true); } DependentSizedArrayType::DependentSizedArrayType(const ASTContext &Context, QualType et, QualType can, Expr *e, ArraySizeModifier sm, unsigned tq, SourceRange brackets) : ArrayType(DependentSizedArray, et, can, sm, tq, e), Context(Context), SizeExpr((Stmt*) e), Brackets(brackets) {} void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ET, ArraySizeModifier SizeMod, unsigned TypeQuals, Expr *E) { ID.AddPointer(ET.getAsOpaquePtr()); ID.AddInteger(SizeMod); ID.AddInteger(TypeQuals); E->Profile(ID, Context, true); } DependentVectorType::DependentVectorType(const ASTContext &Context, QualType ElementType, QualType CanonType, Expr *SizeExpr, SourceLocation Loc, VectorType::VectorKind VecKind) : Type(DependentVector, CanonType, TypeDependence::DependentInstantiation | ElementType->getDependence() | (SizeExpr ? toTypeDependence(SizeExpr->getDependence()) : TypeDependence::None)), Context(Context), ElementType(ElementType), SizeExpr(SizeExpr), Loc(Loc) { VectorTypeBits.VecKind = VecKind; } void DependentVectorType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ElementType, const Expr *SizeExpr, VectorType::VectorKind VecKind) { ID.AddPointer(ElementType.getAsOpaquePtr()); ID.AddInteger(VecKind); SizeExpr->Profile(ID, Context, true); } DependentSizedExtVectorType::DependentSizedExtVectorType( const ASTContext &Context, QualType ElementType, QualType can, Expr *SizeExpr, SourceLocation loc) : Type(DependentSizedExtVector, can, TypeDependence::DependentInstantiation | ElementType->getDependence() | (SizeExpr ? toTypeDependence(SizeExpr->getDependence()) : TypeDependence::None)), Context(Context), SizeExpr(SizeExpr), ElementType(ElementType), loc(loc) { } void DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ElementType, Expr *SizeExpr) { ID.AddPointer(ElementType.getAsOpaquePtr()); SizeExpr->Profile(ID, Context, true); } DependentAddressSpaceType::DependentAddressSpaceType(const ASTContext &Context, QualType PointeeType, QualType can, Expr *AddrSpaceExpr, SourceLocation loc) : Type(DependentAddressSpace, can, TypeDependence::DependentInstantiation | PointeeType->getDependence() | (AddrSpaceExpr ? toTypeDependence(AddrSpaceExpr->getDependence()) : TypeDependence::None)), Context(Context), AddrSpaceExpr(AddrSpaceExpr), PointeeType(PointeeType), loc(loc) {} void DependentAddressSpaceType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType PointeeType, Expr *AddrSpaceExpr) { ID.AddPointer(PointeeType.getAsOpaquePtr()); AddrSpaceExpr->Profile(ID, Context, true); } MatrixType::MatrixType(TypeClass tc, QualType matrixType, QualType canonType, const Expr *RowExpr, const Expr *ColumnExpr) : Type(tc, canonType, (RowExpr ? (matrixType->getDependence() | TypeDependence::Dependent | TypeDependence::Instantiation | (matrixType->isVariablyModifiedType() ? TypeDependence::VariablyModified : TypeDependence::None) | (matrixType->containsUnexpandedParameterPack() || (RowExpr && RowExpr->containsUnexpandedParameterPack()) || (ColumnExpr && ColumnExpr->containsUnexpandedParameterPack()) ? TypeDependence::UnexpandedPack : TypeDependence::None)) : matrixType->getDependence())), ElementType(matrixType) {} ConstantMatrixType::ConstantMatrixType(QualType matrixType, unsigned nRows, unsigned nColumns, QualType canonType) : ConstantMatrixType(ConstantMatrix, matrixType, nRows, nColumns, canonType) {} ConstantMatrixType::ConstantMatrixType(TypeClass tc, QualType matrixType, unsigned nRows, unsigned nColumns, QualType canonType) : MatrixType(tc, matrixType, canonType), NumRows(nRows), NumColumns(nColumns) {} DependentSizedMatrixType::DependentSizedMatrixType( const ASTContext &CTX, QualType ElementType, QualType CanonicalType, Expr *RowExpr, Expr *ColumnExpr, SourceLocation loc) : MatrixType(DependentSizedMatrix, ElementType, CanonicalType, RowExpr, ColumnExpr), Context(CTX), RowExpr(RowExpr), ColumnExpr(ColumnExpr), loc(loc) {} void DependentSizedMatrixType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &CTX, QualType ElementType, Expr *RowExpr, Expr *ColumnExpr) { ID.AddPointer(ElementType.getAsOpaquePtr()); RowExpr->Profile(ID, CTX, true); ColumnExpr->Profile(ID, CTX, true); } VectorType::VectorType(QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind) : VectorType(Vector, vecType, nElements, canonType, vecKind) {} VectorType::VectorType(TypeClass tc, QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind) : Type(tc, canonType, vecType->getDependence()), ElementType(vecType) { VectorTypeBits.VecKind = vecKind; VectorTypeBits.NumElements = nElements; } BitIntType::BitIntType(bool IsUnsigned, unsigned NumBits) : Type(BitInt, QualType{}, TypeDependence::None), IsUnsigned(IsUnsigned), NumBits(NumBits) {} DependentBitIntType::DependentBitIntType(const ASTContext &Context, bool IsUnsigned, Expr *NumBitsExpr) : Type(DependentBitInt, QualType{}, toTypeDependence(NumBitsExpr->getDependence())), Context(Context), ExprAndUnsigned(NumBitsExpr, IsUnsigned) {} bool DependentBitIntType::isUnsigned() const { return ExprAndUnsigned.getInt(); } clang::Expr *DependentBitIntType::getNumBitsExpr() const { return ExprAndUnsigned.getPointer(); } void DependentBitIntType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, bool IsUnsigned, Expr *NumBitsExpr) { ID.AddBoolean(IsUnsigned); NumBitsExpr->Profile(ID, Context, true); } /// getArrayElementTypeNoTypeQual - If this is an array type, return the /// element type of the array, potentially with type qualifiers missing. /// This method should never be used when type qualifiers are meaningful. const Type *Type::getArrayElementTypeNoTypeQual() const { // If this is directly an array type, return it. if (const auto *ATy = dyn_cast(this)) return ATy->getElementType().getTypePtr(); // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) return nullptr; // If this is a typedef for an array type, strip the typedef off without // losing all typedef information. return cast(getUnqualifiedDesugaredType()) ->getElementType().getTypePtr(); } /// getDesugaredType - Return the specified type with any "sugar" removed from /// the type. This takes off typedefs, typeof's etc. If the outer level of /// the type is already concrete, it returns it unmodified. This is similar /// to getting the canonical type, but it doesn't remove *all* typedefs. For /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is /// concrete. QualType QualType::getDesugaredType(QualType T, const ASTContext &Context) { SplitQualType split = getSplitDesugaredType(T); return Context.getQualifiedType(split.Ty, split.Quals); } QualType QualType::getSingleStepDesugaredTypeImpl(QualType type, const ASTContext &Context) { SplitQualType split = type.split(); QualType desugar = split.Ty->getLocallyUnqualifiedSingleStepDesugaredType(); return Context.getQualifiedType(desugar, split.Quals); } // Check that no type class is polymorphic. LLVM style RTTI should be used // instead. If absolutely needed an exception can still be added here by // defining the appropriate macro (but please don't do this). #define TYPE(CLASS, BASE) \ static_assert(!std::is_polymorphic::value, \ #CLASS "Type should not be polymorphic!"); #include "clang/AST/TypeNodes.inc" // Check that no type class has a non-trival destructor. Types are // allocated with the BumpPtrAllocator from ASTContext and therefore // their destructor is not executed. // // FIXME: ConstantArrayType is not trivially destructible because of its // APInt member. It should be replaced in favor of ASTContext allocation. #define TYPE(CLASS, BASE) \ static_assert(std::is_trivially_destructible::value || \ std::is_same::value, \ #CLASS "Type should be trivially destructible!"); #include "clang/AST/TypeNodes.inc" QualType Type::getLocallyUnqualifiedSingleStepDesugaredType() const { switch (getTypeClass()) { #define ABSTRACT_TYPE(Class, Parent) #define TYPE(Class, Parent) \ case Type::Class: { \ const auto *ty = cast(this); \ if (!ty->isSugared()) return QualType(ty, 0); \ return ty->desugar(); \ } #include "clang/AST/TypeNodes.inc" } llvm_unreachable("bad type kind!"); } SplitQualType QualType::getSplitDesugaredType(QualType T) { QualifierCollector Qs; QualType Cur = T; while (true) { const Type *CurTy = Qs.strip(Cur); switch (CurTy->getTypeClass()) { #define ABSTRACT_TYPE(Class, Parent) #define TYPE(Class, Parent) \ case Type::Class: { \ const auto *Ty = cast(CurTy); \ if (!Ty->isSugared()) \ return SplitQualType(Ty, Qs); \ Cur = Ty->desugar(); \ break; \ } #include "clang/AST/TypeNodes.inc" } } } SplitQualType QualType::getSplitUnqualifiedTypeImpl(QualType type) { SplitQualType split = type.split(); // All the qualifiers we've seen so far. Qualifiers quals = split.Quals; // The last type node we saw with any nodes inside it. const Type *lastTypeWithQuals = split.Ty; while (true) { QualType next; // Do a single-step desugar, aborting the loop if the type isn't // sugared. switch (split.Ty->getTypeClass()) { #define ABSTRACT_TYPE(Class, Parent) #define TYPE(Class, Parent) \ case Type::Class: { \ const auto *ty = cast(split.Ty); \ if (!ty->isSugared()) goto done; \ next = ty->desugar(); \ break; \ } #include "clang/AST/TypeNodes.inc" } // Otherwise, split the underlying type. If that yields qualifiers, // update the information. split = next.split(); if (!split.Quals.empty()) { lastTypeWithQuals = split.Ty; quals.addConsistentQualifiers(split.Quals); } } done: return SplitQualType(lastTypeWithQuals, quals); } QualType QualType::IgnoreParens(QualType T) { // FIXME: this seems inherently un-qualifiers-safe. while (const auto *PT = T->getAs()) T = PT->getInnerType(); return T; } /// This will check for a T (which should be a Type which can act as /// sugar, such as a TypedefType) by removing any existing sugar until it /// reaches a T or a non-sugared type. template static const T *getAsSugar(const Type *Cur) { while (true) { if (const auto *Sugar = dyn_cast(Cur)) return Sugar; switch (Cur->getTypeClass()) { #define ABSTRACT_TYPE(Class, Parent) #define TYPE(Class, Parent) \ case Type::Class: { \ const auto *Ty = cast(Cur); \ if (!Ty->isSugared()) return 0; \ Cur = Ty->desugar().getTypePtr(); \ break; \ } #include "clang/AST/TypeNodes.inc" } } } template <> const TypedefType *Type::getAs() const { return getAsSugar(this); } template <> const TemplateSpecializationType *Type::getAs() const { return getAsSugar(this); } template <> const AttributedType *Type::getAs() const { return getAsSugar(this); } /// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic /// sugar off the given type. This should produce an object of the /// same dynamic type as the canonical type. const Type *Type::getUnqualifiedDesugaredType() const { const Type *Cur = this; while (true) { switch (Cur->getTypeClass()) { #define ABSTRACT_TYPE(Class, Parent) #define TYPE(Class, Parent) \ case Class: { \ const auto *Ty = cast(Cur); \ if (!Ty->isSugared()) return Cur; \ Cur = Ty->desugar().getTypePtr(); \ break; \ } #include "clang/AST/TypeNodes.inc" } } } bool Type::isClassType() const { if (const auto *RT = getAs()) return RT->getDecl()->isClass(); return false; } bool Type::isStructureType() const { if (const auto *RT = getAs()) return RT->getDecl()->isStruct(); return false; } bool Type::isObjCBoxableRecordType() const { if (const auto *RT = getAs()) return RT->getDecl()->hasAttr(); return false; } bool Type::isInterfaceType() const { if (const auto *RT = getAs()) return RT->getDecl()->isInterface(); return false; } bool Type::isStructureOrClassType() const { if (const auto *RT = getAs()) { RecordDecl *RD = RT->getDecl(); return RD->isStruct() || RD->isClass() || RD->isInterface(); } return false; } bool Type::isVoidPointerType() const { if (const auto *PT = getAs()) return PT->getPointeeType()->isVoidType(); return false; } bool Type::isUnionType() const { if (const auto *RT = getAs()) return RT->getDecl()->isUnion(); return false; } bool Type::isComplexType() const { if (const auto *CT = dyn_cast(CanonicalType)) return CT->getElementType()->isFloatingType(); return false; } bool Type::isComplexIntegerType() const { // Check for GCC complex integer extension. return getAsComplexIntegerType(); } bool Type::isScopedEnumeralType() const { if (const auto *ET = getAs()) return ET->getDecl()->isScoped(); return false; } const ComplexType *Type::getAsComplexIntegerType() const { if (const auto *Complex = getAs()) if (Complex->getElementType()->isIntegerType()) return Complex; return nullptr; } QualType Type::getPointeeType() const { if (const auto *PT = getAs()) return PT->getPointeeType(); if (const auto *OPT = getAs()) return OPT->getPointeeType(); if (const auto *BPT = getAs()) return BPT->getPointeeType(); if (const auto *RT = getAs()) return RT->getPointeeType(); if (const auto *MPT = getAs()) return MPT->getPointeeType(); if (const auto *DT = getAs()) return DT->getPointeeType(); return {}; } const RecordType *Type::getAsStructureType() const { // If this is directly a structure type, return it. if (const auto *RT = dyn_cast(this)) { if (RT->getDecl()->isStruct()) return RT; } // If the canonical form of this type isn't the right kind, reject it. if (const auto *RT = dyn_cast(CanonicalType)) { if (!RT->getDecl()->isStruct()) return nullptr; // If this is a typedef for a structure type, strip the typedef off without // losing all typedef information. return cast(getUnqualifiedDesugaredType()); } return nullptr; } const RecordType *Type::getAsUnionType() const { // If this is directly a union type, return it. if (const auto *RT = dyn_cast(this)) { if (RT->getDecl()->isUnion()) return RT; } // If the canonical form of this type isn't the right kind, reject it. if (const auto *RT = dyn_cast(CanonicalType)) { if (!RT->getDecl()->isUnion()) return nullptr; // If this is a typedef for a union type, strip the typedef off without // losing all typedef information. return cast(getUnqualifiedDesugaredType()); } return nullptr; } bool Type::isObjCIdOrObjectKindOfType(const ASTContext &ctx, const ObjCObjectType *&bound) const { bound = nullptr; const auto *OPT = getAs(); if (!OPT) return false; // Easy case: id. if (OPT->isObjCIdType()) return true; // If it's not a __kindof type, reject it now. if (!OPT->isKindOfType()) return false; // If it's Class or qualified Class, it's not an object type. if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) return false; // Figure out the type bound for the __kindof type. bound = OPT->getObjectType()->stripObjCKindOfTypeAndQuals(ctx) ->getAs(); return true; } bool Type::isObjCClassOrClassKindOfType() const { const auto *OPT = getAs(); if (!OPT) return false; // Easy case: Class. if (OPT->isObjCClassType()) return true; // If it's not a __kindof type, reject it now. if (!OPT->isKindOfType()) return false; // If it's Class or qualified Class, it's a class __kindof type. return OPT->isObjCClassType() || OPT->isObjCQualifiedClassType(); } ObjCTypeParamType::ObjCTypeParamType(const ObjCTypeParamDecl *D, QualType can, ArrayRef protocols) - : Type(ObjCTypeParam, can, - can->getDependence() & ~TypeDependence::UnexpandedPack), + : Type(ObjCTypeParam, can, toSemanticDependence(can->getDependence())), OTPDecl(const_cast(D)) { initialize(protocols); } ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, ArrayRef typeArgs, ArrayRef protocols, bool isKindOf) : Type(ObjCObject, Canonical, Base->getDependence()), BaseType(Base) { ObjCObjectTypeBits.IsKindOf = isKindOf; ObjCObjectTypeBits.NumTypeArgs = typeArgs.size(); assert(getTypeArgsAsWritten().size() == typeArgs.size() && "bitfield overflow in type argument count"); if (!typeArgs.empty()) memcpy(getTypeArgStorage(), typeArgs.data(), typeArgs.size() * sizeof(QualType)); for (auto typeArg : typeArgs) { addDependence(typeArg->getDependence() & ~TypeDependence::VariablyModified); } // Initialize the protocol qualifiers. The protocol storage is known // after we set number of type arguments. initialize(protocols); } bool ObjCObjectType::isSpecialized() const { // If we have type arguments written here, the type is specialized. if (ObjCObjectTypeBits.NumTypeArgs > 0) return true; // Otherwise, check whether the base type is specialized. if (const auto objcObject = getBaseType()->getAs()) { // Terminate when we reach an interface type. if (isa(objcObject)) return false; return objcObject->isSpecialized(); } // Not specialized. return false; } ArrayRef ObjCObjectType::getTypeArgs() const { // We have type arguments written on this type. if (isSpecializedAsWritten()) return getTypeArgsAsWritten(); // Look at the base type, which might have type arguments. if (const auto objcObject = getBaseType()->getAs()) { // Terminate when we reach an interface type. if (isa(objcObject)) return {}; return objcObject->getTypeArgs(); } // No type arguments. return {}; } bool ObjCObjectType::isKindOfType() const { if (isKindOfTypeAsWritten()) return true; // Look at the base type, which might have type arguments. if (const auto objcObject = getBaseType()->getAs()) { // Terminate when we reach an interface type. if (isa(objcObject)) return false; return objcObject->isKindOfType(); } // Not a "__kindof" type. return false; } QualType ObjCObjectType::stripObjCKindOfTypeAndQuals( const ASTContext &ctx) const { if (!isKindOfType() && qual_empty()) return QualType(this, 0); // Recursively strip __kindof. SplitQualType splitBaseType = getBaseType().split(); QualType baseType(splitBaseType.Ty, 0); if (const auto *baseObj = splitBaseType.Ty->getAs()) baseType = baseObj->stripObjCKindOfTypeAndQuals(ctx); return ctx.getObjCObjectType(ctx.getQualifiedType(baseType, splitBaseType.Quals), getTypeArgsAsWritten(), /*protocols=*/{}, /*isKindOf=*/false); } ObjCInterfaceDecl *ObjCInterfaceType::getDecl() const { ObjCInterfaceDecl *Canon = Decl->getCanonicalDecl(); if (ObjCInterfaceDecl *Def = Canon->getDefinition()) return Def; return Canon; } const ObjCObjectPointerType *ObjCObjectPointerType::stripObjCKindOfTypeAndQuals( const ASTContext &ctx) const { if (!isKindOfType() && qual_empty()) return this; QualType obj = getObjectType()->stripObjCKindOfTypeAndQuals(ctx); return ctx.getObjCObjectPointerType(obj)->castAs(); } namespace { /// Visitor used to perform a simple type transformation that does not change /// the semantics of the type. template struct SimpleTransformVisitor : public TypeVisitor { ASTContext &Ctx; QualType recurse(QualType type) { // Split out the qualifiers from the type. SplitQualType splitType = type.split(); // Visit the type itself. QualType result = static_cast(this)->Visit(splitType.Ty); if (result.isNull()) return result; // Reconstruct the transformed type by applying the local qualifiers // from the split type. return Ctx.getQualifiedType(result, splitType.Quals); } public: explicit SimpleTransformVisitor(ASTContext &ctx) : Ctx(ctx) {} // None of the clients of this transformation can occur where // there are dependent types, so skip dependent types. #define TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) \ QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); } #include "clang/AST/TypeNodes.inc" #define TRIVIAL_TYPE_CLASS(Class) \ QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); } #define SUGARED_TYPE_CLASS(Class) \ QualType Visit##Class##Type(const Class##Type *T) { \ if (!T->isSugared()) \ return QualType(T, 0); \ QualType desugaredType = recurse(T->desugar()); \ if (desugaredType.isNull()) \ return {}; \ if (desugaredType.getAsOpaquePtr() == T->desugar().getAsOpaquePtr()) \ return QualType(T, 0); \ return desugaredType; \ } TRIVIAL_TYPE_CLASS(Builtin) QualType VisitComplexType(const ComplexType *T) { QualType elementType = recurse(T->getElementType()); if (elementType.isNull()) return {}; if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getComplexType(elementType); } QualType VisitPointerType(const PointerType *T) { QualType pointeeType = recurse(T->getPointeeType()); if (pointeeType.isNull()) return {}; if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getPointerType(pointeeType); } QualType VisitBlockPointerType(const BlockPointerType *T) { QualType pointeeType = recurse(T->getPointeeType()); if (pointeeType.isNull()) return {}; if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getBlockPointerType(pointeeType); } QualType VisitLValueReferenceType(const LValueReferenceType *T) { QualType pointeeType = recurse(T->getPointeeTypeAsWritten()); if (pointeeType.isNull()) return {}; if (pointeeType.getAsOpaquePtr() == T->getPointeeTypeAsWritten().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getLValueReferenceType(pointeeType, T->isSpelledAsLValue()); } QualType VisitRValueReferenceType(const RValueReferenceType *T) { QualType pointeeType = recurse(T->getPointeeTypeAsWritten()); if (pointeeType.isNull()) return {}; if (pointeeType.getAsOpaquePtr() == T->getPointeeTypeAsWritten().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getRValueReferenceType(pointeeType); } QualType VisitMemberPointerType(const MemberPointerType *T) { QualType pointeeType = recurse(T->getPointeeType()); if (pointeeType.isNull()) return {}; if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getMemberPointerType(pointeeType, T->getClass()); } QualType VisitConstantArrayType(const ConstantArrayType *T) { QualType elementType = recurse(T->getElementType()); if (elementType.isNull()) return {}; if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getConstantArrayType(elementType, T->getSize(), T->getSizeExpr(), T->getSizeModifier(), T->getIndexTypeCVRQualifiers()); } QualType VisitVariableArrayType(const VariableArrayType *T) { QualType elementType = recurse(T->getElementType()); if (elementType.isNull()) return {}; if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getVariableArrayType(elementType, T->getSizeExpr(), T->getSizeModifier(), T->getIndexTypeCVRQualifiers(), T->getBracketsRange()); } QualType VisitIncompleteArrayType(const IncompleteArrayType *T) { QualType elementType = recurse(T->getElementType()); if (elementType.isNull()) return {}; if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getIncompleteArrayType(elementType, T->getSizeModifier(), T->getIndexTypeCVRQualifiers()); } QualType VisitVectorType(const VectorType *T) { QualType elementType = recurse(T->getElementType()); if (elementType.isNull()) return {}; if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getVectorType(elementType, T->getNumElements(), T->getVectorKind()); } QualType VisitExtVectorType(const ExtVectorType *T) { QualType elementType = recurse(T->getElementType()); if (elementType.isNull()) return {}; if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getExtVectorType(elementType, T->getNumElements()); } QualType VisitConstantMatrixType(const ConstantMatrixType *T) { QualType elementType = recurse(T->getElementType()); if (elementType.isNull()) return {}; if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getConstantMatrixType(elementType, T->getNumRows(), T->getNumColumns()); } QualType VisitFunctionNoProtoType(const FunctionNoProtoType *T) { QualType returnType = recurse(T->getReturnType()); if (returnType.isNull()) return {}; if (returnType.getAsOpaquePtr() == T->getReturnType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getFunctionNoProtoType(returnType, T->getExtInfo()); } QualType VisitFunctionProtoType(const FunctionProtoType *T) { QualType returnType = recurse(T->getReturnType()); if (returnType.isNull()) return {}; // Transform parameter types. SmallVector paramTypes; bool paramChanged = false; for (auto paramType : T->getParamTypes()) { QualType newParamType = recurse(paramType); if (newParamType.isNull()) return {}; if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr()) paramChanged = true; paramTypes.push_back(newParamType); } // Transform extended info. FunctionProtoType::ExtProtoInfo info = T->getExtProtoInfo(); bool exceptionChanged = false; if (info.ExceptionSpec.Type == EST_Dynamic) { SmallVector exceptionTypes; for (auto exceptionType : info.ExceptionSpec.Exceptions) { QualType newExceptionType = recurse(exceptionType); if (newExceptionType.isNull()) return {}; if (newExceptionType.getAsOpaquePtr() != exceptionType.getAsOpaquePtr()) exceptionChanged = true; exceptionTypes.push_back(newExceptionType); } if (exceptionChanged) { info.ExceptionSpec.Exceptions = llvm::makeArrayRef(exceptionTypes).copy(Ctx); } } if (returnType.getAsOpaquePtr() == T->getReturnType().getAsOpaquePtr() && !paramChanged && !exceptionChanged) return QualType(T, 0); return Ctx.getFunctionType(returnType, paramTypes, info); } QualType VisitParenType(const ParenType *T) { QualType innerType = recurse(T->getInnerType()); if (innerType.isNull()) return {}; if (innerType.getAsOpaquePtr() == T->getInnerType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getParenType(innerType); } SUGARED_TYPE_CLASS(Typedef) SUGARED_TYPE_CLASS(ObjCTypeParam) SUGARED_TYPE_CLASS(MacroQualified) QualType VisitAdjustedType(const AdjustedType *T) { QualType originalType = recurse(T->getOriginalType()); if (originalType.isNull()) return {}; QualType adjustedType = recurse(T->getAdjustedType()); if (adjustedType.isNull()) return {}; if (originalType.getAsOpaquePtr() == T->getOriginalType().getAsOpaquePtr() && adjustedType.getAsOpaquePtr() == T->getAdjustedType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getAdjustedType(originalType, adjustedType); } QualType VisitDecayedType(const DecayedType *T) { QualType originalType = recurse(T->getOriginalType()); if (originalType.isNull()) return {}; if (originalType.getAsOpaquePtr() == T->getOriginalType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getDecayedType(originalType); } SUGARED_TYPE_CLASS(TypeOfExpr) SUGARED_TYPE_CLASS(TypeOf) SUGARED_TYPE_CLASS(Decltype) SUGARED_TYPE_CLASS(UnaryTransform) TRIVIAL_TYPE_CLASS(Record) TRIVIAL_TYPE_CLASS(Enum) // FIXME: Non-trivial to implement, but important for C++ SUGARED_TYPE_CLASS(Elaborated) QualType VisitAttributedType(const AttributedType *T) { QualType modifiedType = recurse(T->getModifiedType()); if (modifiedType.isNull()) return {}; QualType equivalentType = recurse(T->getEquivalentType()); if (equivalentType.isNull()) return {}; if (modifiedType.getAsOpaquePtr() == T->getModifiedType().getAsOpaquePtr() && equivalentType.getAsOpaquePtr() == T->getEquivalentType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getAttributedType(T->getAttrKind(), modifiedType, equivalentType); } QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { QualType replacementType = recurse(T->getReplacementType()); if (replacementType.isNull()) return {}; if (replacementType.getAsOpaquePtr() == T->getReplacementType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getSubstTemplateTypeParmType(T->getReplacedParameter(), replacementType); } // FIXME: Non-trivial to implement, but important for C++ SUGARED_TYPE_CLASS(TemplateSpecialization) QualType VisitAutoType(const AutoType *T) { if (!T->isDeduced()) return QualType(T, 0); QualType deducedType = recurse(T->getDeducedType()); if (deducedType.isNull()) return {}; if (deducedType.getAsOpaquePtr() == T->getDeducedType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getAutoType(deducedType, T->getKeyword(), T->isDependentType(), /*IsPack=*/false, T->getTypeConstraintConcept(), T->getTypeConstraintArguments()); } QualType VisitObjCObjectType(const ObjCObjectType *T) { QualType baseType = recurse(T->getBaseType()); if (baseType.isNull()) return {}; // Transform type arguments. bool typeArgChanged = false; SmallVector typeArgs; for (auto typeArg : T->getTypeArgsAsWritten()) { QualType newTypeArg = recurse(typeArg); if (newTypeArg.isNull()) return {}; if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) typeArgChanged = true; typeArgs.push_back(newTypeArg); } if (baseType.getAsOpaquePtr() == T->getBaseType().getAsOpaquePtr() && !typeArgChanged) return QualType(T, 0); return Ctx.getObjCObjectType(baseType, typeArgs, llvm::makeArrayRef(T->qual_begin(), T->getNumProtocols()), T->isKindOfTypeAsWritten()); } TRIVIAL_TYPE_CLASS(ObjCInterface) QualType VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { QualType pointeeType = recurse(T->getPointeeType()); if (pointeeType.isNull()) return {}; if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getObjCObjectPointerType(pointeeType); } QualType VisitAtomicType(const AtomicType *T) { QualType valueType = recurse(T->getValueType()); if (valueType.isNull()) return {}; if (valueType.getAsOpaquePtr() == T->getValueType().getAsOpaquePtr()) return QualType(T, 0); return Ctx.getAtomicType(valueType); } #undef TRIVIAL_TYPE_CLASS #undef SUGARED_TYPE_CLASS }; struct SubstObjCTypeArgsVisitor : public SimpleTransformVisitor { using BaseType = SimpleTransformVisitor; ArrayRef TypeArgs; ObjCSubstitutionContext SubstContext; SubstObjCTypeArgsVisitor(ASTContext &ctx, ArrayRef typeArgs, ObjCSubstitutionContext context) : BaseType(ctx), TypeArgs(typeArgs), SubstContext(context) {} QualType VisitObjCTypeParamType(const ObjCTypeParamType *OTPTy) { // Replace an Objective-C type parameter reference with the corresponding // type argument. ObjCTypeParamDecl *typeParam = OTPTy->getDecl(); // If we have type arguments, use them. if (!TypeArgs.empty()) { QualType argType = TypeArgs[typeParam->getIndex()]; if (OTPTy->qual_empty()) return argType; // Apply protocol lists if exists. bool hasError; SmallVector protocolsVec; protocolsVec.append(OTPTy->qual_begin(), OTPTy->qual_end()); ArrayRef protocolsToApply = protocolsVec; return Ctx.applyObjCProtocolQualifiers( argType, protocolsToApply, hasError, true/*allowOnPointerType*/); } switch (SubstContext) { case ObjCSubstitutionContext::Ordinary: case ObjCSubstitutionContext::Parameter: case ObjCSubstitutionContext::Superclass: // Substitute the bound. return typeParam->getUnderlyingType(); case ObjCSubstitutionContext::Result: case ObjCSubstitutionContext::Property: { // Substitute the __kindof form of the underlying type. const auto *objPtr = typeParam->getUnderlyingType()->castAs(); // __kindof types, id, and Class don't need an additional // __kindof. if (objPtr->isKindOfType() || objPtr->isObjCIdOrClassType()) return typeParam->getUnderlyingType(); // Add __kindof. const auto *obj = objPtr->getObjectType(); QualType resultTy = Ctx.getObjCObjectType( obj->getBaseType(), obj->getTypeArgsAsWritten(), obj->getProtocols(), /*isKindOf=*/true); // Rebuild object pointer type. return Ctx.getObjCObjectPointerType(resultTy); } } llvm_unreachable("Unexpected ObjCSubstitutionContext!"); } QualType VisitFunctionType(const FunctionType *funcType) { // If we have a function type, update the substitution context // appropriately. //Substitute result type. QualType returnType = funcType->getReturnType().substObjCTypeArgs( Ctx, TypeArgs, ObjCSubstitutionContext::Result); if (returnType.isNull()) return {}; // Handle non-prototyped functions, which only substitute into the result // type. if (isa(funcType)) { // If the return type was unchanged, do nothing. if (returnType.getAsOpaquePtr() == funcType->getReturnType().getAsOpaquePtr()) return BaseType::VisitFunctionType(funcType); // Otherwise, build a new type. return Ctx.getFunctionNoProtoType(returnType, funcType->getExtInfo()); } const auto *funcProtoType = cast(funcType); // Transform parameter types. SmallVector paramTypes; bool paramChanged = false; for (auto paramType : funcProtoType->getParamTypes()) { QualType newParamType = paramType.substObjCTypeArgs( Ctx, TypeArgs, ObjCSubstitutionContext::Parameter); if (newParamType.isNull()) return {}; if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr()) paramChanged = true; paramTypes.push_back(newParamType); } // Transform extended info. FunctionProtoType::ExtProtoInfo info = funcProtoType->getExtProtoInfo(); bool exceptionChanged = false; if (info.ExceptionSpec.Type == EST_Dynamic) { SmallVector exceptionTypes; for (auto exceptionType : info.ExceptionSpec.Exceptions) { QualType newExceptionType = exceptionType.substObjCTypeArgs( Ctx, TypeArgs, ObjCSubstitutionContext::Ordinary); if (newExceptionType.isNull()) return {}; if (newExceptionType.getAsOpaquePtr() != exceptionType.getAsOpaquePtr()) exceptionChanged = true; exceptionTypes.push_back(newExceptionType); } if (exceptionChanged) { info.ExceptionSpec.Exceptions = llvm::makeArrayRef(exceptionTypes).copy(Ctx); } } if (returnType.getAsOpaquePtr() == funcProtoType->getReturnType().getAsOpaquePtr() && !paramChanged && !exceptionChanged) return BaseType::VisitFunctionType(funcType); return Ctx.getFunctionType(returnType, paramTypes, info); } QualType VisitObjCObjectType(const ObjCObjectType *objcObjectType) { // Substitute into the type arguments of a specialized Objective-C object // type. if (objcObjectType->isSpecializedAsWritten()) { SmallVector newTypeArgs; bool anyChanged = false; for (auto typeArg : objcObjectType->getTypeArgsAsWritten()) { QualType newTypeArg = typeArg.substObjCTypeArgs( Ctx, TypeArgs, ObjCSubstitutionContext::Ordinary); if (newTypeArg.isNull()) return {}; if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) { // If we're substituting based on an unspecialized context type, // produce an unspecialized type. ArrayRef protocols( objcObjectType->qual_begin(), objcObjectType->getNumProtocols()); if (TypeArgs.empty() && SubstContext != ObjCSubstitutionContext::Superclass) { return Ctx.getObjCObjectType( objcObjectType->getBaseType(), {}, protocols, objcObjectType->isKindOfTypeAsWritten()); } anyChanged = true; } newTypeArgs.push_back(newTypeArg); } if (anyChanged) { ArrayRef protocols( objcObjectType->qual_begin(), objcObjectType->getNumProtocols()); return Ctx.getObjCObjectType(objcObjectType->getBaseType(), newTypeArgs, protocols, objcObjectType->isKindOfTypeAsWritten()); } } return BaseType::VisitObjCObjectType(objcObjectType); } QualType VisitAttributedType(const AttributedType *attrType) { QualType newType = BaseType::VisitAttributedType(attrType); if (newType.isNull()) return {}; const auto *newAttrType = dyn_cast(newType.getTypePtr()); if (!newAttrType || newAttrType->getAttrKind() != attr::ObjCKindOf) return newType; // Find out if it's an Objective-C object or object pointer type; QualType newEquivType = newAttrType->getEquivalentType(); const ObjCObjectPointerType *ptrType = newEquivType->getAs(); const ObjCObjectType *objType = ptrType ? ptrType->getObjectType() : newEquivType->getAs(); if (!objType) return newType; // Rebuild the "equivalent" type, which pushes __kindof down into // the object type. newEquivType = Ctx.getObjCObjectType( objType->getBaseType(), objType->getTypeArgsAsWritten(), objType->getProtocols(), // There is no need to apply kindof on an unqualified id type. /*isKindOf=*/objType->isObjCUnqualifiedId() ? false : true); // If we started with an object pointer type, rebuild it. if (ptrType) newEquivType = Ctx.getObjCObjectPointerType(newEquivType); // Rebuild the attributed type. return Ctx.getAttributedType(newAttrType->getAttrKind(), newAttrType->getModifiedType(), newEquivType); } }; struct StripObjCKindOfTypeVisitor : public SimpleTransformVisitor { using BaseType = SimpleTransformVisitor; explicit StripObjCKindOfTypeVisitor(ASTContext &ctx) : BaseType(ctx) {} QualType VisitObjCObjectType(const ObjCObjectType *objType) { if (!objType->isKindOfType()) return BaseType::VisitObjCObjectType(objType); QualType baseType = objType->getBaseType().stripObjCKindOfType(Ctx); return Ctx.getObjCObjectType(baseType, objType->getTypeArgsAsWritten(), objType->getProtocols(), /*isKindOf=*/false); } }; } // namespace /// Substitute the given type arguments for Objective-C type /// parameters within the given type, recursively. QualType QualType::substObjCTypeArgs(ASTContext &ctx, ArrayRef typeArgs, ObjCSubstitutionContext context) const { SubstObjCTypeArgsVisitor visitor(ctx, typeArgs, context); return visitor.recurse(*this); } QualType QualType::substObjCMemberType(QualType objectType, const DeclContext *dc, ObjCSubstitutionContext context) const { if (auto subs = objectType->getObjCSubstitutions(dc)) return substObjCTypeArgs(dc->getParentASTContext(), *subs, context); return *this; } QualType QualType::stripObjCKindOfType(const ASTContext &constCtx) const { // FIXME: Because ASTContext::getAttributedType() is non-const. auto &ctx = const_cast(constCtx); StripObjCKindOfTypeVisitor visitor(ctx); return visitor.recurse(*this); } QualType QualType::getAtomicUnqualifiedType() const { if (const auto AT = getTypePtr()->getAs()) return AT->getValueType().getUnqualifiedType(); return getUnqualifiedType(); } Optional> Type::getObjCSubstitutions( const DeclContext *dc) const { // Look through method scopes. if (const auto method = dyn_cast(dc)) dc = method->getDeclContext(); // Find the class or category in which the type we're substituting // was declared. const auto *dcClassDecl = dyn_cast(dc); const ObjCCategoryDecl *dcCategoryDecl = nullptr; ObjCTypeParamList *dcTypeParams = nullptr; if (dcClassDecl) { // If the class does not have any type parameters, there's no // substitution to do. dcTypeParams = dcClassDecl->getTypeParamList(); if (!dcTypeParams) return None; } else { // If we are in neither a class nor a category, there's no // substitution to perform. dcCategoryDecl = dyn_cast(dc); if (!dcCategoryDecl) return None; // If the category does not have any type parameters, there's no // substitution to do. dcTypeParams = dcCategoryDecl->getTypeParamList(); if (!dcTypeParams) return None; dcClassDecl = dcCategoryDecl->getClassInterface(); if (!dcClassDecl) return None; } assert(dcTypeParams && "No substitutions to perform"); assert(dcClassDecl && "No class context"); // Find the underlying object type. const ObjCObjectType *objectType; if (const auto *objectPointerType = getAs()) { objectType = objectPointerType->getObjectType(); } else if (getAs()) { ASTContext &ctx = dc->getParentASTContext(); objectType = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, {}, {}) ->castAs(); } else { objectType = getAs(); } /// Extract the class from the receiver object type. ObjCInterfaceDecl *curClassDecl = objectType ? objectType->getInterface() : nullptr; if (!curClassDecl) { // If we don't have a context type (e.g., this is "id" or some // variant thereof), substitute the bounds. return llvm::ArrayRef(); } // Follow the superclass chain until we've mapped the receiver type // to the same class as the context. while (curClassDecl != dcClassDecl) { // Map to the superclass type. QualType superType = objectType->getSuperClassType(); if (superType.isNull()) { objectType = nullptr; break; } objectType = superType->castAs(); curClassDecl = objectType->getInterface(); } // If we don't have a receiver type, or the receiver type does not // have type arguments, substitute in the defaults. if (!objectType || objectType->isUnspecialized()) { return llvm::ArrayRef(); } // The receiver type has the type arguments we want. return objectType->getTypeArgs(); } bool Type::acceptsObjCTypeParams() const { if (auto *IfaceT = getAsObjCInterfaceType()) { if (auto *ID = IfaceT->getInterface()) { if (ID->getTypeParamList()) return true; } } return false; } void ObjCObjectType::computeSuperClassTypeSlow() const { // Retrieve the class declaration for this type. If there isn't one // (e.g., this is some variant of "id" or "Class"), then there is no // superclass type. ObjCInterfaceDecl *classDecl = getInterface(); if (!classDecl) { CachedSuperClassType.setInt(true); return; } // Extract the superclass type. const ObjCObjectType *superClassObjTy = classDecl->getSuperClassType(); if (!superClassObjTy) { CachedSuperClassType.setInt(true); return; } ObjCInterfaceDecl *superClassDecl = superClassObjTy->getInterface(); if (!superClassDecl) { CachedSuperClassType.setInt(true); return; } // If the superclass doesn't have type parameters, then there is no // substitution to perform. QualType superClassType(superClassObjTy, 0); ObjCTypeParamList *superClassTypeParams = superClassDecl->getTypeParamList(); if (!superClassTypeParams) { CachedSuperClassType.setPointerAndInt( superClassType->castAs(), true); return; } // If the superclass reference is unspecialized, return it. if (superClassObjTy->isUnspecialized()) { CachedSuperClassType.setPointerAndInt(superClassObjTy, true); return; } // If the subclass is not parameterized, there aren't any type // parameters in the superclass reference to substitute. ObjCTypeParamList *typeParams = classDecl->getTypeParamList(); if (!typeParams) { CachedSuperClassType.setPointerAndInt( superClassType->castAs(), true); return; } // If the subclass type isn't specialized, return the unspecialized // superclass. if (isUnspecialized()) { QualType unspecializedSuper = classDecl->getASTContext().getObjCInterfaceType( superClassObjTy->getInterface()); CachedSuperClassType.setPointerAndInt( unspecializedSuper->castAs(), true); return; } // Substitute the provided type arguments into the superclass type. ArrayRef typeArgs = getTypeArgs(); assert(typeArgs.size() == typeParams->size()); CachedSuperClassType.setPointerAndInt( superClassType.substObjCTypeArgs(classDecl->getASTContext(), typeArgs, ObjCSubstitutionContext::Superclass) ->castAs(), true); } const ObjCInterfaceType *ObjCObjectPointerType::getInterfaceType() const { if (auto interfaceDecl = getObjectType()->getInterface()) { return interfaceDecl->getASTContext().getObjCInterfaceType(interfaceDecl) ->castAs(); } return nullptr; } QualType ObjCObjectPointerType::getSuperClassType() const { QualType superObjectType = getObjectType()->getSuperClassType(); if (superObjectType.isNull()) return superObjectType; ASTContext &ctx = getInterfaceDecl()->getASTContext(); return ctx.getObjCObjectPointerType(superObjectType); } const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const { // There is no sugar for ObjCObjectType's, just return the canonical // type pointer if it is the right class. There is no typedef information to // return and these cannot be Address-space qualified. if (const auto *T = getAs()) if (T->getNumProtocols() && T->getInterface()) return T; return nullptr; } bool Type::isObjCQualifiedInterfaceType() const { return getAsObjCQualifiedInterfaceType() != nullptr; } const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const { // There is no sugar for ObjCQualifiedIdType's, just return the canonical // type pointer if it is the right class. if (const auto *OPT = getAs()) { if (OPT->isObjCQualifiedIdType()) return OPT; } return nullptr; } const ObjCObjectPointerType *Type::getAsObjCQualifiedClassType() const { // There is no sugar for ObjCQualifiedClassType's, just return the canonical // type pointer if it is the right class. if (const auto *OPT = getAs()) { if (OPT->isObjCQualifiedClassType()) return OPT; } return nullptr; } const ObjCObjectType *Type::getAsObjCInterfaceType() const { if (const auto *OT = getAs()) { if (OT->getInterface()) return OT; } return nullptr; } const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { if (const auto *OPT = getAs()) { if (OPT->getInterfaceType()) return OPT; } return nullptr; } const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const { QualType PointeeType; if (const auto *PT = getAs()) PointeeType = PT->getPointeeType(); else if (const auto *RT = getAs()) PointeeType = RT->getPointeeType(); else return nullptr; if (const auto *RT = PointeeType->getAs()) return dyn_cast(RT->getDecl()); return nullptr; } CXXRecordDecl *Type::getAsCXXRecordDecl() const { return dyn_cast_or_null(getAsTagDecl()); } RecordDecl *Type::getAsRecordDecl() const { return dyn_cast_or_null(getAsTagDecl()); } TagDecl *Type::getAsTagDecl() const { if (const auto *TT = getAs()) return TT->getDecl(); if (const auto *Injected = getAs()) return Injected->getDecl(); return nullptr; } bool Type::hasAttr(attr::Kind AK) const { const Type *Cur = this; while (const auto *AT = Cur->getAs()) { if (AT->getAttrKind() == AK) return true; Cur = AT->getEquivalentType().getTypePtr(); } return false; } namespace { class GetContainedDeducedTypeVisitor : public TypeVisitor { bool Syntactic; public: GetContainedDeducedTypeVisitor(bool Syntactic = false) : Syntactic(Syntactic) {} using TypeVisitor::Visit; Type *Visit(QualType T) { if (T.isNull()) return nullptr; return Visit(T.getTypePtr()); } // The deduced type itself. Type *VisitDeducedType(const DeducedType *AT) { return const_cast(AT); } // Only these types can contain the desired 'auto' type. Type *VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { return Visit(T->getReplacementType()); } Type *VisitElaboratedType(const ElaboratedType *T) { return Visit(T->getNamedType()); } Type *VisitPointerType(const PointerType *T) { return Visit(T->getPointeeType()); } Type *VisitBlockPointerType(const BlockPointerType *T) { return Visit(T->getPointeeType()); } Type *VisitReferenceType(const ReferenceType *T) { return Visit(T->getPointeeTypeAsWritten()); } Type *VisitMemberPointerType(const MemberPointerType *T) { return Visit(T->getPointeeType()); } Type *VisitArrayType(const ArrayType *T) { return Visit(T->getElementType()); } Type *VisitDependentSizedExtVectorType( const DependentSizedExtVectorType *T) { return Visit(T->getElementType()); } Type *VisitVectorType(const VectorType *T) { return Visit(T->getElementType()); } Type *VisitDependentSizedMatrixType(const DependentSizedMatrixType *T) { return Visit(T->getElementType()); } Type *VisitConstantMatrixType(const ConstantMatrixType *T) { return Visit(T->getElementType()); } Type *VisitFunctionProtoType(const FunctionProtoType *T) { if (Syntactic && T->hasTrailingReturn()) return const_cast(T); return VisitFunctionType(T); } Type *VisitFunctionType(const FunctionType *T) { return Visit(T->getReturnType()); } Type *VisitParenType(const ParenType *T) { return Visit(T->getInnerType()); } Type *VisitAttributedType(const AttributedType *T) { return Visit(T->getModifiedType()); } Type *VisitMacroQualifiedType(const MacroQualifiedType *T) { return Visit(T->getUnderlyingType()); } Type *VisitAdjustedType(const AdjustedType *T) { return Visit(T->getOriginalType()); } Type *VisitPackExpansionType(const PackExpansionType *T) { return Visit(T->getPattern()); } }; } // namespace DeducedType *Type::getContainedDeducedType() const { return cast_or_null( GetContainedDeducedTypeVisitor().Visit(this)); } bool Type::hasAutoForTrailingReturnType() const { return isa_and_nonnull( GetContainedDeducedTypeVisitor(true).Visit(this)); } bool Type::hasIntegerRepresentation() const { if (const auto *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isIntegerType(); else return isIntegerType(); } /// Determine whether this type is an integral type. /// /// This routine determines whether the given type is an integral type per /// C++ [basic.fundamental]p7. Although the C standard does not define the /// term "integral type", it has a similar term "integer type", and in C++ /// the two terms are equivalent. However, C's "integer type" includes /// enumeration types, while C++'s "integer type" does not. The \c ASTContext /// parameter is used to determine whether we should be following the C or /// C++ rules when determining whether this type is an integral/integer type. /// /// For cases where C permits "an integer type" and C++ permits "an integral /// type", use this routine. /// /// For cases where C permits "an integer type" and C++ permits "an integral /// or enumeration type", use \c isIntegralOrEnumerationType() instead. /// /// \param Ctx The context in which this type occurs. /// /// \returns true if the type is considered an integral type, false otherwise. bool Type::isIntegralType(const ASTContext &Ctx) const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Int128; // Complete enum types are integral in C. if (!Ctx.getLangOpts().CPlusPlus) if (const auto *ET = dyn_cast(CanonicalType)) return ET->getDecl()->isComplete(); return isBitIntType(); } bool Type::isIntegralOrUnscopedEnumerationType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Int128; if (isBitIntType()) return true; return isUnscopedEnumerationType(); } bool Type::isUnscopedEnumerationType() const { if (const auto *ET = dyn_cast(CanonicalType)) return !ET->getDecl()->isScoped(); return false; } bool Type::isCharType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Char_U || BT->getKind() == BuiltinType::UChar || BT->getKind() == BuiltinType::Char_S || BT->getKind() == BuiltinType::SChar; return false; } bool Type::isWideCharType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::WChar_S || BT->getKind() == BuiltinType::WChar_U; return false; } bool Type::isChar8Type() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Char8; return false; } bool Type::isChar16Type() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Char16; return false; } bool Type::isChar32Type() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Char32; return false; } /// Determine whether this type is any of the built-in character /// types. bool Type::isAnyCharacterType() const { const auto *BT = dyn_cast(CanonicalType); if (!BT) return false; switch (BT->getKind()) { default: return false; case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::WChar_U: case BuiltinType::Char8: case BuiltinType::Char16: case BuiltinType::Char32: case BuiltinType::Char_S: case BuiltinType::SChar: case BuiltinType::WChar_S: return true; } } /// isSignedIntegerType - Return true if this is an integer type that is /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], /// an enum decl which has a signed representation bool Type::isSignedIntegerType() const { if (const auto *BT = dyn_cast(CanonicalType)) { return BT->getKind() >= BuiltinType::Char_S && BT->getKind() <= BuiltinType::Int128; } if (const EnumType *ET = dyn_cast(CanonicalType)) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped()) return ET->getDecl()->getIntegerType()->isSignedIntegerType(); } if (const auto *IT = dyn_cast(CanonicalType)) return IT->isSigned(); if (const auto *IT = dyn_cast(CanonicalType)) return IT->isSigned(); return false; } bool Type::isSignedIntegerOrEnumerationType() const { if (const auto *BT = dyn_cast(CanonicalType)) { return BT->getKind() >= BuiltinType::Char_S && BT->getKind() <= BuiltinType::Int128; } if (const auto *ET = dyn_cast(CanonicalType)) { if (ET->getDecl()->isComplete()) return ET->getDecl()->getIntegerType()->isSignedIntegerType(); } if (const auto *IT = dyn_cast(CanonicalType)) return IT->isSigned(); if (const auto *IT = dyn_cast(CanonicalType)) return IT->isSigned(); return false; } bool Type::hasSignedIntegerRepresentation() const { if (const auto *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isSignedIntegerOrEnumerationType(); else return isSignedIntegerOrEnumerationType(); } /// isUnsignedIntegerType - Return true if this is an integer type that is /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], an enum /// decl which has an unsigned representation bool Type::isUnsignedIntegerType() const { if (const auto *BT = dyn_cast(CanonicalType)) { return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::UInt128; } if (const auto *ET = dyn_cast(CanonicalType)) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped()) return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); } if (const auto *IT = dyn_cast(CanonicalType)) return IT->isUnsigned(); if (const auto *IT = dyn_cast(CanonicalType)) return IT->isUnsigned(); return false; } bool Type::isUnsignedIntegerOrEnumerationType() const { if (const auto *BT = dyn_cast(CanonicalType)) { return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::UInt128; } if (const auto *ET = dyn_cast(CanonicalType)) { if (ET->getDecl()->isComplete()) return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); } if (const auto *IT = dyn_cast(CanonicalType)) return IT->isUnsigned(); if (const auto *IT = dyn_cast(CanonicalType)) return IT->isUnsigned(); return false; } bool Type::hasUnsignedIntegerRepresentation() const { if (const auto *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isUnsignedIntegerOrEnumerationType(); if (const auto *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isUnsignedIntegerOrEnumerationType(); return isUnsignedIntegerOrEnumerationType(); } bool Type::isFloatingType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Half && BT->getKind() <= BuiltinType::Ibm128; if (const auto *CT = dyn_cast(CanonicalType)) return CT->getElementType()->isFloatingType(); return false; } bool Type::hasFloatingRepresentation() const { if (const auto *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isFloatingType(); else return isFloatingType(); } bool Type::isRealFloatingType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->isFloatingPoint(); return false; } bool Type::isRealType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Ibm128; if (const auto *ET = dyn_cast(CanonicalType)) return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); return isBitIntType(); } bool Type::isArithmeticType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Ibm128 && BT->getKind() != BuiltinType::BFloat16; if (const auto *ET = dyn_cast(CanonicalType)) // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2). // If a body isn't seen by the time we get here, return false. // // C++0x: Enumerations are not arithmetic types. For now, just return // false for scoped enumerations since that will disable any // unwanted implicit conversions. return !ET->getDecl()->isScoped() && ET->getDecl()->isComplete(); return isa(CanonicalType) || isBitIntType(); } Type::ScalarTypeKind Type::getScalarTypeKind() const { assert(isScalarType()); const Type *T = CanonicalType.getTypePtr(); if (const auto *BT = dyn_cast(T)) { if (BT->getKind() == BuiltinType::Bool) return STK_Bool; if (BT->getKind() == BuiltinType::NullPtr) return STK_CPointer; if (BT->isInteger()) return STK_Integral; if (BT->isFloatingPoint()) return STK_Floating; if (BT->isFixedPointType()) return STK_FixedPoint; llvm_unreachable("unknown scalar builtin type"); } else if (isa(T)) { return STK_CPointer; } else if (isa(T)) { return STK_BlockPointer; } else if (isa(T)) { return STK_ObjCObjectPointer; } else if (isa(T)) { return STK_MemberPointer; } else if (isa(T)) { assert(cast(T)->getDecl()->isComplete()); return STK_Integral; } else if (const auto *CT = dyn_cast(T)) { if (CT->getElementType()->isRealFloatingType()) return STK_FloatingComplex; return STK_IntegralComplex; } else if (isBitIntType()) { return STK_Integral; } llvm_unreachable("unknown scalar type"); } /// Determines whether the type is a C++ aggregate type or C /// aggregate or union type. /// /// An aggregate type is an array or a class type (struct, union, or /// class) that has no user-declared constructors, no private or /// protected non-static data members, no base classes, and no virtual /// functions (C++ [dcl.init.aggr]p1). The notion of an aggregate type /// subsumes the notion of C aggregates (C99 6.2.5p21) because it also /// includes union types. bool Type::isAggregateType() const { if (const auto *Record = dyn_cast(CanonicalType)) { if (const auto *ClassDecl = dyn_cast(Record->getDecl())) return ClassDecl->isAggregate(); return true; } return isa(CanonicalType); } /// isConstantSizeType - Return true if this is not a variable sized type, /// according to the rules of C99 6.7.5p3. It is not legal to call this on /// incomplete types or dependent types. bool Type::isConstantSizeType() const { assert(!isIncompleteType() && "This doesn't make sense for incomplete types"); assert(!isDependentType() && "This doesn't make sense for dependent types"); // The VAT must have a size, as it is known to be complete. return !isa(CanonicalType); } /// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1) /// - a type that can describe objects, but which lacks information needed to /// determine its size. bool Type::isIncompleteType(NamedDecl **Def) const { if (Def) *Def = nullptr; switch (CanonicalType->getTypeClass()) { default: return false; case Builtin: // Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never // be completed. return isVoidType(); case Enum: { EnumDecl *EnumD = cast(CanonicalType)->getDecl(); if (Def) *Def = EnumD; return !EnumD->isComplete(); } case Record: { // A tagged type (struct/union/enum/class) is incomplete if the decl is a // forward declaration, but not a full definition (C99 6.2.5p22). RecordDecl *Rec = cast(CanonicalType)->getDecl(); if (Def) *Def = Rec; return !Rec->isCompleteDefinition(); } case ConstantArray: case VariableArray: // An array is incomplete if its element type is incomplete // (C++ [dcl.array]p1). // We don't handle dependent-sized arrays (dependent types are never treated // as incomplete). return cast(CanonicalType)->getElementType() ->isIncompleteType(Def); case IncompleteArray: // An array of unknown size is an incomplete type (C99 6.2.5p22). return true; case MemberPointer: { // Member pointers in the MS ABI have special behavior in // RequireCompleteType: they attach a MSInheritanceAttr to the CXXRecordDecl // to indicate which inheritance model to use. auto *MPTy = cast(CanonicalType); const Type *ClassTy = MPTy->getClass(); // Member pointers with dependent class types don't get special treatment. if (ClassTy->isDependentType()) return false; const CXXRecordDecl *RD = ClassTy->getAsCXXRecordDecl(); ASTContext &Context = RD->getASTContext(); // Member pointers not in the MS ABI don't get special treatment. if (!Context.getTargetInfo().getCXXABI().isMicrosoft()) return false; // The inheritance attribute might only be present on the most recent // CXXRecordDecl, use that one. RD = RD->getMostRecentNonInjectedDecl(); // Nothing interesting to do if the inheritance attribute is already set. if (RD->hasAttr()) return false; return true; } case ObjCObject: return cast(CanonicalType)->getBaseType() ->isIncompleteType(Def); case ObjCInterface: { // ObjC interfaces are incomplete if they are @class, not @interface. ObjCInterfaceDecl *Interface = cast(CanonicalType)->getDecl(); if (Def) *Def = Interface; return !Interface->hasDefinition(); } } } bool Type::isSizelessBuiltinType() const { if (const BuiltinType *BT = getAs()) { switch (BT->getKind()) { // SVE Types #define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/AArch64SVEACLETypes.def" #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/RISCVVTypes.def" return true; default: return false; } } return false; } bool Type::isSizelessType() const { return isSizelessBuiltinType(); } bool Type::isVLSTBuiltinType() const { if (const BuiltinType *BT = getAs()) { switch (BT->getKind()) { case BuiltinType::SveInt8: case BuiltinType::SveInt16: case BuiltinType::SveInt32: case BuiltinType::SveInt64: case BuiltinType::SveUint8: case BuiltinType::SveUint16: case BuiltinType::SveUint32: case BuiltinType::SveUint64: case BuiltinType::SveFloat16: case BuiltinType::SveFloat32: case BuiltinType::SveFloat64: case BuiltinType::SveBFloat16: case BuiltinType::SveBool: return true; default: return false; } } return false; } QualType Type::getSveEltType(const ASTContext &Ctx) const { assert(isVLSTBuiltinType() && "unsupported type!"); const BuiltinType *BTy = getAs(); if (BTy->getKind() == BuiltinType::SveBool) // Represent predicates as i8 rather than i1 to avoid any layout issues. // The type is bitcasted to a scalable predicate type when casting between // scalable and fixed-length vectors. return Ctx.UnsignedCharTy; else return Ctx.getBuiltinVectorTypeInfo(BTy).ElementType; } bool QualType::isPODType(const ASTContext &Context) const { // C++11 has a more relaxed definition of POD. if (Context.getLangOpts().CPlusPlus11) return isCXX11PODType(Context); return isCXX98PODType(Context); } bool QualType::isCXX98PODType(const ASTContext &Context) const { // The compiler shouldn't query this for incomplete types, but the user might. // We return false for that case. Except for incomplete arrays of PODs, which // are PODs according to the standard. if (isNull()) return false; if ((*this)->isIncompleteArrayType()) return Context.getBaseElementType(*this).isCXX98PODType(Context); if ((*this)->isIncompleteType()) return false; if (hasNonTrivialObjCLifetime()) return false; QualType CanonicalType = getTypePtr()->CanonicalType; switch (CanonicalType->getTypeClass()) { // Everything not explicitly mentioned is not POD. default: return false; case Type::VariableArray: case Type::ConstantArray: // IncompleteArray is handled above. return Context.getBaseElementType(*this).isCXX98PODType(Context); case Type::ObjCObjectPointer: case Type::BlockPointer: case Type::Builtin: case Type::Complex: case Type::Pointer: case Type::MemberPointer: case Type::Vector: case Type::ExtVector: case Type::BitInt: return true; case Type::Enum: return true; case Type::Record: if (const auto *ClassDecl = dyn_cast(cast(CanonicalType)->getDecl())) return ClassDecl->isPOD(); // C struct/union is POD. return true; } } bool QualType::isTrivialType(const ASTContext &Context) const { // The compiler shouldn't query this for incomplete types, but the user might. // We return false for that case. Except for incomplete arrays of PODs, which // are PODs according to the standard. if (isNull()) return false; if ((*this)->isArrayType()) return Context.getBaseElementType(*this).isTrivialType(Context); if ((*this)->isSizelessBuiltinType()) return true; // Return false for incomplete types after skipping any incomplete array // types which are expressly allowed by the standard and thus our API. if ((*this)->isIncompleteType()) return false; if (hasNonTrivialObjCLifetime()) return false; QualType CanonicalType = getTypePtr()->CanonicalType; if (CanonicalType->isDependentType()) return false; // C++0x [basic.types]p9: // Scalar types, trivial class types, arrays of such types, and // cv-qualified versions of these types are collectively called trivial // types. // As an extension, Clang treats vector types as Scalar types. if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) return true; if (const auto *RT = CanonicalType->getAs()) { if (const auto *ClassDecl = dyn_cast(RT->getDecl())) { // C++11 [class]p6: // A trivial class is a class that has a default constructor, // has no non-trivial default constructors, and is trivially // copyable. return ClassDecl->hasDefaultConstructor() && !ClassDecl->hasNonTrivialDefaultConstructor() && ClassDecl->isTriviallyCopyable(); } return true; } // No other types can match. return false; } bool QualType::isTriviallyCopyableType(const ASTContext &Context) const { if ((*this)->isArrayType()) return Context.getBaseElementType(*this).isTriviallyCopyableType(Context); if (hasNonTrivialObjCLifetime()) return false; // C++11 [basic.types]p9 - See Core 2094 // Scalar types, trivially copyable class types, arrays of such types, and // cv-qualified versions of these types are collectively // called trivially copyable types. QualType CanonicalType = getCanonicalType(); if (CanonicalType->isDependentType()) return false; if (CanonicalType->isSizelessBuiltinType()) return true; // Return false for incomplete types after skipping any incomplete array types // which are expressly allowed by the standard and thus our API. if (CanonicalType->isIncompleteType()) return false; // As an extension, Clang treats vector types as Scalar types. if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) return true; if (const auto *RT = CanonicalType->getAs()) { if (const auto *ClassDecl = dyn_cast(RT->getDecl())) { if (!ClassDecl->isTriviallyCopyable()) return false; } return true; } // No other types can match. return false; } bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const { return !Context.getLangOpts().ObjCAutoRefCount && Context.getLangOpts().ObjCWeak && getObjCLifetime() != Qualifiers::OCL_Weak; } bool QualType::hasNonTrivialToPrimitiveDefaultInitializeCUnion(const RecordDecl *RD) { return RD->hasNonTrivialToPrimitiveDefaultInitializeCUnion(); } bool QualType::hasNonTrivialToPrimitiveDestructCUnion(const RecordDecl *RD) { return RD->hasNonTrivialToPrimitiveDestructCUnion(); } bool QualType::hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD) { return RD->hasNonTrivialToPrimitiveCopyCUnion(); } QualType::PrimitiveDefaultInitializeKind QualType::isNonTrivialToPrimitiveDefaultInitialize() const { if (const auto *RT = getTypePtr()->getBaseElementTypeUnsafe()->getAs()) if (RT->getDecl()->isNonTrivialToPrimitiveDefaultInitialize()) return PDIK_Struct; switch (getQualifiers().getObjCLifetime()) { case Qualifiers::OCL_Strong: return PDIK_ARCStrong; case Qualifiers::OCL_Weak: return PDIK_ARCWeak; default: return PDIK_Trivial; } } QualType::PrimitiveCopyKind QualType::isNonTrivialToPrimitiveCopy() const { if (const auto *RT = getTypePtr()->getBaseElementTypeUnsafe()->getAs()) if (RT->getDecl()->isNonTrivialToPrimitiveCopy()) return PCK_Struct; Qualifiers Qs = getQualifiers(); switch (Qs.getObjCLifetime()) { case Qualifiers::OCL_Strong: return PCK_ARCStrong; case Qualifiers::OCL_Weak: return PCK_ARCWeak; default: return Qs.hasVolatile() ? PCK_VolatileTrivial : PCK_Trivial; } } QualType::PrimitiveCopyKind QualType::isNonTrivialToPrimitiveDestructiveMove() const { return isNonTrivialToPrimitiveCopy(); } bool Type::isLiteralType(const ASTContext &Ctx) const { if (isDependentType()) return false; // C++1y [basic.types]p10: // A type is a literal type if it is: // -- cv void; or if (Ctx.getLangOpts().CPlusPlus14 && isVoidType()) return true; // C++11 [basic.types]p10: // A type is a literal type if it is: // [...] // -- an array of literal type other than an array of runtime bound; or if (isVariableArrayType()) return false; const Type *BaseTy = getBaseElementTypeUnsafe(); assert(BaseTy && "NULL element type"); // Return false for incomplete types after skipping any incomplete array // types; those are expressly allowed by the standard and thus our API. if (BaseTy->isIncompleteType()) return false; // C++11 [basic.types]p10: // A type is a literal type if it is: // -- a scalar type; or // As an extension, Clang treats vector types and complex types as // literal types. if (BaseTy->isScalarType() || BaseTy->isVectorType() || BaseTy->isAnyComplexType()) return true; // -- a reference type; or if (BaseTy->isReferenceType()) return true; // -- a class type that has all of the following properties: if (const auto *RT = BaseTy->getAs()) { // -- a trivial destructor, // -- every constructor call and full-expression in the // brace-or-equal-initializers for non-static data members (if any) // is a constant expression, // -- it is an aggregate type or has at least one constexpr // constructor or constructor template that is not a copy or move // constructor, and // -- all non-static data members and base classes of literal types // // We resolve DR1361 by ignoring the second bullet. if (const auto *ClassDecl = dyn_cast(RT->getDecl())) return ClassDecl->isLiteral(); return true; } // We treat _Atomic T as a literal type if T is a literal type. if (const auto *AT = BaseTy->getAs()) return AT->getValueType()->isLiteralType(Ctx); // If this type hasn't been deduced yet, then conservatively assume that // it'll work out to be a literal type. if (isa(BaseTy->getCanonicalTypeInternal())) return true; return false; } bool Type::isStructuralType() const { // C++20 [temp.param]p6: // A structural type is one of the following: // -- a scalar type; or // -- a vector type [Clang extension]; or if (isScalarType() || isVectorType()) return true; // -- an lvalue reference type; or if (isLValueReferenceType()) return true; // -- a literal class type [...under some conditions] if (const CXXRecordDecl *RD = getAsCXXRecordDecl()) return RD->isStructural(); return false; } bool Type::isStandardLayoutType() const { if (isDependentType()) return false; // C++0x [basic.types]p9: // Scalar types, standard-layout class types, arrays of such types, and // cv-qualified versions of these types are collectively called // standard-layout types. const Type *BaseTy = getBaseElementTypeUnsafe(); assert(BaseTy && "NULL element type"); // Return false for incomplete types after skipping any incomplete array // types which are expressly allowed by the standard and thus our API. if (BaseTy->isIncompleteType()) return false; // As an extension, Clang treats vector types as Scalar types. if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; if (const auto *RT = BaseTy->getAs()) { if (const auto *ClassDecl = dyn_cast(RT->getDecl())) if (!ClassDecl->isStandardLayout()) return false; // Default to 'true' for non-C++ class types. // FIXME: This is a bit dubious, but plain C structs should trivially meet // all the requirements of standard layout classes. return true; } // No other types can match. return false; } // This is effectively the intersection of isTrivialType and // isStandardLayoutType. We implement it directly to avoid redundant // conversions from a type to a CXXRecordDecl. bool QualType::isCXX11PODType(const ASTContext &Context) const { const Type *ty = getTypePtr(); if (ty->isDependentType()) return false; if (hasNonTrivialObjCLifetime()) return false; // C++11 [basic.types]p9: // Scalar types, POD classes, arrays of such types, and cv-qualified // versions of these types are collectively called trivial types. const Type *BaseTy = ty->getBaseElementTypeUnsafe(); assert(BaseTy && "NULL element type"); if (BaseTy->isSizelessBuiltinType()) return true; // Return false for incomplete types after skipping any incomplete array // types which are expressly allowed by the standard and thus our API. if (BaseTy->isIncompleteType()) return false; // As an extension, Clang treats vector types as Scalar types. if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; if (const auto *RT = BaseTy->getAs()) { if (const auto *ClassDecl = dyn_cast(RT->getDecl())) { // C++11 [class]p10: // A POD struct is a non-union class that is both a trivial class [...] if (!ClassDecl->isTrivial()) return false; // C++11 [class]p10: // A POD struct is a non-union class that is both a trivial class and // a standard-layout class [...] if (!ClassDecl->isStandardLayout()) return false; // C++11 [class]p10: // A POD struct is a non-union class that is both a trivial class and // a standard-layout class, and has no non-static data members of type // non-POD struct, non-POD union (or array of such types). [...] // // We don't directly query the recursive aspect as the requirements for // both standard-layout classes and trivial classes apply recursively // already. } return true; } // No other types can match. return false; } bool Type::isNothrowT() const { if (const auto *RD = getAsCXXRecordDecl()) { IdentifierInfo *II = RD->getIdentifier(); if (II && II->isStr("nothrow_t") && RD->isInStdNamespace()) return true; } return false; } bool Type::isAlignValT() const { if (const auto *ET = getAs()) { IdentifierInfo *II = ET->getDecl()->getIdentifier(); if (II && II->isStr("align_val_t") && ET->getDecl()->isInStdNamespace()) return true; } return false; } bool Type::isStdByteType() const { if (const auto *ET = getAs()) { IdentifierInfo *II = ET->getDecl()->getIdentifier(); if (II && II->isStr("byte") && ET->getDecl()->isInStdNamespace()) return true; } return false; } bool Type::isPromotableIntegerType() const { if (const auto *BT = getAs()) switch (BT->getKind()) { case BuiltinType::Bool: case BuiltinType::Char_S: case BuiltinType::Char_U: case BuiltinType::SChar: case BuiltinType::UChar: case BuiltinType::Short: case BuiltinType::UShort: case BuiltinType::WChar_S: case BuiltinType::WChar_U: case BuiltinType::Char8: case BuiltinType::Char16: case BuiltinType::Char32: return true; default: return false; } // Enumerated types are promotable to their compatible integer types // (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2). if (const auto *ET = getAs()){ if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull() || ET->getDecl()->isScoped()) return false; return true; } return false; } bool Type::isSpecifierType() const { // Note that this intentionally does not use the canonical type. switch (getTypeClass()) { case Builtin: case Record: case Enum: case Typedef: case Complex: case TypeOfExpr: case TypeOf: case TemplateTypeParm: case SubstTemplateTypeParm: case TemplateSpecialization: case Elaborated: case DependentName: case DependentTemplateSpecialization: case ObjCInterface: case ObjCObject: return true; default: return false; } } ElaboratedTypeKeyword TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) { switch (TypeSpec) { default: return ETK_None; case TST_typename: return ETK_Typename; case TST_class: return ETK_Class; case TST_struct: return ETK_Struct; case TST_interface: return ETK_Interface; case TST_union: return ETK_Union; case TST_enum: return ETK_Enum; } } TagTypeKind TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) { switch(TypeSpec) { case TST_class: return TTK_Class; case TST_struct: return TTK_Struct; case TST_interface: return TTK_Interface; case TST_union: return TTK_Union; case TST_enum: return TTK_Enum; } llvm_unreachable("Type specifier is not a tag type kind."); } ElaboratedTypeKeyword TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) { switch (Kind) { case TTK_Class: return ETK_Class; case TTK_Struct: return ETK_Struct; case TTK_Interface: return ETK_Interface; case TTK_Union: return ETK_Union; case TTK_Enum: return ETK_Enum; } llvm_unreachable("Unknown tag type kind."); } TagTypeKind TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { switch (Keyword) { case ETK_Class: return TTK_Class; case ETK_Struct: return TTK_Struct; case ETK_Interface: return TTK_Interface; case ETK_Union: return TTK_Union; case ETK_Enum: return TTK_Enum; case ETK_None: // Fall through. case ETK_Typename: llvm_unreachable("Elaborated type keyword is not a tag type kind."); } llvm_unreachable("Unknown elaborated type keyword."); } bool TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) { switch (Keyword) { case ETK_None: case ETK_Typename: return false; case ETK_Class: case ETK_Struct: case ETK_Interface: case ETK_Union: case ETK_Enum: return true; } llvm_unreachable("Unknown elaborated type keyword."); } StringRef TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) { switch (Keyword) { case ETK_None: return {}; case ETK_Typename: return "typename"; case ETK_Class: return "class"; case ETK_Struct: return "struct"; case ETK_Interface: return "__interface"; case ETK_Union: return "union"; case ETK_Enum: return "enum"; } llvm_unreachable("Unknown elaborated type keyword."); } DependentTemplateSpecializationType::DependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, ArrayRef Args, QualType Canon) : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, TypeDependence::DependentInstantiation | (NNS ? toTypeDependence(NNS->getDependence()) : TypeDependence::None)), NNS(NNS), Name(Name) { DependentTemplateSpecializationTypeBits.NumArgs = Args.size(); assert((!NNS || NNS->isDependent()) && "DependentTemplateSpecializatonType requires dependent qualifier"); TemplateArgument *ArgBuffer = getArgBuffer(); for (const TemplateArgument &Arg : Args) { addDependence(toTypeDependence(Arg.getDependence() & TemplateArgumentDependence::UnexpandedPack)); new (ArgBuffer++) TemplateArgument(Arg); } } void DependentTemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, ElaboratedTypeKeyword Keyword, NestedNameSpecifier *Qualifier, const IdentifierInfo *Name, ArrayRef Args) { ID.AddInteger(Keyword); ID.AddPointer(Qualifier); ID.AddPointer(Name); for (const TemplateArgument &Arg : Args) Arg.Profile(ID, Context); } bool Type::isElaboratedTypeSpecifier() const { ElaboratedTypeKeyword Keyword; if (const auto *Elab = dyn_cast(this)) Keyword = Elab->getKeyword(); else if (const auto *DepName = dyn_cast(this)) Keyword = DepName->getKeyword(); else if (const auto *DepTST = dyn_cast(this)) Keyword = DepTST->getKeyword(); else return false; return TypeWithKeyword::KeywordIsTagTypeKind(Keyword); } const char *Type::getTypeClassName() const { switch (TypeBits.TC) { #define ABSTRACT_TYPE(Derived, Base) #define TYPE(Derived, Base) case Derived: return #Derived; #include "clang/AST/TypeNodes.inc" } llvm_unreachable("Invalid type class."); } StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { switch (getKind()) { case Void: return "void"; case Bool: return Policy.Bool ? "bool" : "_Bool"; case Char_S: return "char"; case Char_U: return "char"; case SChar: return "signed char"; case Short: return "short"; case Int: return "int"; case Long: return "long"; case LongLong: return "long long"; case Int128: return "__int128"; case UChar: return "unsigned char"; case UShort: return "unsigned short"; case UInt: return "unsigned int"; case ULong: return "unsigned long"; case ULongLong: return "unsigned long long"; case UInt128: return "unsigned __int128"; case Half: return Policy.Half ? "half" : "__fp16"; case BFloat16: return "__bf16"; case Float: return "float"; case Double: return "double"; case LongDouble: return "long double"; case ShortAccum: return "short _Accum"; case Accum: return "_Accum"; case LongAccum: return "long _Accum"; case UShortAccum: return "unsigned short _Accum"; case UAccum: return "unsigned _Accum"; case ULongAccum: return "unsigned long _Accum"; case BuiltinType::ShortFract: return "short _Fract"; case BuiltinType::Fract: return "_Fract"; case BuiltinType::LongFract: return "long _Fract"; case BuiltinType::UShortFract: return "unsigned short _Fract"; case BuiltinType::UFract: return "unsigned _Fract"; case BuiltinType::ULongFract: return "unsigned long _Fract"; case BuiltinType::SatShortAccum: return "_Sat short _Accum"; case BuiltinType::SatAccum: return "_Sat _Accum"; case BuiltinType::SatLongAccum: return "_Sat long _Accum"; case BuiltinType::SatUShortAccum: return "_Sat unsigned short _Accum"; case BuiltinType::SatUAccum: return "_Sat unsigned _Accum"; case BuiltinType::SatULongAccum: return "_Sat unsigned long _Accum"; case BuiltinType::SatShortFract: return "_Sat short _Fract"; case BuiltinType::SatFract: return "_Sat _Fract"; case BuiltinType::SatLongFract: return "_Sat long _Fract"; case BuiltinType::SatUShortFract: return "_Sat unsigned short _Fract"; case BuiltinType::SatUFract: return "_Sat unsigned _Fract"; case BuiltinType::SatULongFract: return "_Sat unsigned long _Fract"; case Float16: return "_Float16"; case Float128: return "__float128"; case Ibm128: return "__ibm128"; case WChar_S: case WChar_U: return Policy.MSWChar ? "__wchar_t" : "wchar_t"; case Char8: return "char8_t"; case Char16: return "char16_t"; case Char32: return "char32_t"; case NullPtr: return "std::nullptr_t"; case Overload: return ""; case BoundMember: return ""; case PseudoObject: return ""; case Dependent: return ""; case UnknownAny: return ""; case ARCUnbridgedCast: return ""; case BuiltinFn: return ""; case ObjCId: return "id"; case ObjCClass: return "Class"; case ObjCSel: return "SEL"; #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case Id: \ return "__" #Access " " #ImgType "_t"; #include "clang/Basic/OpenCLImageTypes.def" case OCLSampler: return "sampler_t"; case OCLEvent: return "event_t"; case OCLClkEvent: return "clk_event_t"; case OCLQueue: return "queue_t"; case OCLReserveID: return "reserve_id_t"; case IncompleteMatrixIdx: return ""; case OMPArraySection: return ""; case OMPArrayShaping: return ""; case OMPIterator: return ""; #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case Id: \ return #ExtType; #include "clang/Basic/OpenCLExtensionTypes.def" #define SVE_TYPE(Name, Id, SingletonId) \ case Id: \ return Name; #include "clang/Basic/AArch64SVEACLETypes.def" #define PPC_VECTOR_TYPE(Name, Id, Size) \ case Id: \ return #Name; #include "clang/Basic/PPCTypes.def" #define RVV_TYPE(Name, Id, SingletonId) \ case Id: \ return Name; #include "clang/Basic/RISCVVTypes.def" } llvm_unreachable("Invalid builtin type."); } QualType QualType::getNonPackExpansionType() const { // We never wrap type sugar around a PackExpansionType. if (auto *PET = dyn_cast(getTypePtr())) return PET->getPattern(); return *this; } QualType QualType::getNonLValueExprType(const ASTContext &Context) const { if (const auto *RefType = getTypePtr()->getAs()) return RefType->getPointeeType(); // C++0x [basic.lval]: // Class prvalues can have cv-qualified types; non-class prvalues always // have cv-unqualified types. // // See also C99 6.3.2.1p2. if (!Context.getLangOpts().CPlusPlus || (!getTypePtr()->isDependentType() && !getTypePtr()->isRecordType())) return getUnqualifiedType(); return *this; } StringRef FunctionType::getNameForCallConv(CallingConv CC) { switch (CC) { case CC_C: return "cdecl"; case CC_X86StdCall: return "stdcall"; case CC_X86FastCall: return "fastcall"; case CC_X86ThisCall: return "thiscall"; case CC_X86Pascal: return "pascal"; case CC_X86VectorCall: return "vectorcall"; case CC_Win64: return "ms_abi"; case CC_X86_64SysV: return "sysv_abi"; case CC_X86RegCall : return "regcall"; case CC_AAPCS: return "aapcs"; case CC_AAPCS_VFP: return "aapcs-vfp"; case CC_AArch64VectorCall: return "aarch64_vector_pcs"; case CC_IntelOclBicc: return "intel_ocl_bicc"; case CC_SpirFunction: return "spir_function"; case CC_OpenCLKernel: return "opencl_kernel"; case CC_Swift: return "swiftcall"; case CC_SwiftAsync: return "swiftasynccall"; case CC_PreserveMost: return "preserve_most"; case CC_PreserveAll: return "preserve_all"; } llvm_unreachable("Invalid calling convention."); } FunctionProtoType::FunctionProtoType(QualType result, ArrayRef params, QualType canonical, const ExtProtoInfo &epi) : FunctionType(FunctionProto, result, canonical, result->getDependence(), epi.ExtInfo) { FunctionTypeBits.FastTypeQuals = epi.TypeQuals.getFastQualifiers(); FunctionTypeBits.RefQualifier = epi.RefQualifier; FunctionTypeBits.NumParams = params.size(); assert(getNumParams() == params.size() && "NumParams overflow!"); FunctionTypeBits.ExceptionSpecType = epi.ExceptionSpec.Type; FunctionTypeBits.HasExtParameterInfos = !!epi.ExtParameterInfos; FunctionTypeBits.Variadic = epi.Variadic; FunctionTypeBits.HasTrailingReturn = epi.HasTrailingReturn; // Fill in the extra trailing bitfields if present. if (hasExtraBitfields(epi.ExceptionSpec.Type)) { auto &ExtraBits = *getTrailingObjects(); ExtraBits.NumExceptionType = epi.ExceptionSpec.Exceptions.size(); } // Fill in the trailing argument array. auto *argSlot = getTrailingObjects(); for (unsigned i = 0; i != getNumParams(); ++i) { addDependence(params[i]->getDependence() & ~TypeDependence::VariablyModified); argSlot[i] = params[i]; } // Fill in the exception type array if present. if (getExceptionSpecType() == EST_Dynamic) { assert(hasExtraBitfields() && "missing trailing extra bitfields!"); auto *exnSlot = reinterpret_cast(getTrailingObjects()); unsigned I = 0; for (QualType ExceptionType : epi.ExceptionSpec.Exceptions) { // Note that, before C++17, a dependent exception specification does // *not* make a type dependent; it's not even part of the C++ type // system. addDependence( ExceptionType->getDependence() & (TypeDependence::Instantiation | TypeDependence::UnexpandedPack)); exnSlot[I++] = ExceptionType; } } // Fill in the Expr * in the exception specification if present. else if (isComputedNoexcept(getExceptionSpecType())) { assert(epi.ExceptionSpec.NoexceptExpr && "computed noexcept with no expr"); assert((getExceptionSpecType() == EST_DependentNoexcept) == epi.ExceptionSpec.NoexceptExpr->isValueDependent()); // Store the noexcept expression and context. *getTrailingObjects() = epi.ExceptionSpec.NoexceptExpr; addDependence( toTypeDependence(epi.ExceptionSpec.NoexceptExpr->getDependence()) & (TypeDependence::Instantiation | TypeDependence::UnexpandedPack)); } // Fill in the FunctionDecl * in the exception specification if present. else if (getExceptionSpecType() == EST_Uninstantiated) { // Store the function decl from which we will resolve our // exception specification. auto **slot = getTrailingObjects(); slot[0] = epi.ExceptionSpec.SourceDecl; slot[1] = epi.ExceptionSpec.SourceTemplate; // This exception specification doesn't make the type dependent, because // it's not instantiated as part of instantiating the type. } else if (getExceptionSpecType() == EST_Unevaluated) { // Store the function decl from which we will resolve our // exception specification. auto **slot = getTrailingObjects(); slot[0] = epi.ExceptionSpec.SourceDecl; } // If this is a canonical type, and its exception specification is dependent, // then it's a dependent type. This only happens in C++17 onwards. if (isCanonicalUnqualified()) { if (getExceptionSpecType() == EST_Dynamic || getExceptionSpecType() == EST_DependentNoexcept) { assert(hasDependentExceptionSpec() && "type should not be canonical"); addDependence(TypeDependence::DependentInstantiation); } } else if (getCanonicalTypeInternal()->isDependentType()) { // Ask our canonical type whether our exception specification was dependent. addDependence(TypeDependence::DependentInstantiation); } // Fill in the extra parameter info if present. if (epi.ExtParameterInfos) { auto *extParamInfos = getTrailingObjects(); for (unsigned i = 0; i != getNumParams(); ++i) extParamInfos[i] = epi.ExtParameterInfos[i]; } if (epi.TypeQuals.hasNonFastQualifiers()) { FunctionTypeBits.HasExtQuals = 1; *getTrailingObjects() = epi.TypeQuals; } else { FunctionTypeBits.HasExtQuals = 0; } // Fill in the Ellipsis location info if present. if (epi.Variadic) { auto &EllipsisLoc = *getTrailingObjects(); EllipsisLoc = epi.EllipsisLoc; } } bool FunctionProtoType::hasDependentExceptionSpec() const { if (Expr *NE = getNoexceptExpr()) return NE->isValueDependent(); for (QualType ET : exceptions()) // A pack expansion with a non-dependent pattern is still dependent, // because we don't know whether the pattern is in the exception spec // or not (that depends on whether the pack has 0 expansions). if (ET->isDependentType() || ET->getAs()) return true; return false; } bool FunctionProtoType::hasInstantiationDependentExceptionSpec() const { if (Expr *NE = getNoexceptExpr()) return NE->isInstantiationDependent(); for (QualType ET : exceptions()) if (ET->isInstantiationDependentType()) return true; return false; } CanThrowResult FunctionProtoType::canThrow() const { switch (getExceptionSpecType()) { case EST_Unparsed: case EST_Unevaluated: case EST_Uninstantiated: llvm_unreachable("should not call this with unresolved exception specs"); case EST_DynamicNone: case EST_BasicNoexcept: case EST_NoexceptTrue: case EST_NoThrow: return CT_Cannot; case EST_None: case EST_MSAny: case EST_NoexceptFalse: return CT_Can; case EST_Dynamic: // A dynamic exception specification is throwing unless every exception // type is an (unexpanded) pack expansion type. for (unsigned I = 0; I != getNumExceptions(); ++I) if (!getExceptionType(I)->getAs()) return CT_Can; return CT_Dependent; case EST_DependentNoexcept: return CT_Dependent; } llvm_unreachable("unexpected exception specification kind"); } bool FunctionProtoType::isTemplateVariadic() const { for (unsigned ArgIdx = getNumParams(); ArgIdx; --ArgIdx) if (isa(getParamType(ArgIdx - 1))) return true; return false; } void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, const QualType *ArgTys, unsigned NumParams, const ExtProtoInfo &epi, const ASTContext &Context, bool Canonical) { // We have to be careful not to get ambiguous profile encodings. // Note that valid type pointers are never ambiguous with anything else. // // The encoding grammar begins: // type type* bool int bool // If that final bool is true, then there is a section for the EH spec: // bool type* // This is followed by an optional "consumed argument" section of the // same length as the first type sequence: // bool* // Finally, we have the ext info and trailing return type flag: // int bool // // There is no ambiguity between the consumed arguments and an empty EH // spec because of the leading 'bool' which unambiguously indicates // whether the following bool is the EH spec or part of the arguments. ID.AddPointer(Result.getAsOpaquePtr()); for (unsigned i = 0; i != NumParams; ++i) ID.AddPointer(ArgTys[i].getAsOpaquePtr()); // This method is relatively performance sensitive, so as a performance // shortcut, use one AddInteger call instead of four for the next four // fields. assert(!(unsigned(epi.Variadic) & ~1) && !(unsigned(epi.RefQualifier) & ~3) && !(unsigned(epi.ExceptionSpec.Type) & ~15) && "Values larger than expected."); ID.AddInteger(unsigned(epi.Variadic) + (epi.RefQualifier << 1) + (epi.ExceptionSpec.Type << 3)); ID.Add(epi.TypeQuals); if (epi.ExceptionSpec.Type == EST_Dynamic) { for (QualType Ex : epi.ExceptionSpec.Exceptions) ID.AddPointer(Ex.getAsOpaquePtr()); } else if (isComputedNoexcept(epi.ExceptionSpec.Type)) { epi.ExceptionSpec.NoexceptExpr->Profile(ID, Context, Canonical); } else if (epi.ExceptionSpec.Type == EST_Uninstantiated || epi.ExceptionSpec.Type == EST_Unevaluated) { ID.AddPointer(epi.ExceptionSpec.SourceDecl->getCanonicalDecl()); } if (epi.ExtParameterInfos) { for (unsigned i = 0; i != NumParams; ++i) ID.AddInteger(epi.ExtParameterInfos[i].getOpaqueValue()); } epi.ExtInfo.Profile(ID); ID.AddBoolean(epi.HasTrailingReturn); } void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { Profile(ID, getReturnType(), param_type_begin(), getNumParams(), getExtProtoInfo(), Ctx, isCanonicalUnqualified()); } TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType underlying, QualType can) - : Type(tc, can, underlying->getDependence()), + : Type(tc, can, toSemanticDependence(underlying->getDependence())), Decl(const_cast(D)) { assert(!isa(can) && "Invalid canonical type"); } QualType TypedefType::desugar() const { return getDecl()->getUnderlyingType(); } UsingType::UsingType(const UsingShadowDecl *Found, QualType Underlying, QualType Canon) - : Type(Using, Canon, Underlying->getDependence()), + : Type(Using, Canon, toSemanticDependence(Underlying->getDependence())), Found(const_cast(Found)) { assert(Underlying == getUnderlyingType()); } QualType UsingType::getUnderlyingType() const { return QualType(cast(Found->getTargetDecl())->getTypeForDecl(), 0); } QualType MacroQualifiedType::desugar() const { return getUnderlyingType(); } QualType MacroQualifiedType::getModifiedType() const { // Step over MacroQualifiedTypes from the same macro to find the type // ultimately qualified by the macro qualifier. QualType Inner = cast(getUnderlyingType())->getModifiedType(); while (auto *InnerMQT = dyn_cast(Inner)) { if (InnerMQT->getMacroIdentifier() != getMacroIdentifier()) break; Inner = InnerMQT->getModifiedType(); } return Inner; } TypeOfExprType::TypeOfExprType(Expr *E, QualType can) : Type(TypeOfExpr, can, toTypeDependence(E->getDependence()) | (E->getType()->getDependence() & TypeDependence::VariablyModified)), TOExpr(E) {} bool TypeOfExprType::isSugared() const { return !TOExpr->isTypeDependent(); } QualType TypeOfExprType::desugar() const { if (isSugared()) return getUnderlyingExpr()->getType(); return QualType(this, 0); } void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, Expr *E) { E->Profile(ID, Context, true); } DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can) // C++11 [temp.type]p2: "If an expression e involves a template parameter, // decltype(e) denotes a unique dependent type." Hence a decltype type is // type-dependent even if its expression is only instantiation-dependent. : Type(Decltype, can, toTypeDependence(E->getDependence()) | (E->isInstantiationDependent() ? TypeDependence::Dependent : TypeDependence::None) | (E->getType()->getDependence() & TypeDependence::VariablyModified)), E(E), UnderlyingType(underlyingType) {} bool DecltypeType::isSugared() const { return !E->isInstantiationDependent(); } QualType DecltypeType::desugar() const { if (isSugared()) return getUnderlyingType(); return QualType(this, 0); } DependentDecltypeType::DependentDecltypeType(const ASTContext &Context, Expr *E) : DecltypeType(E, Context.DependentTy), Context(Context) {} void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, Expr *E) { E->Profile(ID, Context, true); } UnaryTransformType::UnaryTransformType(QualType BaseType, QualType UnderlyingType, UTTKind UKind, QualType CanonicalType) : Type(UnaryTransform, CanonicalType, BaseType->getDependence()), BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) {} DependentUnaryTransformType::DependentUnaryTransformType(const ASTContext &C, QualType BaseType, UTTKind UKind) : UnaryTransformType(BaseType, C.DependentTy, UKind, QualType()) {} TagType::TagType(TypeClass TC, const TagDecl *D, QualType can) : Type(TC, can, D->isDependentType() ? TypeDependence::DependentInstantiation : TypeDependence::None), decl(const_cast(D)) {} static TagDecl *getInterestingTagDecl(TagDecl *decl) { for (auto I : decl->redecls()) { if (I->isCompleteDefinition() || I->isBeingDefined()) return I; } // If there's no definition (not even in progress), return what we have. return decl; } TagDecl *TagType::getDecl() const { return getInterestingTagDecl(decl); } bool TagType::isBeingDefined() const { return getDecl()->isBeingDefined(); } bool RecordType::hasConstFields() const { std::vector RecordTypeList; RecordTypeList.push_back(this); unsigned NextToCheckIndex = 0; while (RecordTypeList.size() > NextToCheckIndex) { for (FieldDecl *FD : RecordTypeList[NextToCheckIndex]->getDecl()->fields()) { QualType FieldTy = FD->getType(); if (FieldTy.isConstQualified()) return true; FieldTy = FieldTy.getCanonicalType(); if (const auto *FieldRecTy = FieldTy->getAs()) { if (!llvm::is_contained(RecordTypeList, FieldRecTy)) RecordTypeList.push_back(FieldRecTy); } } ++NextToCheckIndex; } return false; } bool AttributedType::isQualifier() const { // FIXME: Generate this with TableGen. switch (getAttrKind()) { // These are type qualifiers in the traditional C sense: they annotate // something about a specific value/variable of a type. (They aren't // always part of the canonical type, though.) case attr::ObjCGC: case attr::ObjCOwnership: case attr::ObjCInertUnsafeUnretained: case attr::TypeNonNull: case attr::TypeNullable: case attr::TypeNullableResult: case attr::TypeNullUnspecified: case attr::LifetimeBound: case attr::AddressSpace: return true; // All other type attributes aren't qualifiers; they rewrite the modified // type to be a semantically different type. default: return false; } } bool AttributedType::isMSTypeSpec() const { // FIXME: Generate this with TableGen? switch (getAttrKind()) { default: return false; case attr::Ptr32: case attr::Ptr64: case attr::SPtr: case attr::UPtr: return true; } llvm_unreachable("invalid attr kind"); } bool AttributedType::isCallingConv() const { // FIXME: Generate this with TableGen. switch (getAttrKind()) { default: return false; case attr::Pcs: case attr::CDecl: case attr::FastCall: case attr::StdCall: case attr::ThisCall: case attr::RegCall: case attr::SwiftCall: case attr::SwiftAsyncCall: case attr::VectorCall: case attr::AArch64VectorPcs: case attr::Pascal: case attr::MSABI: case attr::SysVABI: case attr::IntelOclBicc: case attr::PreserveMost: case attr::PreserveAll: return true; } llvm_unreachable("invalid attr kind"); } CXXRecordDecl *InjectedClassNameType::getDecl() const { return cast(getInterestingTagDecl(Decl)); } IdentifierInfo *TemplateTypeParmType::getIdentifier() const { return isCanonicalUnqualified() ? nullptr : getDecl()->getIdentifier(); } SubstTemplateTypeParmPackType::SubstTemplateTypeParmPackType( const TemplateTypeParmType *Param, QualType Canon, const TemplateArgument &ArgPack) : Type(SubstTemplateTypeParmPack, Canon, TypeDependence::DependentInstantiation | TypeDependence::UnexpandedPack), Replaced(Param), Arguments(ArgPack.pack_begin()) { SubstTemplateTypeParmPackTypeBits.NumArgs = ArgPack.pack_size(); } TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const { return TemplateArgument(llvm::makeArrayRef(Arguments, getNumArgs())); } void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getReplacedParameter(), getArgumentPack()); } void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID, const TemplateTypeParmType *Replaced, const TemplateArgument &ArgPack) { ID.AddPointer(Replaced); ID.AddInteger(ArgPack.pack_size()); for (const auto &P : ArgPack.pack_elements()) ID.AddPointer(P.getAsType().getAsOpaquePtr()); } bool TemplateSpecializationType::anyDependentTemplateArguments( const TemplateArgumentListInfo &Args, ArrayRef Converted) { return anyDependentTemplateArguments(Args.arguments(), Converted); } bool TemplateSpecializationType::anyDependentTemplateArguments( ArrayRef Args, ArrayRef Converted) { for (const TemplateArgument &Arg : Converted) if (Arg.isDependent()) return true; return false; } bool TemplateSpecializationType::anyInstantiationDependentTemplateArguments( ArrayRef Args) { for (const TemplateArgumentLoc &ArgLoc : Args) { if (ArgLoc.getArgument().isInstantiationDependent()) return true; } return false; } TemplateSpecializationType::TemplateSpecializationType( TemplateName T, ArrayRef Args, QualType Canon, QualType AliasedType) : Type(TemplateSpecialization, Canon.isNull() ? QualType(this, 0) : Canon, (Canon.isNull() ? TypeDependence::DependentInstantiation - : Canon->getDependence() & ~(TypeDependence::VariablyModified | - TypeDependence::UnexpandedPack)) | + : toSemanticDependence(Canon->getDependence())) | (toTypeDependence(T.getDependence()) & TypeDependence::UnexpandedPack)), Template(T) { TemplateSpecializationTypeBits.NumArgs = Args.size(); TemplateSpecializationTypeBits.TypeAlias = !AliasedType.isNull(); assert(!T.getAsDependentTemplateName() && "Use DependentTemplateSpecializationType for dependent template-name"); assert((T.getKind() == TemplateName::Template || T.getKind() == TemplateName::SubstTemplateTemplateParm || T.getKind() == TemplateName::SubstTemplateTemplateParmPack) && "Unexpected template name for TemplateSpecializationType"); auto *TemplateArgs = reinterpret_cast(this + 1); for (const TemplateArgument &Arg : Args) { // Update instantiation-dependent, variably-modified, and error bits. // If the canonical type exists and is non-dependent, the template // specialization type can be non-dependent even if one of the type // arguments is. Given: // template using U = int; // U is always non-dependent, irrespective of the type T. // However, U contains an unexpanded parameter pack, even though // its expansion (and thus its desugared type) doesn't. addDependence(toTypeDependence(Arg.getDependence()) & ~TypeDependence::Dependent); if (Arg.getKind() == TemplateArgument::Type) addDependence(Arg.getAsType()->getDependence() & TypeDependence::VariablyModified); new (TemplateArgs++) TemplateArgument(Arg); } // Store the aliased type if this is a type alias template specialization. if (isTypeAlias()) { auto *Begin = reinterpret_cast(this + 1); *reinterpret_cast(Begin + getNumArgs()) = AliasedType; } } void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, TemplateName T, ArrayRef Args, const ASTContext &Context) { T.Profile(ID); for (const TemplateArgument &Arg : Args) Arg.Profile(ID, Context); } QualType QualifierCollector::apply(const ASTContext &Context, QualType QT) const { if (!hasNonFastQualifiers()) return QT.withFastQualifiers(getFastQualifiers()); return Context.getQualifiedType(QT, *this); } QualType QualifierCollector::apply(const ASTContext &Context, const Type *T) const { if (!hasNonFastQualifiers()) return QualType(T, getFastQualifiers()); return Context.getQualifiedType(T, *this); } void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID, QualType BaseType, ArrayRef typeArgs, ArrayRef protocols, bool isKindOf) { ID.AddPointer(BaseType.getAsOpaquePtr()); ID.AddInteger(typeArgs.size()); for (auto typeArg : typeArgs) ID.AddPointer(typeArg.getAsOpaquePtr()); ID.AddInteger(protocols.size()); for (auto proto : protocols) ID.AddPointer(proto); ID.AddBoolean(isKindOf); } void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getBaseType(), getTypeArgsAsWritten(), llvm::makeArrayRef(qual_begin(), getNumProtocols()), isKindOfTypeAsWritten()); } void ObjCTypeParamType::Profile(llvm::FoldingSetNodeID &ID, const ObjCTypeParamDecl *OTPDecl, QualType CanonicalType, ArrayRef protocols) { ID.AddPointer(OTPDecl); ID.AddPointer(CanonicalType.getAsOpaquePtr()); ID.AddInteger(protocols.size()); for (auto proto : protocols) ID.AddPointer(proto); } void ObjCTypeParamType::Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getDecl(), getCanonicalTypeInternal(), llvm::makeArrayRef(qual_begin(), getNumProtocols())); } namespace { /// The cached properties of a type. class CachedProperties { Linkage L; bool local; public: CachedProperties(Linkage L, bool local) : L(L), local(local) {} Linkage getLinkage() const { return L; } bool hasLocalOrUnnamedType() const { return local; } friend CachedProperties merge(CachedProperties L, CachedProperties R) { Linkage MergedLinkage = minLinkage(L.L, R.L); return CachedProperties(MergedLinkage, L.hasLocalOrUnnamedType() || R.hasLocalOrUnnamedType()); } }; } // namespace static CachedProperties computeCachedProperties(const Type *T); namespace clang { /// The type-property cache. This is templated so as to be /// instantiated at an internal type to prevent unnecessary symbol /// leakage. template class TypePropertyCache { public: static CachedProperties get(QualType T) { return get(T.getTypePtr()); } static CachedProperties get(const Type *T) { ensure(T); return CachedProperties(T->TypeBits.getLinkage(), T->TypeBits.hasLocalOrUnnamedType()); } static void ensure(const Type *T) { // If the cache is valid, we're okay. if (T->TypeBits.isCacheValid()) return; // If this type is non-canonical, ask its canonical type for the // relevant information. if (!T->isCanonicalUnqualified()) { const Type *CT = T->getCanonicalTypeInternal().getTypePtr(); ensure(CT); T->TypeBits.CacheValid = true; T->TypeBits.CachedLinkage = CT->TypeBits.CachedLinkage; T->TypeBits.CachedLocalOrUnnamed = CT->TypeBits.CachedLocalOrUnnamed; return; } // Compute the cached properties and then set the cache. CachedProperties Result = computeCachedProperties(T); T->TypeBits.CacheValid = true; T->TypeBits.CachedLinkage = Result.getLinkage(); T->TypeBits.CachedLocalOrUnnamed = Result.hasLocalOrUnnamedType(); } }; } // namespace clang // Instantiate the friend template at a private class. In a // reasonable implementation, these symbols will be internal. // It is terrible that this is the best way to accomplish this. namespace { class Private {}; } // namespace using Cache = TypePropertyCache; static CachedProperties computeCachedProperties(const Type *T) { switch (T->getTypeClass()) { #define TYPE(Class,Base) #define NON_CANONICAL_TYPE(Class,Base) case Type::Class: #include "clang/AST/TypeNodes.inc" llvm_unreachable("didn't expect a non-canonical type here"); #define TYPE(Class,Base) #define DEPENDENT_TYPE(Class,Base) case Type::Class: #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class,Base) case Type::Class: #include "clang/AST/TypeNodes.inc" // Treat instantiation-dependent types as external. if (!T->isInstantiationDependentType()) T->dump(); assert(T->isInstantiationDependentType()); return CachedProperties(ExternalLinkage, false); case Type::Auto: case Type::DeducedTemplateSpecialization: // Give non-deduced 'auto' types external linkage. We should only see them // here in error recovery. return CachedProperties(ExternalLinkage, false); case Type::BitInt: case Type::Builtin: // C++ [basic.link]p8: // A type is said to have linkage if and only if: // - it is a fundamental type (3.9.1); or return CachedProperties(ExternalLinkage, false); case Type::Record: case Type::Enum: { const TagDecl *Tag = cast(T)->getDecl(); // C++ [basic.link]p8: // - it is a class or enumeration type that is named (or has a name // for linkage purposes (7.1.3)) and the name has linkage; or // - it is a specialization of a class template (14); or Linkage L = Tag->getLinkageInternal(); bool IsLocalOrUnnamed = Tag->getDeclContext()->isFunctionOrMethod() || !Tag->hasNameForLinkage(); return CachedProperties(L, IsLocalOrUnnamed); } // C++ [basic.link]p8: // - it is a compound type (3.9.2) other than a class or enumeration, // compounded exclusively from types that have linkage; or case Type::Complex: return Cache::get(cast(T)->getElementType()); case Type::Pointer: return Cache::get(cast(T)->getPointeeType()); case Type::BlockPointer: return Cache::get(cast(T)->getPointeeType()); case Type::LValueReference: case Type::RValueReference: return Cache::get(cast(T)->getPointeeType()); case Type::MemberPointer: { const auto *MPT = cast(T); return merge(Cache::get(MPT->getClass()), Cache::get(MPT->getPointeeType())); } case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: return Cache::get(cast(T)->getElementType()); case Type::Vector: case Type::ExtVector: return Cache::get(cast(T)->getElementType()); case Type::ConstantMatrix: return Cache::get(cast(T)->getElementType()); case Type::FunctionNoProto: return Cache::get(cast(T)->getReturnType()); case Type::FunctionProto: { const auto *FPT = cast(T); CachedProperties result = Cache::get(FPT->getReturnType()); for (const auto &ai : FPT->param_types()) result = merge(result, Cache::get(ai)); return result; } case Type::ObjCInterface: { Linkage L = cast(T)->getDecl()->getLinkageInternal(); return CachedProperties(L, false); } case Type::ObjCObject: return Cache::get(cast(T)->getBaseType()); case Type::ObjCObjectPointer: return Cache::get(cast(T)->getPointeeType()); case Type::Atomic: return Cache::get(cast(T)->getValueType()); case Type::Pipe: return Cache::get(cast(T)->getElementType()); } llvm_unreachable("unhandled type class"); } /// Determine the linkage of this type. Linkage Type::getLinkage() const { Cache::ensure(this); return TypeBits.getLinkage(); } bool Type::hasUnnamedOrLocalType() const { Cache::ensure(this); return TypeBits.hasLocalOrUnnamedType(); } LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) { switch (T->getTypeClass()) { #define TYPE(Class,Base) #define NON_CANONICAL_TYPE(Class,Base) case Type::Class: #include "clang/AST/TypeNodes.inc" llvm_unreachable("didn't expect a non-canonical type here"); #define TYPE(Class,Base) #define DEPENDENT_TYPE(Class,Base) case Type::Class: #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class,Base) case Type::Class: #include "clang/AST/TypeNodes.inc" // Treat instantiation-dependent types as external. assert(T->isInstantiationDependentType()); return LinkageInfo::external(); case Type::BitInt: case Type::Builtin: return LinkageInfo::external(); case Type::Auto: case Type::DeducedTemplateSpecialization: return LinkageInfo::external(); case Type::Record: case Type::Enum: return getDeclLinkageAndVisibility(cast(T)->getDecl()); case Type::Complex: return computeTypeLinkageInfo(cast(T)->getElementType()); case Type::Pointer: return computeTypeLinkageInfo(cast(T)->getPointeeType()); case Type::BlockPointer: return computeTypeLinkageInfo(cast(T)->getPointeeType()); case Type::LValueReference: case Type::RValueReference: return computeTypeLinkageInfo(cast(T)->getPointeeType()); case Type::MemberPointer: { const auto *MPT = cast(T); LinkageInfo LV = computeTypeLinkageInfo(MPT->getClass()); LV.merge(computeTypeLinkageInfo(MPT->getPointeeType())); return LV; } case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: return computeTypeLinkageInfo(cast(T)->getElementType()); case Type::Vector: case Type::ExtVector: return computeTypeLinkageInfo(cast(T)->getElementType()); case Type::ConstantMatrix: return computeTypeLinkageInfo( cast(T)->getElementType()); case Type::FunctionNoProto: return computeTypeLinkageInfo(cast(T)->getReturnType()); case Type::FunctionProto: { const auto *FPT = cast(T); LinkageInfo LV = computeTypeLinkageInfo(FPT->getReturnType()); for (const auto &ai : FPT->param_types()) LV.merge(computeTypeLinkageInfo(ai)); return LV; } case Type::ObjCInterface: return getDeclLinkageAndVisibility(cast(T)->getDecl()); case Type::ObjCObject: return computeTypeLinkageInfo(cast(T)->getBaseType()); case Type::ObjCObjectPointer: return computeTypeLinkageInfo( cast(T)->getPointeeType()); case Type::Atomic: return computeTypeLinkageInfo(cast(T)->getValueType()); case Type::Pipe: return computeTypeLinkageInfo(cast(T)->getElementType()); } llvm_unreachable("unhandled type class"); } bool Type::isLinkageValid() const { if (!TypeBits.isCacheValid()) return true; Linkage L = LinkageComputer{} .computeTypeLinkageInfo(getCanonicalTypeInternal()) .getLinkage(); return L == TypeBits.getLinkage(); } LinkageInfo LinkageComputer::getTypeLinkageAndVisibility(const Type *T) { if (!T->isCanonicalUnqualified()) return computeTypeLinkageInfo(T->getCanonicalTypeInternal()); LinkageInfo LV = computeTypeLinkageInfo(T); assert(LV.getLinkage() == T->getLinkage()); return LV; } LinkageInfo Type::getLinkageAndVisibility() const { return LinkageComputer{}.getTypeLinkageAndVisibility(this); } Optional Type::getNullability(const ASTContext &Context) const { QualType Type(this, 0); while (const auto *AT = Type->getAs()) { // Check whether this is an attributed type with nullability // information. if (auto Nullability = AT->getImmediateNullability()) return Nullability; Type = AT->getEquivalentType(); } return None; } bool Type::canHaveNullability(bool ResultIfUnknown) const { QualType type = getCanonicalTypeInternal(); switch (type->getTypeClass()) { // We'll only see canonical types here. #define NON_CANONICAL_TYPE(Class, Parent) \ case Type::Class: \ llvm_unreachable("non-canonical type"); #define TYPE(Class, Parent) #include "clang/AST/TypeNodes.inc" // Pointer types. case Type::Pointer: case Type::BlockPointer: case Type::MemberPointer: case Type::ObjCObjectPointer: return true; // Dependent types that could instantiate to pointer types. case Type::UnresolvedUsing: case Type::TypeOfExpr: case Type::TypeOf: case Type::Decltype: case Type::UnaryTransform: case Type::TemplateTypeParm: case Type::SubstTemplateTypeParmPack: case Type::DependentName: case Type::DependentTemplateSpecialization: case Type::Auto: return ResultIfUnknown; // Dependent template specializations can instantiate to pointer // types unless they're known to be specializations of a class // template. case Type::TemplateSpecialization: if (TemplateDecl *templateDecl = cast(type.getTypePtr()) ->getTemplateName().getAsTemplateDecl()) { if (isa(templateDecl)) return false; } return ResultIfUnknown; case Type::Builtin: switch (cast(type.getTypePtr())->getKind()) { // Signed, unsigned, and floating-point types cannot have nullability. #define SIGNED_TYPE(Id, SingletonId) case BuiltinType::Id: #define UNSIGNED_TYPE(Id, SingletonId) case BuiltinType::Id: #define FLOATING_TYPE(Id, SingletonId) case BuiltinType::Id: #define BUILTIN_TYPE(Id, SingletonId) #include "clang/AST/BuiltinTypes.def" return false; // Dependent types that could instantiate to a pointer type. case BuiltinType::Dependent: case BuiltinType::Overload: case BuiltinType::BoundMember: case BuiltinType::PseudoObject: case BuiltinType::UnknownAny: case BuiltinType::ARCUnbridgedCast: return ResultIfUnknown; case BuiltinType::Void: case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: #include "clang/Basic/OpenCLImageTypes.def" #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case BuiltinType::Id: #include "clang/Basic/OpenCLExtensionTypes.def" case BuiltinType::OCLSampler: case BuiltinType::OCLEvent: case BuiltinType::OCLClkEvent: case BuiltinType::OCLQueue: case BuiltinType::OCLReserveID: #define SVE_TYPE(Name, Id, SingletonId) \ case BuiltinType::Id: #include "clang/Basic/AArch64SVEACLETypes.def" #define PPC_VECTOR_TYPE(Name, Id, Size) \ case BuiltinType::Id: #include "clang/Basic/PPCTypes.def" #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/RISCVVTypes.def" case BuiltinType::BuiltinFn: case BuiltinType::NullPtr: case BuiltinType::IncompleteMatrixIdx: case BuiltinType::OMPArraySection: case BuiltinType::OMPArrayShaping: case BuiltinType::OMPIterator: return false; } llvm_unreachable("unknown builtin type"); // Non-pointer types. case Type::Complex: case Type::LValueReference: case Type::RValueReference: case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: case Type::DependentSizedArray: case Type::DependentVector: case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: case Type::ConstantMatrix: case Type::DependentSizedMatrix: case Type::DependentAddressSpace: case Type::FunctionProto: case Type::FunctionNoProto: case Type::Record: case Type::DeducedTemplateSpecialization: case Type::Enum: case Type::InjectedClassName: case Type::PackExpansion: case Type::ObjCObject: case Type::ObjCInterface: case Type::Atomic: case Type::Pipe: case Type::BitInt: case Type::DependentBitInt: return false; } llvm_unreachable("bad type kind!"); } llvm::Optional AttributedType::getImmediateNullability() const { if (getAttrKind() == attr::TypeNonNull) return NullabilityKind::NonNull; if (getAttrKind() == attr::TypeNullable) return NullabilityKind::Nullable; if (getAttrKind() == attr::TypeNullUnspecified) return NullabilityKind::Unspecified; if (getAttrKind() == attr::TypeNullableResult) return NullabilityKind::NullableResult; return None; } Optional AttributedType::stripOuterNullability(QualType &T) { QualType AttrTy = T; if (auto MacroTy = dyn_cast(T)) AttrTy = MacroTy->getUnderlyingType(); if (auto attributed = dyn_cast(AttrTy)) { if (auto nullability = attributed->getImmediateNullability()) { T = attributed->getModifiedType(); return nullability; } } return None; } bool Type::isBlockCompatibleObjCPointerType(ASTContext &ctx) const { const auto *objcPtr = getAs(); if (!objcPtr) return false; if (objcPtr->isObjCIdType()) { // id is always okay. return true; } // Blocks are NSObjects. if (ObjCInterfaceDecl *iface = objcPtr->getInterfaceDecl()) { if (iface->getIdentifier() != ctx.getNSObjectName()) return false; // Continue to check qualifiers, below. } else if (objcPtr->isObjCQualifiedIdType()) { // Continue to check qualifiers, below. } else { return false; } // Check protocol qualifiers. for (ObjCProtocolDecl *proto : objcPtr->quals()) { // Blocks conform to NSObject and NSCopying. if (proto->getIdentifier() != ctx.getNSObjectName() && proto->getIdentifier() != ctx.getNSCopyingName()) return false; } return true; } Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const { if (isObjCARCImplicitlyUnretainedType()) return Qualifiers::OCL_ExplicitNone; return Qualifiers::OCL_Strong; } bool Type::isObjCARCImplicitlyUnretainedType() const { assert(isObjCLifetimeType() && "cannot query implicit lifetime for non-inferrable type"); const Type *canon = getCanonicalTypeInternal().getTypePtr(); // Walk down to the base type. We don't care about qualifiers for this. while (const auto *array = dyn_cast(canon)) canon = array->getElementType().getTypePtr(); if (const auto *opt = dyn_cast(canon)) { // Class and Class don't require retention. if (opt->getObjectType()->isObjCClass()) return true; } return false; } bool Type::isObjCNSObjectType() const { const Type *cur = this; while (true) { if (const auto *typedefType = dyn_cast(cur)) return typedefType->getDecl()->hasAttr(); // Single-step desugar until we run out of sugar. QualType next = cur->getLocallyUnqualifiedSingleStepDesugaredType(); if (next.getTypePtr() == cur) return false; cur = next.getTypePtr(); } } bool Type::isObjCIndependentClassType() const { if (const auto *typedefType = dyn_cast(this)) return typedefType->getDecl()->hasAttr(); return false; } bool Type::isObjCRetainableType() const { return isObjCObjectPointerType() || isBlockPointerType() || isObjCNSObjectType(); } bool Type::isObjCIndirectLifetimeType() const { if (isObjCLifetimeType()) return true; if (const auto *OPT = getAs()) return OPT->getPointeeType()->isObjCIndirectLifetimeType(); if (const auto *Ref = getAs()) return Ref->getPointeeType()->isObjCIndirectLifetimeType(); if (const auto *MemPtr = getAs()) return MemPtr->getPointeeType()->isObjCIndirectLifetimeType(); return false; } /// Returns true if objects of this type have lifetime semantics under /// ARC. bool Type::isObjCLifetimeType() const { const Type *type = this; while (const ArrayType *array = type->getAsArrayTypeUnsafe()) type = array->getElementType().getTypePtr(); return type->isObjCRetainableType(); } /// Determine whether the given type T is a "bridgable" Objective-C type, /// which is either an Objective-C object pointer type or an bool Type::isObjCARCBridgableType() const { return isObjCObjectPointerType() || isBlockPointerType(); } /// Determine whether the given type T is a "bridgeable" C type. bool Type::isCARCBridgableType() const { const auto *Pointer = getAs(); if (!Pointer) return false; QualType Pointee = Pointer->getPointeeType(); return Pointee->isVoidType() || Pointee->isRecordType(); } /// Check if the specified type is the CUDA device builtin surface type. bool Type::isCUDADeviceBuiltinSurfaceType() const { if (const auto *RT = getAs()) return RT->getDecl()->hasAttr(); return false; } /// Check if the specified type is the CUDA device builtin texture type. bool Type::isCUDADeviceBuiltinTextureType() const { if (const auto *RT = getAs()) return RT->getDecl()->hasAttr(); return false; } bool Type::hasSizedVLAType() const { if (!isVariablyModifiedType()) return false; if (const auto *ptr = getAs()) return ptr->getPointeeType()->hasSizedVLAType(); if (const auto *ref = getAs()) return ref->getPointeeType()->hasSizedVLAType(); if (const ArrayType *arr = getAsArrayTypeUnsafe()) { if (isa(arr) && cast(arr)->getSizeExpr()) return true; return arr->getElementType()->hasSizedVLAType(); } return false; } QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { switch (type.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Autoreleasing: break; case Qualifiers::OCL_Strong: return DK_objc_strong_lifetime; case Qualifiers::OCL_Weak: return DK_objc_weak_lifetime; } if (const auto *RT = type->getBaseElementTypeUnsafe()->getAs()) { const RecordDecl *RD = RT->getDecl(); if (const auto *CXXRD = dyn_cast(RD)) { /// Check if this is a C++ object with a non-trivial destructor. if (CXXRD->hasDefinition() && !CXXRD->hasTrivialDestructor()) return DK_cxx_destructor; } else { /// Check if this is a C struct that is non-trivial to destroy or an array /// that contains such a struct. if (RD->isNonTrivialToPrimitiveDestroy()) return DK_nontrivial_c_struct; } } return DK_none; } CXXRecordDecl *MemberPointerType::getMostRecentCXXRecordDecl() const { return getClass()->getAsCXXRecordDecl()->getMostRecentNonInjectedDecl(); } void clang::FixedPointValueToString(SmallVectorImpl &Str, llvm::APSInt Val, unsigned Scale) { llvm::FixedPointSemantics FXSema(Val.getBitWidth(), Scale, Val.isSigned(), /*IsSaturated=*/false, /*HasUnsignedPadding=*/false); llvm::APFixedPoint(Val, FXSema).toString(Str); } AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, TypeDependence ExtraDependence, QualType Canon, ConceptDecl *TypeConstraintConcept, ArrayRef TypeConstraintArgs) : DeducedType(Auto, DeducedAsType, ExtraDependence, Canon) { AutoTypeBits.Keyword = (unsigned)Keyword; AutoTypeBits.NumArgs = TypeConstraintArgs.size(); this->TypeConstraintConcept = TypeConstraintConcept; if (TypeConstraintConcept) { TemplateArgument *ArgBuffer = getArgBuffer(); for (const TemplateArgument &Arg : TypeConstraintArgs) { addDependence( toSyntacticDependence(toTypeDependence(Arg.getDependence()))); new (ArgBuffer++) TemplateArgument(Arg); } } } void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType Deduced, AutoTypeKeyword Keyword, bool IsDependent, ConceptDecl *CD, ArrayRef Arguments) { ID.AddPointer(Deduced.getAsOpaquePtr()); ID.AddInteger((unsigned)Keyword); ID.AddBoolean(IsDependent); ID.AddPointer(CD); for (const TemplateArgument &Arg : Arguments) Arg.Profile(ID, Context); }