[clang] [CIR] Verify record_align is a non-zero power of two (PR #214074)
Adam Smith via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 4 14:04:40 PDT 2026
https://github.com/adams381 created https://github.com/llvm/llvm-project/pull/214074
`#cir.record_layout` carries `record_align`, which CIRGen fills from `ASTRecordLayout::getAlignment()` and consumers read as an `llvm::Align`. That constructor asserts the value is a non-zero power of two, so hand-written CIR naming any other alignment aborted the tool rather than reporting a parse error. A zero tripped the non-zero assert and a 3 tripped the power-of-two one, both inside `llvm::Align` with no indication of which attribute was at fault.
Verify the field where it is parsed. Values CIRGen emits are already well-formed, so this only affects hand-written input.
>From 178fceb6f1ac77f20f85720b9376b22932c50f20 Mon Sep 17 00:00:00 2001
From: Adam Smith <adams at nvidia.com>
Date: Tue, 4 Aug 2026 13:56:58 -0700
Subject: [PATCH] [CIR] Verify record_align is a non-zero power of two
`#cir.record_layout` carries `record_align`, which CIRGen fills from
`ASTRecordLayout::getAlignment()` and consumers read as an `llvm::Align`. That
constructor asserts the value is a non-zero power of two, so hand-written CIR
naming any other alignment aborted the tool rather than reporting a parse error.
A zero tripped the non-zero assert and a 3 tripped the power-of-two one, both
inside `llvm::Align` with no indication of which attribute was at fault.
Verify the field where it is parsed. Values CIRGen emits are already
well-formed, so this only affects hand-written input.
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 2 ++
clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 16 ++++++++++++++++
clang/test/CIR/IR/invalid-record-layout.cir | 19 +++++++++++++++++++
3 files changed, 37 insertions(+)
create mode 100644 clang/test/CIR/IR/invalid-record-layout.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index a0fe997156a69..5042ec9ab05aa 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -169,6 +169,8 @@ def CIR_RecordLayoutAttr : CIR_Attr<"RecordLayout", "record_layout"> {
`>`
}];
+ let genVerifyDecl = 1;
+
let canHaveIllegalCXXABIType = 0;
}
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index 264e836718c81..48cedbb44a856 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -920,6 +920,22 @@ LogicalResult DynamicCastInfoAttr::verify(
// RecordLayout lookup
//===----------------------------------------------------------------------===//
+LogicalResult
+RecordLayoutAttr::verify(function_ref<InFlightDiagnostic()> emitError,
+ cir::ArgPassingKind argPassingKind,
+ bool hasTrivialDtor, uint64_t recordAlign) {
+ // record_align comes from ASTRecordLayout::getAlignment() and is consumed as
+ // an llvm::Align, which requires a non-zero power of two. Reject anything
+ // else here so hand-written CIR gets a diagnostic instead of an assertion
+ // failure inside whichever pass reads the field.
+ if (recordAlign == 0)
+ return emitError() << "record_align must be non-zero";
+ if (!llvm::isPowerOf2_64(recordAlign))
+ return emitError() << "record_align must be a power of two, got "
+ << recordAlign;
+ return success();
+}
+
RecordLayoutAttr cir::getRecordLayout(mlir::ModuleOp module,
mlir::StringAttr name) {
auto dict = module->getAttrOfType<mlir::DictionaryAttr>(
diff --git a/clang/test/CIR/IR/invalid-record-layout.cir b/clang/test/CIR/IR/invalid-record-layout.cir
new file mode 100644
index 0000000000000..fa54ef6977acf
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-record-layout.cir
@@ -0,0 +1,19 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+module attributes {
+ cir.record_layouts = {
+ // expected-error @below {{record_align must be non-zero}}
+ S = #cir.record_layout<arg_passing_kind = can_pass_in_regs,
+ has_trivial_dtor = true, record_align = 0>}
+} {
+}
+
+// -----
+
+module attributes {
+ cir.record_layouts = {
+ // expected-error @below {{record_align must be a power of two, got 3}}
+ S = #cir.record_layout<arg_passing_kind = can_pass_in_regs,
+ has_trivial_dtor = true, record_align = 3>}
+} {
+}
More information about the cfe-commits
mailing list