bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: restrict


From: Bruno Haible
Subject: Re: restrict
Date: Mon, 17 Feb 2020 21:55:53 +0100
User-agent: KMail/5.1.3 (Linux/4.4.0-171-generic; KDE/5.18.0; x86_64; ; )

Hi Paul,

> > I'm after warnings that point to undefined behaviour, and since passing a
> > 'char *' in place of an 'unsigned char *', 'FILE *', or similar already
> > generates a compiler warning, using 'restrict' here does not offer an
> > advantage.
> 
> It can still offer an advantage, since GCC doesn't necessarily generate a 
> compiler warning without the 'restrict'. For example, in the following code 
> GCC 
> complains about the call to f but not the call to g:
> 
>    void f (char *restrict, int *restrict);
>    void g (char *, int *);
> 
>    int
>    main (void)
>    {
>      int      a[] = {0, 0, 0};
>      void *p = a;
>      f (p, p);
>      g (p, p);
>    }

True. But it's pretty rare that people use 'void *' pointers and cast them
to pointers of different types.

Also, even a small variation of this code does not produce a warning any more:

   void f (char *restrict, int *restrict);
   void g (char *, int *);

   int
   main (void)
   {
     int        a[] = {0, 0, 0};
     void *p = a;
     f (p, a);    // no warning!
     g (p, a);
   }

> More generally, the role of 'restrict' for optimizations can't be easily 
> separated from its role for warnings. Using 'restrict' to save machine 
> instructions also means that it's better for GCC to generate warnings when 
> the 
> behavior would otherwise be undefined; conversely, typically when GCC 
> generates 
> warnings it's free to optimize more. Because of this close connection, when 
> in 
> doubt it's better to use 'restrict' in a way that benefits optimization as 
> well 
> as warning.

It needs to be weighed against the desire not to produce warnings for valid
uses. For example here:

> >    int snprintf (char *str, size_t size, const char *format, ...);
> > ... since 'restrict' on the first parameter is going to signal a warning
> > for overlaps with the 3rd, 4th, 5th, ... parameter, we don't need 'restrict'
> > on the 3rd parameter.
> 
> If we omit 'restrict' from the 3rd parameter, GCC won't warn when the 3rd 
> parameter overlaps with the 4th. That's a minus.

Actually, GCC doesn't warn here, even with 'restrict', because the 3rd argument
is a const-pointer and the 4th argument, being variadic, is treated like a
const-pointer as well. Test case (enable one of the declarations):

#include <stddef.h>
//extern int smprintf (char *restrict, size_t, char *, ...);                    
            // no warning
//extern int smprintf (char *restrict, size_t, char *restrict, ...);            
            // warning
//extern int smprintf (char *restrict, size_t, const char *, ...);              
            // no warning
//extern int smprintf (char *restrict, size_t, const char *restrict, ...);      
            // no warning
//extern int smprintf (char *restrict, size_t, const char *restrict, char 
*restrict);       // warning
//extern int smprintf (char *restrict, size_t, const char *restrict, const char 
*restrict); // no warning

char buf[10];
int main ()
{
  char fmt[] = "%s";
  smprintf (buf, sizeof buf, fmt, fmt);
}

> This sounds backwards. Ordinarily (without restrict) there is a contract that 
> prevents the compiler from optimizing the implementation in certain ways. 
> With 
> restrict, that part of the contract goes away. From the programmer's point of 
> view, 'restrict' places additional restrictions on the caller, not on the 
> callee. And appropriate use of 'restrict' signals to programmers what the 
> callee 
> can do.

I agree.

> This signal to humans is useful regardless of whether tools like GCC use 
> the signal to generate warnings or optimizations.

I disagree. Given the confusion around what 'restrict' is actually about,
the "signal to humans" is fuzzy. As it stands, GCC >= 8 is the best bet for
a programmer to understand 'restrict'.

> > The "same array" rule comes from what I understood from various explanations
> > of 'restrict' on the web [1], and from what I see in the glibc headers for
> > functions that have multiple output parameters of the same type:
> >    - splice in <bits/fcntl-linux.h>,
> >    - printf_arginfo_size_function in <printf.h>,
> >    - openpty in <pty.h>,
> >    - re_set_registers in <regex.h>,
> >    - copy_file_range in <unistd.h>.
> 
> That stackoverflow explanation is full of confusing answers and none of them 
> are 
> particularly good. And the glibc headers evidently were not written by people 
> who cared about proper use of 'restrict' (possibly because they wrote the 
> headers before 'restrict' existed or was widely supported).

... possibly also because ISO C 99 § 6.7.3.1 is impenetrable.
... possibly also because GCC 8 was not around to teach the programmers.

> > But ecvt, fcvt in <stdlib.h> have 'restrict'. You may want to register a 
> > glibc
> > bug if you think these five functions should have 'restrict' :)
> 
> It's not a bug. It's required by POSIX (which uses 'restrict' more carefully) 
> in 
> its older editions. See:
> 
> https://pubs.opengroup.org/onlinepubs/009695399/functions/ecvt.html

I meant the "glibc bug" the other way around: Someone could tell the glibc 
people
that it makes sense to _add_ 'restrict' to the declarations of splice,
printf_arginfo_size_function, openpty, re_set_registers, copy_file_range.

Bruno




reply via email to

[Prev in Thread] Current Thread [Next in Thread]