blob: 2c63406fba18d20615f60ed91d458d4c0035416c [file] [log] [blame]
//===--- 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<CXXBaseSpecifier*, 4> 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<unsigned>(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<ExprDependence>(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<int Size, char (&Chars)[Size]> struct meta_string;
/// @endcode
bool isValueDependent() const {
return static_cast<bool>(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<typename T>
/// void add(T x, int y) {
/// x + y;
/// }
/// @endcode
bool isTypeDependent() const {
return static_cast<bool>(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<typename T>
/// 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<bool>(getDependence() & ExprDependence::Instantiation);
}
/// Whether this expression contains an unexpanded parameter
/// pack (for C++11 variadic templates).
///
/// Given the following function template:
///
/// \code
/// template<typename F, typename ...Types>
/// void forward(const F &f, Types &&...args) {
/// f(static_cast<Types&&>(args)...);
/// }
/// \endcode
///
/// The expressions \c args and \c static_cast<Types&&>(args) both
/// contain parameter packs.
bool containsUnexpandedParameterPack() const {
return static_cast<bool>(getDependence() & ExprDependence::UnexpandedPack);
}
/// Whether this expression contains subexpressions which had errors, e.g. a
/// TypoExpr.
bool containsErrors() const {
return static_cast<bool>(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<Kinds>(Kind); }
ModifiableType getModifiable() const {
assert(Modifiable != CM_Untested && "Did not test for modifiability.");
return static_cast<ModifiableType>(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<ReferenceType>())
return (isa<LValueReferenceType>(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<ExprValueKind>(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<ExprObjectKind>(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<Expr*>(this)->getSourceBitField();
}
Decl *getReferencedDeclOfCallee();
const Decl *getReferencedDeclOfCallee() const {
return const_cast<Expr*>(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<BuiltinType>(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<llvm::APSInt> 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;
/// 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<PartialDiagnosticAt> *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<PartialDiagnosticAt> *Diag = nullptr) const;
llvm::APSInt EvaluateKnownConstIntCheckOverflow(
const ASTContext &Ctx,
SmallVectorImpl<PartialDiagnosticAt> *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<PartialDiagnosticAt> &Notes,
bool IsConstantInitializer) 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<const Expr*> 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<Expr *>(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<Expr *>(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<Expr *>(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<Expr *>(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<Expr *>(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<Expr *>(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<Expr *>(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<Expr *>(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<Expr *>(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<Expr *>(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<Expr *>(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<Expr *>(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<Expr *> 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<const Expr *> &CommaLHS,
SmallVectorImpl<SubobjectAdjustment> &Adjustments) const;
const Expr *skipRValueSubobjectAdjustments() const {
SmallVector<const Expr *, 8> CommaLHSs;
SmallVector<SubobjectAdjustment, 8> 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<Expr *>::NumLowBitsAvailable <=
llvm::detail::ConstantLog2<alignof(Expr)>::value,
"PointerLikeTypeTraits<Expr*> 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<Expr>(SubExpr); }
Expr *getSubExpr() { return cast<Expr>(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<ConstantExpr, APValue, uint64_t> {
static_assert(std::is_same<uint64_t, llvm::APInt::WordType>::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<APValue>) const {
return ConstantExprBits.ResultKind == ConstantExpr::RSK_APValue;
}
size_t numTrailingObjects(OverloadToken<uint64_t>) const {
return ConstantExprBits.ResultKind == ConstantExpr::RSK_Int64;
}
uint64_t &Int64Result() {
assert(ConstantExprBits.ResultKind == ConstantExpr::RSK_Int64 &&
"invalid accessor");
return *getTrailingObjects<uint64_t>();
}
const uint64_t &Int64Result() const {
return const_cast<ConstantExpr *>(this)->Int64Result();
}
APValue &APValueResult() {
assert(ConstantExprBits.ResultKind == ConstantExpr::RSK_APValue &&
"invalid accessor");
return *getTrailingObjects<APValue>();
}
APValue &APValueResult() const {
return const_cast<ConstantExpr *>(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<APValue::ValueKind>(ConstantExprBits.APValueKind);
}
ResultStorageKind getResultStorageKind() const {
return static_cast<ResultStorageKind>(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<DeclRefExpr, NestedNameSpecifierLoc,
NamedDecl *, ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc> {
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<NestedNameSpecifierLoc>) const {
return hasQualifier();
}
size_t numTrailingObjects(OverloadToken<NamedDecl *>) const {
return hasFoundDecl();
}
size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) 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<NestedNameSpecifierLoc>();
}
/// 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<NamedDecl *>() : D;
}
/// Get the NamedDecl through which this reference occurred.
/// See non-const variant.
const NamedDecl *getFoundDecl() const {
return hasFoundDecl() ? *getTrailingObjects<NamedDecl *>() : 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<ASTTemplateKWAndArgsInfo>()->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<ASTTemplateKWAndArgsInfo>()->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<ASTTemplateKWAndArgsInfo>()->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<ASTTemplateKWAndArgsInfo>()->copyInto(
getTrailingObjects<TemplateArgumentLoc>(), List);
}
/// Retrieve the template arguments provided as part of this
/// template-id.
const TemplateArgumentLoc *getTemplateArgs() const {
if (!hasExplicitTemplateArgs())
return nullptr;
return getTrailingObjects<TemplateArgumentLoc>();
}
/// Retrieve the number of template arguments provided as part of this
/// template-id.
unsigned getNumTemplateArgs() const {
if (!hasExplicitTemplateArgs())
return 0;
return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->NumTemplateArgs;
}
ArrayRef<TemplateArgumentLoc> 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<NonOdrUseReason>(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<CharacterKind>(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<llvm::APFloatBase::Semantics>(
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<llvm::APFloatBase::Semantics>(
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<Expr>(Val); }
Expr *getSubExpr() { return cast<Expr>(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<StringLiteral, unsigned, SourceLocation,
char> {
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<unsigned>) const { return 1; }
unsigned numTrailingObjects(OverloadToken<SourceLocation>) const {
return getNumConcatenated();
}
unsigned numTrailingObjects(OverloadToken<char>) const {
return getByteLength();
}
char *getStrDataAsChar() { return getTrailingObjects<char>(); }
const char *getStrDataAsChar() const { return getTrailingObjects<char>(); }
const uint16_t *getStrDataAsUInt16() const {
return reinterpret_cast<const uint16_t *>(getTrailingObjects<char>());
}
const uint32_t *getStrDataAsUInt32() const {
return reinterpret_cast<const uint32_t *>(getTrailingObjects<char>());
}
/// 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<SourceLocation>()[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<unsigned char>(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>(); }
unsigned getCharByteWidth() const { return StringLiteralBits.CharByteWidth; }
StringKind getKind() const {
return static_cast<StringKind>(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<SourceLocation>()[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<SourceLocation>();
}
tokloc_iterator tokloc_end() const {
return getTrailingObjects<SourceLocation>() + 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<PredefinedExpr, Stmt *> {
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<Stmt *>() = 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<IdentKind>(PredefinedExprBits.Kind);
}
SourceLocation getLocation() const { return PredefinedExprBits.Loc; }
void setLocation(SourceLocation L) { PredefinedExprBits.Loc = L; }
StringLiteral *getFunctionName() {
return hasFunctionName()
? static_cast<StringLiteral *>(*getTrailingObjects<Stmt *>())
: nullptr;
}
const StringLiteral *getFunctionName() const {
return hasFunctionName()
? static_cast<StringLiteral *>(*getTrailingObjects<Stmt *>())
: 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<Stmt *>(),
getTrailingObjects<Stmt *>() + hasFunctionName());
}
const_child_range children() const {
return const_child_range(getTrailingObjects<Stmt *>(),
getTrailingObjects<Stmt *>() + 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<Expr>(Val); }
Expr *getSubExpr() { return cast<Expr>(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<UnaryOperator, FPOptionsOverride> {
Stmt *Val;
size_t numTrailingObjects(OverloadToken<FPOptionsOverride>) const {
return UnaryOperatorBits.HasFPFeatures ? 1 : 0;
}
FPOptionsOverride &getTrailingFPFeatures() {
assert(UnaryOperatorBits.HasFPFeatures);
return *getTrailingObjects<FPOptionsOverride>();
}
const FPOptionsOverride &getTrailingFPFeatures() const {
assert(UnaryOperatorBits.HasFPFeatures);
return *getTrailingObjects<FPOptionsOverride>();
}
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<Opcode>(UnaryOperatorBits.Opc);
}
void setOpcode(Opcode Opc) { UnaryOperatorBits.Opc = Opc; }
Expr *getSubExpr() const { return cast<Expr>(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<uintptr_t>(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<uintptr_t>(Name) | Identifier) {}
/// Create an offsetof node that refers into a C++ base class.
explicit OffsetOfNode(const CXXBaseSpecifier *Base)
: Range(), Data(reinterpret_cast<uintptr_t>(Base) | OffsetOfNode::Base) {}
/// Determine what kind of offsetof node this is.
Kind getKind() const { return static_cast<Kind>(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<FieldDecl *>(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<CXXBaseSpecifier *>(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<OffsetOfExpr, OffsetOfNode, Expr *> {
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<OffsetOfNode>) const {
return NumComps;
}
OffsetOfExpr(const ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> 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<OffsetOfNode> comps,
ArrayRef<Expr*> 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<OffsetOfNode>()[Idx];
}
void setComponent(unsigned Idx, OffsetOfNode ON) {
assert(Idx < NumComps && "Subscript out of range");
getTrailingObjects<OffsetOfNode>()[Idx] = ON;
}
unsigned getNumComponents() const {
return NumComps;
}
Expr* getIndexExpr(unsigned Idx) {
assert(Idx < NumExprs && "Subscript out of range");
return getTrailingObjects<Expr *>()[Idx];
}
const Expr *getIndexExpr(unsigned Idx) const {
assert(Idx < NumExprs && "Subscript out of range");
return getTrailingObjects<Expr *>()[Idx];
}
void setIndexExpr(unsigned Idx, Expr* E) {
assert(Idx < NumComps && "Subscript out of range");
getTrailingObjects<Expr *>()[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<Stmt **>(getTrailingObjects<Expr *>());
return child_range(begin, begin + NumExprs);
}
const_child_range children() const {
Stmt *const *begin =
reinterpret_cast<Stmt *const *>(getTrailingObjects<Expr *>());
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<unsigned>(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<UnaryExprOrTypeTrait>(UnaryExprOrTypeTraitExprBits.Kind);
}
void setKind(UnaryExprOrTypeTrait K) {
assert(K <= UETT_Last && "invalid enum value!");
UnaryExprOrTypeTraitExprBits.Kind = K;
assert(static_cast<unsigned>(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<Expr*>(Argument.Ex);
}
const Expr *getArgumentExpr() const {
return const_cast<UnaryExprOrTypeTraitExpr*>(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<Expr>(SubExprs[LHS]); }
const Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); }
void setLHS(Expr *E) { SubExprs[LHS] = E; }
Expr *getRHS() { return cast<Expr>(SubExprs[RHS]); }
const Expr *getRHS() const { return cast<Expr>(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<Expr>(SubExprs[BASE]); }
const Expr *getBase() const { return cast<Expr>(SubExprs[BASE]); }
void setBase(Expr *E) { SubExprs[BASE] = E; }
Expr *getRowIdx() { return cast<Expr>(SubExprs[ROW_IDX]); }
const Expr *getRowIdx() const { return cast<Expr>(SubExprs[ROW_IDX]); }
void setRowIdx(Expr *E) { SubExprs[ROW_IDX] = E; }
Expr *getColumnIdx() { return cast_or_null<Expr>(SubExprs[COLUMN_IDX]); }
const Expr *getColumnIdx() const {
assert(!isIncomplete() &&
"cannot get the column index of an incomplete expression");
return cast<Expr>(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<Stmt **>(reinterpret_cast<char *>(this) +
CallExprBits.OffsetToTrailingObjects);
}
Stmt *const *getTrailingStmts() const {
return const_cast<CallExpr *>(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<Expr *> PreArgs,
ArrayRef<Expr *> 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(</