autoconf-patches
[Top][All Lists]
Advanced

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

maintainer-check fallout: C++ and type checks


From: Ralf Wildenhues
Subject: maintainer-check fallout: C++ and type checks
Date: Thu, 9 Mar 2006 19:22:48 +0100
User-agent: Mutt/1.5.9i

Autoconf's maintainer-check-c++ is an interesting beast.  ;-)
Four test failures, lots of interesting observations:


(I)
104: AC_PROG_CC_STDC failure:

It fails to find a flag to enable C89/C99 mode.  Not surprising,
because these venerable source snippets, *ahem*, more than 8 years
old, just do not fare too well with C++ compilers.  ;-))
http://sources.redhat.com/cgi-bin/cvsweb.cgi/automake/m4/ccstdc.m4.diff?r1=1.3&r2=1.4&cvsroot=automake
(actually, rcs-5.7 is >10 years old; its Changelog suggests this code
to be 15.  amazed..)

| /* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
| struct buf { int x; };
| FILE * (*rcsopen) (struct buf *, struct stat *, int);
| static char *e (p, i)
|      char **p;                /* line 15 */
|      int i;
| {
|   return p[i];
| }
| static char *f (char * (*g) (char **, int), char **p, ...)
| {
|   char *s;
|   va_list v;
|   va_start (v,p);
|   s = g (p, va_arg (v,int));
|   va_end (v);
|   return s;
| }
*snip*
| int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), 
int, int);
| int argc;
| char **argv;
| int
| main ()
| {                             /* next line is line 49 */
| return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];


Errors output by g++:
| conftest.c:15: error: `p' was not declared in this scope
| conftest.c:15: error: `i' was not declared in this scope
| conftest.c:16: error: initializer expression list treated as compound 
expression
| conftest.c:16: error: expected `,' or `;' before "char"
| conftest.c:18: error: expected unqualified-id before '{' token
| conftest.c:18: error: expected `,' or `;' before '{' token
| conftest.c: In function `int main()':
| conftest.c:49: error: cannot convert `char*' to `char*(*)(char**, int)' for 
argument `1' to `char* f(char*(*)(char**, int), char**, ...)'
| conftest.c:49: error: cannot convert `char*' to `char*(*)(char**, int)' for 
argument `1' to `char* f(char*(*)(char**, int), char**, ...)'


I think the above does not need to be fixed; the trivial patch below
fixes the actual test failure:

        * lib/autoconf/c.m4 (AC_PROG_CC_STDC): If we cannot enable C99
        nor C89 mode, set `$ac_cv_prog_cc_stdc' to `no' instead of
        trying to execute the command `no'.

Index: lib/autoconf/c.m4
===================================================================
RCS file: /cvsroot/autoconf/autoconf/lib/autoconf/c.m4,v
retrieving revision 1.210
diff -u -r1.210 c.m4
--- lib/autoconf/c.m4   24 Jan 2006 00:20:15 -0000      1.210
+++ lib/autoconf/c.m4   9 Mar 2006 00:44:23 -0000
@@ -1054,7 +1054,8 @@
 AC_DEFUN([AC_PROG_CC_STDC],
 [ AC_REQUIRE([AC_PROG_CC])dnl
   _AC_PROG_CC_C99([ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99],
-                  [_AC_PROG_CC_C89([ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89], 
[no])])dnl
+                 [_AC_PROG_CC_C89([ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89],
+                                  [ac_cv_prog_cc_stdc=no])])dnl
   AC_MSG_CHECKING([for $CC option to accept ISO Standard C])
   AC_CACHE_VAL([ac_cv_prog_cc_stdc], [])
   case "x$ac_cv_prog_cc_stdc" in



(II)
Failures of:
91: C keywords
129: AC_CHECK_ALIGNOF
130: AC_CHECK_ALIGNOF

Here, the reason for the failure is similar in all cases:
| a.c: In function `int main()':
| a.c:60: error: types may not be defined in casts

Type definitions inside casts and inside of `sizeof()' violate the C++
standard (ISO/IEC 14882:1998(E): 5.3.3(5) and 5.4(3)).  GCC 3.4 and
newer diagnose this and fail hard.  One possible solution would be to
define a typedef (or a named structure) outside the expression, see
further below.  But this opens a more general issue:

What about user-provided aggregate types, like unnamed structs?  This:
  AC_CHECK_TYPES([struct { int x; }])

fails with `./configure CC=g++', and fails in `AC_LANG([C++])' mode.
User workarounds could be 
  AC_CHECK_TYPES([T], [], [],
                 [AC_INCLUDES_DEFAULT
                  typedef struct { int x; } T;])

or
  AC_CHECK_TYPES([struct T], [], [],
                 [AC_INCLUDES_DEFAULT
                  struct T { int x; };])

For `AC_CHECK_TYPES', this may not actually sound so useful, but for
AC_CHECK_SIZEOF it is; AC_CHECK_SIZEOF calls AC_CHECK_TYPES though,
so we'd have to cater for the former here, to allow its use in the
latter.

Should we document the need for user-provided typedef/named struct?
There is also another possibility: do the typedef'ing in the macros
themselves.  Given the longish comment at the head of types.m4, it
does not seem like a change done lightly, though.  :-/

(Note going the documentation route only for now should still allow
us to go the latter later.  But it'd be nice to solve this issue.)

So here are two patches to address these issues.  What do you think?
This should even be K&R C compatible, right?

It may also be useful to note that function types or pointers to
them do not work well with any of those macros at all, neither
would C99 variable length arrays, or C++ references.  (This is not
addressed in the patch below, and AFAICS not a new constraint.)

Note in the patch below I chose some hopefully unlikely-to-be-already-
used type names.. should they rather all be the same instead?

Unrelated note: Regarding this AC_C_TYPEOF comment:
# Check if the C compiler supports GCC's typeof syntax.
# The test case provokes incompatibilities in the Sun C compilers
# (both Solaris 8 and Solaris 10).

I have verified that the code still provokes failure with the Solaris
compiler.  I have also tested this code on several systems, with several
C and C++ compilers.

Cheers,
Ralf

        * lib/autoconf/c.m4 (AC_C_TYPEOF): Use typedef to avoid defining
        a structure inside a cast, for C++ conformance.
        * lib/autoconf/types.m4 (AC_CHECK_ALIGNOF): Likewise.
        Also fix quoting error in `AC_MSG_FAILURE' arguments.

Index: lib/autoconf/c.m4
===================================================================
RCS file: /cvsroot/autoconf/autoconf/lib/autoconf/c.m4,v
retrieving revision 1.210
diff -u -r1.210 c.m4
--- lib/autoconf/c.m4   24 Jan 2006 00:20:15 -0000      1.210
+++ lib/autoconf/c.m4   9 Mar 2006 04:54:01 -0000
@@ -1447,17 +1448,16 @@
        AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
         [[
           int value;
-          return
-            (! ((void)
-                ((struct {
+          typedef struct {
                   char a [1
                           + ! (($ac_kw (value))
                                (($ac_kw (value)) 0 < ($ac_kw (value)) -1
                                 ? ($ac_kw (value)) - 1
                                 : ~ (~ ($ac_kw (value)) 0
-                                     << sizeof ($ac_kw (value)))))]; } *)
-                 0),
-                0));
+                                     << sizeof ($ac_kw (value)))))]; }
+             ac__typeof_type_;
+          return
+            (! ((void) ((ac__typeof_type_ *) 0), 0));
         ]])],
         [ac_cv_c_typeof=$ac_kw])
        test $ac_cv_c_typeof != no && break
Index: lib/autoconf/types.m4
===================================================================
RCS file: /cvsroot/autoconf/autoconf/lib/autoconf/types.m4,v
retrieving revision 1.32
diff -u -r1.32 types.m4
--- lib/autoconf/types.m4       4 Mar 2006 17:28:34 -0000       1.32
+++ lib/autoconf/types.m4       9 Mar 2006 04:43:33 -0000
@@ -408,13 +416,14 @@
 [if test "$AS_TR_SH([ac_cv_type_$1])" = yes; then
   # The cast to long int works around a bug in the HP C Compiler,
   # see AC_CHECK_SIZEOF for more information.
-  _AC_COMPUTE_INT([(long int) offsetof (struct { char x; $1 y; }, y)],
+  _AC_COMPUTE_INT([(long int) offsetof (ac__type_alignof_, y)],
                  [AS_TR_SH([ac_cv_alignof_$1])],
                  [AC_INCLUDES_DEFAULT([$2])
 #ifndef offsetof
 # define offsetof(type, member) ((char *) &((type *) 0)->member - (char *) 0)
-#endif],
-                 [AC_MSG_FAILURE([cannot compute alignment of ($1), 77])])
+#endif
+typedef struct { char x; $1 y; } ac__type_alignof_;],
+                 [AC_MSG_FAILURE([cannot compute alignment of ($1)], 77)])
 else
   AS_TR_SH([ac_cv_alignof_$1])=0
 fi])dnl



        * lib/autoconf/types.m4 (_AC_CHECK_TYPE_NEW): Use a typedef to
        allow to pass unnamed structs even in C++.
        (AC_CHECK_SIZEOF):  Likewise.
        Also fix quoting error in `AC_MSG_FAILURE' arguments.
        * tests/semantics.at (AC_CHECK_ALIGNOF struct, AC_CHECK_SIZEOF
        struct): New tests for unnamed structs, each both native and
        cross-compiling.

Index: lib/autoconf/types.m4
===================================================================
RCS file: /cvsroot/autoconf/autoconf/lib/autoconf/types.m4,v
retrieving revision 1.32
diff -u -r1.32 types.m4
--- lib/autoconf/types.m4       4 Mar 2006 17:28:34 -0000       1.32
+++ lib/autoconf/types.m4       9 Mar 2006 04:48:03 -0000
@@ -139,13 +139,20 @@
 # (not necessarily size_t etc.).  Equally, instead of defining an unused
 # variable, we just use a cast to avoid warnings from the compiler.
 # Suggested by Paul Eggert.
+# 
+# Now, the next issue is that C++ disallows defining types inside casts
+# and inside `sizeof()', but we would like to allow unnamed structs, for
+# use inside AC_CHECK_SIZEOF, for example.  So we create a typedef of the
+# new type.  Note that this does not obviate the need for the other
+# constructs in general.
 m4_define([_AC_CHECK_TYPE_NEW],
 [AS_VAR_PUSHDEF([ac_Type], [ac_cv_type_$1])dnl
 AC_CACHE_CHECK([for $1], ac_Type,
-[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT([$4])],
-[if (($1 *) 0)
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT([$4])
+typedef $1 ac__type_new_;],
+[if ((ac__type_new_ *) 0)
   return 0;
-if (sizeof ($1))
+if (sizeof (ac__type_new_))
   return 0;])],
                   [AS_VAR_SET(ac_Type, yes)],
                   [AS_VAR_SET(ac_Type, no)])])
@@ -386,10 +393,11 @@
   # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
   # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
   # This bug is HP SR number 8606223364.
-  _AC_COMPUTE_INT([(long int) (sizeof ($1))],
+  _AC_COMPUTE_INT([(long int) (sizeof (ac__type_sizeof_))],
                  [AS_TR_SH([ac_cv_sizeof_$1])],
-                 [AC_INCLUDES_DEFAULT([$3])],
-                 [AC_MSG_FAILURE([cannot compute sizeof ($1), 77])])
+                 [AC_INCLUDES_DEFAULT([$3])
+                  typedef $1 ac__type_sizeof_;],
+                 [AC_MSG_FAILURE([cannot compute sizeof ($1)], 77)])
 else
   AS_TR_SH([ac_cv_sizeof_$1])=0
 fi])dnl
Index: tests/semantics.at
===================================================================
RCS file: /cvsroot/autoconf/autoconf/tests/semantics.at,v
retrieving revision 1.53
diff -u -r1.53 semantics.at
--- tests/semantics.at  5 Jan 2006 21:43:45 -0000       1.53
+++ tests/semantics.at  9 Mar 2006 04:48:03 -0000
@@ -279,6 +279,35 @@
 ])])
 
 
+# AC_CHECK_ALIGNOF struct
+# -----------------------
+# Not cross-compiling.
+AT_CHECK_MACRO([AC_CHECK_ALIGNOF struct],
+[[AC_CHECK_ALIGNOF([struct { char c; }])
+AC_CHECK_ALIGNOF([struct nosuchstruct])
+]],
+[AT_CHECK([[grep "#define ALIGNOF_STRUCT___CHAR_C___ [^0]" config.h]],
+        0, ignore)
+AT_CHECK([[grep "#define ALIGNOF_STRUCT_NOSUCHSTRUCT 0" config.h]],
+        0, ignore)
+])
+
+
+# AC_CHECK_ALIGNOF struct
+# -----------------------
+AT_CHECK_MACRO([AC_CHECK_ALIGNOF struct],
+[[# Exercise the code used when cross-compiling
+cross_compiling=yes
+AC_CHECK_ALIGNOF([struct { char c; }])
+AC_CHECK_ALIGNOF([struct nosuchstruct])
+]],
+[AT_CHECK([[grep "#define ALIGNOF_STRUCT___CHAR_C___ [^0]" config.h]],
+        0, ignore)
+AT_CHECK([[grep "#define ALIGNOF_STRUCT_NOSUCHSTRUCT 0" config.h]],
+        0, ignore)
+])
+
+
 # AC_CHECK_SIZEOF
 # ---------------
 # Not cross-compiling.
@@ -314,6 +343,43 @@
 ])])
 
 
+# AC_CHECK_SIZEOF structs
+# -----------------------
+# Not cross-compiling.
+AT_CHECK_MACRO([AC_CHECK_SIZEOF struct],
+[[AC_C_CONST
+AC_CHECK_SIZEOF([struct { char c; int x; }])
+AC_CHECK_SIZEOF([const struct { const char *p; int x; }])
+AC_CHECK_SIZEOF([struct nosuchstruct])
+]],
+[AT_CHECK([[grep "#define SIZEOF_STRUCT___CHAR_C__INT_X___ [^0]" config.h]],
+        0, ignore)
+AT_CHECK([[grep "#define SIZEOF_CONST_STRUCT___CONST_CHAR_PP__INT_X___ [^0]" 
config.h]],
+        0, ignore)
+AT_CHECK([[grep "#define SIZEOF_STRUCT_NOSUCHSTRUCT 0" config.h]],
+        0, ignore)
+])
+
+
+# AC_CHECK_SIZEOF
+# ---------------
+AT_CHECK_MACRO([AC_CHECK_SIZEOF struct],
+[[# Exercise the code used when cross-compiling
+cross_compiling=yes
+AC_C_CONST
+AC_CHECK_SIZEOF([struct { char c; int x; }])
+AC_CHECK_SIZEOF([const struct { const char *p; int x; }])
+AC_CHECK_SIZEOF([struct nosuchstruct])
+]],
+[AT_CHECK([[grep "#define SIZEOF_STRUCT___CHAR_C__INT_X___ [^0]" config.h]],
+        0, ignore)
+AT_CHECK([[grep "#define SIZEOF_CONST_STRUCT___CONST_CHAR_PP__INT_X___ [^0]" 
config.h]],
+        0, ignore)
+AT_CHECK([[grep "#define SIZEOF_STRUCT_NOSUCHSTRUCT 0" config.h]],
+        0, ignore)
+])
+
+
 # AC_CHECK_TYPES
 # --------------
 # Check that it performs the correct actions.




reply via email to

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