[clang] [CIR] Add CIR vtable attribute (PR #154415)
Andy Kaylor via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 20 15:52:31 PDT 2025
https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/154415
>From f5e0612b8ce090ac7f075307c802f5e4e3704d50 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Mon, 18 Aug 2025 13:51:11 -0700
Subject: [PATCH 1/5] [CIR] Add CIR vtable attribute
This adds the #cir.vtable attribute definition and verification. Generation
of the vtable will be implemented in a later change.
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 40 +++++++++++++++
clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 38 ++++++++++++++
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 3 +-
clang/test/CIR/IR/invalid-vtable.cir | 50 ++++++++++++++++++-
clang/test/CIR/IR/vtable-attr.cir | 12 +++++
5 files changed, 141 insertions(+), 2 deletions(-)
create mode 100644 clang/test/CIR/IR/vtable-attr.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 89b4d25b37ba6..c57fabeccc296 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -496,6 +496,46 @@ def CIR_GlobalViewAttr : CIR_Attr<"GlobalView", "global_view", [
}];
}
+//===----------------------------------------------------------------------===//
+// VTableAttr
+//===----------------------------------------------------------------------===//
+
+def VTableAttr : CIR_Attr<"VTable", "vtable", [TypedAttrInterface]> {
+ let summary = "Represents a C++ vtable";
+ let description = [{
+ Wraps a #cir.const_record containing vtable data.
+
+ Example:
+ ```
+ cir.global linkonce_odr @_ZTV1B = #cir.vtable<<
+ {#cir.const_array<[#cir.null : !cir.ptr<i8>,
+ #cir.global_view<@_ZTI1B> : !cir.ptr<i8>,
+ #cir.global_view<@_ZN1BD1Ev> : !cir.ptr<i8>,
+ #cir.global_view<@_ZN1BD0Ev> : !cir.ptr<i8>,
+ #cir.global_view<@_ZNK1A5quackEv> : !cir.ptr<i8>]>
+ : !cir.array<!cir.ptr<i8> x 5>}>>
+ : !cir.record<"", !cir.array<!cir.ptr<i8> x 5>>
+ ```
+ }];
+
+ // `vtable_data` is a const record with one element, containing an array of
+ // vtable information.
+ let parameters = (ins AttributeSelfTypeParameter<"">:$type,
+ "mlir::ArrayAttr":$vtable_data);
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ "mlir::ArrayAttr":$vtable_data), [{
+ return $_get(type.getContext(), type, vtable_data);
+ }]>
+ ];
+
+ let genVerifyDecl = 1;
+ let assemblyFormat = [{
+ `<` custom<RecordMembers>($vtable_data) `>`
+ }];
+}
+
//===----------------------------------------------------------------------===//
// ConstComplexAttr
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index 5f53a6335f37d..9050db5efc977 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -424,6 +424,44 @@ cir::ConstVectorAttr::verify(function_ref<InFlightDiagnostic()> emitError,
return elementTypeCheck;
}
+//===----------------------------------------------------------------------===//
+// CIR VTableAttr
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::VTableAttr::verify(
+ llvm::function_ref<mlir::InFlightDiagnostic()> emitError, mlir::Type type,
+ mlir::ArrayAttr vtableData) {
+ auto sTy = mlir::dyn_cast_if_present<cir::RecordType>(type);
+ if (!sTy)
+ return emitError() << "expected !cir.record type result";
+ if (sTy.getMembers().empty() || vtableData.empty())
+ return emitError() << "expected record type with one or more subtype";
+
+ for (size_t i = 0; i < sTy.getMembers().size(); ++i) {
+ auto constArrayAttr = mlir::dyn_cast<cir::ConstArrayAttr>(vtableData[i]);
+ if (!constArrayAttr)
+ return emitError() << "expected constant array subtype";
+
+ if (cir::ConstRecordAttr::verify(emitError, type, vtableData).failed())
+ return failure();
+
+ LogicalResult eltTypeCheck = success();
+ auto arrayElts = mlir::cast<ArrayAttr>(constArrayAttr.getElts());
+ arrayElts.walkImmediateSubElements(
+ [&](Attribute attr) {
+ if (mlir::isa<ConstPtrAttr, GlobalViewAttr>(attr))
+ return;
+
+ eltTypeCheck = emitError()
+ << "expected GlobalViewAttr or ConstPtrAttr";
+ },
+ [&](Type type) {});
+ if (eltTypeCheck.failed())
+ return eltTypeCheck;
+ }
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// CIR Dialect
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 72feee8709dc4..0a7a8793943aa 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -342,7 +342,8 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType,
if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,
cir::ConstComplexAttr, cir::ConstRecordAttr,
- cir::GlobalViewAttr, cir::PoisonAttr>(attrType))
+ cir::GlobalViewAttr, cir::PoisonAttr, cir::VTableAttr>(
+ attrType))
return success();
assert(isa<TypedAttr>(attrType) && "What else could we be looking at here?");
diff --git a/clang/test/CIR/IR/invalid-vtable.cir b/clang/test/CIR/IR/invalid-vtable.cir
index b3afb581b2048..0c8a36d26a0a1 100644
--- a/clang/test/CIR/IR/invalid-vtable.cir
+++ b/clang/test/CIR/IR/invalid-vtable.cir
@@ -1,4 +1,4 @@
-// RUN: cir-opt %s -verify-diagnostics
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
!s8i = !cir.int<s, 8>
!u32i = !cir.int<u, 32>
@@ -7,3 +7,51 @@ cir.func @reference_unknown_vtable() {
%0 = cir.vtable.address_point(@some_vtable, address_point = <index = 0, offset = 2>) : !cir.vptr
cir.return
}
+
+// -----
+
+!rec_S = !cir.record<struct "S" {!cir.vptr}>
+!u8i = !cir.int<u, 8>
+!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}>
+module {
+ // expected-error @below {{expected !cir.record type result}}
+ cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>}> : !cir.ptr<!rec_anon_struct>
+ cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
+ cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
+}
+
+// -----
+
+!rec_S = !cir.record<struct "S" {!cir.vptr}>
+!u8i = !cir.int<u, 8>
+!rec_anon_struct = !cir.record<struct {}>
+module {
+ // expected-error @below {{expected record type with one or more subtype}}
+ cir.global external @_ZTV1S = #cir.vtable<{}> : !rec_anon_struct {alignment = 8 : i64}
+ cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
+ cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
+}
+
+// -----
+
+!rec_S = !cir.record<struct "S" {!cir.vptr}>
+!u8i = !cir.int<u, 8>
+!rec_anon_struct = !cir.record<struct {!cir.ptr<!u8i>}>
+module {
+ // expected-error @below {{expected constant array subtype}}
+ cir.global external @_ZTV1S = #cir.vtable<{#cir.ptr<null> : !cir.ptr<!u8i>}> : !rec_anon_struct {alignment = 8 : i64}
+ cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
+ cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
+}
+
+// -----
+
+!rec_S = !cir.record<struct "S" {!cir.vptr}>
+!u64i = !cir.int<u, 64>
+!rec_anon_struct = !cir.record<struct {!cir.array<!u64i x 4>}>
+module {
+ // expected-error @below {{expected GlobalViewAttr or ConstPtrAttr}}
+ cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.int<1> : !u64i, #cir.int<1> : !u64i, #cir.int<3> : !u64i, #cir.int<4> : !u64i]> : !cir.array<!u64i x 4>}> : !rec_anon_struct {alignment = 8 : i64}
+ cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
+ cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
+}
diff --git a/clang/test/CIR/IR/vtable-attr.cir b/clang/test/CIR/IR/vtable-attr.cir
new file mode 100644
index 0000000000000..4826bdcc90953
--- /dev/null
+++ b/clang/test/CIR/IR/vtable-attr.cir
@@ -0,0 +1,12 @@
+// RUN: cir-opt %s | FileCheck %s
+
+!rec_S = !cir.record<struct "S" {!cir.vptr}>
+!u8i = !cir.int<u, 8>
+!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}>
+module {
+ cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>}> : !rec_anon_struct {alignment = 8 : i64}
+ // CHECK: cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>}> : !rec_anon_struct {alignment = 8 : i64}
+
+ cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
+ cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
+}
>From d37efd2fbe1c9633fe8a11722d8d7a1d5f834f41 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Wed, 20 Aug 2025 13:04:35 -0700
Subject: [PATCH 2/5] Address review feedback
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 52 ++++++++++++++-----
clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 4 +-
2 files changed, 41 insertions(+), 15 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index c57fabeccc296..8cd8f83c15834 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -500,28 +500,54 @@ def CIR_GlobalViewAttr : CIR_Attr<"GlobalView", "global_view", [
// VTableAttr
//===----------------------------------------------------------------------===//
-def VTableAttr : CIR_Attr<"VTable", "vtable", [TypedAttrInterface]> {
+def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", [TypedAttrInterface]> {
let summary = "Represents a C++ vtable";
let description = [{
- Wraps a #cir.const_record containing vtable data.
+ Wraps a #cir.const_record containing one or more vtable arrays.
- Example:
+ In most cases, the anonymous record type wrapped by this attribute will
+ contain a single array corresponding to the vtable for one class. However,
+ in the case of multiple inheritence, the anonymous structure may contain
+ multiple arrays, each of which is a vtable.
+
+ Example 1 (single vtable):
+ ```mlir
+ cir.global linkonce_odr @_ZTV6Mother =
+ #cir.vtable<{
+ #cir.const_array<[
+ #cir.ptr<null> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZTI6Mother> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZN6Mother9MotherFooEv> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr<!u8i>
+ ]> : !cir.array<!cir.ptr<!u8i> x 4>
+ }> : !rec_anon_struct1
```
- cir.global linkonce_odr @_ZTV1B = #cir.vtable<<
- {#cir.const_array<[#cir.null : !cir.ptr<i8>,
- #cir.global_view<@_ZTI1B> : !cir.ptr<i8>,
- #cir.global_view<@_ZN1BD1Ev> : !cir.ptr<i8>,
- #cir.global_view<@_ZN1BD0Ev> : !cir.ptr<i8>,
- #cir.global_view<@_ZNK1A5quackEv> : !cir.ptr<i8>]>
- : !cir.array<!cir.ptr<i8> x 5>}>>
- : !cir.record<"", !cir.array<!cir.ptr<i8> x 5>>
+
+ Example 2 (multiple vtables):
+ ```mlir
+ cir.global linkonce_odr @_ZTV5Child =
+ #cir.vtable<{
+ #cir.const_array<[
+ #cir.ptr<null> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZTI5Child> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZN5Child9MotherFooEv> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr<!u8i>
+ ]> : !cir.array<!cir.ptr<!u8i> x 4>,
+ #cir.const_array<[
+ #cir.ptr<-8 : i64> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZTI5Child> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZN6Father9FatherFooEv> : !cir.ptr<!u8i>
+ ]> : !cir.array<!cir.ptr<!u8i> x 3>
+ }> : !rec_anon_struct2
```
}];
// `vtable_data` is a const record with one element, containing an array of
// vtable information.
- let parameters = (ins AttributeSelfTypeParameter<"">:$type,
- "mlir::ArrayAttr":$vtable_data);
+ let parameters = (ins
+ AttributeSelfTypeParameter<"">:$type,
+ "mlir::ArrayAttr":$vtable_data
+ );
let builders = [
AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index 9050db5efc977..3581ebb74a0a4 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -448,14 +448,14 @@ LogicalResult cir::VTableAttr::verify(
LogicalResult eltTypeCheck = success();
auto arrayElts = mlir::cast<ArrayAttr>(constArrayAttr.getElts());
arrayElts.walkImmediateSubElements(
- [&](Attribute attr) {
+ [&](mlir::Attribute attr) {
if (mlir::isa<ConstPtrAttr, GlobalViewAttr>(attr))
return;
eltTypeCheck = emitError()
<< "expected GlobalViewAttr or ConstPtrAttr";
},
- [&](Type type) {});
+ [&](mlir::Type type) {});
if (eltTypeCheck.failed())
return eltTypeCheck;
}
>From 98c808fc6bb2a4ab48b311f617bdffeacd812742 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Wed, 20 Aug 2025 15:29:05 -0700
Subject: [PATCH 3/5] Use range for vtable data verification
---
clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index 3581ebb74a0a4..4814369505c2c 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -437,14 +437,14 @@ LogicalResult cir::VTableAttr::verify(
if (sTy.getMembers().empty() || vtableData.empty())
return emitError() << "expected record type with one or more subtype";
- for (size_t i = 0; i < sTy.getMembers().size(); ++i) {
- auto constArrayAttr = mlir::dyn_cast<cir::ConstArrayAttr>(vtableData[i]);
+ if (cir::ConstRecordAttr::verify(emitError, type, vtableData).failed())
+ return failure();
+
+ for (const auto &data : vtableData.getAsRange<mlir::Attribute>()) {
+ const auto &constArrayAttr = mlir::dyn_cast<cir::ConstArrayAttr>(data);
if (!constArrayAttr)
return emitError() << "expected constant array subtype";
- if (cir::ConstRecordAttr::verify(emitError, type, vtableData).failed())
- return failure();
-
LogicalResult eltTypeCheck = success();
auto arrayElts = mlir::cast<ArrayAttr>(constArrayAttr.getElts());
arrayElts.walkImmediateSubElements(
>From 32180c9946ccd27a814dc1835c78efa0ace16cef Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Wed, 20 Aug 2025 15:46:14 -0700
Subject: [PATCH 4/5] Add multi-vtable test
---
clang/test/CIR/IR/vtable-attr.cir | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/clang/test/CIR/IR/vtable-attr.cir b/clang/test/CIR/IR/vtable-attr.cir
index 4826bdcc90953..3854208ff78cc 100644
--- a/clang/test/CIR/IR/vtable-attr.cir
+++ b/clang/test/CIR/IR/vtable-attr.cir
@@ -1,12 +1,19 @@
// RUN: cir-opt %s | FileCheck %s
+!rec_Q = !cir.record<struct "Q" {!cir.vptr}>
!rec_S = !cir.record<struct "S" {!cir.vptr}>
+!rec_S2 = !cir.record<struct "S2" {!rec_Q, !rec_S}>
!u8i = !cir.int<u, 8>
!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>}>
+!rec_anon_struct1 = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>, !cir.array<!cir.ptr<!u8i> x 3>}>
module {
cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>}> : !rec_anon_struct {alignment = 8 : i64}
// CHECK: cir.global external @_ZTV1S = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>}> : !rec_anon_struct {alignment = 8 : i64}
+ cir.global external @_ZTV2S2 = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>, #cir.const_array<[#cir.ptr<-8 : i64> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN2S23keyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 3>}> : !rec_anon_struct1 {alignment = 8 : i64}
+ // CHECK: cir.global external @_ZTV2S2 = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>, #cir.const_array<[#cir.ptr<-8 : i64> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN2S23keyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 3>}> : !rec_anon_struct1 {alignment = 8 : i64}
+
cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
+ cir.func private dso_local @_ZN2S23keyEv(%arg0: !cir.ptr<!rec_S2>)
}
>From 1736a32bbd5d6a693f82e122fae13792d97cad51 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Wed, 20 Aug 2025 15:52:11 -0700
Subject: [PATCH 5/5] One more test case
---
clang/test/CIR/IR/invalid-vtable.cir | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/clang/test/CIR/IR/invalid-vtable.cir b/clang/test/CIR/IR/invalid-vtable.cir
index 0c8a36d26a0a1..60aa9b29e2677 100644
--- a/clang/test/CIR/IR/invalid-vtable.cir
+++ b/clang/test/CIR/IR/invalid-vtable.cir
@@ -55,3 +55,19 @@ module {
cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
}
+
+// -----
+
+!rec_Q = !cir.record<struct "Q" {!cir.vptr}>
+!rec_S = !cir.record<struct "S" {!cir.vptr}>
+!rec_S2 = !cir.record<struct "S2" {!rec_Q, !rec_S}>
+!u8i = !cir.int<u, 8>
+!rec_anon_struct = !cir.record<struct {!cir.array<!cir.ptr<!u8i> x 4>, !cir.ptr<!u8i>}>
+module {
+ // expected-error @below {{expected constant array subtype}}
+ cir.global external @_ZTV2S2 = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S3keyEv> : !cir.ptr<!u8i>, #cir.global_view<@_ZN1S6nonKeyEv> : !cir.ptr<!u8i>]> : !cir.array<!cir.ptr<!u8i> x 4>, #cir.ptr<null> : !cir.ptr<!u8i>}> : !rec_anon_struct {alignment = 8 : i64}
+
+ cir.func private dso_local @_ZN1S3keyEv(%arg0: !cir.ptr<!rec_S>)
+ cir.func private dso_local @_ZN1S6nonKeyEv(%arg0: !cir.ptr<!rec_S>)
+ cir.func private dso_local @_ZN2S23keyEv(%arg0: !cir.ptr<!rec_S2>)
+}
More information about the cfe-commits
mailing list