Re: AC_CHECK_DECLS vs. Clang

Noah Misch <[email protected]>
Newsgroups gmane.comp.sysutils.autoconf.patches
Message-ID <[email protected]>
On Sun, Mar 08, 2015 at 12:13:44AM -0500, Noah Misch wrote:
> The Clang compiler furnishes implicit declarations for built-in functions,
> even when the identifier in question is not used as a function designator.
> This thwarts AC_CHECK_DECLS:
> 
> configure:11565: checking whether strlcpy is declared
> configure:11565: clang -c -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -g -O2  -D_GNU_SOURCE -I/usr/include/libxml2  conftest.c >&5
> conftest.c:166:10: warning: implicitly declaring library function 'strlcpy' with type 'unsigned long (char *, const char *, unsigned long)'
>   (void) strlcpy;
>          ^
> conftest.c:166:10: note: please include the header <string.h> or explicitly provide a declaration for 'strlcpy'
> 1 warning generated.
> configure:11565: $? = 0
> configure:11565: result: yes
> 
> 
> Full config.log:
> http://buildfarm.postgresql.org/cgi-bin/show_stage_log.pl?nm=treepie&dt=2015-03-07%2006%3A22%3A38&stg=config
> 
> Clang has always behaved this way, but strlcpy() and strlcat() were unaffected
> until Clang 3.0 added them as builtins.  To fix this, I plan to introduce
> ac_c_decl_warn_flag by analogy to ac_c_preproc_warn_flag.  With no explicit
> declarations, a typical compiler (ac_c_decl_warn_flag='') reports an error for
> "(void) strchr;".  Clang (ac_c_decl_warn_flag=yes) reports a warning, but
> adding a declaration silences the warning.  A compiler that emits some warning
> with or without a declaration is unusable.

Here is the patch.  There's a risk that incidental warnings will make
AC_CHECK_DECL wrongly report a declaration missing.  If, for example, an
AC_CHECK_DECL test includes a header that elicits a deprecation warning, that
test will report any declaration missing.  The Autoconf test suite does pass
under "clang -Weverything -Wno-unused-macros -Wno-main" or "clang -Wno-main".
"-Wno-unused-macros" suppresses warnings about unused confdefs.h macros like
PACKAGE_URL, warnings which would otherwise snag on one of the new sanity
checks.  (Unrelated to AC_CHECK_DECL, the "C unit tests" group needs
"-Wno-main".)  I considered -fno-builtin instead of checking for warnings, but
the loss of realism outweighs the benefit of mitigating this risk.

The new code caches its test results.  _AC_PROG_PREPROC_WORKS_IFELSE, which
inspired the new code, does not cache.  Did I overlook a good reason for not
caching the results of tests like these?

I manually tested with C, C++, Objective C and Objective C++ languages.

Thanks,
nm


commit aaf9aba (HEAD, master)
Author:     Noah Misch <[email protected]>
AuthorDate: Mon Apr 13 01:38:15 2015 -0400
Commit:     Noah Misch <[email protected]>
CommitDate: Mon Apr 13 01:38:15 2015 -0400

    AC_CHECK_DECL, AC_CHECK_DECLS: port to the Clang compiler
    
    * lib/autoconf/general.m4 (_AC_UNDECLARED_WARNING): New macro.
    (_AC_CHECK_DECL_BODY): Call it once per language; treat warnings as
    errors when its verdict indicates that.
    * tests/semantics.at (AC_CHECK_DECLS): Add a macro call that relies on
    the new semantics.  Avoid -Wmissing-variable-declarations warnings.
    * doc/autoconf.texi (Generic Declarations): Document the implications.
    * NEWS: Mention this change.

diff --git a/NEWS b/NEWS
index 2df5a80..f691179 100644
--- a/NEWS
+++ b/NEWS
@@ -61,6 +61,9 @@ GNU Autoconf NEWS - User visible changes.
 - AC_USE_SYSTEM_EXTENSIONS now enables more system extensions on HP-UX,
   MINIX 3, and OS X.
 
+- AC_CHECK_DECL and AC_CHECK_DECLS can now report missing declarations for
+  functions that are also Clang compiler builtins.
+
 - AC_FUNC_VFORK now checks for the signal-handling bug in Solaris 2.4 'vfork'.
   Formerly, it ignored this bug, so that Emacs could use some tricky
   code on that platform.  Solaris 2.4 has not been supported since
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index d9e833d..350855b 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -6315,6 +6315,12 @@ parentheses for types which can be zero-initialized:
 AC_CHECK_DECL([basename(char *)])
 @end example
 
+Some compilers don't indicate every missing declaration by the error
+status.  This macro checks the standard error from such compilers and
+considers a declaration missing if any warnings have been reported.  For
+most compilers, though, warnings do not affect this macro's outcome
+unless @code{AC_LANG_WERROR} is also specified.
+
 This macro caches its result in the @code{ac_cv_have_decl_@var{symbol}}
 variable, with characters not suitable for a variable name mapped to
 underscores.
@@ -6375,6 +6381,12 @@ You fall into the second category only in extreme situations: either
 your files may be used without being configured, or they are used during
 the configuration.  In most cases the traditional approach is enough.
 
+Some compilers don't indicate every missing declaration by the error
+status.  This macro checks the standard error from such compilers and
+considers a declaration missing if any warnings have been reported.  For
+most compilers, though, warnings do not affect this macro's outcome
+unless @code{AC_LANG_WERROR} is also specified.
+
 This macro caches its results in @code{ac_cv_have_decl_@var{symbol}}
 variables, with characters not suitable for a variable name mapped to
 underscores.
diff --git a/lib/autoconf/general.m4 b/lib/autoconf/general.m4
index 2d1a291..09896e2 100644
--- a/lib/autoconf/general.m4
+++ b/lib/autoconf/general.m4
@@ -2864,15 +2864,72 @@ AC_DEFUN([AC_CHECK_FILES],
 ## ------------------------------- ##
 
 
+# _AC_UNDECLARED_WARNING
+# ----------------------
+# Set ac_[]_AC_LANG_ABBREV[]_decl_warn_flag=yes if the compiler uses a warning,
+# not a more-customary error, to report some undeclared identifiers.  Fail when
+# an affected compiler warns also on valid input.  _AC_PROG_PREPROC_WORKS_IFELSE
+# solves a related problem.
+AC_DEFUN([_AC_UNDECLARED_WARNING],
+[# The Clang compiler raises a warning for an undeclared identifier that matches
+# a compiler builtin function.  All extant Clang versions are affected, as of
+# Clang 3.6.0.  Test a builtin known to every version.  This problem affects the
+# C and Objective C languages, but Clang does report an error under C++ and
+# Objective C++.
+#
+# Passing -fno-builtin to the compiler would suppress this problem.  That
+# strategy would have the advantage of being insensitive to stray warnings, but
+# it would make tests less realistic.
+AC_CACHE_CHECK([how $[]_AC_CC[] reports undeclared, standard C functions],
+[ac_cv_[]_AC_LANG_ABBREV[]_decl_report],
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [(void) strchr;])],
+  [AS_IF([test -s conftest.err], [dnl
+    # For AC_CHECK_DECL to react to warnings, the compiler must be silent on
+    # valid AC_CHECK_DECL input.  No library function is consistently available
+    # on freestanding implementations, so test against a dummy declaration.
+    # Include always-available headers on the off chance that they somehow
+    # elicit warnings.
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([dnl
+#include <float.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+extern void ac_decl (int, char *);],
+[@%:@ifdef __cplusplus
+  (void) ac_decl ((int) 0, (char *) 0);
+  (void) ac_decl;
+@%:@else
+  (void) ac_decl;
+@%:@endif
+])],
+      [AS_IF([test -s conftest.err],
+	[AC_MSG_FAILURE([cannot detect from compiler exit status or warnings])],
+	[ac_cv_[]_AC_LANG_ABBREV[]_decl_report=warning])],
+      [AC_MSG_FAILURE([cannot compile a simple declaration test])])],
+    [AC_MSG_FAILURE([compiler does not report undeclared identifiers])])],
+  [ac_cv_[]_AC_LANG_ABBREV[]_decl_report=error])])
+
+case $ac_cv_[]_AC_LANG_ABBREV[]_decl_report in
+  warning) ac_[]_AC_LANG_ABBREV[]_decl_warn_flag=yes ;;
+  *) ac_[]_AC_LANG_ABBREV[]_decl_warn_flag= ;;
+esac
+])# _AC_UNDECLARED_WARNING
+
 # _AC_CHECK_DECL_BODY
 # -------------------
 # Shell function body for AC_CHECK_DECL.
 m4_define([_AC_CHECK_DECL_BODY],
 [  AS_LINENO_PUSH([$[]1])
+  # Initialize each $ac_[]_AC_LANG_ABBREV[]_decl_warn_flag once.
+  AC_DEFUN([_AC_UNDECLARED_WARNING_]_AC_LANG_ABBREV,
+	   [_AC_UNDECLARED_WARNING])dnl
+  AC_REQUIRE([_AC_UNDECLARED_WARNING_]_AC_LANG_ABBREV)dnl
   [as_decl_name=`echo $][2|sed 's/ *(.*//'`]
   [as_decl_use=`echo $][2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`]
   AC_CACHE_CHECK([whether $as_decl_name is declared], [$[]3],
-  [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$[]4],
+  [ac_save_werror_flag=$ac_[]_AC_LANG_ABBREV[]_werror_flag
+  ac_[]_AC_LANG_ABBREV[]_werror_flag="$ac_[]_AC_LANG_ABBREV[]_decl_warn_flag$ac_[]_AC_LANG_ABBREV[]_werror_flag"
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$[]4],
 [@%:@ifndef $[]as_decl_name
 @%:@ifdef __cplusplus
   (void) $[]as_decl_use;
@@ -2883,6 +2940,7 @@ m4_define([_AC_CHECK_DECL_BODY],
 ])],
 		   [AS_VAR_SET([$[]3], [yes])],
 		   [AS_VAR_SET([$[]3], [no])])])
+  ac_[]_AC_LANG_ABBREV[]_werror_flag=$ac_save_werror_flag
   AS_LINENO_POP
 ])# _AC_CHECK_DECL_BODY
 
diff --git a/tests/semantics.at b/tests/semantics.at
index a7abd52..1294545 100644
--- a/tests/semantics.at
+++ b/tests/semantics.at
@@ -101,15 +101,18 @@ esac
 
 # AC_CHECK_DECLS
 # --------------
-# Check that it performs the correct actions:
+# For the benefit of _AC_UNDECLARED_WARNING compilers, these INCLUDES sections
+# should not elicit warnings.
 AT_CHECK_MACRO([AC_CHECK_DECLS],
 [[AC_CHECK_DECLS([yes, no, myenum, mystruct, myfunc, mymacro1, mymacro2],,,
-		 [[int yes = 1;
+		 [[extern int yes;
 		   enum { myenum };
-		   struct { int x[20]; } mystruct;
+		   extern struct { int x[20]; } mystruct;
 		   extern int myfunc();
 		   #define mymacro1(arg) arg
 		   #define mymacro2]])
+  # Clang reports a warning for an undeclared builtin.
+  AC_CHECK_DECLS([strerror],,, [[]])
   # The difference in space-before-open-paren is intentional.
   AC_CHECK_DECLS([basenam (char *), dirnam(char *),
 		  [moreargs (char, short, int, long, void *, char [], float, double)]],,,
@@ -148,6 +151,7 @@ AT_CHECK_MACRO([AC_CHECK_DECLS],
 #define HAVE_DECL_MYMACRO2 1
 #define HAVE_DECL_MYSTRUCT 1
 #define HAVE_DECL_NO 0
+#define HAVE_DECL_STRERROR 0
 #define HAVE_DECL_YES 1
 ])])
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.