summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/Expr.cpp4
-rw-r--r--clang/lib/AST/ExprClassification.cpp1
-rw-r--r--clang/lib/AST/ExprConstant.cpp511
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp1
-rw-r--r--clang/lib/AST/StmtPrinter.cpp8
-rw-r--r--clang/lib/AST/StmtProfile.cpp5
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp19
-rw-r--r--clang/lib/CodeGen/CGExprComplex.cpp9
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp9
-rw-r--r--clang/lib/Edit/RewriteObjCFoundationAPI.cpp1
-rw-r--r--clang/lib/Lex/PPMacroExpansion.cpp1
-rw-r--r--clang/lib/Parse/ParseExpr.cpp3
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp34
-rw-r--r--clang/lib/Sema/SemaCast.cpp70
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp1
-rw-r--r--clang/lib/Sema/TreeTransform.h26
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp6
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp1
22 files changed, 712 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);
}
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index abe10d383dc..4e97fba2621 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4209,6 +4209,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
switch (E->getCastKind()) {
case CK_ToVoid:
case CK_BitCast:
+ case CK_LValueToRValueBitCast:
case CK_ArrayToPointerDecay:
case CK_FunctionToPointerDecay:
case CK_NullToMemberPointer:
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index fe31f836286..695facd50b6 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -711,6 +711,25 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
break;
}
+ case CK_LValueToRValueBitCast: {
+ if (Dest.isIgnored()) {
+ CGF.EmitAnyExpr(E->getSubExpr(), AggValueSlot::ignored(),
+ /*ignoreResult=*/true);
+ break;
+ }
+
+ LValue SourceLV = CGF.EmitLValue(E->getSubExpr());
+ Address SourceAddress =
+ Builder.CreateElementBitCast(SourceLV.getAddress(), CGF.Int8Ty);
+ Address DestAddress =
+ Builder.CreateElementBitCast(Dest.getAddress(), CGF.Int8Ty);
+ llvm::Value *SizeVal = llvm::ConstantInt::get(
+ CGF.SizeTy,
+ CGF.getContext().getTypeSizeInChars(E->getType()).getQuantity());
+ Builder.CreateMemCpy(DestAddress, SourceAddress, SizeVal);
+ break;
+ }
+
case CK_DerivedToBase:
case CK_BaseToDerived:
case CK_UncheckedDerivedToBase: {
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index 4906b632925..6a5fb45ba25 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -464,6 +464,15 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy), Op->getExprLoc());
}
+ case CK_LValueToRValueBitCast: {
+ LValue SourceLVal = CGF.EmitLValue(Op);
+ Address Addr = Builder.CreateElementBitCast(SourceLVal.getAddress(),
+ CGF.ConvertTypeForMem(DestTy));
+ LValue DestLV = CGF.MakeAddrLValue(Addr, DestTy);
+ DestLV.setTBAAInfo(TBAAAccessInfo::getMayAliasInfo());
+ return EmitLoadOfLValue(DestLV, Op->getExprLoc());
+ }
+
case CK_BitCast:
case CK_BaseToDerived:
case CK_DerivedToBase:
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 4a0494295d2..9f4b686ad90 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1115,6 +1115,7 @@ public:
case CK_ToVoid:
case CK_Dynamic:
case CK_LValueBitCast:
+ case CK_LValueToRValueBitCast:
case CK_NullToMemberPointer:
case CK_UserDefinedConversion:
case CK_CPointerToObjCPointerCast:
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 5e979c0de97..ef6b84737b0 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -2033,6 +2033,15 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return EmitLoadOfLValue(LV, CE->getExprLoc());
}
+ case CK_LValueToRValueBitCast: {
+ LValue SourceLVal = CGF.EmitLValue(E);
+ Address Addr = Builder.CreateElementBitCast(SourceLVal.getAddress(),
+ CGF.ConvertTypeForMem(DestTy));
+ LValue DestLV = CGF.MakeAddrLValue(Addr, DestTy);
+ DestLV.setTBAAInfo(TBAAAccessInfo::getMayAliasInfo());
+ return EmitLoadOfLValue(DestLV, CE->getExprLoc());
+ }
+
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index 4dfe170ed62..6f4a880b649 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1042,6 +1042,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
case CK_Dependent:
case CK_BitCast:
case CK_LValueBitCast:
+ case CK_LValueToRValueBitCast:
case CK_BaseToDerived:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index 7e1f3b4dfdf..5021ff8aac5 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1630,6 +1630,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
.Case("__builtin_FILE", true)
.Case("__builtin_FUNCTION", true)
.Case("__builtin_COLUMN", true)
+ .Case("__builtin_bit_cast", true)
.Default(false);
}
});
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index dbea7741183..b5c01fe60fb 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1223,6 +1223,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_static_cast:
Res = ParseCXXCasts();
break;
+ case tok::kw___builtin_bit_cast:
+ Res = ParseBuiltinBitCast();
+ break;
case tok::kw_typeid:
Res = ParseCXXTypeid();
break;
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 222c1182629..9d296f18527 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -3513,3 +3513,37 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
ConsumeAnyToken();
return Result;
}
+
+/// Parse a __builtin_bit_cast(T, E).
+ExprResult Parser::ParseBuiltinBitCast() {
+ SourceLocation KWLoc = ConsumeToken();
+
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume(diag::err_expected_lparen_after, "__builtin_bit_cast"))
+ return ExprError();
+
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS(AttrFactory);
+ ParseSpecifierQualifierList(DS);
+
+ // Parse the abstract-declarator, if present.
+ Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext);
+ ParseDeclarator(DeclaratorInfo);
+
+ if (ExpectAndConsume(tok::comma)) {
+ Diag(Tok.getLocation(), diag::err_expected) << tok::comma;
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return ExprError();
+ }
+
+ ExprResult Operand = ParseExpression();
+
+ if (T.consumeClose())
+ return ExprError();
+
+ if (Operand.isInvalid() || DeclaratorInfo.isInvalidType())
+ return ExprError();
+
+ return Actions.ActOnBuiltinBitCastExpr(KWLoc, DeclaratorInfo, Operand,
+ T.getCloseLocation());
+}
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 46d0f57dc77..9ca6e4ab0e2 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -87,6 +87,7 @@ namespace {
void CheckDynamicCast();
void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization);
void CheckCStyleCast();
+ void CheckBuiltinBitCast();
void updatePartOfExplicitCastFlags(CastExpr *CE) {
// Walk down from the CE to the OrigSrcExpr, and mark all immediate
@@ -331,6 +332,38 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
}
}
+ExprResult Sema::ActOnBuiltinBitCastExpr(SourceLocation KWLoc, Declarator &D,
+ ExprResult Operand,
+ SourceLocation RParenLoc) {
+ assert(!D.isInvalidType());
+
+ TypeSourceInfo *TInfo = GetTypeForDeclaratorCast(D, Operand.get()->getType());
+ if (D.isInvalidType())
+ return ExprError();
+
+ return BuildBuiltinBitCastExpr(KWLoc, TInfo, Operand.get(), RParenLoc);
+}
+
+ExprResult Sema::BuildBuiltinBitCastExpr(SourceLocation KWLoc,
+ TypeSourceInfo *TSI, Expr *Operand,
+ SourceLocation RParenLoc) {
+ CastOperation Op(*this, TSI->getType(), Operand);
+ Op.OpRange = SourceRange(KWLoc, RParenLoc);
+ TypeLoc TL = TSI->getTypeLoc();
+ Op.DestRange = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
+
+ if (!Operand->isTypeDependent() && !TSI->getType()->isDependentType()) {
+ Op.CheckBuiltinBitCast();
+ if (Op.SrcExpr.isInvalid())
+ return ExprError();
+ }
+
+ BuiltinBitCastExpr *BCE =
+ new (Context) BuiltinBitCastExpr(Op.ResultType, Op.ValueKind, Op.Kind,
+ Op.SrcExpr.get(), TSI, KWLoc, RParenLoc);
+ return Op.complete(BCE);
+}
+
/// Try to diagnose a failed overloaded cast. Returns true if
/// diagnostics were emitted.
static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
@@ -2764,6 +2797,43 @@ void CastOperation::CheckCStyleCast() {
checkCastAlign();
}
+void CastOperation::CheckBuiltinBitCast() {
+ QualType SrcType = SrcExpr.get()->getType();
+ if (SrcExpr.get()->isRValue())
+ SrcExpr = Self.CreateMaterializeTemporaryExpr(SrcType, SrcExpr.get(),
+ /*IsLValueReference=*/false);
+
+ CharUnits DestSize = Self.Context.getTypeSizeInChars(DestType);
+ CharUnits SourceSize = Self.Context.getTypeSizeInChars(SrcType);
+ if (DestSize != SourceSize) {
+ Self.Diag(OpRange.getBegin(), diag::err_bit_cast_type_size_mismatch)
+ << (int)SourceSize.getQuantity() << (int)DestSize.getQuantity();
+ SrcExpr = ExprError();
+ return;
+ }
+
+ if (!DestType.isTriviallyCopyableType(Self.Context)) {
+ Self.Diag(OpRange.getBegin(), diag::err_bit_cast_non_trivially_copyable)
+ << 1;
+ SrcExpr = ExprError();
+ return;
+ }
+
+ if (!SrcType.isTriviallyCopyableType(Self.Context)) {
+ Self.Diag(OpRange.getBegin(), diag::err_bit_cast_non_trivially_copyable)
+ << 0;
+ SrcExpr = ExprError();
+ return;
+ }
+
+ if (Self.Context.hasSameUnqualifiedType(DestType, SrcType)) {
+ Kind = CK_NoOp;
+ return;
+ }
+
+ Kind = CK_LValueToRValueBitCast;
+}
+
/// DiagnoseCastQual - Warn whenever casts discards a qualifiers, be it either
/// const, volatile or both.
static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr,
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 5274532b0ff..9fd924a8cad 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1201,6 +1201,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::CoyieldExprClass:
case Expr::CXXConstCastExprClass:
case Expr::CXXReinterpretCastExprClass:
+ case Expr::BuiltinBitCastExprClass:
case Expr::CXXStdInitializerListExprClass:
case Expr::DesignatedInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 953889c6a02..7edb2a8d809 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2652,6 +2652,16 @@ public:
ListInitialization);
}
+ /// Build a new C++ __builtin_bit_cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildBuiltinBitCastExpr(SourceLocation KWLoc,
+ TypeSourceInfo *TSI, Expr *Sub,
+ SourceLocation RParenLoc) {
+ return getSema().BuildBuiltinBitCastExpr(KWLoc, TSI, Sub, RParenLoc);
+ }
+
/// Build a new C++ typeid(type) expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -10247,6 +10257,22 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformBuiltinBitCastExpr(BuiltinBitCastExpr *BCE) {
+ TypeSourceInfo *TSI =
+ getDerived().TransformType(BCE->getTypeInfoAsWritten());
+ if (!TSI)
+ return ExprError();
+
+ ExprResult Sub = getDerived().TransformExpr(BCE->getSubExpr());
+ if (Sub.isInvalid())
+ return ExprError();
+
+ return getDerived().RebuildBuiltinBitCastExpr(BCE->getBeginLoc(), TSI,
+ Sub.get(), BCE->getEndLoc());
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E) {
return getDerived().TransformCXXNamedCastExpr(E);
}
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 82f055c3ec8..58103eaf9a0 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1510,6 +1510,12 @@ void ASTStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
E->setRParenLoc(ReadSourceLocation());
}
+void ASTStmtReader::VisitBuiltinBitCastExpr(BuiltinBitCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ E->KWLoc = ReadSourceLocation();
+ E->RParenLoc = ReadSourceLocation();
+}
+
void ASTStmtReader::VisitUserDefinedLiteral(UserDefinedLiteral *E) {
VisitCallExpr(E);
E->UDSuffixLoc = ReadSourceLocation();
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 20a6b7d74ce..486cc14e6b0 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1451,6 +1451,12 @@ void ASTStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
Code = serialization::EXPR_CXX_FUNCTIONAL_CAST;
}
+void ASTStmtWriter::VisitBuiltinBitCastExpr(BuiltinBitCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ Record.AddSourceLocation(E->getBeginLoc());
+ Record.AddSourceLocation(E->getEndLoc());
+}
+
void ASTStmtWriter::VisitUserDefinedLiteral(UserDefinedLiteral *E) {
VisitCallExpr(E);
Record.AddSourceLocation(E->UDSuffixLoc);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 628d4315bcb..d95fb314f3c 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1687,6 +1687,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::CXXReinterpretCastExprClass:
case Stmt::CXXConstCastExprClass:
case Stmt::CXXFunctionalCastExprClass:
+ case Stmt::BuiltinBitCastExprClass:
case Stmt::ObjCBridgedCastExprClass: {
Bldr.takeNodes(Pred);
const auto *C = cast<CastExpr>(S);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 3b5a437e3c1..f436650fbdd 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -380,6 +380,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_Dependent:
case CK_ArrayToPointerDecay:
case CK_BitCast:
+ case CK_LValueToRValueBitCast:
case CK_AddressSpaceConversion:
case CK_BooleanToSignedIntegral:
case CK_IntegralToPointer:
OpenPOWER on IntegriCloud