[tblgen] Fix behavior of !isa to prevent premature folding (#130442)

The test included with this commit shows a case where, even though a
record's true type was !isa<> some unrelated class, the isa<> operator
wolud use the declared type of the argument it was examining in order to
conclude that the !isa<> expression had to be be false.

The issues is fixed by checking to make sure that the argument to the
!isa operator is fully concrete before declaring its result to be false.
This commit is contained in:
Krzysztof Drewniak 2025-03-18 22:05:37 -05:00 committed by GitHub
parent 1028ea9e26
commit 193866bc24
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 39 additions and 4 deletions

View File

@ -2115,10 +2115,12 @@ const Init *IsAOpInit::Fold() const {
return IntInit::get(getRecordKeeper(), 1);
if (isa<RecordRecTy>(CheckType)) {
// If the target type is not a subclass of the expression type, or if
// the expression has fully resolved to a record, we know that it can't
// be of the required type.
if (!CheckType->typeIsConvertibleTo(TI->getType()) || isa<DefInit>(Expr))
// If the target type is not a subclass of the expression type once the
// expression has been made concrete, or if the expression has fully
// resolved to a record, we know that it can't be of the required type.
if ((!CheckType->typeIsConvertibleTo(TI->getType()) &&
Expr->isConcrete()) ||
isa<DefInit>(Expr))
return IntInit::get(getRecordKeeper(), 0);
} else {
// We treat non-record types as not castable.

View File

@ -0,0 +1,33 @@
// RUN: llvm-tblgen %s | FileCheck %s
// CHECK: --- Defs ---
// CHECK: def Op1 { // Op
// CHECK-NEXT: string res = "yes";
// CHECK-NEXT: }
// CHECK: def Op2 { // Op
// CHECK-NEXT: string res = "no";
// CHECK-NEXT: }
class A<int a> {
int x = a;
}
class B<int a> : A<a> {
bit y = 0;
}
class C<int a> {
int z = !add(a, 16);
}
class D<int a> : B<a>, C<a>;
def E1 : D<5>;
def E2 : B<2>;
class Op<A value> {
string res = !if(!isa<C>(value), "yes", "no");
}
def Op1 : Op<E1>;
def Op2 : Op<E2>;