diff options
| author | Erik Pilkington <erik.pilkington@gmail.com> | 2019-07-02 18:28:13 +0000 |
|---|---|---|
| committer | Erik Pilkington <erik.pilkington@gmail.com> | 2019-07-02 18:28:13 +0000 |
| commit | eee944e7f9e60df44714eb547d0b876ee5dc7290 (patch) | |
| tree | bfbb77d0b88de0f45c22ce3747d8d214d0f5a0d7 /clang/lib/AST | |
| parent | 5613874947462fd4ceb4f66926c879269609463f (diff) | |
| download | bcm5719-llvm-eee944e7f9e60df44714eb547d0b876ee5dc7290.tar.gz bcm5719-llvm-eee944e7f9e60df44714eb547d0b876ee5dc7290.zip | |
[C++2a] Add __builtin_bit_cast, used to implement std::bit_cast
This commit adds a new builtin, __builtin_bit_cast(T, v), which performs a
bit_cast from a value v to a type T. This expression can be evaluated at
compile time under specific circumstances.
The compile time evaluation currently doesn't support bit-fields, but I'm
planning on fixing this in a follow up (some of the logic for figuring this out
is in CodeGen). I'm also planning follow-ups for supporting some more esoteric
types that the constexpr evaluator supports, as well as extending
__builtin_memcpy constexpr evaluation to use the same infrastructure.
rdar://44987528
Differential revision: https://reviews.llvm.org/D62825
llvm-svn: 364954
Diffstat (limited to 'clang/lib/AST')
| -rw-r--r-- | clang/lib/AST/Expr.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/AST/ExprClassification.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 511 | ||||
| -rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/AST/StmtPrinter.cpp | 8 | ||||
| -rw-r--r-- | clang/lib/AST/StmtProfile.cpp | 5 |
6 files changed, 523 insertions, 7 deletions
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index d342bda962d..f8017bb7ade 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1862,6 +1862,7 @@ bool CastExpr::CastConsistency() const { case CK_FloatingComplexToBoolean: case CK_IntegralComplexToBoolean: case CK_LValueBitCast: // -> bool& + case CK_LValueToRValueBitCast: case CK_UserDefinedConversion: // operator bool() case CK_BuiltinFnToFnPtr: case CK_FixedPointToBoolean: @@ -3506,7 +3507,8 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case CXXStaticCastExprClass: case CXXReinterpretCastExprClass: case CXXConstCastExprClass: - case CXXFunctionalCastExprClass: { + case CXXFunctionalCastExprClass: + case BuiltinBitCastExprClass: { // While volatile reads are side-effecting in both C and C++, we treat them // as having possible (not definite) side-effects. This allows idiomatic // code to behave without warning, such as sizeof(*v) for a volatile- diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 757a17660a1..c61ee703aca 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -343,6 +343,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: case Expr::ObjCBridgedCastExprClass: + case Expr::BuiltinBitCastExprClass: // Only in C++ can casts be interesting at all. if (!Lang.CPlusPlus) return Cl::CL_PRValue; return ClassifyUnnamed(Ctx, cast<ExplicitCastExpr>(E)->getTypeAsWritten()); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index df7dd191782..a71cc8e123f 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -47,6 +47,7 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/FixedPoint.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" @@ -56,8 +57,10 @@ #define DEBUG_TYPE "exprconstant" using namespace clang; +using llvm::APInt; using llvm::APSInt; using llvm::APFloat; +using llvm::Optional; static bool IsGlobalLValue(APValue::LValueBase B); @@ -2657,10 +2660,6 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E, 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. /// /// \param Info Information about the ongoing evaluation. @@ -5376,6 +5375,489 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, //===----------------------------------------------------------------------===// 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> class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> { @@ -5510,6 +5992,9 @@ public: CCEDiag(E, diag::note_constexpr_invalid_cast) << 1; return static_cast<Derived*>(this)->VisitCastExpr(E); } + bool VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *E) { + return static_cast<Derived*>(this)->VisitCastExpr(E); + } bool VisitBinaryOperator(const BinaryOperator *E) { switch (E->getOpcode()) { @@ -5802,6 +6287,14 @@ public: return false; 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); @@ -6651,7 +7144,6 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { switch (E->getCastKind()) { default: break; - case CK_BitCast: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: @@ -8176,7 +8668,7 @@ public: } bool Success(const APValue &V, const Expr *E) { - if (V.isLValue() || V.isAddrLabelDiff()) { + if (V.isLValue() || V.isAddrLabelDiff() || V.isIndeterminate()) { Result = V; return true; } @@ -10598,6 +11090,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_LValueToRValue: case CK_AtomicToNonAtomic: case CK_NoOp: + case CK_LValueToRValueBitCast: return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_MemberPointerToBoolean: @@ -11210,6 +11703,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_LValueToRValue: case CK_AtomicToNonAtomic: case CK_NoOp: + case CK_LValueToRValueBitCast: return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_Dependent: @@ -12512,6 +13006,11 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::ChooseExprClass: { 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!"); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 79be51cd9c8..99556a6e70d 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3634,6 +3634,7 @@ recurse: case Expr::AtomicExprClass: case Expr::SourceLocExprClass: case Expr::FixedPointLiteralClass: + case Expr::BuiltinBitCastExprClass: { if (!NullOut) { // As bad as this diagnostic is, it's better than crashing. diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 83c017fdc87..46802d765e1 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1703,6 +1703,14 @@ void StmtPrinter::VisitCXXConstCastExpr(CXXConstCastExpr *Node) { VisitCXXNamedCastExpr(Node); } +void StmtPrinter::VisitBuiltinBitCastExpr(BuiltinBitCastExpr *Node) { + OS << "__builtin_bit_cast("; + Node->getTypeInfoAsWritten()->getType().print(OS, Policy); + OS << ", "; + PrintExpr(Node->getSubExpr()); + OS << ")"; +} + void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) { OS << "typeid("; if (Node->isTypeOperand()) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index c5da5bfda9c..f92c3dc60ba 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1569,6 +1569,11 @@ void StmtProfiler::VisitCXXConstCastExpr(const CXXConstCastExpr *S) { VisitCXXNamedCastExpr(S); } +void StmtProfiler::VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *S) { + VisitExpr(S); + VisitType(S->getTypeInfoAsWritten()->getType()); +} + void StmtProfiler::VisitUserDefinedLiteral(const UserDefinedLiteral *S) { VisitCallExpr(S); } |

