On 20/11/2019 00:02, Luc Van Oostenryck wrote: > Function attributes need to be parsed differently than > the usual specifiers. For example, in code like: > #define __noreturn __attribute__((noreturn)) > __noreturn void foo(int a); > the __noreturn attribute should apply to the function type, > while a specifier like 'const' would apply to its return type. > It's even more clear when function pointers are involved: > __noreturn void (*fptr)(void); > here too, the attribute should be applied to the function type, > not the its return type, nor to the declared pointer type. Hmm, it _is_ applied to the 'pointed to' type; ie the pointer base type. I don't quite know how to say that succinctly (so just ignore my rambling! ;-) ATB, Ramsay Jones > > Add some testcases to cover some of the situations concerning > the parsing of these function pointers. > > Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx> > --- > validation/attr-visible.c | 13 +++++++++ > validation/attr-visible2.c | 10 +++++++ > validation/bitwise-function-pointer.c | 17 ++++++++++++ > validation/function-attribute-inner.c | 10 +++++++ > validation/function-attribute-omitted.c | 14 ++++++++++ > validation/function-attribute-pointer.c | 34 ++++++++++++++++++++++++ > validation/function-attribute-void-ptr.c | 14 ++++++++++ > validation/function-attribute.c | 15 ++++++----- > validation/pure-function.c | 17 +++++++++--- > 9 files changed, 134 insertions(+), 10 deletions(-) > create mode 100644 validation/attr-visible.c > create mode 100644 validation/attr-visible2.c > create mode 100644 validation/bitwise-function-pointer.c > create mode 100644 validation/function-attribute-inner.c > create mode 100644 validation/function-attribute-omitted.c > create mode 100644 validation/function-attribute-pointer.c > create mode 100644 validation/function-attribute-void-ptr.c > > diff --git a/validation/attr-visible.c b/validation/attr-visible.c > new file mode 100644 > index 000000000..38ee85752 > --- /dev/null > +++ b/validation/attr-visible.c > @@ -0,0 +1,13 @@ > +#define __visible __attribute__((externally_visible)) > + > +__visible void foo(void) > +{ > +} > + > +int flag __visible; > + > +/* > + * check-name: attr-visible > + * check-command: sparse -Wdecl $file > + * check-known-to-fail > + */ > diff --git a/validation/attr-visible2.c b/validation/attr-visible2.c > new file mode 100644 > index 000000000..62949b479 > --- /dev/null > +++ b/validation/attr-visible2.c > @@ -0,0 +1,10 @@ > +#define __visible __attribute__((externally_visible)) > + > +int flag __visible; > +int arr[2] __visible; > + > +/* > + * check-name: attr-visible-after > + * check-command: sparse -Wdecl $file > + * check-known-to-fail > + */ > diff --git a/validation/bitwise-function-pointer.c b/validation/bitwise-function-pointer.c > new file mode 100644 > index 000000000..544f2fc00 > --- /dev/null > +++ b/validation/bitwise-function-pointer.c > @@ -0,0 +1,17 @@ > +#define __bitwise __attribute__((bitwise)) > + > +typedef unsigned int __bitwise t; > + > +unsigned int fun(void); > + > +static t (*ptr)(void) = fun; > + > +/* > + * check-name: bitwise-function-pointer > + * > + * check-error-start > +bitwise-function-pointer.c:7:25: warning: incorrect type in initializer (different base types) > +bitwise-function-pointer.c:7:25: expected restricted t ( *static [toplevel] ptr )( ... ) > +bitwise-function-pointer.c:7:25: got unsigned int ( * )( ... ) > + * check-error-end > + */ > diff --git a/validation/function-attribute-inner.c b/validation/function-attribute-inner.c > new file mode 100644 > index 000000000..178c7c019 > --- /dev/null > +++ b/validation/function-attribute-inner.c > @@ -0,0 +1,10 @@ > +#define __noreturn __attribute__((__noreturn__)) > + > +void __noreturn fun(void); > + > +_Static_assert([void (__noreturn *)(void)] == [typeof(&fun)], ""); > + > +/* > + * check-name: function-attribute-inner > + * check-known-to-fail > + */ > diff --git a/validation/function-attribute-omitted.c b/validation/function-attribute-omitted.c > new file mode 100644 > index 000000000..43b301d8f > --- /dev/null > +++ b/validation/function-attribute-omitted.c > @@ -0,0 +1,14 @@ > +#define __pure __attribute__((pure)) > +#define __noreturn __attribute__((noreturn)) > + > + > +int __pure p(int i); > +int p(int i) { return i; } > + > +void __noreturn n(void); > +void n(void) { while (1) ; } > + > +/* > + * check-name: function-attribute-omitted > + * check-known-to-fail > + */ > diff --git a/validation/function-attribute-pointer.c b/validation/function-attribute-pointer.c > new file mode 100644 > index 000000000..27f43bfb6 > --- /dev/null > +++ b/validation/function-attribute-pointer.c > @@ -0,0 +1,34 @@ > +#define __noreturn __attribute__((__noreturn__)) > + > +void set_die(void (*)(void)); > +void set_die_nr(__noreturn void (*)(void)); > + > +void die(void); > +void __noreturn die_nr(void); > + > +static void foo(void) > +{ > + set_die(die); > + set_die(die_nr); > + set_die_nr(die_nr); > + set_die_nr(die); > + > + void (*fptr0)(void) = die; > + void (*fptr1)(void) = die_nr; > + __noreturn void (*fptr3)(void) = die_nr; > + __noreturn void (*fptr2)(void) = die; > +} > + > +/* > + * check-name: function-attribute-pointer > + * check-known-to-fail > + * > + * check-error-start > +function-attribute-pointer.c:14:20: warning: incorrect type in argument 1 (different modifiers) > +function-attribute-pointer.c:14:20: expected void ( [noreturn] * )( ... ) > +function-attribute-pointer.c:14:20: got void ( * )( ... ) > +function-attribute-pointer.c:19:42: warning: incorrect type in initializer (different modifiers) > +function-attribute-pointer.c:19:42: expected void ( [noreturn] *fptr2 )( ... ) > +function-attribute-pointer.c:19:42: got void ( * )( ... ) > + * check-error-end > + */ > diff --git a/validation/function-attribute-void-ptr.c b/validation/function-attribute-void-ptr.c > new file mode 100644 > index 000000000..0092b63c3 > --- /dev/null > +++ b/validation/function-attribute-void-ptr.c > @@ -0,0 +1,14 @@ > +#define __noreturn __attribute__((__noreturn__)) > + > +void fun(void *); > +void __noreturn die(void); > + > +static void foo(void) > +{ > + void *ptr = die; > + fun(die); > +} > + > +/* > + * check-name: function-attribute-void-ptr > + */ > diff --git a/validation/function-attribute.c b/validation/function-attribute.c > index 0f2c75922..2be180c42 100644 > --- a/validation/function-attribute.c > +++ b/validation/function-attribute.c > @@ -1,17 +1,20 @@ > #define __pure __attribute__((pure)) > > -struct s { > - int x; > -}; > > -static __pure struct s *grab(struct s *ptr) > +static __pure int funi(int val) > +{ > + return val; > +} > + > +static __pure int *funp(int *ptr) > { > return ptr; > } > > -static void foo(struct s *ptr) > +static void foo(int val, int *ptr) > { > - struct s *ptr = grab(ptr); > + int nbr = funi(val); > + int *res = funp(ptr); > } > > /* > diff --git a/validation/pure-function.c b/validation/pure-function.c > index 04bb85e4d..9692cc842 100644 > --- a/validation/pure-function.c > +++ b/validation/pure-function.c > @@ -1,16 +1,25 @@ > > -static __attribute__((__pure__)) int pure1(void) > +static __attribute__((__pure__)) int pure_int(int v) > { > - int i = 0; > + int i = v; > return i; > } > > -static __attribute__((__pure__)) void *pure2(void) > +static __attribute__((__pure__)) void *pure_ptr(void *p) > { > - void *i = (void *)0; > + void *i = p; > return i; > } > > +static void foo(int v, void *p) > +{ > + int val = pure_int(v); > + void *ptr = pure_ptr(p); > + > + (void)val; > + (void)ptr; > +} > + > /* > * check-name: Pure function attribute > */ >