bug-gnulib
[Top][All Lists]
Advanced

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

snippet/warn-on-use: Don't cause wrong AC_CHECK_DECL results with clang


From: Bruno Haible
Subject: snippet/warn-on-use: Don't cause wrong AC_CHECK_DECL results with clang
Date: Tue, 20 Sep 2022 23:47:41 +0200

Building a gnulib testdir on native Windows, with clang and the MSVC header
files, I get these errors:

source='../../gltests/test-string-c++.cc' object='test-string-c++.obj' 
libtool=no \
DEPDIR=.deps depmode=msvc7 /bin/sh ../../build-aux/depcomp \
/home/bruno/msvc/compile clang-cl -ferror-limit=0 -DHAVE_CONFIG_H 
-DEXEEXT=\".exe\" -I. -I../../gltests -I..  -DGNULIB_STRICT_CHECKING=1 
-DIN_GNULIB_TESTS=1 -I. -I../../gltests -I.. -I../../gltests/.. -I../gllib 
-I../../gltests/../gllib -D_WIN32_WINNT=_WIN32_WINNT_WIN7 
-I/usr/local/msvcclang64/include -Wall -Wno-extra-semi-stmt 
-Wno-unused-function -Wno-inconsistent-dllimport -Wno-reserved-id-macro 
-Wno-undef -Wno-missing-field-initializers -Wno-unused-parameter 
-Wno-gnu-include-next -Wno-implicit-int-conversion -Wno-sign-compare 
-Wno-sign-conversion -Wno-comma -Wno-unused-macros 
-Wno-nonportable-system-include-path -Wno-format-nonliteral 
-Wno-deprecated-declarations -Wno-tautological-unsigned-zero-compare 
-Wno-used-but-marked-unused -Wno-parentheses-equality  -Wno-error -MD -O2 -c -o 
test-string-c++.obj `cygpath -w '../../gltests/test-string-c++.cc'`
In file included from 
C:\cygwin64\home\bruno\testdir-all-windows\gltests\test-string-c++.cc:22:
../gllib\string.h(1107,19): error: no member named 'strndup' in the global 
namespace; did you mean 'strdup'?
_GL_CXXALIAS_SYS (strndup, char *, (char const *__s, size_t __n));
~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  strdup
../gllib\string.h(322,20): note: expanded from macro '_GL_CXXALIAS_SYS'
          return ::func;                                      \
                 ~~^
../gllib\string.h(1026,19): note: 'strdup' declared here
_GL_CXXALIASWARN (strdup);
                  ^
../gllib\string.h(1107,1): error: cannot initialize return object of type 
'gnulib::_gl_strndup_wrapper::type' (aka 'char *(*)(const char *, unsigned long 
long)') with an lvalue of type 'typeof (strdup)' (aka 'char *(const char *)'): 
different number of parameters (2 vs 1)
_GL_CXXALIAS_SYS (strndup, char *, (char const *__s, size_t __n));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../gllib\string.h(322,18): note: expanded from macro '_GL_CXXALIAS_SYS'
          return ::func;                                      \
                 ^~~~~~
../gllib\string.h(1109,19): error: use of undeclared identifier 'strndup'; did 
you mean 'strdup'?
_GL_CXXALIASWARN (strndup);
                  ^~~~~~~
                  strdup
../gllib\string.h(394,24): note: expanded from macro '_GL_CXXALIASWARN'
   _GL_CXXALIASWARN_1 (func, GNULIB_NAMESPACE)
                       ^
../gllib\string.h(396,24): note: expanded from macro '_GL_CXXALIASWARN_1'
   _GL_CXXALIASWARN_2 (func, namespace)
                       ^
../gllib\string.h(401,22): note: expanded from macro '_GL_CXXALIASWARN_2'
    _GL_WARN_ON_USE (func, \
                     ^
../gllib\string.h(564,31): note: expanded from macro '_GL_WARN_ON_USE'
_GL_WARN_EXTERN_C __typeof__ (function) function \
                              ^
../gllib\string.h(1026,19): note: 'strdup' declared here
_GL_CXXALIASWARN (strdup);
                  ^
../gllib\string.h(1109,19): warning: The symbol ::strdup refers to the system 
function. Use gnulib::strdup instead. [-Wuser-defined-warnings]
_GL_CXXALIASWARN (strndup);
                  ^
../gllib\string.h(1026,1): note: from 'diagnose_if' attribute on 'strdup':
_GL_CXXALIASWARN (strdup);
^~~~~~~~~~~~~~~~~~~~~~~~~
../gllib\string.h(394,4): note: expanded from macro '_GL_CXXALIASWARN'
   _GL_CXXALIASWARN_1 (func, GNULIB_NAMESPACE)
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../gllib\string.h(396,4): note: expanded from macro '_GL_CXXALIASWARN_1'
   _GL_CXXALIASWARN_2 (func, namespace)
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../gllib\string.h(401,5): note: expanded from macro '_GL_CXXALIASWARN_2'
    _GL_WARN_ON_USE (func, \
    ^~~~~~~~~~~~~~~~~~~~~~~~
../gllib\string.h(565,19): note: expanded from macro '_GL_WARN_ON_USE'
  __attribute__ ((__diagnose_if__ (1, message, "warning")))
                  ^                ~
65 warnings and 3 errors generated.
make[4]: *** [Makefile:23359: test-string-c++.obj] Error 1


The cause is that the MSVC header files don't declare strndup(), and with
MSVC accordingly HAVE_DECL_STRNDUP is 0, but with clang, HAVE_DECL_STRNDUP
is 1. The cause is that the clang compiler provides implicit function
declarations of many ISO C functions (see the -fno-builtin-* command line
options [1]).

See:
=============== foo.c ===================
#include <string.h>
int main () {
#undef strndup
  (void) strndup;
}
=========================================
clang:
foo.c(4,10): warning: implicitly declaring library function 'strndup' with type 
'char *(const char *, unsigned long long)' [-Wimplicit-function-declaration]
  (void) strndup;
         ^
foo.c(4,10): note: include the header <string.h> or explicitly provide a 
declaration for 'strndup'
1 warning generated.

Thus, clang "invents" a declaration when there is none.

$ clang -Wall -fno-builtin-strndup foo.c
foo.c:4:10: error: use of undeclared identifier 'strndup'
  (void) strndup;
         ^
1 error generated.


The problem is that these implicit function declarations are present in C
mode but not in C++ mode. Thus, the effects of HAVE_DECL_STRNDUP being 1
are neutralized in C mode (by precisely these implicit function declarations),
but not in C++ mode.

Put differently: Gnulib assumes that the value of HAVE_DECL_STRNDUP is valid
equally in C mode and in C++ mode; which it isn't here.

The main macro which defines HAVE_DECL_STRNDUP is AC_CHECK_DECL, and we have
a workaround for these implicit function declarations since 2020 [2]. A similar
workaround also went into Autoconf 2.71. (It uses clang's -fno-builtin option;
earlier it used -Werror. See [3].)

What's the problem, then? It is that the gl_WARN_ON_USE_PREPARE macro, which
also checks for declarations and sets ac_cv_decl_strndup as a "shortcut",
does not have a clang workaround. This patch fixes it.

[1] https://clang.llvm.org/docs/ClangCommandLineReference.html
[2] https://lists.gnu.org/archive/html/bug-gnulib/2020-01/msg00030.html
[3] https://lists.gnu.org/archive/html/autoconf-patches/2015-04/msg00022.html


2022-09-20  Bruno Haible  <bruno@clisp.org>

        snippet/warn-on-use: Don't cause wrong AC_CHECK_DECL results with clang.
        * m4/warn-on-use.m4 (gl_WARN_ON_USE_PREPARE): Use the clang command-line
        option that disables implicit built-in function declarations in clang.

diff --git a/m4/warn-on-use.m4 b/m4/warn-on-use.m4
index d43355ab17..a81731f31c 100644
--- a/m4/warn-on-use.m4
+++ b/m4/warn-on-use.m4
@@ -1,4 +1,4 @@
-# warn-on-use.m4 serial 9
+# warn-on-use.m4 serial 10
 dnl Copyright (C) 2010-2022 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -32,17 +32,30 @@ AC_DEFUN([gl_WARN_ON_USE_PREPARE],
           undefining macros.])])dnl
      for gl_func in m4_flatten([$2]); do
        AS_VAR_PUSHDEF([gl_Symbol], [gl_cv_have_raw_decl_$gl_func])dnl
+       dnl As a workaround to implicit built-in function declarations in
+       dnl clang (e.g. strndup), reference ac_compile_for_check_decl instead
+       dnl of ac_compile.  If, for whatever reason, the override of AC_PROG_CC
+       dnl in zzgnulib.m4 is inactive, use the original ac_compile.
+       ac_save_ac_compile="$ac_compile"
+       if test -n "$ac_compile_for_check_decl"; then
+         ac_compile="$ac_compile_for_check_decl"
+       fi
        AC_CACHE_CHECK([whether $gl_func is declared without a macro],
          [gl_Symbol],
          [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$1],
 [[#undef $gl_func
   (void) $gl_func;]])],
            [AS_VAR_SET([gl_Symbol], [yes])], [AS_VAR_SET([gl_Symbol], [no])])])
+       ac_compile="$ac_save_ac_compile"
        AS_VAR_IF([gl_Symbol], [yes],
          [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_RAW_DECL_$gl_func]), [1])
-          dnl shortcut - if the raw declaration exists, then set a cache
-          dnl variable to allow skipping any later AC_CHECK_DECL efforts
-          eval ac_cv_have_decl_$gl_func=yes])
+          dnl Shortcut for an AC_CHECK_DECL invocation that may come later:
+          dnl If the raw declaration exists with the given includes, then
+          dnl AC_CHECK_DECL with its many includes would see it as well.
+          dnl So, set a cache variable to allow skipping any later
+          dnl AC_CHECK_DECL invocation for $gl_func.
+          eval "ac_cv_have_decl_$gl_func=yes"
+         ])
        AS_VAR_POPDEF([gl_Symbol])dnl
      done
     ])






reply via email to

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