width ? &width : NULL, decl_attrs, expr, NULL,
DEPRECATED_NORMAL);
+ /* When this field has name, its type is a top level type, we should
+ call verify_counted_by_for_top_anonymous_type. */
+ if (DECL_NAME (value) != NULL_TREE
+ && declspecs->typespec_kind == ctsk_tagdef)
+ verify_counted_by_for_top_anonymous_type (declspecs->type);
+
finish_decl (value, loc, NULL_TREE, NULL_TREE, NULL_TREE);
DECL_INITIAL (value) = width;
if (width)
}
}
-/* Verify the argument of the counted_by attribute of each of the
- FIELDS_WITH_COUNTED_BY is a valid field of the containing structure,
- STRUCT_TYPE, Report error and remove the corresponding attribute
- when it's not. */
+/* Verify the argument of the counted_by attribute of each field of
+ the containing structure, OUTMOST_STRUCT_TYPE, including its inner
+ anonymous struct/union, Report error and remove the corresponding
+ attribute when it's not. */
static void
-verify_counted_by_attribute (tree struct_type,
- auto_vec<tree> *fields_with_counted_by)
+verify_counted_by_attribute (tree outmost_struct_type,
+ tree cur_struct_type)
{
- for (tree field_decl : *fields_with_counted_by)
+ for (tree field = TYPE_FIELDS (cur_struct_type); field;
+ field = TREE_CHAIN (field))
{
- tree attr_counted_by = lookup_attribute ("counted_by",
- DECL_ATTRIBUTES (field_decl));
+ if (c_flexible_array_member_type_p (TREE_TYPE (field))
+ || TREE_CODE (TREE_TYPE (field)) == POINTER_TYPE)
+ {
+ tree attr_counted_by = lookup_attribute ("counted_by",
+ DECL_ATTRIBUTES (field));
- if (!attr_counted_by)
- continue;
+ if (!attr_counted_by)
+ continue;
- /* If there is an counted_by attribute attached to the field,
- verify it. */
+ /* If there is an counted_by attribute attached to the field,
+ verify it. */
- tree fieldname = TREE_VALUE (TREE_VALUE (attr_counted_by));
+ tree fieldname = TREE_VALUE (TREE_VALUE (attr_counted_by));
- /* Verify the argument of the attrbute is a valid field of the
- containing structure. */
+ /* Verify the argument of the attrbute is a valid field of the
+ containing structure. */
- tree counted_by_field = lookup_field (struct_type, fieldname);
+ tree counted_by_field = lookup_field (outmost_struct_type,
+ fieldname);
- /* Error when the field is not found in the containing structure and
- remove the corresponding counted_by attribute from the field_decl. */
- if (!counted_by_field)
- {
- error_at (DECL_SOURCE_LOCATION (field_decl),
+ /* Error when the field is not found in the containing structure
+ and remove the corresponding counted_by attribute from the
+ field_decl. */
+ if (!counted_by_field)
+ {
+ error_at (DECL_SOURCE_LOCATION (field),
"argument %qE to the %<counted_by%> attribute"
" is not a field declaration in the same structure"
- " as %qD", fieldname, field_decl);
- DECL_ATTRIBUTES (field_decl)
- = remove_attribute ("counted_by", DECL_ATTRIBUTES (field_decl));
- }
- else
- /* Error when the field is not with an integer type. */
- {
- while (TREE_CHAIN (counted_by_field))
- counted_by_field = TREE_CHAIN (counted_by_field);
- tree real_field = TREE_VALUE (counted_by_field);
-
- if (!INTEGRAL_TYPE_P (TREE_TYPE (real_field)))
+ " as %qD", fieldname, field);
+ DECL_ATTRIBUTES (field)
+ = remove_attribute ("counted_by", DECL_ATTRIBUTES (field));
+ }
+ else
+ /* Error when the field is not with an integer type. */
{
- error_at (DECL_SOURCE_LOCATION (field_decl),
+ while (TREE_CHAIN (counted_by_field))
+ counted_by_field = TREE_CHAIN (counted_by_field);
+ tree real_field = TREE_VALUE (counted_by_field);
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (real_field)))
+ {
+ error_at (DECL_SOURCE_LOCATION (field),
"argument %qE to the %<counted_by%> attribute"
" is not a field declaration with an integer type",
fieldname);
- DECL_ATTRIBUTES (field_decl)
- = remove_attribute ("counted_by",
- DECL_ATTRIBUTES (field_decl));
+ DECL_ATTRIBUTES (field)
+ = remove_attribute ("counted_by",
+ DECL_ATTRIBUTES (field));
+ }
}
}
+ else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
+ && (DECL_NAME (field) == NULL_TREE))
+ verify_counted_by_attribute (outmost_struct_type, TREE_TYPE (field));
}
}
+/* Caller should make sure the TYPE is a top-level type (i.e. not being
+ nested in other structure/uniona). For such type, verify its counted_by
+ if it is an anonymous structure/union. */
+
+void
+verify_counted_by_for_top_anonymous_type (tree type)
+{
+ if (!RECORD_OR_UNION_TYPE_P (type))
+ return;
+
+ if (C_TYPE_FIELDS_HAS_COUNTED_BY (type)
+ && c_type_tag (type) == NULL_TREE)
+ verify_counted_by_attribute (type, type);
+}
+
/* TYPE is a struct or union that we're applying may_alias to after the body is
parsed. Fixup any POINTER_TO types. */
until now.) */
bool saw_named_field = false;
- auto_vec<tree> fields_with_counted_by;
for (x = fieldlist; x; x = DECL_CHAIN (x))
{
/* Whether this field is the last field of the structure or union.
pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic,
"flexible array member in a struct with no named "
"members is a GCC extension");
-
- /* If there is a counted_by attribute attached to this field,
- record it here and do more verification later after the
- whole structure is complete. */
if (lookup_attribute ("counted_by", DECL_ATTRIBUTES (x)))
- fields_with_counted_by.safe_push (x);
+ C_TYPE_FIELDS_HAS_COUNTED_BY (t) = 1;
}
- if (TREE_CODE (TREE_TYPE (x)) == POINTER_TYPE)
- /* If there is a counted_by attribute attached to this field,
- record it here and do more verification later after the
- whole structure is complete. */
- if (lookup_attribute ("counted_by", DECL_ATTRIBUTES (x)))
- fields_with_counted_by.safe_push (x);
+ if (TREE_CODE (TREE_TYPE (x)) == POINTER_TYPE
+ && lookup_attribute ("counted_by", DECL_ATTRIBUTES (x)))
+ C_TYPE_FIELDS_HAS_COUNTED_BY (t) = 1;
+
+ /* If the field is an anonymous structure that includes a field
+ with counted_by attribute, this structure should also be marked
+ too. */
+ if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))
+ && C_TYPE_FIELDS_HAS_COUNTED_BY (TREE_TYPE (x))
+ && DECL_NAME (x) == NULL_TREE
+ && c_type_tag (TREE_TYPE (x)) == NULL_TREE)
+ C_TYPE_FIELDS_HAS_COUNTED_BY (t) = 1;
if (pedantic && TREE_CODE (t) == RECORD_TYPE
&& flexible_array_type_p (TREE_TYPE (x)))
C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t);
C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t);
C_TYPE_FIELDS_NON_CONSTEXPR (x) = C_TYPE_FIELDS_NON_CONSTEXPR (t);
+ C_TYPE_FIELDS_HAS_COUNTED_BY (x) = C_TYPE_FIELDS_HAS_COUNTED_BY (t);
C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t);
C_TYPE_VARIABLY_MODIFIED (x) = C_TYPE_VARIABLY_MODIFIED (t);
C_TYPE_INCOMPLETE_VARS (x) = NULL_TREE;
struct_parse_info->struct_types.safe_push (t);
}
- if (fields_with_counted_by.length () > 0)
- verify_counted_by_attribute (t, &fields_with_counted_by);
+ /* Only when the enclosing struct/union type is not anonymous, do more
+ verification on the fields with counted_by attributes. */
+ if (C_TYPE_FIELDS_HAS_COUNTED_BY (t) && c_type_tag (t) != NULL_TREE)
+ verify_counted_by_attribute (t, t);
return t;
}
}
finish_declspecs (specs);
+ /* When the decl is declared, its type is a top level type, we should
+ call verify_counted_by_for_top_anonymous_type. */
+ if (specs->typespec_kind == ctsk_tagdef)
+ verify_counted_by_for_top_anonymous_type (specs->type);
+
bool gnu_auto_type_p = specs->typespec_word == cts_auto_type;
bool std_auto_type_p = specs->c23_auto_p;
bool any_auto_type_p = gnu_auto_type_p || std_auto_type_p;
c_parser_declspecs (parser, specs, true, true, true, true, false,
!have_gnu_attrs, true, cla_nonabstract_decl);
finish_declspecs (specs);
+ /* When the param is declared, its type is a top level type, we should
+ call verify_counted_by_for_top_anonymous_type. */
+ if (specs->typespec_kind == ctsk_tagdef)
+ verify_counted_by_for_top_anonymous_type (specs->type);
+
pending_xref_error ();
prefix_attrs = specs->attrs;
specs->attrs = NULL_TREE;
{
pending_xref_error ();
finish_declspecs (specs);
+ /* When the typename is declared, its type is a top level type, we should
+ call verify_counted_by_for_top_anonymous_type. */
+ if (specs->typespec_kind == ctsk_tagdef)
+ verify_counted_by_for_top_anonymous_type (specs->type);
}
declarator = c_parser_declarator (parser,
specs->typespec_kind != ctsk_none,
permitted for a constexpr object. */
#define C_TYPE_FIELDS_NON_CONSTEXPR(TYPE) TREE_LANG_FLAG_4 (TYPE)
+/* In a RECORD_TYPE or UNION_TYPE, nonzero if any component has a
+ counted_by attribute. */
+#define C_TYPE_FIELDS_HAS_COUNTED_BY(TYPE) TYPE_LANG_FLAG_3 (TYPE)
+
/* In a RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE
nonzero if the definition of the type has already started. */
#define C_TYPE_BEING_DEFINED(TYPE) TYPE_LANG_FLAG_0 (TYPE)
extern void c_bind (location_t, tree, bool);
extern bool tag_exists_p (enum tree_code, tree);
+extern void verify_counted_by_for_top_anonymous_type (tree);
+
/* In c-errors.cc */
extern bool pedwarn_c90 (location_t, diagnostics::option_id, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
build_counted_by_ref (tree datum, tree subdatum,
tree *counted_by_type)
{
- tree type = TREE_TYPE (datum);
tree sub_type = TREE_TYPE (subdatum);
if (!c_flexible_array_member_type_p (sub_type)
&& TREE_CODE (sub_type) != POINTER_TYPE)
tree attr_counted_by = lookup_attribute ("counted_by",
DECL_ATTRIBUTES (subdatum));
+ if (!attr_counted_by)
+ return NULL_TREE;
+
tree counted_by_ref = NULL_TREE;
*counted_by_type = NULL_TREE;
- if (attr_counted_by)
+
+ tree type = TREE_TYPE (datum);
+
+ /* If the type of the containing structure is an anonymous struct/union,
+ and this anonymous struct/union is not a root type, get the first
+ outer named structure/union type. */
+ while (TREE_CODE (datum) == COMPONENT_REF
+ && c_type_tag (type) == NULL_TREE
+ && DECL_NAME (TREE_OPERAND (datum, 1)) == NULL_TREE)
{
- tree field_id = TREE_VALUE (TREE_VALUE (attr_counted_by));
- counted_by_ref
- = build_component_ref (UNKNOWN_LOCATION,
- datum, field_id,
- UNKNOWN_LOCATION, UNKNOWN_LOCATION);
- counted_by_ref = build_fold_addr_expr (counted_by_ref);
+ datum = TREE_OPERAND (datum, 0);
+ type = TREE_TYPE (datum);
+ }
+ tree field_id = TREE_VALUE (TREE_VALUE (attr_counted_by));
+ tree counted_by_field = lookup_field (type, field_id);
+ gcc_assert (counted_by_field);
+
+ tree counted_by_subdatum;
+ do
+ {
+ counted_by_subdatum = TREE_VALUE (counted_by_field);
/* Get the TYPE of the counted_by field. */
- tree counted_by_field = lookup_field (type, field_id);
- gcc_assert (counted_by_field);
+ *counted_by_type = TREE_TYPE (counted_by_subdatum);
- do
- {
- *counted_by_type = TREE_TYPE (TREE_VALUE (counted_by_field));
- counted_by_field = TREE_CHAIN (counted_by_field);
- }
- while (counted_by_field);
+ counted_by_ref
+ = build3 (COMPONENT_REF, TREE_TYPE (counted_by_subdatum),
+ datum, counted_by_subdatum, NULL_TREE);
+
+ datum = counted_by_ref;
+ counted_by_field = TREE_CHAIN (counted_by_field);
}
+ while (counted_by_field);
+
+ counted_by_ref = build_fold_addr_expr (counted_by_ref);
return counted_by_ref;
}
--- /dev/null
+/* Test the attribute counted_by for pointer field in anonymous struct/union
+ and its usage in __builtin_dynamic_object_size. */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#define PTR_TYPE char
+#define FAM_TYPE char
+#include "counted-by-anonymous-2.c"
--- /dev/null
+/* Test the attribute counted_by for pointer field in anonymous struct/union
+ and its usage in __builtin_dynamic_object_size. */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#define PTR_TYPE float
+#define FAM_TYPE float
+#include "counted-by-anonymous-2.c"
--- /dev/null
+/* Test the attribute counted_by for pointer field in anonymous struct/union
+ and its usage in __builtin_dynamic_object_size. */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+struct A {
+ int a;
+ char *b;
+};
+struct B {
+ float a;
+ double b;
+};
+#define PTR_TYPE struct A
+#define FAM_TYPE struct B
+#include "counted-by-anonymous-2.c"
--- /dev/null
+/* Test the attribute counted_by for pointer field in anonymous struct/union
+ and its usage in __builtin_dynamic_object_size. */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+union A {
+ int a;
+ char *b;
+};
+union B {
+ float a;
+ double b;
+};
+#define PTR_TYPE union A
+#define FAM_TYPE union B
+#include "counted-by-anonymous-2.c"
--- /dev/null
+/* Test the attribute counted_by for pointer field in anonymous struct/union
+ and its usage in __builtin_dynamic_object_size. */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#include "builtin-object-size-common.h"
+#ifndef PTR_TYPE
+#define PTR_TYPE int
+#endif
+#ifndef FAM_TYPE
+#define FAM_TYPE int
+#endif
+
+#define __counted_by(member) \
+ __attribute__((__counted_by__(member)))
+
+struct nested_mixed {
+ struct {
+ union {
+ int b;
+ float f;
+ };
+ int n;
+ };
+ struct {
+ PTR_TYPE *pointer __counted_by(n);
+ FAM_TYPE c[] __counted_by(b);
+ };
+} *nested_mixed_annotated;
+
+
+void __attribute__((__noinline__)) setup (int pointer_array_count,
+ int fam_count)
+{
+ nested_mixed_annotated
+ = (struct nested_mixed *) malloc (sizeof (struct nested_mixed)
+ + fam_count * sizeof (FAM_TYPE));
+ nested_mixed_annotated->pointer
+ = (PTR_TYPE *) malloc (sizeof (PTR_TYPE) * pointer_array_count);
+ nested_mixed_annotated->b = fam_count;
+ nested_mixed_annotated->n = pointer_array_count;
+ return;
+}
+
+void __attribute__((__noinline__)) test ()
+{
+ EXPECT(__builtin_dynamic_object_size(nested_mixed_annotated->c, 1),
+ nested_mixed_annotated->b * sizeof (FAM_TYPE));
+ EXPECT(__builtin_dynamic_object_size(nested_mixed_annotated->pointer, 1),
+ nested_mixed_annotated->n * sizeof (PTR_TYPE));
+}
+
+void cleanup ()
+{
+ free (nested_mixed_annotated->pointer);
+ free (nested_mixed_annotated);
+}
+
+int main(int argc, char *argv[])
+{
+ setup (10,20);
+ test ();
+ DONE ();
+ cleanup ();
+ return 0;
+}
--- /dev/null
+/* Testing the correct usage of attribute counted_by for anonymous
+ structures with -fms-extensions. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fms-extensions" } */
+
+#define __counted_by(member) \
+ __attribute__((__counted_by__(member)))
+
+/* Do not support the inward-to-outward counted-by field reference for
+ ms-extensions since checking the validity of such reference depends
+ on unknown situation at the end of the structure definition. */
+struct bar {
+ char *buf __counted_by (n); /* { dg-error "attribute is not a field declaration in the same structure as" } */
+};
+
+struct foo {
+ int n;
+ struct bar;
+};
+
+/* However, at the same time, support the outward-to-inward counted-by
+ field reference for ms-extensions. */
+struct ids
+{
+ int length_ad;
+ int length_na;
+};
+
+typedef union
+{
+ int length_hb;
+ float other;
+} ids_2;
+
+struct person
+{
+ int age;
+ int weight;
+ struct ids; // Anonymous structure, no name needed
+ ids_2; // Anonymous union, no name needed
+ char *address __attribute__ ((counted_by (length_ad)));
+ char *hobby __attribute__ ((counted_by (length_hb)));
+ char name[] __attribute__ ((counted_by (length_na)));
+};
--- /dev/null
+/* Testing the correct usage of attribute counted_by for anonymous
+ structures. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+#define __counted_by(member) \
+ __attribute__((__counted_by__(member)))
+
+struct fam_in_union {
+ int count;
+ union {
+ char a;
+ char fam[] __counted_by(count);
+ };
+};
+
+struct fam_in_union_2 {
+ int count;
+ union inside {
+ char a;
+ char fam[] __counted_by(count); /* { dg-error "attribute is not a field declaration in the same structure as" } */
+ } inside_u;
+};
+
+struct fam_in_struct {
+ int count;
+ struct {
+ char a;
+ char fam[] __counted_by(count);
+ };
+};
+
+struct fam_in_struct_2 {
+ int count;
+ struct insidestruct {
+ char a;
+ char fam[] __counted_by(count); /* { dg-error "attribute is not a field declaration in the same structure as" } */
+ } inside_s;
+};
+
+struct pointer_in_union {
+ union {
+ char a;
+ char* p __counted_by(count);
+ };
+ int count;
+};
+
+struct pointer_in_union_2 {
+ union insideunion {
+ char a;
+ char* p __counted_by(count); /* { dg-error "attribute is not a field declaration in the same structure as" } */
+ } inside_u;
+ int count;
+};
+
+struct pointer_in_union_3 {
+ union {
+ char b;
+ char* p __counted_by(countp); /* { dg-error "attribute is not a field declaration with an integer type" } */
+
+ };
+ float countp;
+};
+
+struct pointer_in_struct {
+ struct {
+ int count_q;
+ char *p __counted_by(count_p);
+ float *q __counted_by(count_q);
+ int count_fam;
+ struct {
+ int count_p;
+ char a;
+ char fam[] __counted_by(count_fam);
+ };
+ };
+};
+
+struct nested_mixed {
+ struct {
+ union {
+ int b;
+ float f;
+ };
+ int n;
+ };
+ struct {
+ int *pointer __counted_by(n);
+ float *pointer_2 __counted_by(f); /* { dg-error "attribute is not a field declaration with an integer type" } */
+ char c[] __counted_by(b);
+ };
+} *array_nested_annotated;
+
+/* Support an untagged type as its own top-level type. */
+
+/* A. Variable declaration. */
+
+struct { int a0; char b0[] __attribute__ ((counted_by (a0))); } x0;
+struct { char b0[] __attribute__ ((counted_by (a0))); } x00; /* { dg-error "attribute is not a field declaration in the same structure as" } */
+
+struct { int a; char b[] __attribute__ ((counted_by (a))); } *x;
+struct { char b1[] __attribute__ ((counted_by (a1))); } *x1; /* { dg-error "attribute is not a field declaration in the same structure as" } */
+
+struct { char *e __attribute__ ((counted_by (f))); int f; } *x2;
+struct { char *e1 __attribute__ ((counted_by (f1))); } *x3; /* { dg-error "attribute is not a field declaration in the same structure as" } */
+
+struct { char *e4 __attribute__ ((counted_by (f4))); int f4; } **x4;
+struct { char *e5 __attribute__ ((counted_by (f5))); } **x5; /* { dg-error "attribute is not a field declaration in the same structure as" } */
+
+/* B. Function declaration and definitions. */
+struct { int c0; char d0[] __attribute__ ((counted_by (c0))); } func0 (int a, int b);
+struct { char d[] __attribute__ ((counted_by (c))); } func00 (int a, int b); /* { dg-error "attribute is not a field declaration in the same structure as" } */
+
+struct { int c; char d[] __attribute__ ((counted_by (c))); } *func (int a, int b);
+struct { char d1[] __attribute__ ((counted_by (c1))); } *func1 (int a, int b); /* { dg-error "attribute is not a field declaration in the same structure as" } */
+
+struct { int c2; char *d2 __attribute__ ((counted_by (c2))); } *func2 () { return 0; }
+struct { char *d3 __attribute__ ((counted_by (c3))); } *func3 () { return 0; } /* { dg-error "attribute is not a field declaration in the same structure as" } */
+
+struct { int c4; char *d4 __attribute__ ((counted_by (c4))); } **func4 () { return 0; }
+struct { char *d5 __attribute__ ((counted_by (c5))); } **func5 () { return 0; } /* { dg-error "attribute is not a field declaration in the same structure as" } */
+
+/* C. Parameter declaration. */
+void func6 (struct { float *f __attribute__ ((counted_by (g))); int g; } *pa, int count); /* { dg-warning "anonymous struct declared inside parameter list will not be visible outside" } */
+void func7 (struct { float *f1 __attribute__ ((counted_by (g1)));} *pa, int count); /* { dg-error "attribute is not a field declaration in the same structure as" } */
+ /* { dg-warning "anonymous struct declared inside parameter list will not be visible outside" "" { target *-*-* } .-1 } */
+
+/* D. Typename. */
+int foo ()
+{
+ int res = sizeof (struct {int count; char *p __attribute__ ((counted_by (count))); });
+
+ res += alignof (struct {char *p1 __attribute__ ((counted_by (count1))); }); /* { dg-error "attribute is not a field declaration in the same structure as" } */
+ return res;
+}
+
+typedef struct {
+ int mc;
+ char *d __attribute__ ((counted_by (mc)));
+} mys;
+
+typedef struct {
+ char *md1 __attribute__ ((counted_by (mc1))); /* { dg-error "attribute is not a field declaration in the same structure as" } */
+} mys1;
+
+
+/* Support an unnamed field with a named struct/union. */
+struct s0 { struct { int a0; char b0[] __attribute__ ((counted_by (a0))); } x; } yy0;
+struct s00 { struct { char c0[] __attribute__ ((counted_by (d0))); } x; } yy00; /* { dg-error "attribute is not a field declaration in the same structure as" } */
+
+struct s { struct { int a; char b[] __attribute__ ((counted_by (a))); } *x; } *y;
+struct s1 { struct { char c[] __attribute__ ((counted_by (d))); } *x; } *yy; /* { dg-error "attribute is not a field declaration in the same structure as" } */
+
+struct s2 { struct { char *b __attribute__ ((counted_by (a))); int a; } *x; } *y2;
+struct s3 { struct { char *c __attribute__ ((counted_by (d))); } *x; } *y3; /* { dg-error "attribute is not a field declaration in the same structure as" } */
+
+struct s4 { struct { char *b4 __attribute__ ((counted_by (a4))); int a4; } x[3]; } *y4;
+struct s5 { struct { char *c5 __attribute__ ((counted_by (d5))); } x[4]; } *y5; /* { dg-error "attribute is not a field declaration in the same structure as" } */
+
+struct s6 { struct { char *b6 __attribute__ ((counted_by (a6))); int a6; } *x[3]; } *y6;
+
+struct s7 { struct { char *c7 __attribute__ ((counted_by (d7))); } *x[4]; } *y7; /* { dg-error "attribute is not a field declaration in the same structure as" } */
--- /dev/null
+/* Testing the attribute counted_by for anonymous structures as ms-extensions.
+ used in bounds sanitizer. */
+/* { dg-do run } */
+/* { dg-options "-O2 -fms-extensions -fsanitize=bounds" } */
+/* { dg-output "index 12 out of bounds for type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 22 out of bounds for type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 31 out of bounds for type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+
+struct ids
+{
+ int length_ad;
+ int length_na;
+};
+
+typedef union
+{
+ int length_hb;
+ float other;
+} ids_2;
+
+struct person
+{
+ int age;
+ int weight;
+ struct ids; // Anonymous structure, no name needed
+ ids_2; // Anonymous union, no name needed
+ char *address __attribute__ ((counted_by (length_ad)));
+ char *hobby __attribute__ ((counted_by (length_hb)));
+ char name[] __attribute__ ((counted_by (length_na)));
+} *Jim;
+
+static void
+setup (int address_l, int name_l, int hb_l)
+{
+ Jim = (struct person *) __builtin_malloc (sizeof (struct person)
+ + name_l * sizeof (char));
+ Jim->length_na = name_l;
+ Jim->address = (char *) __builtin_malloc (sizeof (char) * address_l);
+ Jim->length_ad = address_l;
+ Jim->hobby = (char *) __builtin_malloc (sizeof (char) * hb_l);
+ Jim->length_hb = hb_l;
+}
+
+static void
+cleanup ()
+{
+ __builtin_free (Jim->address);
+ __builtin_free (Jim->hobby);
+ __builtin_free (Jim);
+}
+
+int main()
+{
+ setup (20, 10, 30);
+ Jim->name[12] = 'a';
+ Jim->address[22] = 'k';
+ Jim->hobby[31] = 'h';
+ return 0;
+}
--- /dev/null
+/* Testing the attribute counted_by for anonymous structures as plan9-extensions.
+ used in bounds sanitizer. */
+/* { dg-do run } */
+/* { dg-options "-O2 -fplan9-extensions -fsanitize=bounds" } */
+/* { dg-output "index 12 out of bounds for type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 22 out of bounds for type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 31 out of bounds for type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+struct ids
+{
+ int length_ad;
+ int length_na;
+};
+
+typedef union
+{
+ int length_hb;
+ float other;
+} ids_2;
+
+struct person
+{
+ int age;
+ int weight;
+ struct ids; // Anonymous structure, no name needed
+ ids_2; // Anonymous union, no name needed
+ char *address __attribute__ ((counted_by (length_ad)));
+ char *hobby __attribute__ ((counted_by (length_hb)));
+ char name[] __attribute__ ((counted_by (length_na)));
+} *Jim;
+
+static void
+set_counted_by (struct ids *p, ids_2 *p2,
+ int address_l, int name_l, int hb_l)
+{
+ p->length_ad = address_l;
+ p->length_na = name_l;
+ p2->length_hb = hb_l;
+}
+
+static void
+setup (int address_l, int name_l, int hb_l)
+{
+ Jim = (struct person *) __builtin_malloc (sizeof (struct person)
+ + name_l * sizeof (char));
+ Jim->address = (char *) __builtin_malloc (sizeof (char) * address_l);
+ Jim->hobby = (char *) __builtin_malloc (sizeof (char) * hb_l);
+ set_counted_by (Jim, Jim, address_l, name_l, hb_l);
+}
+
+static void
+cleanup ()
+{
+ __builtin_free (Jim->address);
+ __builtin_free (Jim->hobby);
+ __builtin_free (Jim);
+}
+
+int main()
+{
+ setup (20, 10, 30);
+ Jim->name[12] = 'a';
+ Jim->address[22] = 'k';
+ Jim->hobby[31] = 'h';
+ return 0;
+}
--- /dev/null
+/* Testing the attribute counted_by for anonymous structures as the top-level
+ type and as the type for an unnamed field. */
+/* { dg-do run } */
+/* { dg-options "-O2 -fsanitize=bounds" } */
+/* { dg-output "index 11 out of bounds for type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 22 out of bounds for type 'char \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+
+struct { int a; char b[] __attribute__ ((counted_by (a))); } *x;
+struct s { struct { int a; char b[] __attribute__ ((counted_by (a))); } *x; } *y;
+
+int main ()
+{
+ x = (typeof (x)) __builtin_malloc (sizeof (*x) + sizeof (char) * 10);
+ x->a = 10;
+ x->b[11] = 0;
+
+ y = (struct s *) __builtin_malloc (sizeof (struct s));
+ y->x = (typeof (y->x)) __builtin_malloc (sizeof (y->x) + sizeof (char) * 20);
+ y->x->a = 20;
+ y->x->b[22] = 0;
+ return 0;
+}