Why is no warning given for the wrong use of __attribute__((pure)) in GCC?

319 Views Asked by At

I am trying to understand pure functions, and have been reading through the Wikipedia article on that topic. I wrote the minimal sample program as follows:

#include <stdio.h>

static int a = 1;

static __attribute__((pure)) int pure_function(int x, int y)
{
        return x + y;
}

static __attribute__((pure)) int impure_function(int x, int y)
{
        a++;
        return x + y;
}

int main(void)
{
        printf("pure_function(0, 0) = %d\n", pure_function(0, 0));
        printf("impure_function(0, 0) = %d\n", impure_function(0, 0));

        return 0;
}

I compiled this program with gcc -O2 -Wall -Wextra, expecting that an error, or at least a warning, should have been issued for decorating impure_function() with __attribute__((pure)). However, I received no warnings or errors, and the program also ran without issues.

Isn't marking impure_function() with __attribute__((pure)) incorrect? If so, why does it compile without any errors or warnings, even with the -Wextra and -Wall flags?

Thanks in advance!

2

There are 2 best solutions below

1
On BEST ANSWER

A pure function is a hint for the optimizing compiler. Probably, gcc don't care about pure functions when you pass just -O0 to it (the default optimizations). So if f is pure (and defined outside of your translation unit, e.g. in some outside library), the GCC compiler might optimize y = f(x) + f(x); into something like

{ 
  int tmp = f(x); /// tmp is a fresh variable, not appearing elsewhere
  y = tmp + tmp;
}

but if f is not pure (which is the usual case: think of f calling printf or malloc), such an optimization is forbidden.

Standard math functions like sin or sqrt are pure (except for IEEE rounding mode craziness, see http://floating-point-gui.de/ and Fluctuat for more), and they are complex enough to compute to make such optimizations worthwhile.

You might compile your code with gcc -O2 -Wall -fdump-tree-all to guess what is happening inside the compiler. You could add the -fverbose-asm -S flags to get a generated *.s assembler file.

You could also read the Bismon draft report (notably its section §1.4). It might give some intuitions related to your question.

In your particular case, I am guessing that gcc is inlining your calls; and then purity matters less.

If you have time to spend, you might consider writing your own GCC plugin to make such a warning. You'll spend months in writing it! These old slides might still be useful to you, even if the details are obsolete.

At the theoretical level, be aware of Rice's theorem. A consequence of it is that perfect optimization of pure functions is probably impossible.

Be aware of the GCC Resource Center, located in Bombay.

1
On

Doing this is incorrect and you are responsible for using the attribute correctly.

Look at this example:

static __attribute__((pure)) int impure_function(int x, int y)
{
        extern int a;
        a++;
        return x + y;
}

void caller()
{
    impure_function(1, 1);
}

Code generated by GCC (with -O1) for the function caller is:

caller():
        ret

As you can see, the impure_function call was completely removed because compiler treats it as "pure".

GCC can mark the function as "pure" internally automatically if it sees its definition:

static __attribute__((noinline)) int pure_function(int x, int y)
{
        return x + y;
}

void caller()
{
    pure_function(1, 1);
}

Generated code:

caller():
        ret

So there is no point in using this attribute on functions that are visible to the compiler. It is supposed to be used when definition is not available, for example when function is defined in another DLL. That means that when it is used in a proper place the compiler won't be able to perform a sanity check anyway. Implementing a warning thus is not very useful (although not meaningless).

I don't think there is anything stopping GCC developers from implementing such warning, except time that must be spend.