llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Pengxiang Huang (Pengxiang-Huang)

<details>
<summary>Changes</summary>

Implements for:  #<!-- -->186914

Move the call to `ActOnFields()` before `ParseLexedCAttributeList()` in 
ParseStructUnionBody for reordering so that the struct type is complete when 
late-parsed attributes like counted_by get evaluated. This is a prerequisite 
for supporting sizeof/offsetof expressions in counted_by evaluation. 

Update the heuristic for `GetEnclosingNamedOrTopAnonRecord`. Remove the 
`isCompleteDefinition()` condition since it will always return true under the 
new ordering. The `GetEnclosingNamedOrTopAnonRecord` intend to treat the 
unnamed and anonymous struct permissively. 

Add one test to verify the new ordering still make sure the function of unnamed 
and anonymous struct works normally. 


---
Full diff: https://github.com/llvm/llvm-project/pull/187166.diff


3 Files Affected:

- (modified) clang/lib/Parse/ParseDecl.cpp (+3-3) 
- (modified) clang/lib/Sema/SemaBoundsSafety.cpp (+1-2) 
- (added) clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs-anon.c (+65) 


``````````diff
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 72935f427b7f8..fe281f156e988 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4989,13 +4989,13 @@ void Parser::ParseStructUnionBody(SourceLocation 
RecordLoc,
   // If attributes exist after struct contents, parse them.
   MaybeParseGNUAttributes(attrs, &LateFieldAttrs);
 
-  // Late parse field attributes if necessary.
-  ParseLexedCAttributeList(LateFieldAttrs, /*EnterScope=*/false);
-
   SmallVector<Decl *, 32> FieldDecls(TagDecl->fields());
 
   Actions.ActOnFields(getCurScope(), RecordLoc, TagDecl, FieldDecls,
                       T.getOpenLocation(), T.getCloseLocation(), attrs);
+
+  // Late parse field attributes if necessary.
+  ParseLexedCAttributeList(LateFieldAttrs, /*EnterScope=*/false);
   StructScope.Exit();
   Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, T.getRange());
 }
diff --git a/clang/lib/Sema/SemaBoundsSafety.cpp 
b/clang/lib/Sema/SemaBoundsSafety.cpp
index 8c8e37d321938..faf352b3a366f 100644
--- a/clang/lib/Sema/SemaBoundsSafety.cpp
+++ b/clang/lib/Sema/SemaBoundsSafety.cpp
@@ -32,8 +32,7 @@ static const RecordDecl 
*GetEnclosingNamedOrTopAnonRecord(const FieldDecl *FD) {
   // However, the struct may not be fully processed yet to determine
   // whether it's anonymous or not. In that case, this function treats it as
   // an anonymous struct and tries to find a named parent.
-  while (RD && (RD->isAnonymousStructOrUnion() ||
-                (!RD->isCompleteDefinition() && RD->getName().empty()))) {
+  while (RD && (RD->isAnonymousStructOrUnion() || RD->getName().empty())) {
     const auto *Parent = dyn_cast<RecordDecl>(RD->getParent());
     if (!Parent)
       break;
diff --git a/clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs-anon.c 
b/clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs-anon.c
new file mode 100644
index 0000000000000..8b74f46b064f5
--- /dev/null
+++ b/clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs-anon.c
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -fexperimental-late-parse-attributes -fsyntax-only -verify 
%s
+
+// Test that counted_by works correctly with late parsing when ActOnFields
+// is called before late-parsed attributes are evaluated. This allows offset
+// expressions in counted_by to be evaluated.
+
+#define __counted_by(f)  __attribute__((counted_by(f)))
+
+struct size_known {
+  int field;
+};
+
+//==============================================================================
+// Verify anonymous struct handling works corrctly under currect ordering.
+// GetEnclosingNamedOrTopAnonRecord must correctly walk through anonymous
+// structs when the struct is already marked complete.
+//==============================================================================
+
+// count in outer struct, buf in anonymous struct
+struct on_pointer_anon_buf {
+  int count;
+  struct {
+    struct size_known *buf __counted_by(count);
+  };
+};
+
+// both count and buf in anonymous struct
+struct on_pointer_anon_both {
+  struct {
+    int count;
+    struct size_known *buf __counted_by(count);
+  };
+};
+
+// nested anonymous structs
+struct on_pointer_nested_anon {
+  int count;
+  struct {
+    struct {
+      struct size_known *buf __counted_by(count);
+    };
+  };
+};
+
+//==============================================================================
+// Verify non-anonymous unnamed structs correctly reject counted_by if it
+// reference fields in the outer struct.
+//==============================================================================
+
+// count in outer, buf in non-anonymous unnamed struct — should reject
+struct on_pointer_named_inner {
+  int count; // expected-note{{'count' declared here}}
+  struct {
+               // expected-error@+1{{'counted_by' field 'count' isn't within 
the same struct as the annotated pointer}}
+    struct size_known *buf __counted_by(count); 
+  } inner;
+};
+
+// both in non-anonymous unnamed struct — should accept
+struct on_pointer_named_inner_both {
+  struct {
+    int count;
+    struct size_known *buf __counted_by(count);
+  } inner;
+};

``````````

</details>


https://github.com/llvm/llvm-project/pull/187166
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to