llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Henrik G. Olsson (hnrklssn) <details> <summary>Changes</summary> The attributes `sized_by`, `counted_by_or_null` and `sized_by_or_null` have been added as variants on `counted_by`, each with slightly different semantics. `sized_by` takes a byte size parameter instead of an element count, allowing pointees with unknown size. The `counted_by_or_null` and `sized_by_or_null` variants are equivalent to their base variants, except the pointer can be null regardless of count/size value. If the pointer is null the size is effectively 0. rdar://125400354 --- Patch is 91.46 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/93231.diff 30 Files Affected: - (modified) clang/docs/ReleaseNotes.rst (+6) - (modified) clang/include/clang/Basic/Attr.td (+30) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+8-8) - (modified) clang/include/clang/Sema/Sema.h (+3-1) - (modified) clang/lib/AST/TypePrinter.cpp (+3) - (modified) clang/lib/Parse/ParseDecl.cpp (+8-2) - (modified) clang/lib/Sema/SemaDeclAttr.cpp (+54-16) - (modified) clang/lib/Sema/SemaType.cpp (+5-3) - (modified) clang/lib/Sema/TreeTransform.h (+2-1) - (added) clang/test/AST/attr-counted-by-or-null-late-parsed-struct-ptrs.c (+45) - (added) clang/test/AST/attr-counted-by-or-null-struct-ptrs.c (+117) - (added) clang/test/AST/attr-sized-by-late-parsed-struct-ptrs.c (+45) - (added) clang/test/AST/attr-sized-by-or-null-late-parsed-struct-ptrs.c (+45) - (added) clang/test/AST/attr-sized-by-or-null-struct-ptrs.c (+117) - (added) clang/test/AST/attr-sized-by-struct-ptrs.c (+117) - (added) clang/test/Sema/attr-counted-by-or-null-late-parsed-off.c (+26) - (added) clang/test/Sema/attr-counted-by-or-null-late-parsed-struct-ptrs.c (+255) - (added) clang/test/Sema/attr-counted-by-or-null-struct-ptrs-sizeless-types.c (+17) - (added) clang/test/Sema/attr-counted-by-or-null-struct-ptrs.c (+225) - (added) clang/test/Sema/attr-counted-by-or-null-vla-sizeless-types.c (+11) - (added) clang/test/Sema/attr-sized-by-late-parsed-off.c (+26) - (added) clang/test/Sema/attr-sized-by-late-parsed-struct-ptrs.c (+243) - (added) clang/test/Sema/attr-sized-by-or-null-late-parsed-off.c (+26) - (added) clang/test/Sema/attr-sized-by-or-null-late-parsed-struct-ptrs.c (+243) - (added) clang/test/Sema/attr-sized-by-or-null-struct-ptrs-sizeless-types.c (+16) - (added) clang/test/Sema/attr-sized-by-or-null-struct-ptrs.c (+211) - (added) clang/test/Sema/attr-sized-by-or-null-vla-sizeless-types.c (+11) - (added) clang/test/Sema/attr-sized-by-struct-ptrs-sizeless-types.c (+16) - (added) clang/test/Sema/attr-sized-by-struct-ptrs.c (+211) - (added) clang/test/Sema/attr-sized-by-vla-sizeless-types.c (+11) ``````````diff diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 2f83f5c6d54e9..841ef07f2e99b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -425,6 +425,12 @@ Attribute Changes in Clang size_t count; }; +- The attributes ``sized_by``, ``counted_by_or_null`` and ``sized_by_or_null``` + have been added as variants on ``counted_by``, each with slightly different semantics. + ``sized_by`` takes a byte size parameter instead of an element count, allowing pointees + with unknown size. The ``counted_by_or_null`` and ``sized_by_or_null`` variants are equivalent + to their base variants, except the pointer can be null regardless of count/size value. + If the pointer is null the size is effectively 0. Improvements to Clang's diagnostics ----------------------------------- diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 7a7721239a28f..70877f0dd2ba8 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2236,6 +2236,36 @@ def CountedBy : DeclOrTypeAttr { let LangOpts = [COnly]; } +def CountedByOrNull : DeclOrTypeAttr { + let Spellings = [Clang<"counted_by_or_null">]; + let Subjects = SubjectList<[Field], ErrorDiag>; + let Args = [ExprArgument<"Count">, IntArgument<"NestedLevel", 1>]; + let LateParsed = LateAttrParseExperimentalExt; + let ParseArgumentsAsUnevaluated = 1; + let Documentation = [CountedByDocs]; + let LangOpts = [COnly]; +} + +def SizedBy : DeclOrTypeAttr { + let Spellings = [Clang<"sized_by">]; + let Subjects = SubjectList<[Field], ErrorDiag>; + let Args = [ExprArgument<"Size">, IntArgument<"NestedLevel", 1>]; + let LateParsed = LateAttrParseExperimentalExt; + let ParseArgumentsAsUnevaluated = 1; + let Documentation = [CountedByDocs]; + let LangOpts = [COnly]; +} + +def SizedByOrNull : DeclOrTypeAttr { + let Spellings = [Clang<"sized_by_or_null">]; + let Subjects = SubjectList<[Field], ErrorDiag>; + let Args = [ExprArgument<"Size">, IntArgument<"NestedLevel", 1>]; + let LateParsed = LateAttrParseExperimentalExt; + let ParseArgumentsAsUnevaluated = 1; + let Documentation = [CountedByDocs]; + let LangOpts = [COnly]; +} + // This is a marker used to indicate that an __unsafe_unretained qualifier was // ignored because ARC is not enabled. The usual representation for this // qualifier is as an ObjCOwnership attribute with Kind == "none". diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 8e6596410c5d0..93672ccfd59d9 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6532,27 +6532,27 @@ def warn_superclass_variable_sized_type_not_at_end : Warning< " in superclass %3">, InGroup<ObjCFlexibleArray>; def err_flexible_array_count_not_in_same_struct : Error< - "'counted_by' field %0 isn't within the same struct as the flexible array">; + "'%select{counted_by|sized_by|counted_by_or_null|sized_by_or_null}1' field %0 isn't within the same struct as the flexible array">; def err_counted_by_attr_not_on_ptr_or_flexible_array_member : Error< - "'counted_by' only applies to pointers or C99 flexible array members">; + "'%select{counted_by|sized_by|counted_by_or_null|sized_by_or_null}0' only applies to pointers%select{ or C99 flexible array members|||}0">; def err_counted_by_attr_on_array_not_flexible_array_member : Error< "'counted_by' on arrays only applies to C99 flexible array members">; def err_counted_by_attr_refer_to_itself : Error< "'counted_by' cannot refer to the flexible array member %0">; def err_counted_by_must_be_in_structure : Error< - "field %0 in 'counted_by' not inside structure">; + "field %0 in '%select{counted_by|sized_by|counted_by_or_null|sized_by_or_null}1' not inside structure">; def err_counted_by_attr_argument_not_integer : Error< - "'counted_by' requires a non-boolean integer type argument">; + "'%select{counted_by|sized_by|counted_by_or_null|sized_by_or_null}0' requires a non-boolean integer type argument">; def err_counted_by_attr_only_support_simple_decl_reference : Error< - "'counted_by' argument must be a simple declaration reference">; + "'%select{counted_by|sized_by|counted_by_or_null|sized_by_or_null}0' argument must be a simple declaration reference">; def err_counted_by_attr_in_union : Error< - "'counted_by' cannot be applied to a union member">; + "'%select{counted_by|sized_by|counted_by_or_null|sized_by_or_null}0' cannot be applied to a union member">; def err_counted_by_attr_refer_to_union : Error< - "'counted_by' argument cannot refer to a union member">; + "'%select{counted_by|sized_by|counted_by_or_null|sized_by_or_null}0' argument cannot refer to a union member">; def note_flexible_array_counted_by_attr_field : Note< "field %0 declared here">; def err_counted_by_attr_pointee_unknown_size : Error< - "'counted_by' cannot be applied to %select{" + "'%select{counted_by|counted_by_or_null}3' cannot be applied to %select{" "a pointer with pointee|" // pointer "an array with element}0" // array " of unknown size because %1 is %select{" diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index cd06bd9c230df..2ea7eb71a8f2e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11397,7 +11397,9 @@ class Sema final : public SemaBase { SourceLocation AttrLoc); QualType BuildCountAttributedArrayOrPointerType(QualType WrappedTy, - Expr *CountExpr); + Expr *CountExpr, + bool CountInBytes, + bool OrNull); QualType BuildAddressSpaceAttr(QualType &T, LangAS ASIdx, Expr *AddrSpace, SourceLocation AttrLoc); diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 87f0a8728d850..6f346ca894f60 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1905,6 +1905,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, break; case attr::CountedBy: + case attr::CountedByOrNull: + case attr::SizedBy: + case attr::SizedByOrNull: case attr::LifetimeBound: case attr::TypeNonNull: case attr::TypeNullable: diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 8405b44685ae4..1dc307484204c 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -662,7 +662,10 @@ void Parser::ParseGNUAttributeArgs( ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc, Form); return; - } else if (AttrKind == ParsedAttr::AT_CountedBy) { + } else if (AttrKind == ParsedAttr::AT_CountedBy || + AttrKind == ParsedAttr::AT_CountedByOrNull || + AttrKind == ParsedAttr::AT_SizedBy || + AttrKind == ParsedAttr::AT_SizedByOrNull) { ParseBoundsAttribute(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc, Form); return; @@ -4806,7 +4809,7 @@ static void DiagnoseCountAttributedTypeInUnnamedAnon(ParsingDeclSpec &DS, if (!RD->containsDecl(DD.getDecl())) { P.Diag(VD->getBeginLoc(), diag::err_flexible_array_count_not_in_same_struct) - << DD.getDecl(); + << DD.getDecl() << CAT->getKind(); P.Diag(DD.getDecl()->getBeginLoc(), diag::note_flexible_array_counted_by_attr_field) << DD.getDecl(); @@ -4964,6 +4967,9 @@ void Parser::ParseLexedCAttribute(LateParsedAttribute &LA, /*SyntaxUsed=*/ParsedForm.getSyntax()); switch (AttrKind) { case ParsedAttr::Kind::AT_CountedBy: + case ParsedAttr::Kind::AT_CountedByOrNull: + case ParsedAttr::Kind::AT_SizedBy: + case ParsedAttr::Kind::AT_SizedByOrNull: ParseBoundsAttribute(LA.AttrName, LA.AttrNameLoc, Attrs, /*ScopeName=*/ScopeName, SourceLocation(), /*Form=*/ParsedForm); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index c8b71631076ba..ebce77d368e50 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -8641,22 +8641,33 @@ enum class CountedByInvalidPointeeTypeKind { VALID, }; -static bool CheckCountedByAttrOnField( - Sema &S, FieldDecl *FD, Expr *E, - llvm::SmallVectorImpl<TypeCoupledDeclRefInfo> &Decls) { +static bool +CheckCountedByAttrOnField(Sema &S, FieldDecl *FD, Expr *E, + llvm::SmallVectorImpl<TypeCoupledDeclRefInfo> &Decls, + bool CountInBytes, bool OrNull) { // Check the context the attribute is used in + unsigned Kind = CountInBytes; + if (OrNull) + Kind += 2; + if (FD->getParent()->isUnion()) { S.Diag(FD->getBeginLoc(), diag::err_counted_by_attr_in_union) - << FD->getSourceRange(); + << Kind << FD->getSourceRange(); return true; } const auto FieldTy = FD->getType(); + if (FieldTy->isArrayType() && (CountInBytes || OrNull)) { + S.Diag(FD->getBeginLoc(), + diag::err_counted_by_attr_not_on_ptr_or_flexible_array_member) + << Kind << FD->getLocation(); + return true; + } if (!FieldTy->isArrayType() && !FieldTy->isPointerType()) { S.Diag(FD->getBeginLoc(), diag::err_counted_by_attr_not_on_ptr_or_flexible_array_member) - << FD->getLocation(); + << Kind << FD->getLocation(); return true; } @@ -8667,7 +8678,7 @@ static bool CheckCountedByAttrOnField( StrictFlexArraysLevel, true)) { S.Diag(FD->getBeginLoc(), diag::err_counted_by_attr_on_array_not_flexible_array_member) - << FD->getLocation(); + << Kind << FD->getLocation(); return true; } @@ -8697,9 +8708,10 @@ static bool CheckCountedByAttrOnField( InvalidTypeKind = CountedByInvalidPointeeTypeKind::FLEXIBLE_ARRAY_MEMBER; } - if (InvalidTypeKind != CountedByInvalidPointeeTypeKind::VALID) { + if (InvalidTypeKind != CountedByInvalidPointeeTypeKind::VALID && + !CountInBytes) { S.Diag(FD->getBeginLoc(), diag::err_counted_by_attr_pointee_unknown_size) - << SelectPtrOrArr << PointeeTy << (int)InvalidTypeKind + << SelectPtrOrArr << PointeeTy << (int)InvalidTypeKind << OrNull << FD->getSourceRange(); return true; } @@ -8708,7 +8720,7 @@ static bool CheckCountedByAttrOnField( if (!E->getType()->isIntegerType() || E->getType()->isBooleanType()) { S.Diag(E->getBeginLoc(), diag::err_counted_by_attr_argument_not_integer) - << E->getSourceRange(); + << Kind << E->getSourceRange(); return true; } @@ -8716,7 +8728,7 @@ static bool CheckCountedByAttrOnField( if (!DRE) { S.Diag(E->getBeginLoc(), diag::err_counted_by_attr_only_support_simple_decl_reference) - << E->getSourceRange(); + << Kind << E->getSourceRange(); return true; } @@ -8727,7 +8739,7 @@ static bool CheckCountedByAttrOnField( } if (!CountFD) { S.Diag(E->getBeginLoc(), diag::err_counted_by_must_be_in_structure) - << CountDecl << E->getSourceRange(); + << CountDecl << Kind << E->getSourceRange(); S.Diag(CountDecl->getBeginLoc(), diag::note_flexible_array_counted_by_attr_field) @@ -8738,7 +8750,7 @@ static bool CheckCountedByAttrOnField( if (FD->getParent() != CountFD->getParent()) { if (CountFD->getParent()->isUnion()) { S.Diag(CountFD->getBeginLoc(), diag::err_counted_by_attr_refer_to_union) - << CountFD->getSourceRange(); + << Kind << CountFD->getSourceRange(); return true; } // Whether CountRD is an anonymous struct is not determined at this @@ -8750,7 +8762,7 @@ static bool CheckCountedByAttrOnField( if (RD != CountRD) { S.Diag(E->getBeginLoc(), diag::err_flexible_array_count_not_in_same_struct) - << CountFD << E->getSourceRange(); + << CountFD << Kind << E->getSourceRange(); S.Diag(CountFD->getBeginLoc(), diag::note_flexible_array_counted_by_attr_field) << CountFD << CountFD->getSourceRange(); @@ -8770,12 +8782,35 @@ static void handleCountedByAttrField(Sema &S, Decl *D, const ParsedAttr &AL) { if (!CountExpr) return; + bool CountInBytes; + bool OrNull; + switch (AL.getKind()) { + case ParsedAttr::AT_CountedBy: + CountInBytes = false; + OrNull = false; + break; + case ParsedAttr::AT_CountedByOrNull: + CountInBytes = false; + OrNull = true; + break; + case ParsedAttr::AT_SizedBy: + CountInBytes = true; + OrNull = false; + break; + case ParsedAttr::AT_SizedByOrNull: + CountInBytes = true; + OrNull = true; + break; + default: + llvm_unreachable("unexpected counted_by family attribute"); + } + llvm::SmallVector<TypeCoupledDeclRefInfo, 1> Decls; - if (CheckCountedByAttrOnField(S, FD, CountExpr, Decls)) + if (CheckCountedByAttrOnField(S, FD, CountExpr, Decls, CountInBytes, OrNull)) return; - QualType CAT = - S.BuildCountAttributedArrayOrPointerType(FD->getType(), CountExpr); + QualType CAT = S.BuildCountAttributedArrayOrPointerType( + FD->getType(), CountExpr, CountInBytes, OrNull); FD->setType(CAT); } @@ -9802,6 +9837,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, break; case ParsedAttr::AT_CountedBy: + case ParsedAttr::AT_CountedByOrNull: + case ParsedAttr::AT_SizedBy: + case ParsedAttr::AT_SizedByOrNull: handleCountedByAttrField(S, D, AL); break; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index ef0b6b701a52c..832a30992f24a 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -9346,15 +9346,17 @@ BuildTypeCoupledDecls(Expr *E, } QualType Sema::BuildCountAttributedArrayOrPointerType(QualType WrappedTy, - Expr *CountExpr) { + Expr *CountExpr, + bool CountInBytes, + bool OrNull) { assert(WrappedTy->isIncompleteArrayType() || WrappedTy->isPointerType()); llvm::SmallVector<TypeCoupledDeclRefInfo, 1> Decls; BuildTypeCoupledDecls(CountExpr, Decls); /// When the resulting expression is invalid, we still create the AST using /// the original count expression for the sake of AST dump. - return Context.getCountAttributedType( - WrappedTy, CountExpr, /*CountInBytes*/ false, /*OrNull*/ false, Decls); + return Context.getCountAttributedType(WrappedTy, CountExpr, CountInBytes, + OrNull, Decls); } /// getDecltypeForExpr - Given an expr, will return the decltype for diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 29444f0edc2ae..cf96c9e2af68f 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -7344,7 +7344,8 @@ QualType TreeTransform<Derived>::TransformCountAttributedType( if (getDerived().AlwaysRebuild() || InnerTy != OldTy->desugar() || OldCount != NewCount) { // Currently, CountAttributedType can only wrap incomplete array types. - Result = SemaRef.BuildCountAttributedArrayOrPointerType(InnerTy, NewCount); + Result = SemaRef.BuildCountAttributedArrayOrPointerType( + InnerTy, NewCount, OldTy->isCountInBytes(), OldTy->isOrNull()); } TLB.push<CountAttributedTypeLoc>(Result); diff --git a/clang/test/AST/attr-counted-by-or-null-late-parsed-struct-ptrs.c b/clang/test/AST/attr-counted-by-or-null-late-parsed-struct-ptrs.c new file mode 100644 index 0000000000000..975c0a0231943 --- /dev/null +++ b/clang/test/AST/attr-counted-by-or-null-late-parsed-struct-ptrs.c @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -fexperimental-late-parse-attributes %s -ast-dump | FileCheck %s + +#define __counted_by_or_null(f) __attribute__((counted_by_or_null(f))) + +struct size_known { + int field; +}; + +//============================================================================== +// __counted_by_or_null on struct member pointer in decl attribute position +//============================================================================== + +struct on_member_pointer_complete_ty { + struct size_known *buf __counted_by_or_null(count); + int count; +}; +// CHECK-LABEL: struct on_member_pointer_complete_ty definition +// CHECK-NEXT: |-FieldDecl {{.*}} buf 'struct size_known * __counted_by_or_null(count)':'struct size_known *' +// CHECK-NEXT: `-FieldDecl {{.*}} referenced count 'int' + +struct on_pointer_anon_count { + struct size_known *buf __counted_by_or_null(count); + struct { + int count; + }; +}; + +// CHECK-LABEL: struct on_pointer_anon_count definition +// CHECK-NEXT: |-FieldDecl {{.*}} buf 'struct size_known * __counted_by_or_null(count)':'struct size_known *' +// CHECK-NEXT: |-RecordDecl {{.*}} struct definition +// CHECK-NEXT: | `-FieldDecl {{.*}} count 'int' +// CHECK-NEXT: |-FieldDecl {{.*}} implicit 'struct on_pointer_anon_count::(anonymous at {{.*}})' +// CHECK-NEXT: `-IndirectFieldDecl {{.*}} implicit referenced count 'int' +// CHECK-NEXT: |-Field {{.*}} '' 'struct on_pointer_anon_count::(anonymous at {{.*}})' +// CHECK-NEXT: `-Field {{.*}} 'count' 'int' + +//============================================================================== +// __counted_by_or_null on struct member pointer in type attribute position +//============================================================================== +// TODO: Correctly parse counted_by_or_null as a type attribute. Currently it is parsed +// as a declaration attribute and is **not** late parsed resulting in the `count` +// field being unavailable. +// +// See `clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs.c` for test +// cases. diff --git a/clang/test/AST/attr-counted-by-or-null-struct-ptrs.c b/clang/test/AST/attr-counted-by-or-null-struct-ptrs.c new file mode 100644 index 0000000000000..cedb3f1192eda --- /dev/null +++ b/clang/test/AST/attr-counted-by-or-null-struct-ptrs.c @@ -0,0 +1,117 @@ +// RUN: %clang_cc1 %s -ast-dump | FileCheck %s + +#define __counted_by_or_null(f) __attribute__((counted_by_or_null(f))) + +struct size_unknown; +struct size_known { + int field; +}; + +//============================================================================== +// __counted_by_or_null on struct member pointer in decl attribute position +//============================================================================== + +// CHECK-LABEL: RecordDecl {{.+}} struct on_member_pointer_complete_ty definition +// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int' +// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known * __counted_by_or_null(count)':'struct size_known *' +struct on_member_pointer_complete_ty { + int count; + struct size_known * buf __counted_by_or_null(count); +}; + +// CHECK-LABEL: RecordDecl {{.+}} struct on_pointer_anon_buf definition +// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int' +// CHECK-NEXT: |-RecordDecl {{.+}} struct definition +// CHECK-NEXT: | `-FieldDecl {{.+}} buf 'struct size_known * __counted_by_or_null(count)':'struct size_known *' +// CHECK-NEXT: |-FieldDecl {{.+}} implicit 'struct on_pointer_anon_buf::(anonymous at [[ANON_STRUCT_PATH:.+]])' +// CHECK-NEXT: `-IndirectFieldDecl {{.+}} implicit buf 'struct size_known * __counted_by_or_null(count)':'struct size_known *' +// CHECK-NEXT: |-Field {{.+}} '' 'struct on_pointer_anon_buf::(anonymous at [[ANON_STRUCT_PATH]])' +// CHECK-NEXT: `-Field {{.+}} 'buf' 'struct size_known * __counted_by_or_null(count)':'struct size_known *' +struct on_pointer_anon_buf { + int count; + struct { + struct size_known *buf __counted_by_or_null(count); + }; +}; + +struct on_pointer_anon_count { + struct { + int count; + }; + struct size_known *buf __counted_by_or_null(count); +}; + +//============================================================================== +// __counted_by_or_null on struct member pointer in type attribute position +//===============... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/93231 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits