[llvm-branch-commits] [clang] release/22.x: [Clang][CodeGen] Fix __builtin_counted_by_ref for nested struct FAMs (#182575) (#182590) (PR #182606)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Feb 20 14:29:32 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
Author: None (llvmbot)
<details>
<summary>Changes</summary>
Backport 09a3d830a888f15abca0ca51f68786e5517cd61f
Requested by: @<!-- -->efriedma-quic
---
Full diff: https://github.com/llvm/llvm-project/pull/182606.diff
3 Files Affected:
- (modified) clang/lib/CodeGen/CGExpr.cpp (+12-1)
- (modified) clang/test/CodeGen/attr-counted-by-pr88931.c (+6-1)
- (modified) clang/test/CodeGen/builtin-counted-by-ref.c (+27)
``````````diff
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 999726340aaed..4749caceb5a2c 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1187,7 +1187,18 @@ static bool getGEPIndicesToField(CodeGenFunction &CGF, const RecordDecl *RD,
llvm::Value *CodeGenFunction::GetCountedByFieldExprGEP(
const Expr *Base, const FieldDecl *FAMDecl, const FieldDecl *CountDecl) {
- const RecordDecl *RD = CountDecl->getParent()->getOuterLexicalRecordContext();
+ // Find the record containing the count field. Walk up through anonymous
+ // structs/unions (which are transparent in C) but stop at named records.
+ // Using getOuterLexicalRecordContext() here would be wrong because it walks
+ // past named nested structs to the outermost record, causing a crash when a
+ // struct with a counted_by FAM is defined nested inside another struct.
+ const RecordDecl *RD = CountDecl->getParent();
+ while (RD->isAnonymousStructOrUnion()) {
+ const auto *Parent = dyn_cast<RecordDecl>(RD->getLexicalParent());
+ if (!Parent)
+ break;
+ RD = Parent;
+ }
// Find the base struct expr (i.e. p in p->a.b.c.d).
const Expr *StructBase = StructAccessBase(RD).Visit(Base);
diff --git a/clang/test/CodeGen/attr-counted-by-pr88931.c b/clang/test/CodeGen/attr-counted-by-pr88931.c
index 1bd6f24461422..ded301f521f71 100644
--- a/clang/test/CodeGen/attr-counted-by-pr88931.c
+++ b/clang/test/CodeGen/attr-counted-by-pr88931.c
@@ -15,7 +15,12 @@ void init(void * __attribute__((pass_dynamic_object_size(0))));
// CHECK-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 4
-// CHECK-NEXT: tail call void @init(ptr noundef nonnull [[ARRAY]], i64 noundef -1) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[P]], align 4
+// CHECK-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64
+// CHECK-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 2
+// CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[COUNTED_BY_LOAD]], -1
+// CHECK-NEXT: [[TMP1:%.*]] = select i1 [[TMP0]], i64 [[FLEXIBLE_ARRAY_MEMBER_SIZE]], i64 0
+// CHECK-NEXT: tail call void @init(ptr noundef nonnull [[ARRAY]], i64 noundef [[TMP1]]) #[[ATTR2:[0-9]+]]
// CHECK-NEXT: ret void
//
void test1(struct bar *p) {
diff --git a/clang/test/CodeGen/builtin-counted-by-ref.c b/clang/test/CodeGen/builtin-counted-by-ref.c
index d44dbf5d0c1a2..8b1ef0edb8bd9 100644
--- a/clang/test/CodeGen/builtin-counted-by-ref.c
+++ b/clang/test/CodeGen/builtin-counted-by-ref.c
@@ -233,3 +233,30 @@ struct d *test4(int size, int *data) {
*__builtin_counted_by_ref(p->ptr) = size;
return p;
}
+
+// Test for FAM struct defined nested inside another struct (issue #182575).
+// The nested struct is named (not anonymous), so getOuterLexicalRecordContext()
+// would incorrectly resolve to 'struct outer' instead of 'struct inner'.
+struct outer {
+ struct inner {
+ int counter;
+ int ent[] __attribute__((counted_by(counter)));
+ } *entries;
+};
+
+// X86_64-LABEL: define dso_local ptr @test5(
+// X86_64-SAME: i32 noundef [[COUNT:%.*]]) #[[ATTR0]] {
+// X86_64: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds [[STRUCT_INNER:%.*]], ptr {{%.*}}, i32 0, i32 0
+// X86_64-NEXT: store i32 [[TMP1:%.*]], ptr [[DOT_COUNTED_BY_GEP]], align 4
+//
+// I386-LABEL: define dso_local ptr @test5(
+// I386-SAME: i32 noundef [[COUNT:%.*]]) #[[ATTR0]] {
+// I386: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds [[STRUCT_INNER:%.*]], ptr {{%.*}}, i32 0, i32 0
+// I386-NEXT: store i32 [[TMP1:%.*]], ptr [[DOT_COUNTED_BY_GEP]], align 4
+//
+struct inner *test5(int count) {
+ struct inner *entries = __builtin_malloc(sizeof(*entries) + count * sizeof(*entries->ent));
+ if (entries)
+ *__builtin_counted_by_ref(entries->ent) = count;
+ return entries;
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/182606
More information about the llvm-branch-commits
mailing list