[gcc r17-3181] Use positional_argument in callback_only attribute handler

Josef Melcr via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:37807a10d8816f650d38d6f59a4e230ddc9f785a

commit r17-3181-g37807a10d8816f650d38d6f59a4e230ddc9f785a
Author: Josef Melcr <[email protected]>
Date:   Thu Jul 30 15:21:19 2026 +0200

    Use positional_argument in callback_only attribute handler
    
    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.
    
            PR testsuite/126708
    
    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]>

Diff:
---
 gcc/c-family/c-attribs.cc            | 102 +++++++++++++++--------------------
 gcc/testsuite/gcc.dg/attr-callback.c |  46 +++++++++++-----
 2 files changed, 76 insertions(+), 72 deletions(-)

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 1ed02850a911..aecfdcda4906 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,18 @@ 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 +4811,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 d9cc67c3affe..74c8287471bd 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.  */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.