Changeset View
Changeset View
Standalone View
Standalone View
cfe/trunk/lib/AST/ExprConstant.cpp
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
#include "clang/AST/Expr.h" | #include "clang/AST/Expr.h" | ||||
#include "clang/AST/OSLog.h" | #include "clang/AST/OSLog.h" | ||||
#include "clang/AST/RecordLayout.h" | #include "clang/AST/RecordLayout.h" | ||||
#include "clang/AST/StmtVisitor.h" | #include "clang/AST/StmtVisitor.h" | ||||
#include "clang/AST/TypeLoc.h" | #include "clang/AST/TypeLoc.h" | ||||
#include "clang/Basic/Builtins.h" | #include "clang/Basic/Builtins.h" | ||||
#include "clang/Basic/FixedPoint.h" | #include "clang/Basic/FixedPoint.h" | ||||
#include "clang/Basic/TargetInfo.h" | #include "clang/Basic/TargetInfo.h" | ||||
#include "llvm/ADT/Optional.h" | |||||
#include "llvm/ADT/SmallBitVector.h" | #include "llvm/ADT/SmallBitVector.h" | ||||
#include "llvm/Support/SaveAndRestore.h" | #include "llvm/Support/SaveAndRestore.h" | ||||
#include "llvm/Support/raw_ostream.h" | #include "llvm/Support/raw_ostream.h" | ||||
#include <cstring> | #include <cstring> | ||||
#include <functional> | #include <functional> | ||||
#define DEBUG_TYPE "exprconstant" | #define DEBUG_TYPE "exprconstant" | ||||
using namespace clang; | using namespace clang; | ||||
using llvm::APInt; | |||||
using llvm::APSInt; | using llvm::APSInt; | ||||
using llvm::APFloat; | using llvm::APFloat; | ||||
using llvm::Optional; | |||||
static bool IsGlobalLValue(APValue::LValueBase B); | static bool IsGlobalLValue(APValue::LValueBase B); | ||||
namespace { | namespace { | ||||
struct LValue; | struct LValue; | ||||
struct CallStackFrame; | struct CallStackFrame; | ||||
struct EvalInfo; | struct EvalInfo; | ||||
▲ Show 20 Lines • Show All 2,583 Lines • ▼ Show 20 Lines | if (Imag) { | ||||
if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfComponent)) | if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfComponent)) | ||||
return false; | return false; | ||||
LVal.Offset += SizeOfComponent; | LVal.Offset += SizeOfComponent; | ||||
} | } | ||||
LVal.addComplex(Info, E, EltTy, Imag); | LVal.addComplex(Info, E, EltTy, Imag); | ||||
return true; | return true; | ||||
} | } | ||||
static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, | |||||
QualType Type, const LValue &LVal, | |||||
APValue &RVal); | |||||
/// Try to evaluate the initializer for a variable declaration. | /// Try to evaluate the initializer for a variable declaration. | ||||
/// | /// | ||||
/// \param Info Information about the ongoing evaluation. | /// \param Info Information about the ongoing evaluation. | ||||
/// \param E An expression to be used when printing diagnostics. | /// \param E An expression to be used when printing diagnostics. | ||||
/// \param VD The variable whose initializer should be obtained. | /// \param VD The variable whose initializer should be obtained. | ||||
/// \param Frame The frame in which the variable was created. Must be null | /// \param Frame The frame in which the variable was created. Must be null | ||||
/// if this variable is not local to the evaluation. | /// if this variable is not local to the evaluation. | ||||
/// \param Result Filled in with a pointer to the value of the variable. | /// \param Result Filled in with a pointer to the value of the variable. | ||||
▲ Show 20 Lines • Show All 2,699 Lines • ▼ Show 20 Lines | return HandleConstructorCall(E, This, ArgValues.data(), Definition, | ||||
Info, Result); | Info, Result); | ||||
} | } | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
// Generic Evaluation | // Generic Evaluation | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
namespace { | namespace { | ||||
class BitCastBuffer { | |||||
// FIXME: We're going to need bit-level granularity when we support | |||||
// bit-fields. | |||||
// FIXME: Its possible under the C++ standard for 'char' to not be 8 bits, but | |||||
// we don't support a host or target where that is the case. Still, we should | |||||
// use a more generic type in case we ever do. | |||||
SmallVector<Optional<unsigned char>, 32> Bytes; | |||||
static_assert(std::numeric_limits<unsigned char>::digits >= 8, | |||||
"Need at least 8 bit unsigned char"); | |||||
bool TargetIsLittleEndian; | |||||
public: | |||||
BitCastBuffer(CharUnits Width, bool TargetIsLittleEndian) | |||||
: Bytes(Width.getQuantity()), | |||||
TargetIsLittleEndian(TargetIsLittleEndian) {} | |||||
LLVM_NODISCARD | |||||
bool readObject(CharUnits Offset, CharUnits Width, | |||||
SmallVectorImpl<unsigned char> &Output) const { | |||||
for (CharUnits I = Offset, E = Offset + Width; I != E; ++I) { | |||||
// If a byte of an integer is uninitialized, then the whole integer is | |||||
// uninitalized. | |||||
if (!Bytes[I.getQuantity()]) | |||||
return false; | |||||
Output.push_back(*Bytes[I.getQuantity()]); | |||||
} | |||||
if (llvm::sys::IsLittleEndianHost != TargetIsLittleEndian) | |||||
std::reverse(Output.begin(), Output.end()); | |||||
return true; | |||||
} | |||||
void writeObject(CharUnits Offset, SmallVectorImpl<unsigned char> &Input) { | |||||
if (llvm::sys::IsLittleEndianHost != TargetIsLittleEndian) | |||||
std::reverse(Input.begin(), Input.end()); | |||||
size_t Index = 0; | |||||
for (unsigned char Byte : Input) { | |||||
assert(!Bytes[Offset.getQuantity() + Index] && "overwriting a byte?"); | |||||
Bytes[Offset.getQuantity() + Index] = Byte; | |||||
++Index; | |||||
} | |||||
} | |||||
size_t size() { return Bytes.size(); } | |||||
}; | |||||
/// Traverse an APValue to produce an BitCastBuffer, emulating how the current | |||||
/// target would represent the value at runtime. | |||||
class APValueToBufferConverter { | |||||
EvalInfo &Info; | |||||
BitCastBuffer Buffer; | |||||
const CastExpr *BCE; | |||||
APValueToBufferConverter(EvalInfo &Info, CharUnits ObjectWidth, | |||||
const CastExpr *BCE) | |||||
: Info(Info), | |||||
Buffer(ObjectWidth, Info.Ctx.getTargetInfo().isLittleEndian()), | |||||
BCE(BCE) {} | |||||
bool visit(const APValue &Val, QualType Ty) { | |||||
return visit(Val, Ty, CharUnits::fromQuantity(0)); | |||||
} | |||||
// Write out Val with type Ty into Buffer starting at Offset. | |||||
bool visit(const APValue &Val, QualType Ty, CharUnits Offset) { | |||||
assert((size_t)Offset.getQuantity() <= Buffer.size()); | |||||
// As a special case, nullptr_t has an indeterminate value. | |||||
if (Ty->isNullPtrType()) | |||||
return true; | |||||
// Dig through Src to find the byte at SrcOffset. | |||||
switch (Val.getKind()) { | |||||
case APValue::Indeterminate: | |||||
case APValue::None: | |||||
return true; | |||||
case APValue::Int: | |||||
return visitInt(Val.getInt(), Ty, Offset); | |||||
case APValue::Float: | |||||
return visitFloat(Val.getFloat(), Ty, Offset); | |||||
case APValue::Array: | |||||
return visitArray(Val, Ty, Offset); | |||||
case APValue::Struct: | |||||
return visitRecord(Val, Ty, Offset); | |||||
case APValue::ComplexInt: | |||||
case APValue::ComplexFloat: | |||||
case APValue::Vector: | |||||
case APValue::FixedPoint: | |||||
// FIXME: We should support these. | |||||
case APValue::Union: | |||||
case APValue::MemberPointer: | |||||
case APValue::AddrLabelDiff: { | |||||
Info.FFDiag(BCE->getBeginLoc(), | |||||
diag::note_constexpr_bit_cast_unsupported_type) | |||||
<< Ty; | |||||
return false; | |||||
} | |||||
case APValue::LValue: | |||||
llvm_unreachable("LValue subobject in bit_cast?"); | |||||
} | |||||
} | |||||
bool visitRecord(const APValue &Val, QualType Ty, CharUnits Offset) { | |||||
const RecordDecl *RD = Ty->getAsRecordDecl(); | |||||
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); | |||||
// Visit the base classes. | |||||
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { | |||||
for (size_t I = 0, E = CXXRD->getNumBases(); I != E; ++I) { | |||||
const CXXBaseSpecifier &BS = CXXRD->bases_begin()[I]; | |||||
CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl(); | |||||
if (!visitRecord(Val.getStructBase(I), BS.getType(), | |||||
Layout.getBaseClassOffset(BaseDecl) + Offset)) | |||||
return false; | |||||
} | |||||
} | |||||
// Visit the fields. | |||||
unsigned FieldIdx = 0; | |||||
for (FieldDecl *FD : RD->fields()) { | |||||
if (FD->isBitField()) { | |||||
Info.FFDiag(BCE->getBeginLoc(), | |||||
diag::note_constexpr_bit_cast_unsupported_bitfield); | |||||
return false; | |||||
} | |||||
uint64_t FieldOffsetBits = Layout.getFieldOffset(FieldIdx); | |||||
assert(FieldOffsetBits % Info.Ctx.getCharWidth() == 0 && | |||||
"only bit-fields can have sub-char alignment"); | |||||
CharUnits FieldOffset = | |||||
Info.Ctx.toCharUnitsFromBits(FieldOffsetBits) + Offset; | |||||
QualType FieldTy = FD->getType(); | |||||
if (!visit(Val.getStructField(FieldIdx), FieldTy, FieldOffset)) | |||||
return false; | |||||
++FieldIdx; | |||||
} | |||||
return true; | |||||
} | |||||
bool visitArray(const APValue &Val, QualType Ty, CharUnits Offset) { | |||||
const auto *CAT = | |||||
dyn_cast_or_null<ConstantArrayType>(Ty->getAsArrayTypeUnsafe()); | |||||
if (!CAT) | |||||
return false; | |||||
CharUnits ElemWidth = Info.Ctx.getTypeSizeInChars(CAT->getElementType()); | |||||
unsigned NumInitializedElts = Val.getArrayInitializedElts(); | |||||
unsigned ArraySize = Val.getArraySize(); | |||||
// First, initialize the initialized elements. | |||||
for (unsigned I = 0; I != NumInitializedElts; ++I) { | |||||
const APValue &SubObj = Val.getArrayInitializedElt(I); | |||||
if (!visit(SubObj, CAT->getElementType(), Offset + I * ElemWidth)) | |||||
return false; | |||||
} | |||||
// Next, initialize the rest of the array using the filler. | |||||
if (Val.hasArrayFiller()) { | |||||
const APValue &Filler = Val.getArrayFiller(); | |||||
for (unsigned I = NumInitializedElts; I != ArraySize; ++I) { | |||||
if (!visit(Filler, CAT->getElementType(), Offset + I * ElemWidth)) | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
bool visitInt(const APSInt &Val, QualType Ty, CharUnits Offset) { | |||||
CharUnits Width = Info.Ctx.getTypeSizeInChars(Ty); | |||||
SmallVector<unsigned char, 8> Bytes(Width.getQuantity()); | |||||
llvm::StoreIntToMemory(Val, &*Bytes.begin(), Width.getQuantity()); | |||||
Buffer.writeObject(Offset, Bytes); | |||||
return true; | |||||
} | |||||
bool visitFloat(const APFloat &Val, QualType Ty, CharUnits Offset) { | |||||
APSInt AsInt(Val.bitcastToAPInt()); | |||||
return visitInt(AsInt, Ty, Offset); | |||||
} | |||||
public: | |||||
static Optional<BitCastBuffer> convert(EvalInfo &Info, const APValue &Src, | |||||
const CastExpr *BCE) { | |||||
CharUnits DstSize = Info.Ctx.getTypeSizeInChars(BCE->getType()); | |||||
APValueToBufferConverter Converter(Info, DstSize, BCE); | |||||
if (!Converter.visit(Src, BCE->getSubExpr()->getType())) | |||||
return None; | |||||
return Converter.Buffer; | |||||
} | |||||
}; | |||||
/// Write an BitCastBuffer into an APValue. | |||||
class BufferToAPValueConverter { | |||||
EvalInfo &Info; | |||||
const BitCastBuffer &Buffer; | |||||
const CastExpr *BCE; | |||||
BufferToAPValueConverter(EvalInfo &Info, const BitCastBuffer &Buffer, | |||||
const CastExpr *BCE) | |||||
: Info(Info), Buffer(Buffer), BCE(BCE) {} | |||||
// Emit an unsupported bit_cast type error. Sema refuses to build a bit_cast | |||||
// with an invalid type, so anything left is a deficiency on our part (FIXME). | |||||
// Ideally this will be unreachable. | |||||
llvm::NoneType unsupportedType(QualType Ty) { | |||||
Info.FFDiag(BCE->getBeginLoc(), | |||||
diag::note_constexpr_bit_cast_unsupported_type) | |||||
<< Ty; | |||||
return None; | |||||
} | |||||
Optional<APValue> visit(const BuiltinType *T, CharUnits Offset, | |||||
const EnumType *EnumSugar = nullptr) { | |||||
if (T->isNullPtrType()) { | |||||
uint64_t NullValue = Info.Ctx.getTargetNullPointerValue(QualType(T, 0)); | |||||
return APValue((Expr *)nullptr, | |||||
/*Offset=*/CharUnits::fromQuantity(NullValue), | |||||
APValue::NoLValuePath{}, /*IsNullPtr=*/true); | |||||
} | |||||
CharUnits SizeOf = Info.Ctx.getTypeSizeInChars(T); | |||||
SmallVector<uint8_t, 8> Bytes; | |||||
if (!Buffer.readObject(Offset, SizeOf, Bytes)) { | |||||
// If this is std::byte or unsigned char, then its okay to store an | |||||
// indeterminate value. | |||||
bool IsStdByte = EnumSugar && EnumSugar->isStdByteType(); | |||||
bool IsUChar = | |||||
!EnumSugar && (T->isSpecificBuiltinType(BuiltinType::UChar) || | |||||
T->isSpecificBuiltinType(BuiltinType::Char_U)); | |||||
if (!IsStdByte && !IsUChar) { | |||||
QualType DisplayType(EnumSugar ? (Type *)EnumSugar : T, 0); | |||||
Info.FFDiag(BCE->getExprLoc(), | |||||
diag::note_constexpr_bit_cast_indet_dest) | |||||
<< DisplayType << Info.Ctx.getLangOpts().CharIsSigned; | |||||
return None; | |||||
} | |||||
return APValue::IndeterminateValue(); | |||||
} | |||||
APSInt Val(SizeOf.getQuantity() * Info.Ctx.getCharWidth(), true); | |||||
llvm::LoadIntFromMemory(Val, &*Bytes.begin(), Bytes.size()); | |||||
if (T->isIntegralOrEnumerationType()) { | |||||
Val.setIsSigned(T->isSignedIntegerOrEnumerationType()); | |||||
return APValue(Val); | |||||
} | |||||
if (T->isRealFloatingType()) { | |||||
const llvm::fltSemantics &Semantics = | |||||
Info.Ctx.getFloatTypeSemantics(QualType(T, 0)); | |||||
return APValue(APFloat(Semantics, Val)); | |||||
} | |||||
return unsupportedType(QualType(T, 0)); | |||||
} | |||||
Optional<APValue> visit(const RecordType *RTy, CharUnits Offset) { | |||||
const RecordDecl *RD = RTy->getAsRecordDecl(); | |||||
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); | |||||
unsigned NumBases = 0; | |||||
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) | |||||
NumBases = CXXRD->getNumBases(); | |||||
APValue ResultVal(APValue::UninitStruct(), NumBases, | |||||
std::distance(RD->field_begin(), RD->field_end())); | |||||
// Visit the base classes. | |||||
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { | |||||
for (size_t I = 0, E = CXXRD->getNumBases(); I != E; ++I) { | |||||
const CXXBaseSpecifier &BS = CXXRD->bases_begin()[I]; | |||||
CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl(); | |||||
if (BaseDecl->isEmpty() || | |||||
Info.Ctx.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero()) | |||||
continue; | |||||
Optional<APValue> SubObj = visitType( | |||||
BS.getType(), Layout.getBaseClassOffset(BaseDecl) + Offset); | |||||
if (!SubObj) | |||||
return None; | |||||
ResultVal.getStructBase(I) = *SubObj; | |||||
} | |||||
} | |||||
// Visit the fields. | |||||
unsigned FieldIdx = 0; | |||||
for (FieldDecl *FD : RD->fields()) { | |||||
// FIXME: We don't currently support bit-fields. A lot of the logic for | |||||
// this is in CodeGen, so we need to factor it around. | |||||
if (FD->isBitField()) { | |||||
Info.FFDiag(BCE->getBeginLoc(), | |||||
diag::note_constexpr_bit_cast_unsupported_bitfield); | |||||
return None; | |||||
} | |||||
uint64_t FieldOffsetBits = Layout.getFieldOffset(FieldIdx); | |||||
assert(FieldOffsetBits % Info.Ctx.getCharWidth() == 0); | |||||
CharUnits FieldOffset = | |||||
CharUnits::fromQuantity(FieldOffsetBits / Info.Ctx.getCharWidth()) + | |||||
Offset; | |||||
QualType FieldTy = FD->getType(); | |||||
Optional<APValue> SubObj = visitType(FieldTy, FieldOffset); | |||||
if (!SubObj) | |||||
return None; | |||||
ResultVal.getStructField(FieldIdx) = *SubObj; | |||||
++FieldIdx; | |||||
} | |||||
return ResultVal; | |||||
} | |||||
Optional<APValue> visit(const EnumType *Ty, CharUnits Offset) { | |||||
QualType RepresentationType = Ty->getDecl()->getIntegerType(); | |||||
assert(!RepresentationType.isNull() && | |||||
"enum forward decl should be caught by Sema"); | |||||
const BuiltinType *AsBuiltin = | |||||
RepresentationType.getCanonicalType()->getAs<BuiltinType>(); | |||||
assert(AsBuiltin && "non-integral enum underlying type?"); | |||||
// Recurse into the underlying type. Treat std::byte transparently as | |||||
// unsigned char. | |||||
return visit(AsBuiltin, Offset, /*EnumTy=*/Ty); | |||||
} | |||||
Optional<APValue> visit(const ConstantArrayType *Ty, CharUnits Offset) { | |||||
size_t Size = Ty->getSize().getLimitedValue(); | |||||
CharUnits ElementWidth = Info.Ctx.getTypeSizeInChars(Ty->getElementType()); | |||||
APValue ArrayValue(APValue::UninitArray(), Size, Size); | |||||
for (size_t I = 0; I != Size; ++I) { | |||||
Optional<APValue> ElementValue = | |||||
visitType(Ty->getElementType(), Offset + I * ElementWidth); | |||||
if (!ElementValue) | |||||
return None; | |||||
ArrayValue.getArrayInitializedElt(I) = std::move(*ElementValue); | |||||
} | |||||
return ArrayValue; | |||||
} | |||||
Optional<APValue> visit(const Type *Ty, CharUnits Offset) { | |||||
return unsupportedType(QualType(Ty, 0)); | |||||
} | |||||
Optional<APValue> visitType(QualType Ty, CharUnits Offset) { | |||||
QualType Can = Ty.getCanonicalType(); | |||||
switch (Can->getTypeClass()) { | |||||
#define TYPE(Class, Base) \ | |||||
case Type::Class: \ | |||||
return visit(cast<Class##Type>(Can.getTypePtr()), Offset); | |||||
#define ABSTRACT_TYPE(Class, Base) | |||||
#define NON_CANONICAL_TYPE(Class, Base) \ | |||||
case Type::Class: \ | |||||
llvm_unreachable("non-canonical type should be impossible!"); | |||||
#define DEPENDENT_TYPE(Class, Base) \ | |||||
case Type::Class: \ | |||||
llvm_unreachable( \ | |||||
"dependent types aren't supported in the constant evaluator!"); | |||||
#define NON_CANONICAL_UNLESS_DEPENDENT(Class, Base) \ | |||||
case Type::Class: \ | |||||
llvm_unreachable("either dependent or not canonical!"); | |||||
#include "clang/AST/TypeNodes.def" | |||||
} | |||||
} | |||||
public: | |||||
// Pull out a full value of type DstType. | |||||
static Optional<APValue> convert(EvalInfo &Info, BitCastBuffer &Buffer, | |||||
const CastExpr *BCE) { | |||||
BufferToAPValueConverter Converter(Info, Buffer, BCE); | |||||
return Converter.visitType(BCE->getType(), CharUnits::fromQuantity(0)); | |||||
} | |||||
}; | |||||
static bool checkBitCastConstexprEligibilityType(SourceLocation Loc, | |||||
QualType Ty, EvalInfo *Info, | |||||
const ASTContext &Ctx, | |||||
bool CheckingDest) { | |||||
Ty = Ty.getCanonicalType(); | |||||
auto diag = [&](int Reason) { | |||||
if (Info) | |||||
Info->FFDiag(Loc, diag::note_constexpr_bit_cast_invalid_type) | |||||
<< CheckingDest << (Reason == 4) << Reason; | |||||
return false; | |||||
}; | |||||
auto note = [&](int Construct, QualType NoteTy, SourceLocation NoteLoc) { | |||||
if (Info) | |||||
Info->Note(NoteLoc, diag::note_constexpr_bit_cast_invalid_subtype) | |||||
<< NoteTy << Construct << Ty; | |||||
return false; | |||||
}; | |||||
if (Ty->isUnionType()) | |||||
return diag(0); | |||||
if (Ty->isPointerType()) | |||||
return diag(1); | |||||
if (Ty->isMemberPointerType()) | |||||
return diag(2); | |||||
if (Ty.isVolatileQualified()) | |||||
return diag(3); | |||||
if (RecordDecl *Record = Ty->getAsRecordDecl()) { | |||||
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(Record)) { | |||||
for (CXXBaseSpecifier &BS : CXXRD->bases()) | |||||
if (!checkBitCastConstexprEligibilityType(Loc, BS.getType(), Info, Ctx, | |||||
CheckingDest)) | |||||
return note(1, BS.getType(), BS.getBeginLoc()); | |||||
} | |||||
for (FieldDecl *FD : Record->fields()) { | |||||
if (FD->getType()->isReferenceType()) | |||||
return diag(4); | |||||
if (!checkBitCastConstexprEligibilityType(Loc, FD->getType(), Info, Ctx, | |||||
CheckingDest)) | |||||
return note(0, FD->getType(), FD->getBeginLoc()); | |||||
} | |||||
} | |||||
if (Ty->isArrayType() && | |||||
!checkBitCastConstexprEligibilityType(Loc, Ctx.getBaseElementType(Ty), | |||||
Info, Ctx, CheckingDest)) | |||||
return false; | |||||
return true; | |||||
} | |||||
static bool checkBitCastConstexprEligibility(EvalInfo *Info, | |||||
const ASTContext &Ctx, | |||||
const CastExpr *BCE) { | |||||
bool DestOK = checkBitCastConstexprEligibilityType( | |||||
BCE->getBeginLoc(), BCE->getType(), Info, Ctx, true); | |||||
bool SourceOK = DestOK && checkBitCastConstexprEligibilityType( | |||||
BCE->getBeginLoc(), | |||||
BCE->getSubExpr()->getType(), Info, Ctx, false); | |||||
return SourceOK; | |||||
} | |||||
static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue, | |||||
APValue &SourceValue, | |||||
const CastExpr *BCE) { | |||||
assert(CHAR_BIT == 8 && Info.Ctx.getTargetInfo().getCharWidth() == 8 && | |||||
"no host or target supports non 8-bit chars"); | |||||
assert(SourceValue.isLValue() && | |||||
"LValueToRValueBitcast requires an lvalue operand!"); | |||||
if (!checkBitCastConstexprEligibility(&Info, Info.Ctx, BCE)) | |||||
return false; | |||||
LValue SourceLValue; | |||||
APValue SourceRValue; | |||||
SourceLValue.setFrom(Info.Ctx, SourceValue); | |||||
if (!handleLValueToRValueConversion(Info, BCE, | |||||
BCE->getSubExpr()->getType().withConst(), | |||||
SourceLValue, SourceRValue)) | |||||
return false; | |||||
// Read out SourceValue into a char buffer. | |||||
Optional<BitCastBuffer> Buffer = | |||||
APValueToBufferConverter::convert(Info, SourceRValue, BCE); | |||||
if (!Buffer) | |||||
return false; | |||||
// Write out the buffer into a new APValue. | |||||
Optional<APValue> MaybeDestValue = | |||||
BufferToAPValueConverter::convert(Info, *Buffer, BCE); | |||||
if (!MaybeDestValue) | |||||
return false; | |||||
DestValue = std::move(*MaybeDestValue); | |||||
return true; | |||||
} | |||||
template <class Derived> | template <class Derived> | ||||
class ExprEvaluatorBase | class ExprEvaluatorBase | ||||
: public ConstStmtVisitor<Derived, bool> { | : public ConstStmtVisitor<Derived, bool> { | ||||
private: | private: | ||||
Derived &getDerived() { return static_cast<Derived&>(*this); } | Derived &getDerived() { return static_cast<Derived&>(*this); } | ||||
bool DerivedSuccess(const APValue &V, const Expr *E) { | bool DerivedSuccess(const APValue &V, const Expr *E) { | ||||
return getDerived().Success(V, E); | return getDerived().Success(V, E); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E) { | ||||
CCEDiag(E, diag::note_constexpr_invalid_cast) << 0; | CCEDiag(E, diag::note_constexpr_invalid_cast) << 0; | ||||
return static_cast<Derived*>(this)->VisitCastExpr(E); | return static_cast<Derived*>(this)->VisitCastExpr(E); | ||||
} | } | ||||
bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) { | bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) { | ||||
if (!Info.Ctx.getLangOpts().CPlusPlus2a) | if (!Info.Ctx.getLangOpts().CPlusPlus2a) | ||||
CCEDiag(E, diag::note_constexpr_invalid_cast) << 1; | CCEDiag(E, diag::note_constexpr_invalid_cast) << 1; | ||||
return static_cast<Derived*>(this)->VisitCastExpr(E); | return static_cast<Derived*>(this)->VisitCastExpr(E); | ||||
} | } | ||||
bool VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *E) { | |||||
return static_cast<Derived*>(this)->VisitCastExpr(E); | |||||
} | |||||
bool VisitBinaryOperator(const BinaryOperator *E) { | bool VisitBinaryOperator(const BinaryOperator *E) { | ||||
switch (E->getOpcode()) { | switch (E->getOpcode()) { | ||||
default: | default: | ||||
return Error(E); | return Error(E); | ||||
case BO_Comma: | case BO_Comma: | ||||
VisitIgnoredValue(E->getLHS()); | VisitIgnoredValue(E->getLHS()); | ||||
▲ Show 20 Lines • Show All 276 Lines • ▼ Show 20 Lines | case CK_LValueToRValue: { | ||||
return false; | return false; | ||||
APValue RVal; | APValue RVal; | ||||
// Note, we use the subexpression's type in order to retain cv-qualifiers. | // Note, we use the subexpression's type in order to retain cv-qualifiers. | ||||
if (!handleLValueToRValueConversion(Info, E, E->getSubExpr()->getType(), | if (!handleLValueToRValueConversion(Info, E, E->getSubExpr()->getType(), | ||||
LVal, RVal)) | LVal, RVal)) | ||||
return false; | return false; | ||||
return DerivedSuccess(RVal, E); | return DerivedSuccess(RVal, E); | ||||
} | } | ||||
case CK_LValueToRValueBitCast: { | |||||
APValue DestValue, SourceValue; | |||||
if (!Evaluate(SourceValue, Info, E->getSubExpr())) | |||||
return false; | |||||
if (!handleLValueToRValueBitCast(Info, DestValue, SourceValue, E)) | |||||
return false; | |||||
return DerivedSuccess(DestValue, E); | |||||
} | |||||
} | } | ||||
return Error(E); | return Error(E); | ||||
} | } | ||||
bool VisitUnaryPostInc(const UnaryOperator *UO) { | bool VisitUnaryPostInc(const UnaryOperator *UO) { | ||||
return VisitUnaryPostIncDec(UO); | return VisitUnaryPostIncDec(UO); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 833 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { | bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { | ||||
const Expr *SubExpr = E->getSubExpr(); | const Expr *SubExpr = E->getSubExpr(); | ||||
switch (E->getCastKind()) { | switch (E->getCastKind()) { | ||||
default: | default: | ||||
break; | break; | ||||
case CK_BitCast: | case CK_BitCast: | ||||
case CK_CPointerToObjCPointerCast: | case CK_CPointerToObjCPointerCast: | ||||
case CK_BlockPointerToObjCPointerCast: | case CK_BlockPointerToObjCPointerCast: | ||||
case CK_AnyPointerToBlockPointerCast: | case CK_AnyPointerToBlockPointerCast: | ||||
case CK_AddressSpaceConversion: | case CK_AddressSpaceConversion: | ||||
if (!Visit(SubExpr)) | if (!Visit(SubExpr)) | ||||
return false; | return false; | ||||
// Bitcasts to cv void* are static_casts, not reinterpret_casts, so are | // Bitcasts to cv void* are static_casts, not reinterpret_casts, so are | ||||
▲ Show 20 Lines • Show All 1,508 Lines • ▼ Show 20 Lines | bool Success(uint64_t Value, const Expr *E) { | ||||
return Success(Value, E, Result); | return Success(Value, E, Result); | ||||
} | } | ||||
bool Success(CharUnits Size, const Expr *E) { | bool Success(CharUnits Size, const Expr *E) { | ||||
return Success(Size.getQuantity(), E); | return Success(Size.getQuantity(), E); | ||||
} | } | ||||
bool Success(const APValue &V, const Expr *E) { | bool Success(const APValue &V, const Expr *E) { | ||||
if (V.isLValue() || V.isAddrLabelDiff()) { | if (V.isLValue() || V.isAddrLabelDiff() || V.isIndeterminate()) { | ||||
Result = V; | Result = V; | ||||
return true; | return true; | ||||
} | } | ||||
return Success(V.getInt(), E); | return Success(V.getInt(), E); | ||||
} | } | ||||
bool ZeroInitialization(const Expr *E) { return Success(0, E); } | bool ZeroInitialization(const Expr *E) { return Success(0, E); } | ||||
▲ Show 20 Lines • Show All 2,405 Lines • ▼ Show 20 Lines | bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { | ||||
case CK_ARCExtendBlockObject: | case CK_ARCExtendBlockObject: | ||||
case CK_CopyAndAutoreleaseBlockObject: | case CK_CopyAndAutoreleaseBlockObject: | ||||
return Error(E); | return Error(E); | ||||
case CK_UserDefinedConversion: | case CK_UserDefinedConversion: | ||||
case CK_LValueToRValue: | case CK_LValueToRValue: | ||||
case CK_AtomicToNonAtomic: | case CK_AtomicToNonAtomic: | ||||
case CK_NoOp: | case CK_NoOp: | ||||
case CK_LValueToRValueBitCast: | |||||
return ExprEvaluatorBaseTy::VisitCastExpr(E); | return ExprEvaluatorBaseTy::VisitCastExpr(E); | ||||
case CK_MemberPointerToBoolean: | case CK_MemberPointerToBoolean: | ||||
case CK_PointerToBoolean: | case CK_PointerToBoolean: | ||||
case CK_IntegralToBoolean: | case CK_IntegralToBoolean: | ||||
case CK_FloatingToBoolean: | case CK_FloatingToBoolean: | ||||
case CK_BooleanToSignedIntegral: | case CK_BooleanToSignedIntegral: | ||||
case CK_FloatingComplexToBoolean: | case CK_FloatingComplexToBoolean: | ||||
▲ Show 20 Lines • Show All 596 Lines • ▼ Show 20 Lines | bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { | ||||
case CK_FixedPointToBoolean: | case CK_FixedPointToBoolean: | ||||
case CK_FixedPointToIntegral: | case CK_FixedPointToIntegral: | ||||
case CK_IntegralToFixedPoint: | case CK_IntegralToFixedPoint: | ||||
llvm_unreachable("invalid cast kind for complex value"); | llvm_unreachable("invalid cast kind for complex value"); | ||||
case CK_LValueToRValue: | case CK_LValueToRValue: | ||||
case CK_AtomicToNonAtomic: | case CK_AtomicToNonAtomic: | ||||
case CK_NoOp: | case CK_NoOp: | ||||
case CK_LValueToRValueBitCast: | |||||
return ExprEvaluatorBaseTy::VisitCastExpr(E); | return ExprEvaluatorBaseTy::VisitCastExpr(E); | ||||
case CK_Dependent: | case CK_Dependent: | ||||
case CK_LValueBitCast: | case CK_LValueBitCast: | ||||
case CK_UserDefinedConversion: | case CK_UserDefinedConversion: | ||||
return Error(E); | return Error(E); | ||||
case CK_FloatingRealToComplex: { | case CK_FloatingRealToComplex: { | ||||
▲ Show 20 Lines • Show All 1,286 Lines • ▼ Show 20 Lines | #include "clang/AST/StmtNodes.inc" | ||||
} | } | ||||
case Expr::CXXDefaultArgExprClass: | case Expr::CXXDefaultArgExprClass: | ||||
return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx); | return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx); | ||||
case Expr::CXXDefaultInitExprClass: | case Expr::CXXDefaultInitExprClass: | ||||
return CheckICE(cast<CXXDefaultInitExpr>(E)->getExpr(), Ctx); | return CheckICE(cast<CXXDefaultInitExpr>(E)->getExpr(), Ctx); | ||||
case Expr::ChooseExprClass: { | case Expr::ChooseExprClass: { | ||||
return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(), Ctx); | return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(), Ctx); | ||||
} | } | ||||
case Expr::BuiltinBitCastExprClass: { | |||||
if (!checkBitCastConstexprEligibility(nullptr, Ctx, cast<CastExpr>(E))) | |||||
return ICEDiag(IK_NotICE, E->getBeginLoc()); | |||||
return CheckICE(cast<CastExpr>(E)->getSubExpr(), Ctx); | |||||
} | |||||
} | } | ||||
llvm_unreachable("Invalid StmtClass!"); | llvm_unreachable("Invalid StmtClass!"); | ||||
} | } | ||||
/// Evaluate an expression as a C++11 integral constant expression. | /// Evaluate an expression as a C++11 integral constant expression. | ||||
static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx, | static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx, | ||||
const Expr *E, | const Expr *E, | ||||
▲ Show 20 Lines • Show All 220 Lines • Show Last 20 Lines |