git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] describe: fix --no-exact-match

From
René Scharfe <l.s.r@web.de>
Date
Aug 11, 2023, 17:59 UTC
Message-ID
<fbeadf7d-c16f-0612-6256-fc4355e89638@web.de>
In-Reply-To
<20230811151102.GE2303200@coredump.intra.peff.net>
Am 11.08.23 um 17:11 schrieb Jeff King:
Show 20 quoted lines
> On Thu, Aug 10, 2023 at 09:10:33PM +0200, René Scharfe wrote:
>
>>> I'm not sure there's a portable and non-insane way of doing what we want
>>> here. At least at compile-time.
>>
>> We need a wrapper with the correct signature.  The wrapper is plugged
>> into struct option.  The typed callback is called by the wrapper and
>> can be used for a type check in the struct macro.  Demo patch below.
>
> OK, clever. So we have two functions, one with a real body, and the
> other which is used with the void pointer. How do we make sure that the
> real-body one matches the type passed to OPT_CALLBACK(), if it is only
> seeing the void wrapper? I guess that is this bit in short_name:
>
>> +#define OPT_CALLBACK_F_T(s, l, v, a, h, f, cb) { \
>> +	.type = OPTION_CALLBACK, \
>> +	.short_name = (s) + (0 ? cb(NULL, NULL, 0, (v)) : 0), \
>
> which would cause the compiler to barf, and presumably eliminate the
> dead code (or at the very least never call it at runtime).

Yes, a fake call that doesn't make it into the generated object code, but is real enough for type checking.

Show 13 quoted lines
> So I think that works. Though...
>
>> +#define DEFINE_PARSE_OPT_CB(name)				\
>> +static inline int name ## __void(const struct option *opt,	\
>> +				 const char *arg, int unset)	\
>> +{								\
>> +	return name(opt, arg, unset, opt->value);		\
>> +}								\
>
> we are defining an inline function with the explicit goal of passing it
> as a function pointer. I don't remember all of the standard's rules
> here. Are we guaranteed that it will create a linkable version if
> necessary?

I don't see on which basis the compiler could refuse. We can't expect the function address to be the same across compilation units, but we don't need that. If there's a compiler that won't do it or a standards verse that makes this dubious then I'd like to know very much.

> We could probably drop the "inline" (and perhaps would need to add
> MAYBE_UNUSED in such a case).

Yes, we can use a non-inline function as well, but then we'd need to define it once somewhere and declare it separately, though, which is inconvenient. It needs to have the same visibility as the typed function.

We better not use MAYBE_UNUSED because the wrapper is the actually invoked callback.

Show 31 quoted lines
>> diff --git a/builtin/describe.c b/builtin/describe.c
>> index b28a4a1f82..ce16c36de2 100644
>> --- a/builtin/describe.c
>> +++ b/builtin/describe.c
>> @@ -558,15 +558,17 @@ static void describe(const char *arg, int last_one)
>>  	strbuf_release(&sb);
>>  }
>>
>> -static int option_parse_exact_match(const struct option *opt, const char *arg,
>> -				    int unset)
>> +static int option_parse_exact_match(const struct option *opt UNUSED,
>> +				    const char *arg, int unset, int *value)
>>  {
>>  	BUG_ON_OPT_ARG(arg);
>>
>> -	max_candidates = unset ? DEFAULT_CANDIDATES : 0;
>> +	*value = unset ? DEFAULT_CANDIDATES : 0;
>>  	return 0;
>>  }
>>
>> +DEFINE_PARSE_OPT_CB(option_parse_exact_match);
>
> I wondered about combining these, like:
>
>   DEFINE_PARSE_OPT_CB(option_parse_exact_match, int) {
> 	...the real body here...
>   }
>
> But I guess that may confuse non-compiler parsers, and it doesn't leave
> room for annotations like the UNUSED above (which ironically is still
> needed, since now we pass opt->value as its own parameter).

I get the idea. Something that looks like a function attribute or decorator. I don't see no nice way to achieve that, though.

> So I dunno. Clever, for sure, and I think it would work. I'm not sure if
> the extra code merits the return or not.

Sure, why check types -- script languages get work done as well. (I'm fresh off a Python basics training, nice quirky language..) But we're in C land and static typing is supposed to help us get our operations correct and portable.

A good example in parseopt: The patch below adds type checking to the int options and yields 79 warning about incompatible pointers, because enum pointers were used in integer option definitions. The storage size of enums depends on the member values and the compiler; an enum could be char-sized. When we access such a thing with an int pointer we write up to seven bytes of garbage ... somewhere. We better fix that.

It also gives me 73 sign warnings because we like to use unsigned int to store int options for some reason. No problem storage-wise. I have to admit that I don't really understand why -Wpointer-sign is in -Wall and not only in -Wpedantic. But it could mean a user gives a negative value for something and we interpret it as a huge value. Probably still worth fixing to avoid the general weirdness.

My point is: If we don't check types we deviate.  It just happens.
René
PS: We could simplify the type check like this:
	.short_name = (s) + (0 && (v) == (int *)0), \

This yields -Wcompare-distinct-pointer-types for all 152 cases, which may suffice. But comparisons of pointers are only defined for those that point to the same object or just past it if I'm not mistaken, so this way works only by accident and the comparison part of the warning is misleading anyway. Sill looking for a simpler type check..

diff --git a/parse-options.h b/parse-options.h
index f957931cfa..dafea28b55 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -168,9 +168,14 @@ struct option {
 	parse_opt_subcommand_fn *subcommand_fn;
 };

+static inline int parse_options_noop_int_ptr(int *p UNUSED)
+{
+	return 0;
+}
+
 #define OPT_BIT_F(s, l, v, h, b, f) { \
 	.type = OPTION_BIT, \
-	.short_name = (s), \
+	.short_name = (s) + (0 ? parse_options_noop_int_ptr((v)) : 0), \
 	.long_name = (l), \
 	.value = (v), \
 	.help = (h), \
@@ -180,7 +185,7 @@ struct option {
 }
 #define OPT_COUNTUP_F(s, l, v, h, f) { \
 	.type = OPTION_COUNTUP, \
-	.short_name = (s), \
+	.short_name = (s) + (0 ? parse_options_noop_int_ptr((v)) : 0), \
 	.long_name = (l), \
 	.value = (v), \
 	.help = (h), \
@@ -188,7 +193,7 @@ struct option {
 }
 #define OPT_SET_INT_F(s, l, v, h, i, f) { \
 	.type = OPTION_SET_INT, \
-	.short_name = (s), \
+	.short_name = (s) + (0 ? parse_options_noop_int_ptr((v)) : 0), \
 	.long_name = (l), \
 	.value = (v), \
 	.help = (h), \
@@ -227,7 +232,7 @@ struct option {
 }
 #define OPT_INTEGER_F(s, l, v, h, f) { \
 	.type = OPTION_INTEGER, \
-	.short_name = (s), \
+	.short_name = (s) + (0 ? parse_options_noop_int_ptr((v)) : 0), \
 	.long_name = (l), \
 	.value = (v), \
 	.argh = N_("n"), \
@@ -245,7 +250,7 @@ struct option {
 #define OPT_BIT(s, l, v, h, b)      OPT_BIT_F(s, l, v, h, b, 0)
 #define OPT_BITOP(s, l, v, h, set, clear) { \
 	.type = OPTION_BITOP, \
-	.short_name = (s), \
+	.short_name = (s) + (0 ? parse_options_noop_int_ptr((v)) : 0), \
 	.long_name = (l), \
 	.value = (v), \
 	.help = (h), \
@@ -255,7 +260,7 @@ struct option {
 }
 #define OPT_NEGBIT(s, l, v, h, b) { \
 	.type = OPTION_NEGBIT, \
-	.short_name = (s), \
+	.short_name = (s) + (0 ? parse_options_noop_int_ptr((v)) : 0), \
 	.long_name = (l), \
 	.value = (v), \
 	.help = (h), \
@@ -267,7 +272,7 @@ struct option {
 #define OPT_BOOL(s, l, v, h)        OPT_BOOL_F(s, l, v, h, 0)
 #define OPT_HIDDEN_BOOL(s, l, v, h) { \
 	.type = OPTION_SET_INT, \
-	.short_name = (s), \
+	.short_name = (s) + (0 ? parse_options_noop_int_ptr((v)) : 0), \
 	.long_name = (l), \
 	.value = (v), \
 	.help = (h), \
@@ -276,7 +281,7 @@ struct option {
 }
 #define OPT_CMDMODE_F(s, l, v, h, i, f) { \
 	.type = OPTION_SET_INT, \
-	.short_name = (s), \
+	.short_name = (s) + (0 ? parse_options_noop_int_ptr((v)) : 0), \
 	.long_name = (l), \
 	.value = (v), \
 	.help = (h), \
Previous: Jeff KingNext: Jeff King
Message 62 of 66 in “ls-tree: fix --no-full-name”
  1. ls-tree: fix --no-full-nameRené Scharfe, Jul 18, 2023
  2. Junio C HamanoJul 18, 2023
  3. Junio C HamanoJul 18, 2023
  4. René ScharfeJul 21, 2023
  5. René ScharfeJul 21, 2023
  6. Junio C HamanoJul 21, 2023
  7. René ScharfeJul 21, 2023
  8. Junio C HamanoJul 21, 2023
  9. Junio C HamanoJul 21, 2023
  10. René ScharfeJul 24, 2023
  11. Junio C HamanoJul 24, 2023
  12. René ScharfeJul 24, 2023
  13. Junio C HamanoJul 24, 2023
  14. René ScharfeJul 28, 2023
  15. Phillip WoodJul 28, 2023
  16. René ScharfeJul 29, 2023
  17. Junio C HamanoJul 31, 2023
  18. Junio C HamanoAug 4, 2023
  19. Phillip WoodAug 4, 2023
  20. René ScharfeAug 5, 2023
  21. 0/5 show negatability of options in short helpRené Scharfe, Jul 24, 2023
  22. 1/5 subtree: disallow --no-{help,quiet,debug,branch,message}René Scharfe, Jul 24, 2023
  23. 2/5 t1502, docs: disallow --no-helpRené Scharfe, Jul 24, 2023
  24. 3/5 t1502: move optionspec help output to a fileRené Scharfe, Jul 24, 2023
  25. 4/5 t1502: test option negationRené Scharfe, Jul 24, 2023
  26. 5/5 parse-options: show negatability of options in short helpRené Scharfe, Jul 24, 2023
  27. 0/8 show negatability of options in short helpRené Scharfe, Aug 5, 2023
  28. 1/8 subtree: disallow --no-{help,quiet,debug,branch,message}René Scharfe, Aug 5, 2023
  29. 2/8 t1502, docs: disallow --no-helpRené Scharfe, Aug 5, 2023
  30. 3/8 t1502: move optionspec help output to a fileRené Scharfe, Aug 5, 2023
  31. 4/8 t1502: test option negationRené Scharfe, Aug 5, 2023
  32. 5/8 parse-options: show negatability of options in short helpRené Scharfe, Aug 5, 2023
  33. 6/8 parse-options: factor out usage_indent() and usage_padding()René Scharfe, Aug 5, 2023
  34. 7/8 parse-options: no --[no-]no-...René Scharfe, Aug 5, 2023
  35. 8/8 parse-options: simplify usage_padding()René Scharfe, Aug 5, 2023
  36. Junio C HamanoAug 5, 2023
  37. show-branch: fix --no-sparseRené Scharfe, Jul 21, 2023
  38. Junio C HamanoJul 21, 2023
  39. René ScharfeJul 21, 2023
  40. show-branch: disallow --no-{date,topo}-orderRené Scharfe, Jul 21, 2023
  41. reset: disallow --no-{mixed,soft,hard,merge,keep}René Scharfe, Jul 21, 2023
  42. pack-objects: fix --no-quietRené Scharfe, Jul 21, 2023
  43. pack-objects: fix --no-keep-true-parentsRené Scharfe, Jul 21, 2023
  44. Junio C HamanoJul 21, 2023
  45. branch: disallow --no-{all,remotes}René Scharfe, Jul 21, 2023
  46. am: unify definition of --keep-cr and --no-keep-crRené Scharfe, Jul 21, 2023
  47. describe: fix --no-exact-matchRené Scharfe, Jul 21, 2023
  48. Junio C HamanoJul 21, 2023
  49. Junio C HamanoJul 21, 2023
  50. Jeff KingAug 8, 2023
  51. Jeff KingAug 8, 2023
  52. Junio C HamanoAug 9, 2023
  53. Jeff KingAug 9, 2023
  54. René ScharfeAug 9, 2023
  55. Junio C HamanoAug 9, 2023
  56. Jeff KingAug 10, 2023
  57. Junio C HamanoAug 10, 2023
  58. René ScharfeAug 10, 2023
  59. Jeff KingAug 10, 2023
  60. René ScharfeAug 10, 2023
  61. Jeff KingAug 11, 2023
  62. René ScharfeAug 11, 2023
  63. Jeff KingAug 11, 2023
  64. René ScharfeAug 12, 2023
  65. Jeff KingAug 11, 2023
  66. René ScharfeAug 11, 2023

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.