diff options
Diffstat (limited to 'clang/lib')
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: |