c-family: add btf_type_tag and btf_decl_tag attributes

Add two new c-family attributes, "btf_type_tag" and "btf_decl_tag"
along with attribute handlers for them.  These attributes may be
used to annotate types or declarations respectively with arbitrary
strings, which will be recorded in DWARF and/or BTF information.
Both attributes accept exactly one string argument.  Wide strings
are not supported.

gcc/c-family/
	* c-attribs.cc (c_common_attribute_table): Add btf_decl_tag and
	btf_type_tag attributes.
	(handle_btf_decl_tag_attribute): New handler for btf_decl_tag.
	(hanlde_btf_type_tag_attribute): New handler for btf_type_tag.
	(btf_tag_args_ok): Helper for new attribute handlers.

gcc/testsuite/
	* gcc.dg/attr-btf-decl-tag-1.c: New test.
	* gcc.dg/attr-btf-decl-tag-2.c: New test.
	* gcc.dg/attr-btf-type-tag-1.c: New test.
	* gcc.dg/attr-btf-type-tag-2.c: New test.
	* gcc.dg/attr-btf-type-tag-3.c: New test.
This commit is contained in:
David Faust
2025-02-05 10:35:13 -08:00
parent 4e44fe4280
commit 7e80927e9b
6 changed files with 167 additions and 1 deletions

View File

@@ -189,6 +189,9 @@ static tree handle_fd_arg_attribute (tree *, tree, tree, int, bool *);
static tree handle_flag_enum_attribute (tree *, tree, tree, int, bool *);
static tree handle_null_terminated_string_arg_attribute (tree *, tree, tree, int, bool *);
static tree handle_btf_decl_tag_attribute (tree *, tree, tree, int, bool *);
static tree handle_btf_type_tag_attribute (tree *, tree, tree, int, bool *);
/* Helper to define attribute exclusions. */
#define ATTR_EXCL(name, function, type, variable) \
{ name, function, type, variable }
@@ -657,7 +660,11 @@ const struct attribute_spec c_common_gnu_attributes[] =
{ "flag_enum", 0, 0, false, true, false, false,
handle_flag_enum_attribute, NULL },
{ "null_terminated_string_arg", 1, 1, false, true, true, false,
handle_null_terminated_string_arg_attribute, NULL}
handle_null_terminated_string_arg_attribute, NULL},
{ "btf_type_tag", 1, 1, false, true, false, false,
handle_btf_type_tag_attribute, NULL},
{ "btf_decl_tag", 1, 1, true, false, false, false,
handle_btf_decl_tag_attribute, NULL}
};
const struct scoped_attribute_specs c_common_gnu_attribute_table =
@@ -5172,6 +5179,107 @@ handle_null_terminated_string_arg_attribute (tree *node, tree name, tree args,
return NULL_TREE;
}
/* Common argument checking for btf_type_tag and btf_decl_tag.
Return true if the ARGS are valid, otherwise emit an error and
return false. */
static bool
btf_tag_args_ok (tree name, tree args)
{
if (!args) /* Correct number of args (1) is checked for us. */
return false;
else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
{
error ("%qE attribute requires a string argument", name);
return false;
}
/* Only narrow character strings are accepted. */
tree argtype = TREE_TYPE (TREE_TYPE (TREE_VALUE (args)));
if (!(argtype == char_type_node
|| argtype == char8_type_node
|| argtype == signed_char_type_node
|| argtype == unsigned_char_type_node))
{
error ("unsupported wide string type argument in %qE attribute", name);
return false;
}
return true;
}
/* Handle the "btf_decl_tag" attribute. */
static tree
handle_btf_decl_tag_attribute (tree * ARG_UNUSED (node), tree name, tree args,
int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (!btf_tag_args_ok (name, args))
*no_add_attrs = true;
return NULL_TREE;
}
/* Handle the "btf_type_tag" attribute. */
static tree
handle_btf_type_tag_attribute (tree *node, tree name, tree args,
int flags, bool *no_add_attrs)
{
if (!btf_tag_args_ok (name, args))
{
*no_add_attrs = true;
return NULL_TREE;
}
if (TREE_CODE (*node) == FUNCTION_TYPE || TREE_CODE (*node) == METHOD_TYPE)
{
warning (OPT_Wattributes,
"%qE attribute does not apply to functions", name);
*no_add_attrs = true;
return NULL_TREE;
}
/* Ensure a variant type is always created to hold the type_tag,
unless ATTR_FLAG_IN_PLACE is set. Same logic as in
common_handle_aligned_attribute. */
tree decl = NULL_TREE;
tree *type = NULL;
bool is_type = false;
if (DECL_P (*node))
{
decl = *node;
type = &TREE_TYPE (decl);
is_type = TREE_CODE (*node) == TYPE_DECL;
}
else if (TYPE_P (*node))
type = node, is_type = true;
if (is_type)
{
if ((flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
/* OK, modify the type in place. */;
/* If we have a TYPE_DECL, then copy the type, so that we
don't accidentally modify a builtin type. See pushdecl. */
else if (decl && TREE_TYPE (decl) != error_mark_node
&& DECL_ORIGINAL_TYPE (decl) == NULL_TREE)
{
tree tt = TREE_TYPE (decl);
*type = build_variant_type_copy (*type);
DECL_ORIGINAL_TYPE (decl) = tt;
TYPE_NAME (*type) = decl;
TREE_USED (*type) = TREE_USED (decl);
TREE_TYPE (decl) = *type;
}
else
*type = build_variant_type_copy (*type);
}
return NULL_TREE;
}
/* Handle the "nonstring" variable attribute. */
static tree

View File

@@ -0,0 +1,14 @@
/* Test btf_decl_tag attribute argument checking. */
/* { dg-do compile } */
void *vptr __attribute__((btf_decl_tag("vptr"), btf_decl_tag ("perthread")));
struct Foo
{
int x __attribute__((btf_decl_tag (0x55))); /* { dg-error "requires a string" } */
char *c __attribute__((btf_decl_tag (L"Lstr"))); /* { dg-error "unsupported wide string" } */
};
extern int foo (int x, int y __attribute__((btf_decl_tag))); /* { dg-error "wrong number of arguments" } */
char *str __attribute__((btf_decl_tag("A", "B"))); /* { dg-error "wrong number of arguments" } */

View File

@@ -0,0 +1,15 @@
/* Test btf_decl_tag attribute argument checking for wide string types. */
/* { dg-do compile } */
/* { dg-options "--std=c11" } */
int **my_ptr __attribute__((btf_decl_tag("my_ptr")));
void *x __attribute__((btf_decl_tag (U"Ustr"))); /* { dg-error "unsupported wide string" } */
const int y __attribute__((btf_decl_tag (u"ustr"))); /* { dg-error "unsupported wide string" } */
union U
{
int x;
char c __attribute__((btf_decl_tag (u8"u8str"))); /* OK. */
};

View File

@@ -0,0 +1,12 @@
/* Test btf_type_tag attribute argument checking. */
/* { dg-do compile } */
void * __attribute__((btf_type_tag ("A"), btf_type_tag ("vptr"))) a;
int __attribute__((btf_type_tag (5))) b; /* { dg-error "requires a string" } */
char * __attribute__((btf_type_tag (L"Lstr"))) c; /* { dg-error "unsupported wide string" } */
int * __attribute__((btf_type_tag)) d; /* { dg-error "wrong number of arguments" } */
char * __attribute__((btf_type_tag ("A", "B"))) e; /* { dg-error "wrong number of arguments" } */

View File

@@ -0,0 +1,9 @@
/* Test btf_type_tag attribute argument checking for wide string types. */
/* { dg-do compile } */
/* { dg-options "--std=c11" } */
int __attribute__((btf_type_tag (U"Ustr"))) x; /* { dg-error "unsupported wide string" } */
int __attribute__((btf_type_tag (u"ustr"))) y; /* { dg-error "unsupported wide string" } */
int __attribute__((btf_type_tag (u8"u8str"))) z; /* OK. */

View File

@@ -0,0 +1,8 @@
/* Test btf_type_tag attribute warnings. */
/* { dg-do compile } */
int __attribute__((btf_type_tag ("A"))) a (int x); /* { dg-warning "does not apply to functions" } */
__attribute__((btf_type_tag ("B"))) int *b (int y); /* { dg-warning "does not apply to functions" } */
int *c (int z) __attribute__((btf_type_tag ("C"))); /* { dg-warning "does not apply to functions" } */