Author: Timm Baeder Date: 2024-12-17T13:23:14+01:00 New Revision: 56fd46edb38e4bab7e48c668683ba72709beb64f
URL: https://github.com/llvm/llvm-project/commit/56fd46edb38e4bab7e48c668683ba72709beb64f DIFF: https://github.com/llvm/llvm-project/commit/56fd46edb38e4bab7e48c668683ba72709beb64f.diff LOG: [clang][bytecode] Remove a bitcast nullptr_t special case (#120188) We still need to check the input pointer, so let this go through BitCastPrim. Added: Modified: clang/lib/AST/ByteCode/Compiler.cpp clang/lib/AST/ByteCode/Interp.h clang/lib/AST/ByteCode/Opcodes.td clang/test/AST/ByteCode/builtin-bit-cast.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 7f6295e126dcfe..59c77f0ce78d2b 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -6483,14 +6483,6 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) { QualType ToType = E->getType(); std::optional<PrimType> ToT = classify(ToType); - // Bitcasting TO nullptr_t is always fine. - if (ToType->isNullPtrType()) { - if (!this->discard(SubExpr)) - return false; - - return this->emitNullPtr(0, nullptr, E); - } - assert(!ToType->isReferenceType()); // Prepare storage for the result in case we discard. @@ -6523,8 +6515,8 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) { return false; } - if (!ToT || ToT == PT_Ptr) { - if (!this->emitBitCastPtr(E)) + if (!ToT) { + if (!this->emitBitCast(E)) return false; return DiscardResult ? this->emitPopPtr(E) : true; } @@ -6540,8 +6532,8 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) { ToType->isSpecificBuiltinType(BuiltinType::Char_U)); uint32_t ResultBitWidth = std::max(Ctx.getBitWidth(ToType), 8u); - if (!this->emitBitCast(*ToT, ToTypeIsUChar || ToType->isStdByteType(), - ResultBitWidth, TargetSemantics, E)) + if (!this->emitBitCastPrim(*ToT, ToTypeIsUChar || ToType->isStdByteType(), + ResultBitWidth, TargetSemantics, E)) return false; if (DiscardResult) diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 2a6ea69475f787..8461d1e98f9777 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -3030,43 +3030,51 @@ bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) { bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E); template <PrimType Name, class T = typename PrimConv<Name>::T> -inline bool BitCast(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, - uint32_t ResultBitWidth, const llvm::fltSemantics *Sem) { +inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, + uint32_t ResultBitWidth, + const llvm::fltSemantics *Sem) { const Pointer &FromPtr = S.Stk.pop<Pointer>(); if (!CheckLoad(S, OpPC, FromPtr)) return false; - size_t BuffSize = ResultBitWidth / 8; - llvm::SmallVector<std::byte> Buff(BuffSize); - bool HasIndeterminateBits = false; + if constexpr (std::is_same_v<T, Pointer>) { + // The only pointer type we can validly bitcast to is nullptr_t. + S.Stk.push<Pointer>(); + return true; + } else { - Bits FullBitWidth(ResultBitWidth); - Bits BitWidth = FullBitWidth; + size_t BuffSize = ResultBitWidth / 8; + llvm::SmallVector<std::byte> Buff(BuffSize); + bool HasIndeterminateBits = false; - if constexpr (std::is_same_v<T, Floating>) { - assert(Sem); - BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem)); - } + Bits FullBitWidth(ResultBitWidth); + Bits BitWidth = FullBitWidth; - if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth, - HasIndeterminateBits)) - return false; + if constexpr (std::is_same_v<T, Floating>) { + assert(Sem); + BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem)); + } - if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte)) - return false; + if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth, + HasIndeterminateBits)) + return false; - if constexpr (std::is_same_v<T, Floating>) { - assert(Sem); - S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem)); - } else { - assert(!Sem); - S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth)); + if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte)) + return false; + + if constexpr (std::is_same_v<T, Floating>) { + assert(Sem); + S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem)); + } else { + assert(!Sem); + S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth)); + } + return true; } - return true; } -inline bool BitCastPtr(InterpState &S, CodePtr OpPC) { +inline bool BitCast(InterpState &S, CodePtr OpPC) { const Pointer &FromPtr = S.Stk.pop<Pointer>(); Pointer &ToPtr = S.Stk.peek<Pointer>(); diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 0638f8249805f8..123c21fa43eceb 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -839,13 +839,14 @@ def IsConstantContext: Opcode; def CheckAllocations : Opcode; def BitCastTypeClass : TypeClass { - let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, IntAP, IntAPS, Bool, Float]; + let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, + IntAP, IntAPS, Bool, Float, Ptr]; } -def BitCast : Opcode { +def BitCastPrim : Opcode { let Types = [BitCastTypeClass]; let Args = [ArgBool, ArgUint32, ArgFltSemantics]; let HasGroup = 1; } -def BitCastPtr : Opcode; +def BitCast : Opcode; diff --git a/clang/test/AST/ByteCode/builtin-bit-cast.cpp b/clang/test/AST/ByteCode/builtin-bit-cast.cpp index 8a5bef635b8fde..187f180afd3da3 100644 --- a/clang/test/AST/ByteCode/builtin-bit-cast.cpp +++ b/clang/test/AST/ByteCode/builtin-bit-cast.cpp @@ -507,3 +507,11 @@ typedef bool bool9 __attribute__((ext_vector_type(9))); // both-error@+2 {{constexpr variable 'bad_bool9_to_short' must be initialized by a constant expression}} // both-note@+1 {{bit_cast involving type 'bool __attribute__((ext_vector_type(9)))' (vector of 9 'bool' values) is not allowed in a constant expression; element size 1 * element count 9 is not a multiple of the byte size 8}} constexpr unsigned short bad_bool9_to_short = __builtin_bit_cast(unsigned short, bool9{1,1,0,1,0,1,0,1,0}); + +// both-warning@+2 {{returning reference to local temporary object}} +// both-note@+1 {{temporary created here}} +constexpr const intptr_t &returns_local() { return 0L; } + +// both-error@+2 {{constexpr variable 'test_nullptr_bad' must be initialized by a constant expression}} +// both-note@+1 {{read of temporary whose lifetime has ended}} +constexpr nullptr_t test_nullptr_bad = __builtin_bit_cast(nullptr_t, returns_local()); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits