|
@@ -47,6 +47,7 @@
|
|
#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"
|
|
@@ -56,8 +57,10 @@
|
|
#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);
|
|
|
|
|
|
@@ -2657,10 +2660,6 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E,
|
|
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.
|
|
@@ -5376,6 +5375,489 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
|
|
//===----------------------------------------------------------------------===//
|
|
//===----------------------------------------------------------------------===//
|
|
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> {
|
|
@@ -5510,6 +5992,9 @@ public:
|
|
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()) {
|
|
@@ -5802,6 +6287,14 @@ public:
|
|
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);
|
|
@@ -6651,7 +7144,6 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
|
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:
|
|
@@ -8176,7 +8668,7 @@ public:
|
|
}
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
@@ -10598,6 +11090,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
|
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:
|
|
@@ -11210,6 +11703,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
|
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:
|
|
@@ -12512,6 +13006,11 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &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!");
|