IntrinsicInst
has all of its constructors deleted here:
class IntrinsicInst : public CallInst {
public:
IntrinsicInst() = delete;
IntrinsicInst(const IntrinsicInst &) = delete;
IntrinsicInst &operator=(const IntrinsicInst &) = delete;
which means there can’t ever be instances of IntrinsicInst
or any of its children. However, this class is actively being used in cast
s for intrinsic matching, for example for llvm.instrprof.increment.step
here:
if (auto *IPIS = dyn_cast<InstrProfIncrementInstStep>(&Instr)) {
lowerIncrement(IPIS);
MadeChange = true;
}
Here, InstrProfIncrementInstStep
is inherited from InstrProfIncrementInst
, which inherits from InstrProfCntrInstBase
, which inherits from InstrProfInstBase
, which inherits from IntrinsicInst
. AFAIU, this code is essentially static_cast
ing the actual CallInst
instance to InstrProfIncrementInstStep
(a downcast), which according to cppreference, I believe, is UB:
static_cast<target-type>(expression)
- If
target-type
is a reference to some complete classD
and expression is an lvalue of its non-virtual baseB
, ortarget-type
is a pointer to some complete classD
and expression is a prvalue pointer to its non-virtual baseB
,static_cast
performs a downcast.
<…>
If the object expression refers or points to is actually a base class subobject of an object of typeD
, the result refers to the enclosing object of typeD
. Otherwise, the behavior is undefined[.]
I’ve also found a similar discussion on Operator
utility class: Undefined behavior in Operator class?, however I don’t think the code was changed.
So it this actually UB and should something be done about this?
The classof
implementations in intrinsics don’t violate classof
contract, I guess, defined here as:
To be more precise, let
classof
be inside a classC
. Then the contract forclassof
is “returntrue
if the dynamic type of the argument is-aC
”. As long as your implementation fulfills this contract, you can tweak and optimize it as much as you want.
But to prevent Operator
(and IntrinsicInst
) situation shouldn’t it be the opposite, like “return true
only if the dynamic type of the argument is-a C
” or even “return true
if and only if the dynamic type of the argument is-a C
”?