[PATCH] Use positional_argument in callback_only attribute handler
Josef Melcr <[email protected]> Mon, 3 Aug 2026 16:13:02 +0200
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
Hi, this is what I came up with. I couldn't eliminate all the manual checking, as positional_argument doesn't check for nested types for example, but I tried to use it wherever I could. Regtested with the rest of the series without problems. OK for master? Best regards, Josef -- >8 -- This patch replaces some of the manual bounds checking done in the callback_only attribute handler with calls to positional_argument. Since positional_argument issues warnings and the attribute handler issues errors, I decided to downgrade the errors to warnings for consistency. gcc/c-family/ChangeLog: * c-attribs.cc (handle_callback_only_attribute): Use positional_argument for bounds checking in callback_only attribute handler, downgrade errors to warnings for consistency. gcc/testsuite/ChangeLog: * gcc.dg/attr-callback.c: Expect warnings instead of errors, adjust expected messages. Signed-off-by: Josef Melcr <[email protected]> --- gcc/c-family/c-attribs.cc | 103 ++++++++++++--------------- gcc/testsuite/gcc.dg/attr-callback.c | 46 ++++++++---- 2 files changed, 77 insertions(+), 72 deletions(-) diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index 1ed02850a91..01150136a55 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -4682,66 +4682,52 @@ handle_callback_only_attribute (tree *node, tree name, tree args, tree decl = *node; if (TREE_CODE (decl) != FUNCTION_DECL) { - error_at (DECL_SOURCE_LOCATION (decl), - "%qE attribute can only be used on functions", name); + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, + "%qE attribute can only be used on functions", name); *no_add_attrs = true; } - tree cb_fn_idx_node = TREE_VALUE (args); - if (TREE_CODE (cb_fn_idx_node) != INTEGER_CST) + tree val = positional_argument (decl, name, TREE_VALUE (args), POINTER_TYPE, + 1, POSARG_ZERO); + if (!val) { - error_at (DECL_SOURCE_LOCATION (decl), - "argument specifying callback function position is not an " - "integer constant"); *no_add_attrs = true; return NULL_TREE; } + TREE_VALUE (args) = val; + /* We have to use the function type for validation, as DECL_ARGUMENTS returns NULL at this point. */ - int callback_fn_idx = TREE_INT_CST_LOW (cb_fn_idx_node); + int callback_fn_idx = TREE_INT_CST_LOW (val); tree decl_type_args = TYPE_ARG_TYPES (TREE_TYPE (decl)); tree it; - int decl_nargs = list_length (decl_type_args); for (it = decl_type_args; it != NULL_TREE; it = TREE_CHAIN (it)) if (it == void_list_node) - { - --decl_nargs; - break; - } + break; + if (callback_fn_idx == CB_UNKNOWN_POS) { - error_at (DECL_SOURCE_LOCATION (decl), - "callback function position cannot be marked as unknown"); + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, + "callback function position cannot be marked as unknown"); *no_add_attrs = true; return NULL_TREE; } + --callback_fn_idx; - if (callback_fn_idx >= decl_nargs) - { - error_at (DECL_SOURCE_LOCATION (decl), - "callback function position out of range"); - *no_add_attrs = true; - return NULL_TREE; - } - /* Search for the type of the callback function - in parameters of the original function. */ + /* Search for the type of the callback function in parameters of the original + function. We know it's there because it's been validated by + positional_argument. */ tree cfn = chain_index (callback_fn_idx, decl_type_args); - if (cfn == NULL_TREE) - { - error_at (DECL_SOURCE_LOCATION (decl), - "could not retrieve callback function from arguments"); - *no_add_attrs = true; - return NULL_TREE; - } + gcc_checking_assert (cfn != NULL_TREE); cfn = TREE_VALUE (cfn); tree cfn_pointee_type = TREE_TYPE (cfn); if (TREE_CODE (cfn) != POINTER_TYPE || TREE_CODE (cfn_pointee_type) != FUNCTION_TYPE) { - error_at (DECL_SOURCE_LOCATION (decl), - "argument no. %d is not an address of a function", - callback_fn_idx + 1); + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, + "argument no. %d is not an address of a function", + callback_fn_idx + 1); *no_add_attrs = true; return NULL_TREE; } @@ -4759,9 +4745,9 @@ handle_callback_only_attribute (tree *node, tree name, tree args, } if (cfn_nargs != type_nargs) { - error_at (DECL_SOURCE_LOCATION (decl), - "argument number mismatch, %d expected, got %d", type_nargs, - cfn_nargs); + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, + "argument number mismatch, %d expected, got %d", type_nargs, + cfn_nargs); *no_add_attrs = true; return NULL_TREE; } @@ -4777,12 +4763,23 @@ handle_callback_only_attribute (tree *node, tree name, tree args, { if (TREE_CODE (TREE_VALUE (cfn_it)) != INTEGER_CST) { - error_at (DECL_SOURCE_LOCATION (decl), - "argument no. %d is not an integer constant", curr + 1); + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, + "argument no. %d is not an integer constant", curr + 1); *no_add_attrs = true; continue; } + tree expected_type = TREE_VALUE (it); + tree arg_val = positional_argument (decl, name, TREE_VALUE (cfn_it), + TREE_CODE (expected_type), curr + 1, + POSARG_ZERO); + if (!arg_val) + { + *no_add_attrs = true; + return NULL_TREE; + } + + TREE_VALUE (cfn_it) = arg_val; int arg_idx = TREE_INT_CST_LOW (TREE_VALUE (cfn_it)); /* No need to check for type compatibility, @@ -4791,29 +4788,19 @@ handle_callback_only_attribute (tree *node, tree name, tree args, continue; arg_idx -= 1; - /* Report an error if the position is out of bounds, - but we can still check the rest of the arguments. */ - if (arg_idx >= decl_nargs) - { - error_at (DECL_SOURCE_LOCATION (decl), - "callback argument index %d is out of range", arg_idx + 1); - *no_add_attrs = true; - continue; - } - tree arg_type = chain_index (arg_idx, decl_type_args); gcc_checking_assert (arg_type != NULL_TREE); arg_type = TREE_VALUE (arg_type); - tree expected_type = TREE_VALUE (it); /* Check the type of the value we are about to pass ("arg_type") for compatibility with the actual type the callback function expects ("expected_type"). */ if (!types_compatible_p (expected_type, arg_type)) { - error_at (DECL_SOURCE_LOCATION (decl), - "argument type at index %d is not compatible with callback " - "argument type at index %d", - arg_idx + 1, curr + 1); + warning_at ( + DECL_SOURCE_LOCATION (decl), OPT_Wattributes, + "argument type at index %d is not compatible with callback " + "argument type at index %d", + arg_idx + 1, curr + 1); *no_add_attrs = true; continue; } @@ -4825,10 +4812,10 @@ handle_callback_only_attribute (tree *node, tree name, tree args, for (; it; it = lookup_attribute ("callback_only", TREE_CHAIN (it))) if (callback_get_fn_index (it) == callback_fn_idx) { - error_at (DECL_SOURCE_LOCATION (decl), - "function declaration has multiple callback attributes " - "describing argument no. %d", - callback_fn_idx + 1); + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, + "function declaration has multiple callback attributes " + "describing argument no. %d", + callback_fn_idx + 1); *no_add_attrs = true; break; } diff --git a/gcc/testsuite/gcc.dg/attr-callback.c b/gcc/testsuite/gcc.dg/attr-callback.c index d9cc67c3aff..74c8287471b 100755 --- a/gcc/testsuite/gcc.dg/attr-callback.c +++ b/gcc/testsuite/gcc.dg/attr-callback.c @@ -25,15 +25,15 @@ unknown_2(void (*)(int*, double*), int*, double*, char*); [[gnu::callback_only(1, 0, 3, 3)]] void -too_many(void (*)(int*, double*), int*, double*); /* { dg-error "argument number mismatch, 2 expected, got 3" }*/ +too_many(void (*)(int*, double*), int*, double*); /* { dg-warning "argument number mismatch, 2 expected, got 3" }*/ [[gnu::callback_only(1, 2)]] void -too_few_1(void (*)(int*, double*), int*, double*); /* { dg-error "argument number mismatch, 2 expected, got 1" }*/ +too_few_1(void (*)(int*, double*), int*, double*); /* { dg-warning "argument number mismatch, 2 expected, got 1" }*/ [[gnu::callback_only(1)]] void -too_few_2(void (*)(int*, double*), int*, double*); /* { dg-error "argument number mismatch, 2 expected, got 0" }*/ +too_few_2(void (*)(int*, double*), int*, double*); /* { dg-warning "argument number mismatch, 2 expected, got 0" }*/ [[gnu::callback_only(3, 1)]] void @@ -45,52 +45,70 @@ downcast(char*, void* (*)(float*), double*); [[gnu::callback_only(1, 2, 5)]] void -out_of_range_1(char (*)(float*, double*), float*, double*, int*); /* { dg-error "callback argument index 5 is out of range" } */ +out_of_range_1(char (*)(float*, double*), float*, double*, int*); /* { dg-warning "exceeds the number of function parameters" } */ [[gnu::callback_only(1, -2, 3)]] void -out_of_range_2(char (*)(float*, double*), float*, double*, int*); /* { dg-error "callback argument index -2 is out of range" } */ +out_of_range_2(char (*)(float*, double*), float*, double*, int*); /* { dg-warning "exceeds the number of function parameters" } */ [[gnu::callback_only(-1, 2, 3)]] void -out_of_range_3(char (*)(float*, double*), float*, double*, int*); /* { dg-error "callback function index -1 is out of range" } */ +out_of_range_3(char (*)(float*, double*), float*, double*, int*); /* { dg-warning "exceeds the number of function parameters" } */ [[gnu::callback_only(67, 2, 3)]] void -out_of_range_4(char (*)(float*, double*), float*, double*, int*); /* { dg-error "callback function index 67 is out of range" } */ +out_of_range_4(char (*)(float*, double*), float*, double*, int*); /* { dg-warning "exceeds the number of function parameters" } */ [[gnu::callback_only(0, 2, 3)]] void -unknown_fn(char (*)(float*, double*), float*, double*, int*); /* { dg-error "callback function position cannot be marked as unknown" } */ +unknown_fn(char (*)(float*, double*), float*, double*, int*); /* { dg-warning "callback function position cannot be marked as unknown" } */ [[gnu::callback_only(1, 2)]] void -not_a_fn(int, int); /* { dg-error "argument no. 1 is not an address of a function" } */ +not_a_fn(int, int); /* { dg-warning "refers to" } */ struct S { int x; }; +static struct S placeholder; + +static int one = 1; + +static const int const_one = 1; + [[gnu::callback_only(1, 2)]] void -incompatible_types_1(void (*)(struct S*), struct S); /* { dg-error "argument type at index 2 is not compatible with callback argument type at index 1" } */ +incompatible_types_1(void (*)(struct S*), struct S); /* { dg-warning "refers to" } */ [[gnu::callback_only(1, 3, 2)]] void -incompatible_types_2(void (*)(struct S*, int*), int*, double); /* { dg-error "argument type at index 3 is not compatible with callback argument type at index 1" } */ +incompatible_types_2(void (*)(struct S*, int*), int*, double); /* { dg-warning "refers to" } */ [[gnu::callback_only(1, "2")]] void -wrong_arg_type_1(void (*)(void*), void*); /* { dg-error "argument no. 1 is not an integer constant" } */ +wrong_arg_type_1(void (*)(void*), void*); /* { dg-warning "argument no. 1 is not an integer constant" } */ [[gnu::callback_only("not a number", 2, 2)]] void -wrong_arg_type_2(void (*)(void*, void*), void*); /* { dg-error "argument specifying callback function position is not an integer constant" } */ +wrong_arg_type_2(void (*)(void*, void*), void*); /* { dg-warning "has type" } */ + +[[gnu::callback_only(placeholder, 2, 2)]] +void +wrong_arg_type_3(void (*)(void*, void*), void*); /* { dg-warning "has type" } */ + +[[gnu::callback_only(one, 2, 2)]] +void +int_identifier(void (*)(void*, void*), void*); /* { dg-warning "is not an integer constant" } */ + +[[gnu::callback_only(one, 2, 2)]] +void +int_identifier_1(void (*)(void*, void*), void*); /* { dg-warning "is not an integer constant" } */ [[gnu::callback_only(1, 2), gnu::callback_only(1, 3)]] void -multiple_single_fn(void (*)(int*), int*, int*); /* { dg-error "function declaration has multiple callback attributes describing argument no. 1" } */ +multiple_single_fn(void (*)(int*), int*, int*); /* { dg-warning "function declaration has multiple callback attributes describing argument no. 1" } */ /* Check that the attribute won't resolve outside of our namespace. */ -- 2.55.0