gcc-4.7 was released. It apparently fixes bug #50021 <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50021>. So the option -Wsuggest-attribute=pure is a little bit more useful than before. I tried it, and it gave me an understanding of what attribute 'pure' means (together with the GCC doc, of course, and the list of functions declared 'pure' in glibc).
In order to enable GCC to do better optimizations of user code, let me enable the attribute on some public functions. I don't find it worth bothering with internal or 'static' functions. 2012-03-24 Bruno Haible <br...@clisp.org> Enable common subexpression optimization in GCC. * lib/dirent.in.h (_GL_ATTRIBUTE_PURE): Define, like in string.in.h. (alphasort): Declare with GCC attribute 'pure'. * lib/stdlib.in.h (_GL_ATTRIBUTE_PURE): Define, like in string.in.h. (atoll): Declare with GCC attribute 'pure'. * lib/string.in.h (mbslen, mbsnlen, mbschr, mbsrchr, mbsstr, mbscasecmp, mbsncasecmp, mbspcasecmp, mbscasestr, mbscspn, mbspbrk, mbsspn, strverscmp): Declare with GCC attribute 'pure'. * lib/wchar.in.h (_GL_ATTRIBUTE_PURE): Define, like in string.in.h. (btowc, wctob, wcwidth, wmemchr, wmemcmp, wcslen, wcsnlen, wcscmp, wcsncmp, wcscasecmp, wcsncasecmp, wcschr, wcsrchr, wcscspn, wcsspn, wcspbrk, wcsstr, wcswidth): Declare with GCC attribute 'pure'. --- lib/dirent.in.h.orig Sat Mar 24 22:47:16 2012 +++ lib/dirent.in.h Sat Mar 24 18:44:11 2012 @@ -55,6 +55,14 @@ # endif #endif +/* The __attribute__ feature is available in gcc versions 2.5 and later. + The attribute __pure__ was added in gcc 2.96. */ +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) +# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) +#else +# define _GL_ATTRIBUTE_PURE /* empty */ +#endif + /* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ /* The definition of _GL_ARG_NONNULL is copied here. */ @@ -229,6 +237,7 @@ # if !@HAVE_ALPHASORT@ _GL_FUNCDECL_SYS (alphasort, int, (const struct dirent **, const struct dirent **) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1, 2))); # endif /* Need to cast, because on glibc systems, the parameters are --- lib/stdlib.in.h.orig Sat Mar 24 22:47:16 2012 +++ lib/stdlib.in.h Sat Mar 24 18:45:34 2012 @@ -94,6 +94,14 @@ # include <unistd.h> #endif +/* The __attribute__ feature is available in gcc versions 2.5 and later. + The attribute __pure__ was added in gcc 2.96. */ +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) +# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) +#else +# define _GL_ATTRIBUTE_PURE /* empty */ +#endif + /* The definition of _Noreturn is copied here. */ /* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ @@ -138,7 +146,9 @@ /* Parse a signed decimal integer. Returns the value of the integer. Errors are not detected. */ # if !@HAVE_ATOLL@ -_GL_FUNCDECL_SYS (atoll, long long, (const char *string) _GL_ARG_NONNULL ((1))); +_GL_FUNCDECL_SYS (atoll, long long, (const char *string) + _GL_ATTRIBUTE_PURE + _GL_ARG_NONNULL ((1))); # endif _GL_CXXALIAS_SYS (atoll, long long, (const char *string)); _GL_CXXALIASWARN (atoll); --- lib/string.in.h.orig Sat Mar 24 22:47:16 2012 +++ lib/string.in.h Sat Mar 24 18:49:22 2012 @@ -724,10 +724,14 @@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # define mbslen rpl_mbslen # endif -_GL_FUNCDECL_RPL (mbslen, size_t, (const char *string) _GL_ARG_NONNULL ((1))); +_GL_FUNCDECL_RPL (mbslen, size_t, (const char *string) + _GL_ATTRIBUTE_PURE + _GL_ARG_NONNULL ((1))); _GL_CXXALIAS_RPL (mbslen, size_t, (const char *string)); # else -_GL_FUNCDECL_SYS (mbslen, size_t, (const char *string) _GL_ARG_NONNULL ((1))); +_GL_FUNCDECL_SYS (mbslen, size_t, (const char *string) + _GL_ATTRIBUTE_PURE + _GL_ARG_NONNULL ((1))); _GL_CXXALIAS_SYS (mbslen, size_t, (const char *string)); # endif _GL_CXXALIASWARN (mbslen); @@ -737,6 +741,7 @@ /* Return the number of multibyte characters in the character string starting at STRING and ending at STRING + LEN. */ _GL_EXTERN_C size_t mbsnlen (const char *string, size_t len) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1)); #endif @@ -750,10 +755,12 @@ # define mbschr rpl_mbschr /* avoid collision with HP-UX function */ # endif _GL_FUNCDECL_RPL (mbschr, char *, (const char *string, int c) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1))); _GL_CXXALIAS_RPL (mbschr, char *, (const char *string, int c)); # else _GL_FUNCDECL_SYS (mbschr, char *, (const char *string, int c) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1))); _GL_CXXALIAS_SYS (mbschr, char *, (const char *string, int c)); # endif @@ -770,10 +777,12 @@ # define mbsrchr rpl_mbsrchr /* avoid collision with system function */ # endif _GL_FUNCDECL_RPL (mbsrchr, char *, (const char *string, int c) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1))); _GL_CXXALIAS_RPL (mbsrchr, char *, (const char *string, int c)); # else _GL_FUNCDECL_SYS (mbsrchr, char *, (const char *string, int c) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1))); _GL_CXXALIAS_SYS (mbsrchr, char *, (const char *string, int c)); # endif @@ -786,6 +795,7 @@ Unlike strstr(), this function works correctly in multibyte locales with encodings different from UTF-8. */ _GL_EXTERN_C char * mbsstr (const char *haystack, const char *needle) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1, 2)); #endif @@ -797,6 +807,7 @@ different lengths! Unlike strcasecmp(), this function works correctly in multibyte locales. */ _GL_EXTERN_C int mbscasecmp (const char *s1, const char *s2) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1, 2)); #endif @@ -811,6 +822,7 @@ Unlike strncasecmp(), this function works correctly in multibyte locales. But beware that N is not a byte count but a character count! */ _GL_EXTERN_C int mbsncasecmp (const char *s1, const char *s2, size_t n) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1, 2)); #endif @@ -824,6 +836,7 @@ Unlike strncasecmp(), this function works correctly in multibyte locales. */ _GL_EXTERN_C char * mbspcasecmp (const char *string, const char *prefix) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1, 2)); #endif @@ -834,6 +847,7 @@ strlen (haystack) < strlen (needle) ! Unlike strcasestr(), this function works correctly in multibyte locales. */ _GL_EXTERN_C char * mbscasestr (const char *haystack, const char *needle) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1, 2)); #endif @@ -844,6 +858,7 @@ if none exists. Unlike strcspn(), this function works correctly in multibyte locales. */ _GL_EXTERN_C size_t mbscspn (const char *string, const char *accept) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1, 2)); #endif @@ -857,10 +872,12 @@ # define mbspbrk rpl_mbspbrk /* avoid collision with HP-UX function */ # endif _GL_FUNCDECL_RPL (mbspbrk, char *, (const char *string, const char *accept) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1, 2))); _GL_CXXALIAS_RPL (mbspbrk, char *, (const char *string, const char *accept)); # else _GL_FUNCDECL_SYS (mbspbrk, char *, (const char *string, const char *accept) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1, 2))); _GL_CXXALIAS_SYS (mbspbrk, char *, (const char *string, const char *accept)); # endif @@ -874,6 +891,7 @@ if none exists. Unlike strspn(), this function works correctly in multibyte locales. */ _GL_EXTERN_C size_t mbsspn (const char *string, const char *reject) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1, 2)); #endif @@ -993,6 +1011,7 @@ #if @GNULIB_STRVERSCMP@ # if !@HAVE_STRVERSCMP@ _GL_FUNCDECL_SYS (strverscmp, int, (const char *, const char *) + _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1, 2))); # endif _GL_CXXALIAS_SYS (strverscmp, int, (const char *, const char *)); --- lib/wchar.in.h.orig Sat Mar 24 22:47:17 2012 +++ lib/wchar.in.h Sat Mar 24 18:55:45 2012 @@ -83,6 +83,14 @@ #ifndef _@GUARD_PREFIX@_WCHAR_H #define _@GUARD_PREFIX@_WCHAR_H +/* The __attribute__ feature is available in gcc versions 2.5 and later. + The attribute __pure__ was added in gcc 2.96. */ +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) +# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) +#else +# define _GL_ATTRIBUTE_PURE /* empty */ +#endif + /* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ /* The definition of _GL_ARG_NONNULL is copied here. */ @@ -135,11 +143,11 @@ # undef btowc # define btowc rpl_btowc # endif -_GL_FUNCDECL_RPL (btowc, wint_t, (int c)); +_GL_FUNCDECL_RPL (btowc, wint_t, (int c) _GL_ATTRIBUTE_PURE); _GL_CXXALIAS_RPL (btowc, wint_t, (int c)); # else # if !@HAVE_BTOWC@ -_GL_FUNCDECL_SYS (btowc, wint_t, (int c)); +_GL_FUNCDECL_SYS (btowc, wint_t, (int c) _GL_ATTRIBUTE_PURE); # endif _GL_CXXALIAS_SYS (btowc, wint_t, (int c)); # endif @@ -160,12 +168,12 @@ # undef wctob # define wctob rpl_wctob # endif -_GL_FUNCDECL_RPL (wctob, int, (wint_t wc)); +_GL_FUNCDECL_RPL (wctob, int, (wint_t wc) _GL_ATTRIBUTE_PURE); _GL_CXXALIAS_RPL (wctob, int, (wint_t wc)); # else # if !defined wctob && !@HAVE_DECL_WCTOB@ /* wctob is provided by gnulib, or wctob exists but is not declared. */ -_GL_FUNCDECL_SYS (wctob, int, (wint_t wc)); +_GL_FUNCDECL_SYS (wctob, int, (wint_t wc) _GL_ATTRIBUTE_PURE); # endif _GL_CXXALIAS_SYS (wctob, int, (wint_t wc)); # endif @@ -426,12 +434,12 @@ # undef wcwidth # define wcwidth rpl_wcwidth # endif -_GL_FUNCDECL_RPL (wcwidth, int, (wchar_t)); +_GL_FUNCDECL_RPL (wcwidth, int, (wchar_t) _GL_ATTRIBUTE_PURE); _GL_CXXALIAS_RPL (wcwidth, int, (wchar_t)); # else # if !@HAVE_DECL_WCWIDTH@ /* wcwidth exists but is not declared. */ -_GL_FUNCDECL_SYS (wcwidth, int, (wchar_t)); +_GL_FUNCDECL_SYS (wcwidth, int, (wchar_t) _GL_ATTRIBUTE_PURE); # endif _GL_CXXALIAS_SYS (wcwidth, int, (wchar_t)); # endif @@ -448,7 +456,8 @@ /* Search N wide characters of S for C. */ #if @GNULIB_WMEMCHR@ # if !@HAVE_WMEMCHR@ -_GL_FUNCDECL_SYS (wmemchr, wchar_t *, (const wchar_t *s, wchar_t c, size_t n)); +_GL_FUNCDECL_SYS (wmemchr, wchar_t *, (const wchar_t *s, wchar_t c, size_t n) + _GL_ATTRIBUTE_PURE); # endif /* On some systems, this function is defined as an overloaded function: extern "C++" { @@ -479,7 +488,8 @@ #if @GNULIB_WMEMCMP@ # if !@HAVE_WMEMCMP@ _GL_FUNCDECL_SYS (wmemcmp, int, - (const wchar_t *s1, const wchar_t *s2, size_t n)); + (const wchar_t *s1, const wchar_t *s2, size_t n) + _GL_ATTRIBUTE_PURE); # endif _GL_CXXALIAS_SYS (wmemcmp, int, (const wchar_t *s1, const wchar_t *s2, size_t n)); @@ -549,7 +559,7 @@ /* Return the number of wide characters in S. */ #if @GNULIB_WCSLEN@ # if !@HAVE_WCSLEN@ -_GL_FUNCDECL_SYS (wcslen, size_t, (const wchar_t *s)); +_GL_FUNCDECL_SYS (wcslen, size_t, (const wchar_t *s) _GL_ATTRIBUTE_PURE); # endif _GL_CXXALIAS_SYS (wcslen, size_t, (const wchar_t *s)); _GL_CXXALIASWARN (wcslen); @@ -565,7 +575,8 @@ /* Return the number of wide characters in S, but at most MAXLEN. */ #if @GNULIB_WCSNLEN@ # if !@HAVE_WCSNLEN@ -_GL_FUNCDECL_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen)); +_GL_FUNCDECL_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen) + _GL_ATTRIBUTE_PURE); # endif _GL_CXXALIAS_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen)); _GL_CXXALIASWARN (wcsnlen); @@ -684,7 +695,8 @@ /* Compare S1 and S2. */ #if @GNULIB_WCSCMP@ # if !@HAVE_WCSCMP@ -_GL_FUNCDECL_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2)); +_GL_FUNCDECL_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2) + _GL_ATTRIBUTE_PURE); # endif _GL_CXXALIAS_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2)); _GL_CXXALIASWARN (wcscmp); @@ -701,7 +713,8 @@ #if @GNULIB_WCSNCMP@ # if !@HAVE_WCSNCMP@ _GL_FUNCDECL_SYS (wcsncmp, int, - (const wchar_t *s1, const wchar_t *s2, size_t n)); + (const wchar_t *s1, const wchar_t *s2, size_t n) + _GL_ATTRIBUTE_PURE); # endif _GL_CXXALIAS_SYS (wcsncmp, int, (const wchar_t *s1, const wchar_t *s2, size_t n)); @@ -718,7 +731,8 @@ /* Compare S1 and S2, ignoring case. */ #if @GNULIB_WCSCASECMP@ # if !@HAVE_WCSCASECMP@ -_GL_FUNCDECL_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2)); +_GL_FUNCDECL_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2) + _GL_ATTRIBUTE_PURE); # endif _GL_CXXALIAS_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2)); _GL_CXXALIASWARN (wcscasecmp); @@ -735,7 +749,8 @@ #if @GNULIB_WCSNCASECMP@ # if !@HAVE_WCSNCASECMP@ _GL_FUNCDECL_SYS (wcsncasecmp, int, - (const wchar_t *s1, const wchar_t *s2, size_t n)); + (const wchar_t *s1, const wchar_t *s2, size_t n) + _GL_ATTRIBUTE_PURE); # endif _GL_CXXALIAS_SYS (wcsncasecmp, int, (const wchar_t *s1, const wchar_t *s2, size_t n)); @@ -803,7 +818,8 @@ /* Find the first occurrence of WC in WCS. */ #if @GNULIB_WCSCHR@ # if !@HAVE_WCSCHR@ -_GL_FUNCDECL_SYS (wcschr, wchar_t *, (const wchar_t *wcs, wchar_t wc)); +_GL_FUNCDECL_SYS (wcschr, wchar_t *, (const wchar_t *wcs, wchar_t wc) + _GL_ATTRIBUTE_PURE); # endif /* On some systems, this function is defined as an overloaded function: extern "C++" { @@ -832,7 +848,8 @@ /* Find the last occurrence of WC in WCS. */ #if @GNULIB_WCSRCHR@ # if !@HAVE_WCSRCHR@ -_GL_FUNCDECL_SYS (wcsrchr, wchar_t *, (const wchar_t *wcs, wchar_t wc)); +_GL_FUNCDECL_SYS (wcsrchr, wchar_t *, (const wchar_t *wcs, wchar_t wc) + _GL_ATTRIBUTE_PURE); # endif /* On some systems, this function is defined as an overloaded function: extern "C++" { @@ -862,7 +879,8 @@ of wide characters not in REJECT. */ #if @GNULIB_WCSCSPN@ # if !@HAVE_WCSCSPN@ -_GL_FUNCDECL_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t *reject)); +_GL_FUNCDECL_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t *reject) + _GL_ATTRIBUTE_PURE); # endif _GL_CXXALIAS_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t *reject)); _GL_CXXALIASWARN (wcscspn); @@ -879,7 +897,8 @@ of wide characters in ACCEPT. */ #if @GNULIB_WCSSPN@ # if !@HAVE_WCSSPN@ -_GL_FUNCDECL_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *accept)); +_GL_FUNCDECL_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *accept) + _GL_ATTRIBUTE_PURE); # endif _GL_CXXALIAS_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *accept)); _GL_CXXALIASWARN (wcsspn); @@ -896,7 +915,8 @@ #if @GNULIB_WCSPBRK@ # if !@HAVE_WCSPBRK@ _GL_FUNCDECL_SYS (wcspbrk, wchar_t *, - (const wchar_t *wcs, const wchar_t *accept)); + (const wchar_t *wcs, const wchar_t *accept) + _GL_ATTRIBUTE_PURE); # endif /* On some systems, this function is defined as an overloaded function: extern "C++" { @@ -928,7 +948,8 @@ #if @GNULIB_WCSSTR@ # if !@HAVE_WCSSTR@ _GL_FUNCDECL_SYS (wcsstr, wchar_t *, - (const wchar_t *haystack, const wchar_t *needle)); + (const wchar_t *haystack, const wchar_t *needle) + _GL_ATTRIBUTE_PURE); # endif /* On some systems, this function is defined as an overloaded function: extern "C++" { @@ -982,11 +1003,13 @@ # undef wcswidth # define wcswidth rpl_wcswidth # endif -_GL_FUNCDECL_RPL (wcswidth, int, (const wchar_t *s, size_t n)); +_GL_FUNCDECL_RPL (wcswidth, int, (const wchar_t *s, size_t n) + _GL_ATTRIBUTE_PURE); _GL_CXXALIAS_RPL (wcswidth, int, (const wchar_t *s, size_t n)); # else # if !@HAVE_WCSWIDTH@ -_GL_FUNCDECL_SYS (wcswidth, int, (const wchar_t *s, size_t n)); +_GL_FUNCDECL_SYS (wcswidth, int, (const wchar_t *s, size_t n) + _GL_ATTRIBUTE_PURE); # endif _GL_CXXALIAS_SYS (wcswidth, int, (const wchar_t *s, size_t n)); # endif