[Top][All Lists]
[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.
- maintainer-check fallout: C++ and type checks,
Ralf Wildenhues <=