diff --git a/Makefile.in b/Makefile.in index a684a6a1f..1c192f3a2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -167,13 +167,17 @@ $(OBJDIR)/machdep.ml : src/machdep-ml.c configure.ac Makefile.in @echo " sizeof_float: int; (* Size of \"float\" *)" >> $@ @echo " sizeof_double: int; (* Size of \"double\" *)" >> $@ @echo " sizeof_longdouble: int; (* Size of \"long double\" *)" >> $@ + @echo " sizeof_float128: int; (* Size of \"__float128\" *)" >> $@ @echo " sizeof_floatcomplex: int; (* Size of \"float _Complex\" *)" >> $@ @echo " sizeof_doublecomplex: int; (* Size of \"double _Complex\" *)" >> $@ @echo " sizeof_longdoublecomplex: int; (* Size of \"long double _Complex\" *)" >> $@ + @echo " sizeof_complex128: int; (* Size of \"__complex128\" *)" >> $@ @echo " sizeof_void: int; (* Size of \"void\" *)" >> $@ @echo " sizeof_fun: int; (* Size of function *)" >> $@ @echo " size_t: string; (* Type of \"sizeof(T)\" *)" >> $@ @echo " wchar_t: string; (* Type of \"wchar_t\" *)" >> $@ + @echo " char16_t: string; (* Type of \"char16_t\" *)" >> $@ + @echo " char32_t: string; (* Type of \"char32_t\" *)" >> $@ @echo " alignof_short: int; (* Alignment of \"short\" *)" >> $@ @echo " alignof_int: int; (* Alignment of \"int\" *)" >> $@ @echo " alignof_bool: int; (* Alignment of \"_Bool\" *)" >> $@ @@ -184,9 +188,11 @@ $(OBJDIR)/machdep.ml : src/machdep-ml.c configure.ac Makefile.in @echo " alignof_float: int; (* Alignment of \"float\" *)" >> $@ @echo " alignof_double: int; (* Alignment of \"double\" *)" >> $@ @echo " alignof_longdouble: int; (* Alignment of \"long double\" *)" >> $@ + @echo " alignof_float128: int; (* Alignment of \"__float128\" *)" >> $@ @echo " alignof_floatcomplex: int; (* Alignment of \"float _Complex\" *)" >> $@ @echo " alignof_doublecomplex: int; (* Alignment of \"double _Complex\" *)" >> $@ @echo " alignof_longdoublecomplex: int; (* Alignment of \"long double _Complex\" *)" >> $@ + @echo " alignof_complex128: int; (* Alignment of \"__float128\" *)" >> $@ @echo " alignof_str: int; (* Alignment of strings *)" >> $@ @echo " alignof_fun: int; (* Alignment of function *)" >> $@ @echo " alignof_aligned: int; (* Alignment of anything with the \"aligned\" attribute *)" >> $@ diff --git a/config.h.in b/config.h.in index c43dbebe2..26d6cbaeb 100644 --- a/config.h.in +++ b/config.h.in @@ -12,6 +12,9 @@ /* Define to 1 if you have the `mkdir' function. */ #undef HAVE_MKDIR +/* Define to 1 if you have the header file. */ +#undef HAVE_QUADMATH_H + /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT @@ -42,6 +45,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_UCHAR_H + /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H @@ -75,6 +81,12 @@ /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME +/* Real integer type corresponding to char16_t. */ +#undef TYPE_CHAR16_T + +/* Real integer type corresponding to char32_t. */ +#undef TYPE_CHAR32_T + /* Real integer type corresponding to size_t. */ #undef TYPE_SIZE_T diff --git a/configure b/configure index 38be2c0c4..7a301ad71 100755 --- a/configure +++ b/configure @@ -5220,7 +5220,7 @@ $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi -for ac_header in stdlib.h strings.h sys/time.h unistd.h wchar.h stdbool.h +for ac_header in stdlib.h strings.h sys/time.h unistd.h wchar.h stdbool.h quadmath.h uchar.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -5519,6 +5519,16 @@ $as_echo_n "checking for real definition of size_t... " >&6; } #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5538,6 +5548,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5559,6 +5579,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5578,6 +5608,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5599,6 +5639,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5618,6 +5668,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5639,6 +5699,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5658,6 +5728,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5679,6 +5759,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5698,6 +5788,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5734,6 +5834,16 @@ $as_echo_n "checking for real definition of wchar_t... " >&6; } #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5753,6 +5863,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5774,6 +5894,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5793,6 +5923,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5814,6 +5954,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5833,6 +5983,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5854,6 +6014,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5873,6 +6043,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5894,6 +6074,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5913,6 +6103,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ @@ -5938,6 +6138,636 @@ _ACEOF $as_echo "$real_type" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for real definition of char16_t" >&5 +$as_echo_n "checking for real definition of char16_t... " >&6; } + real_type='' + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +int foo(int x); +char16_t foo(char16_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='int' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +unsigned int foo(unsigned int x); +char16_t foo(char16_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='unsigned int' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +long foo(long x); +char16_t foo(char16_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='long' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +unsigned long foo(unsigned long x); +char16_t foo(char16_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='unsigned long' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +long long foo(long long x); +char16_t foo(char16_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='long long' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +unsigned long long foo(unsigned long long x); +char16_t foo(char16_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='unsigned long long' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +short foo(short x); +char16_t foo(char16_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='short' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +unsigned short foo(unsigned short x); +char16_t foo(char16_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='unsigned short' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +char foo(char x); +char16_t foo(char16_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='char' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +unsigned char foo(unsigned char x); +char16_t foo(char16_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='unsigned char' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + if test -z "$real_type"; then + as_fn_error $? "cannot find definition of char16_t" "$LINENO" 5 + fi + +cat >>confdefs.h <<_ACEOF +#define TYPE_CHAR16_T "$real_type" +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $real_type" >&5 +$as_echo "$real_type" >&6; } + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for real definition of char32_t" >&5 +$as_echo_n "checking for real definition of char32_t... " >&6; } + real_type='' + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +int foo(int x); +char32_t foo(char32_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='int' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +unsigned int foo(unsigned int x); +char32_t foo(char32_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='unsigned int' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +long foo(long x); +char32_t foo(char32_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='long' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +unsigned long foo(unsigned long x); +char32_t foo(char32_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='unsigned long' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +long long foo(long long x); +char32_t foo(char32_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='long long' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +unsigned long long foo(unsigned long long x); +char32_t foo(char32_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='unsigned long long' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +short foo(short x); +char32_t foo(char32_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='short' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +unsigned short foo(unsigned short x); +char32_t foo(char32_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='unsigned short' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +char foo(char x); +char32_t foo(char32_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='char' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + if test -z "$real_type"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif +/* We define a prototype with one type and the function with + another type. This will result in compilation error + unless the types are really identical. */ +unsigned char foo(unsigned char x); +char32_t foo(char32_t x) { return x; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + real_type='unsigned char' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + + + if test -z "$real_type"; then + as_fn_error $? "cannot find definition of char32_t" "$LINENO" 5 + fi + +cat >>confdefs.h <<_ACEOF +#define TYPE_CHAR32_T "$real_type" +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $real_type" >&5 +$as_echo "$real_type" >&6; } + + # ----------------- finish up ------------------- # names of the variables that get substituted in files; for example, # write @CIL_VERSION@ somewhere in a written file to get it substituted diff --git a/configure.ac b/configure.ac index fb9369277..dbfa9f704 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ # script; any text which isn't an M4/autoconf directive gets # copied verbatim to that script. -# also, in general, watch out: the M4 quoting charactes are +# also, in general, watch out: the M4 quoting characters are # the square brackets: [ and ]. if you want to pass brackets # to something, you can quote the brackets with more brackets. # I don't know how to pass a single (unbalanced) bracket .. @@ -168,7 +168,7 @@ AC_MSG_RESULT($UNDERSCORE_NAME) # checks for header files AC_HEADER_STDC -AC_CHECK_HEADERS(stdlib.h strings.h sys/time.h unistd.h wchar.h stdbool.h) +AC_CHECK_HEADERS(stdlib.h strings.h sys/time.h unistd.h wchar.h stdbool.h quadmath.h uchar.h) # checks for typedefs, structures, and compiler characteristics AC_C_CONST @@ -183,6 +183,8 @@ AC_CHECK_FUNCS(mkdir select socket __sysv_signal) # Find out the true definitions of some integer types CIL_CHECK_INTEGER_TYPE(size_t, TYPE_SIZE_T) CIL_CHECK_INTEGER_TYPE(wchar_t, TYPE_WCHAR_T) +CIL_CHECK_INTEGER_TYPE(char16_t, TYPE_CHAR16_T) +CIL_CHECK_INTEGER_TYPE(char32_t, TYPE_CHAR32_T) # ----------------- finish up ------------------- # names of the variables that get substituted in files; for example, diff --git a/m4/cil.m4 b/m4/cil.m4 index 8ca22021c..584e32606 100644 --- a/m4/cil.m4 +++ b/m4/cil.m4 @@ -5,6 +5,16 @@ AC_DEFUN([__CIL_CHECK_INTEGER_TYPE_TYPE], [ AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include #include +#include +#if __APPLE__ + // C11 7.28 defines these to be the same as uint_least16_t and uint_least32_t. + // The standard mandates a uchar.h file to contain these typedefs, but Mac does + // not have that header file + typedef uint_least16_t char16_t; + typedef uint_least32_t char32_t; +#else + #include +#endif /* We define a prototype with one type and the function with another type. This will result in compilation error unless the types are really identical. */ diff --git a/src/check.ml b/src/check.ml index faa54075e..23436f43c 100644 --- a/src/check.ml +++ b/src/check.ml @@ -278,6 +278,7 @@ let rec checkType (t: typ) (ctx: ctxType) = (fun (an, at, aa) -> checkType at CTFArg; checkAttributes aa) (argsToList targs) + | TDefault -> () (* Check that a type is a promoted integral type *) and checkIntegralType (t: typ) = @@ -504,12 +505,12 @@ and checkExp (isconst: bool) (e: exp) : typ = | Imag e -> let te = checkExp isconst e in typeOfRealAndImagComponents te - | AlignOf(t) -> begin + | AlignOf(t) | AlignOf_C11(t) -> begin (* Sizeof cannot be applied to certain types *) checkType t CTSizeof; typeOf e end - | AlignOfE(e') -> + | AlignOfE(e') | AlignOfE_C11(e') -> (* The expression in an AlignOfE can be anything *) let te = checkExp false e' in checkType te CTSizeof; @@ -618,7 +619,12 @@ and checkExp (isconst: bool) (e: exp) : typ = (* | TComp _ -> E.s (bug "Cast of a composite type") *) | TVoid _ -> E.s (bug "Cast of a void type") | _ -> tres - end) + end + | Generic (exp, lst) -> + let typ = checkExp false exp in + List.iter (fun (t, e) -> checkType t CTExp; ignore (checkExp false e)) lst; + typ + ) () (* The argument of withContext *) and checkInit (i: init) : typ = diff --git a/src/cil.ml b/src/cil.ml index 376d175fb..9e0e446c8 100755 --- a/src/cil.ml +++ b/src/cil.ml @@ -277,6 +277,7 @@ and typ = | TBuiltin_va_list of attributes (** This is the same as the gcc's type with the same name *) + | TDefault (** Various kinds of integers *) and ikind = @@ -302,6 +303,8 @@ and fkind = | FComplexFloat (** [float _Complex] *) | FComplexDouble (** [double _Complex] *) | FComplexLongDouble (** [long double _Complex]*) + | FFloat128 (** [__float128] *) + | FComplexFloat128 (** [__complex128] *) (** An attribute has a name and some optional parameters *) and attribute = Attr of string * attrparam list @@ -326,6 +329,9 @@ and attrparam = | AAlignOf of typ | AAlignOfE of attrparam | AAlignOfS of typsig + | AAlignOf_C11 of typ (* We differentiate between the C11 _Alignof and the GCC __alignof__ *) + | AAlignOfE_C11 of attrparam + | AAlignOfS_C11 of typsig | AUnOp of unop * attrparam | ABinOp of binop * attrparam * attrparam | ADot of attrparam * string (** a.foo **) @@ -433,6 +439,8 @@ and varinfo = { mutable vinline: bool; (** Whether this varinfo is for an inline function. *) + mutable vthreadlocal: bool; + mutable vdecl: location; (** Location of variable declaration *) vinit: initinfo; @@ -509,6 +517,8 @@ and exp = | AlignOf of typ (** Has [unsigned int] type *) | AlignOfE of exp + | AlignOf_C11 of typ (** Has [unsigned int] type *) + | AlignOfE_C11 of exp | UnOp of unop * exp * typ (** Unary operation. Includes the type of the result *) @@ -537,7 +547,11 @@ and exp = * It is not printed. Given an lval of type * [TArray(T)] produces an expression of type * [TPtr(T)]. *) + | Generic of exp * ((typ * exp) list) + +and wstring_type = | Wchar_t | Char16_t | Char32_t +and encoding = No_encoding | Utf8 (** Literal constants *) and constant = @@ -547,8 +561,8 @@ and constant = * {!Cil.integer} or {!Cil.kinteger} to create these. Watch * out for integers that cannot be represented on 64 bits. * OCAML does not give Overflow exceptions. *) - | CStr of string (** String constant (of pointer type) *) - | CWStr of int64 list (** Wide string constant (of type "wchar_t *") *) + | CStr of string * encoding (** String constant (of pointer type) *) + | CWStr of int64 list * wstring_type (** Wide string constant (of type "wchar_t *") *) | CChr of char (** Character constant. This has type int, so use * charConstToInt to read the value in case * sign-extension is needed. *) @@ -1285,10 +1299,13 @@ let upointType = ref voidType (* An integer type that fits a pointer difference. Initialized by initCIL *) let ptrdiffType = ref voidType -(* An integer type that fits wchar_t. Initialized by initCIL *) +(* Integer types that fit wchar_t, char16_t and char32_t. Initialized by initCIL *) let wcharKind = ref IChar let wcharType = ref voidType - +let char16Kind = ref IChar +let char16Type = ref voidType +let char32Kind = ref IChar +let char32Type = ref voidType (* An integer type that is the type of sizeof. Initialized by initCIL *) let typeOfSizeOf = ref voidType @@ -1409,7 +1426,7 @@ type attributeClass = let attributeHash: (string, attributeClass) H.t = let table = H.create 13 in List.iter (fun a -> H.add table a (AttrName false)) - [ "section"; "constructor"; "destructor"; "unused"; "used"; "weak"; + [ "section"; "constructor"; "destructor"; "unused"; "used"; "weak"; "no_instrument_function"; "alias"; "no_check_memory_usage"; "exception"; "model"; (* "restrict"; *) "aconst"; "__asm__" (* Gcc uses this to specify the name to be used in @@ -1423,15 +1440,15 @@ let attributeHash: (string, attributeClass) H.t = List.iter (fun a -> H.add table a (AttrFunType false)) [ "format"; "regparm"; "longcall"; - "noinline"; "always_inline"; "gnu_inline"; "leaf"; + "noinline"; "always_inline"; "gnu_inline"; "leaf"; "c_noreturn"; "artificial"; "warn_unused_result"; "nonnull"; ]; List.iter (fun a -> H.add table a (AttrFunType true)) - [ "stdcall";"cdecl"; "fastcall" ]; + [ "stdcall";"cdecl"; "fastcall"; ]; List.iter (fun a -> H.add table a AttrType) - [ "const"; "volatile"; "restrict"; "mode" ]; + [ "const"; "volatile"; "restrict"; "mode"; ]; table @@ -1519,6 +1536,7 @@ let rec typeAttrs = function | TEnum (enum, a) -> addAttributes enum.eattr a | TFun (_, _, _, a) -> a | TBuiltin_va_list a -> a + | TDefault -> [] let setTypeAttrs t a = @@ -1533,6 +1551,7 @@ let setTypeAttrs t a = | TEnum (enum, _) -> TEnum (enum, a) | TFun (r, args, v, _) -> TFun(r,args,v,a) | TBuiltin_va_list _ -> TBuiltin_va_list a + | TDefault -> TDefault let typeAddAttributes a0 t = @@ -1555,6 +1574,7 @@ begin | TComp (comp, a) -> TComp (comp, add a) | TNamed (t, a) -> TNamed (t, add a) | TBuiltin_va_list a -> TBuiltin_va_list (add a) + | TDefault -> TDefault end let typeRemoveAttributes (anl: string list) t = @@ -1570,6 +1590,7 @@ let typeRemoveAttributes (anl: string list) t = | TComp (comp, a) -> TComp (comp, drop a) | TNamed (t, a) -> TNamed (t, drop a) | TBuiltin_va_list a -> TBuiltin_va_list (drop a) + | TDefault -> TDefault let unrollType (t: typ) : typ = let rec withAttrs (al: attributes) (t: typ) : typ = @@ -1616,9 +1637,11 @@ let typeOfRealAndImagComponents t = | FFloat -> FFloat (* [float] *) | FDouble -> FDouble (* [double] *) | FLongDouble -> FLongDouble (* [long double] *) + | FFloat128 -> FFloat128 | FComplexFloat -> FFloat | FComplexDouble -> FDouble | FComplexLongDouble -> FLongDouble + | FComplexFloat128 -> FFloat128 in TFloat (newfkind fkind, attrs) | _ -> E.s (E.bug "unexpected non-numerical type for argument to __real__") @@ -1628,14 +1651,16 @@ let getComplexFkind = function | FFloat -> FComplexFloat | FDouble -> FComplexDouble | FLongDouble -> FComplexLongDouble + | FFloat128 -> FComplexFloat128 | FComplexFloat -> FComplexFloat | FComplexDouble -> FComplexDouble | FComplexLongDouble -> FComplexLongDouble + | FComplexFloat128 -> FComplexFloat128 let var vi : lval = (Var vi, NoOffset) (* let assign vi e = Instrs(Set (var vi, e), lu) *) -let mkString s = Const(CStr s) +let mkString s = Const(CStr (s, No_encoding)) let mkWhile ~(guard:exp) ~(body: stmt list) : stmt list = @@ -1703,9 +1728,11 @@ let d_fkind () = function FFloat -> text "float" | FDouble -> text "double" | FLongDouble -> text "long double" + | FFloat128 -> text "__float128" | FComplexFloat -> text "_Complex float" | FComplexDouble -> text "_Complex double" | FComplexLongDouble -> text "_Complex long double" + | FComplexFloat128 -> text "__complex128" let d_storage () = function NoStorage -> nil @@ -1771,9 +1798,10 @@ let d_const () c = text (prefix ^ (Int64.to_string i ^ suffix)) ) - | CStr(s) -> text ("\"" ^ escape_string s ^ "\"") - | CWStr(s) -> + | CStr(s, enc) -> let prefix = match enc with No_encoding -> "" | Utf8 -> "u8" in text (prefix ^ "\"" ^ escape_string s ^ "\"") + | CWStr(s, st) -> (* text ("L\"" ^ escape_string s ^ "\"") *) + let prefix = match st with Wchar_t -> "L" | Char16_t -> "u" | Char32_t -> "U" in (List.fold_left (fun acc elt -> acc ++ if (elt >= Int64.zero && @@ -1782,7 +1810,7 @@ let d_const () c = else ( text (Printf.sprintf "\\x%LX\"" elt) ++ break ++ (text "\"")) - ) (text "L\"") s ) ++ text "\"" + ) (text (prefix ^ "\"")) s ) ++ text "\"" (* we cannot print L"\xabcd" "feedme" as L"\xabcdfeedme" -- * the former has 7 wide characters and the later has 3. *) @@ -1794,9 +1822,11 @@ let d_const () c = FFloat -> chr 'f' | FDouble -> nil | FLongDouble -> chr 'L' + | FFloat128 -> chr 'q' | FComplexFloat -> text "iF" | FComplexDouble -> chr 'i' - | FComplexLongDouble -> text "iL") + | FComplexLongDouble -> text "iL" + | FComplexFloat128 -> text "iQ") | CEnum(_, s, ei) -> text s @@ -1846,10 +1876,11 @@ let getParenthLevel (e: exp) = | Lval(Mem _ , _) -> derefStarLevel (* 20 *) | Lval(Var _, (Field _|Index _)) -> indexLevel (* 20 *) | SizeOf _ | SizeOfE _ | SizeOfStr _ -> 20 - | AlignOf _ | AlignOfE _ -> 20 + | AlignOf _ | AlignOfE _ | AlignOf_C11 _ | AlignOfE_C11 _ -> 20 | Lval(Var _, NoOffset) -> 0 (* Plain variables *) | Const _ -> 0 (* Constants *) + | Generic _ -> 0 (*TODO*) let getParenthLevelAttrParam (a: attrparam) = @@ -1857,7 +1888,7 @@ let getParenthLevelAttrParam (a: attrparam) = match a with AInt _ | AStr _ | ACons _ -> 0 | ASizeOf _ | ASizeOfE _ | ASizeOfS _ -> 20 - | AAlignOf _ | AAlignOfE _ | AAlignOfS _ -> 20 + | AAlignOf _ | AAlignOfE _ | AAlignOfS _ | AAlignOf_C11 _ | AAlignOfE_C11 _ | AAlignOfS_C11 _ -> 20 | AUnOp (uo, _) -> getParenthLevel (UnOp(uo, zero, intType)) | ABinOp (bo, _, _) -> getParenthLevel (BinOp(bo, zero, zero, intType)) | AAddrOf _ -> 30 @@ -1923,9 +1954,9 @@ let rec typeOf (e: exp) : typ = (* The type of a string is a pointer to characters ! The only case when * you would want it to be an array is as an argument to sizeof, but we * have SizeOfStr for that *) - | Const(CStr s) -> !stringLiteralType + | Const(CStr (_, _)) -> !stringLiteralType - | Const(CWStr s) -> TPtr(!wcharType,[]) + | Const(CWStr (s,st)) -> TPtr((match st with Wchar_t -> !wcharType | Char16_t -> !char16Type | Char32_t -> !char32Type), []) | Const(CReal (_, fk, _)) -> TFloat(fk, []) @@ -1934,7 +1965,7 @@ let rec typeOf (e: exp) : typ = | Imag e -> typeOfRealAndImagComponents @@ typeOf e | Lval(lv) -> typeOfLval lv | SizeOf _ | SizeOfE _ | SizeOfStr _ -> !typeOfSizeOf - | AlignOf _ | AlignOfE _ -> !typeOfSizeOf + | AlignOf _ | AlignOfE _ | AlignOf_C11 _ | AlignOfE_C11 _ -> !typeOfSizeOf | UnOp (_, _, t) | BinOp (_, _, _, t) | Question (_, _, _, t) @@ -1946,6 +1977,14 @@ let rec typeOf (e: exp) : typ = TArray (t,_, a) -> TPtr(t, a) | _ -> E.s (E.bug "typeOf: StartOf on a non-array") end + | Generic (exp, lst) -> + let typeOfExp = typeOf exp in + let rec findType lst = + match lst with + [] -> voidType + | (t, e) :: rest -> if t = typeOfExp then typeOf e else findType rest + in + findType lst and typeOfInit (i: init) : typ = match i with @@ -2202,9 +2241,11 @@ let rec alignOf_int t = | TFloat(FFloat, _) -> !M.theMachine.M.alignof_float | TFloat(FDouble, _) -> !M.theMachine.M.alignof_double | TFloat(FLongDouble, _) -> !M.theMachine.M.alignof_longdouble + | TFloat(FFloat128, _) -> !M.theMachine.M.alignof_float128 | TFloat(FComplexFloat, _) -> !M.theMachine.M.alignof_floatcomplex | TFloat(FComplexDouble, _) -> !M.theMachine.M.alignof_doublecomplex | TFloat(FComplexLongDouble, _) -> !M.theMachine.M.alignof_longdoublecomplex + | TFloat(FComplexFloat128, _) -> !M.theMachine.M.alignof_complex128 | TNamed (t, _) -> alignOf_int t.ttype | TArray (t, _, _) -> alignOf_int t | TPtr _ | TBuiltin_va_list _ -> !M.theMachine.M.alignof_ptr @@ -2233,8 +2274,36 @@ let rec alignOf_int t = | TFun _ as t -> raise (SizeOfError ("function", t)) | TVoid _ as t -> raise (SizeOfError ("void", t)) + | TDefault -> raise (SizeOfError ("default", t)) + in + let is_power_of_two n = + let log2 = (log10 (float_of_int n)) /. (log10 2.) in + ceil log2 = floor log2 in - match filterAttributes "aligned" (typeAttrs t) with + let rec strictest_alignment (current:int) (lst:attribute list) = + match lst with + [] -> current + | (Attr(_, [a]) as at)::rest -> begin + match intOfAttrparam a with + Some 0 -> strictest_alignment current rest + | Some n -> + if not (is_power_of_two n) then begin + ignore(warn "Invalid alignment value specified by attribute %a\n" (!pd_attr) at); + strictest_alignment current rest + end + else strictest_alignment (max current n) rest + | None -> + ignore (warn "alignment attribute \"%a\" not understood on %a" (!pd_attr) at (!pd_type) t); + strictest_alignment current rest + end + | Attr(_, []) :: rest -> + strictest_alignment (max current !M.theMachine.M.alignof_aligned) rest; + | at :: rest -> + ignore (warn "alignment attribute \"%a\" not understood on %a" + (!pd_attr) at (!pd_type) t); + strictest_alignment current rest + in + match filterAttributes "aligned" (typeAttrs t) @ filterAttributes "alignas" (typeAttrs t) with [] -> (* no __aligned__ attribute, so get the default alignment *) alignOfType () @@ -2242,24 +2311,23 @@ let rec alignOf_int t = ignore (warn "ignoring recursive align attributes on %a" (!pd_type) t); alignOfType () - | (Attr(_, [a]) as at)::rest -> begin - if rest <> [] then - ignore (warn "ignoring duplicate align attributes on %a" - (!pd_type) t); - match intOfAttrparam a with - Some n -> n + | (Attr(_, [a]) as at)::rest -> + let current = match intOfAttrparam a with + Some 0 -> alignOfType () + | Some n -> + if not (is_power_of_two n) then + alignOfType (ignore(warn "Invalid alignment value specified by attribute %a\n" (!pd_attr) at)) + else n | None -> - ignore (warn "alignment attribute \"%a\" not understood on %a" - (!pd_attr) at (!pd_type) t); - alignOfType () - end + ignore (warn "alignment attribute \"%a\" not understood on %a" + (!pd_attr) at (!pd_type) t); + alignOfType () + in + strictest_alignment current rest | Attr(_, [])::rest -> (* aligned with no arg means a power of two at least as large as any alignment on the system.*) - if rest <> [] then - ignore(warn "ignoring duplicate align attributes on %a" - (!pd_type) t); - !M.theMachine.M.alignof_aligned + strictest_alignment !M.theMachine.M.alignof_aligned rest | at::_ -> ignore (warn "alignment attribute \"%a\" not understood on %a" (!pd_attr) at (!pd_type) t); @@ -2278,10 +2346,20 @@ and intOfAttrparam (a:attrparam) : int option = AInt(n) -> n | ABinOp(Shiftlt, a1, a2) -> (doit a1) lsl (doit a2) | ABinOp(Div, a1, a2) -> (doit a1) / (doit a2) + | ABinOp(PlusA, a1, a2) -> (doit a1) + (doit a2) + | ABinOp(MinusA, a1, a2) -> (doit a1) - (doit a2) + | ABinOp(Mult, a1, a2) -> (doit a1) * (doit a2) + | ABinOp(Shiftrt, a1, a2) -> (doit a1) lsr (doit a2) + | ABinOp(BAnd, a1, a2) -> (doit a1) land (doit a2) + | ABinOp(BOr, a1, a2) -> (doit a1) lor (doit a2) + | ABinOp(BXor, a1, a2) -> (doit a1) lxor (doit a2) + | ABinOp(LAnd, a1, a2) -> (doit a1) land (doit a2) + | ABinOp(LOr, a1, a2) -> (doit a1) lor (doit a2) + | AUnOp(Neg, a1) -> -(doit a1) | ASizeOf(t) -> let bs = bitsSizeOf t in bs / 8 - | AAlignOf(t) -> + | AAlignOf(t) | AAlignOf_C11(t)-> alignOf_int t | _ -> raise (SizeOfError ("", voidType)) in @@ -2465,9 +2543,11 @@ and bitsSizeOf t = | TFloat(FDouble, _) -> 8 * !M.theMachine.M.sizeof_double | TFloat(FLongDouble, _) -> 8 * !M.theMachine.M.sizeof_longdouble | TFloat(FFloat, _) -> 8 * !M.theMachine.M.sizeof_float + | TFloat(FFloat128, _) -> 8 * !M.theMachine.M.sizeof_float128 | TFloat(FComplexDouble, _) -> 8 * !M.theMachine.M.sizeof_doublecomplex | TFloat(FComplexLongDouble, _) -> 8 * !M.theMachine.M.sizeof_longdoublecomplex | TFloat(FComplexFloat, _) -> 8 * !M.theMachine.M.sizeof_floatcomplex + | TFloat(FComplexFloat128, _) -> !M.theMachine.M.sizeof_complex128 | TEnum (ei, _) -> bitsSizeOf (TInt(ei.ekind, [])) | TPtr _ -> 8 * !M.theMachine.M.sizeof_ptr | TBuiltin_va_list _ -> 8 * !M.theMachine.M.sizeof_ptr @@ -2545,6 +2625,7 @@ and bitsSizeOf t = 0 | TFun _ -> raise (SizeOfError ("function", t)) + | TDefault -> raise (SizeOfError("default", t)) and addTrailing nrbits roundto = @@ -2643,7 +2724,8 @@ and constFold (machdep: bool) (e: exp) : exp = end | SizeOfE e when machdep -> constFold machdep (SizeOf (typeOf e)) | SizeOfStr s when machdep -> kinteger !kindOfSizeOf (1 + String.length s) - | AlignOf t when machdep -> kinteger !kindOfSizeOf (alignOf_int t) + | AlignOf t + | AlignOf_C11 t when machdep -> kinteger !kindOfSizeOf (alignOf_int t) | AlignOfE e when machdep -> begin (* The alignment of an expression is not always the alignment of its * type. I know that for strings this is not true *) @@ -2653,6 +2735,12 @@ and constFold (machdep: bool) (e: exp) : exp = (* For an array, it is the alignment of the array ! *) | _ -> constFold machdep (AlignOf (typeOf e)) end + | AlignOfE_C11 e when machdep -> begin + match e with + Const (CStr _) when not !msvcMode -> + kinteger !kindOfSizeOf !M.theMachine.M.alignof_str + | _ -> constFold machdep (AlignOf_C11 (typeOf e)) +end | CastE(it, AddrOf (Mem (CastE(TPtr(bt, _), z)), off)) @@ -2805,13 +2893,15 @@ let rec isConstant = function | Lval _ -> false | Real e -> isConstant e | Imag e -> isConstant e - | SizeOf _ | SizeOfE _ | SizeOfStr _ | AlignOf _ | AlignOfE _ -> true + | SizeOf _ | SizeOfE _ | SizeOfStr _ | AlignOf _ | AlignOfE _ | AlignOf_C11 _ | AlignOfE_C11 _ -> true | CastE (_, e) -> isConstant e | AddrOf (Var vi, off) | StartOf (Var vi, off) -> vi.vglob && isConstantOffset off | AddrOf (Mem e, off) | StartOf(Mem e, off) -> isConstant e && isConstantOffset off | AddrOfLabel _ -> true + | Generic _ -> false (*TODO*) + and isConstantOffset = function NoOffset -> true | Field(fi, off) -> isConstantOffset off @@ -3415,6 +3505,7 @@ class defaultCilPrinterClass : cilPrinter = object (self) let stom, rest = separateStorageModifiers v.vattr in (* First the storage modifiers *) text (if v.vinline then "__inline " else "") + ++ text (if v.vthreadlocal then "_Thread_local " else "") ++ d_storage () v.vstorage ++ (self#pAttrs () stom) ++ (self#pType (Some (text v.vname)) () v.vtype) @@ -3490,12 +3581,16 @@ class defaultCilPrinterClass : cilPrinter = object (self) | Real e -> text "__real__(" ++ self#pExp () e ++ chr ')' | SizeOfStr s -> - text "sizeof(" ++ d_const () (CStr s) ++ chr ')' + text "sizeof(" ++ d_const () (CStr (s, No_encoding)) ++ chr ')' | AlignOf (t) -> text "__alignof__(" ++ self#pType None () t ++ chr ')' | AlignOfE (e) -> text "__alignof__(" ++ self#pExp () e ++ chr ')' + | AlignOf_C11 (t) -> + text "_Alignof(" ++ self#pType None () t ++ chr ')' + | AlignOfE_C11 (e) -> + text "_Alignof(" ++ self#pExp () e ++ chr ')' | AddrOf(lv) -> text "& " ++ (self#pLvalPrec addrOfLevel () lv) | AddrOfLabel(sref) -> begin @@ -3514,6 +3609,14 @@ class defaultCilPrinterClass : cilPrinter = object (self) | StartOf(lv) -> self#pLval () lv + | Generic(e, lst) -> + let rec print_generic_exp l doc = + match l with + | [] -> doc + | (t, e1) :: rest -> print_generic_exp rest (doc ++ text ", " ++ (self#pType None () t) ++ text ":" ++ self#pExp () e1) + in + text "_Generic(" ++ self#pExp () e ++ print_generic_exp lst nil ++ text ")" + (* Print an expression, given the precedence of the context in which it * appears. *) method private pExpPrec (contextprec: int) () (e: exp) = @@ -4450,6 +4553,7 @@ class defaultCilPrinterClass : cilPrinter = object (self) ++ self#pAttrs () a ++ text " " ++ name + | TDefault -> text "default" (**** PRINTING ATTRIBUTES *********) @@ -4473,6 +4577,11 @@ class defaultCilPrinterClass : cilPrinter = object (self) *) | "volatile", [] -> text "volatile", false | "restrict", [] -> text "__restrict", false + | "c_noreturn", [] -> text "_Noreturn", false + | "alignas", args -> + text "_Alignas(" + ++ docList (self#pAttrParam ()) () args + ++ text ")", false | "missingproto", [] -> text "/* missing proto */", false | "cdecl", [] when !msvcMode -> text "__cdecl", false | "stdcall", [] when !msvcMode -> text "__stdcall", false @@ -4551,6 +4660,9 @@ class defaultCilPrinterClass : cilPrinter = object (self) | AAlignOfE a -> text "__alignof__(" ++ self#pAttrParam () a ++ text ")" | AAlignOf t -> text "__alignof__(" ++ self#pType None () t ++ text ")" | AAlignOfS ts -> text "__alignof__()" + | AAlignOf_C11 t -> text "_Alignof(" ++ self#pType None () t ++ text ")" + | AAlignOfE_C11 a -> text "_Alignof(" ++ self#pAttrParam () a ++ text ")" + | AAlignOfS_C11 ts -> text "_Alignof()" | AUnOp(u,a1) -> (d_unop () u) ++ chr ' ' ++ (self#pAttrPrec level () a1) @@ -4785,6 +4897,7 @@ class plainCilPrinterClass = end | TBuiltin_va_list a -> dprintf "TBuiltin_va_list(%a)" self#pAttrs a + | TDefault -> dprintf "TDefault" (* Some plain pretty-printers. Unlike the above these expose all the @@ -4794,23 +4907,24 @@ class plainCilPrinterClass = let d_plainconst () c = match c with CInt64(i, ik, so) -> - let fmt = if isSigned ik then "%d" else "%x" in + let fmt = if isSigned ik then "%d" else "%x" in dprintf "Int64(%s,%a,%s)" (Int64.format fmt i) d_ikind ik (match so with Some s -> s | _ -> "None") - | CStr(s) -> - text ("CStr(\"" ^ escape_string s ^ "\")") - | CWStr(s) -> + | CStr(s, enc) -> + let enc_string = match enc with No_encoding -> "_" | Utf8 -> "UTF8" in + text ("CStr(\"" ^ escape_string s ^ "\"," ^ enc_string ^ ")") + | CWStr(s,_) -> dprintf "CWStr(%a)" d_const c - | CChr(c) -> text ("CChr('" ^ escape_char c ^ "')") - | CReal(f, fk, so) -> + | CChr(c) -> text ("CChr('" ^ escape_char c ^ "')") + | CReal(f, fk, so) -> dprintf "CReal(%f, %a, %s)" f d_fkind fk (match so with Some s -> s | _ -> "None") - | CEnum(_, s, _) -> text s + | CEnum(_, s, _) -> text s in text "Const(" ++ d_plainconst () c ++ text ")" @@ -4851,11 +4965,15 @@ class plainCilPrinterClass = | SizeOfE (e) -> text "sizeofE(" ++ self#pExp () e ++ chr ')' | SizeOfStr (s) -> - text "sizeofStr(" ++ d_const () (CStr s) ++ chr ')' + text "sizeofStr(" ++ d_const () (CStr (s, No_encoding)) ++ chr ')' | AlignOf (t) -> text "__alignof__(" ++ self#pType None () t ++ chr ')' | AlignOfE (e) -> text "__alignof__(" ++ self#pExp () e ++ chr ')' + | AlignOf_C11 (t) -> + text "_Alignof(" ++ self#pType None () t ++ chr ')' + | AlignOfE_C11 (e) -> + text "_Alignof(" ++ self#pExp () e ++ chr ')' | Imag e -> text "__imag__(" ++ self#pExp () e ++ chr ')' | Real e -> @@ -4863,6 +4981,13 @@ class plainCilPrinterClass = | StartOf lv -> dprintf "StartOf(%a)" self#pLval lv | AddrOf (lv) -> dprintf "AddrOf(%a)" self#pLval lv | AddrOfLabel (sref) -> dprintf "AddrOfLabel(%a)" self#pStmt !sref + | Generic(e, lst) -> + let rec print_generic_exp l doc = + match l with + | [] -> doc + | (t, e1) :: rest -> print_generic_exp rest (doc ++ text "," ++ (self#pType None () t) ++ text ":" ++ self#pExp () e1) + in + text "_Generic(" ++ self#pExp () e ++ text "," ++ print_generic_exp lst nil @@ -5038,6 +5163,7 @@ let makeVarinfo global name ?init typ = vdecl = lu; vinit = {init=init}; vinline = false; + vthreadlocal = false; vattr = []; vstorage = NoStorage; vaddrof = false; @@ -5354,6 +5480,12 @@ and childrenExp (vis: cilVisitor) (e: exp) : exp = | AlignOfE e1 -> let e1' = vExp e1 in if e1' != e1 then AlignOfE e1' else e + | AlignOf_C11 t -> + let t' = vTyp t in + if t' != t then AlignOf_C11 t' else e + | AlignOfE_C11 e1 -> + let e1' = vExp e1 in + if e1' != e1 then AlignOfE_C11 e1' else e | Lval lv -> let lv' = vLval lv in if lv' != lv then Lval lv' else e @@ -5376,6 +5508,8 @@ and childrenExp (vis: cilVisitor) (e: exp) : exp = | StartOf lv -> let lv' = vLval lv in if lv' != lv then StartOf lv' else e + | Generic(e, lst) -> e (*TODO*) + and visitCilInit (vis: cilVisitor) (forglob: varinfo) (atoff: offset) (i: init) : init = @@ -5702,7 +5836,13 @@ and childrenAttrparam (vis: cilVisitor) (aa: attrparam) : attrparam = | AAlignOfE e -> let e' = fAttrP e in if e' != e then AAlignOfE e' else aa - | ASizeOfS _ | AAlignOfS _ -> + | AAlignOf_C11 t -> + let t' = fTyp t in + if t' != t then AAlignOf_C11 t' else aa + | AAlignOfE_C11 e -> + let e' = fAttrP e in + if e' != e then AAlignOfE_C11 e' else aa + | ASizeOfS _ | AAlignOfS _ | AAlignOfS_C11 _ -> ignore (warn "Visitor inside of a type signature."); aa | AUnOp (uo, e1) -> @@ -6111,6 +6251,7 @@ class typeSigVisitor(typeSigConverter: typ->typsig) = object match ap with | ASizeOf t -> ChangeTo (ASizeOfS (typeSigConverter t)) | AAlignOf t -> ChangeTo (AAlignOfS (typeSigConverter t)) + | AAlignOf_C11 t -> ChangeTo (AAlignOfS_C11 (typeSigConverter t)) | _ -> DoChildren end @@ -6160,6 +6301,7 @@ let rec typeSigWithAttrs ?(ignoreSign=false) doattr t = TSFun(typeSig rt, (Util.list_map_opt (fun (_, atype, _) -> (typeSig atype)) args), isva, doattr a) | TNamed(t, a) -> typeSigAddAttrs (doattr a) (typeSig t.ttype) | TBuiltin_va_list al -> TSBase (TBuiltin_va_list (doattr al)) + | TDefault -> TSBase (TDefault) let typeSig t = typeSigWithAttrs (fun al -> al) t @@ -6187,7 +6329,7 @@ let typeSigAttrs = function let dExp: doc -> exp = - fun d -> Const(CStr(sprint ~width:!lineLength d)) + fun d -> Const(CStr(sprint ~width:!lineLength d, No_encoding)) let dInstr: doc -> location -> instr = fun d l -> Asm([], [sprint ~width:!lineLength d], [], [], [], l) @@ -7021,6 +7163,10 @@ let initCIL () = typeOfSizeOf := TInt(!kindOfSizeOf, []); wcharKind := findIkindName !M.theMachine.M.wchar_t; wcharType := TInt(!wcharKind, []); + char16Kind := findIkindName !M.theMachine.M.char16_t; + char16Type := TInt(!char16Kind, []); + char32Kind := findIkindName !M.theMachine.M.char32_t; + char32Type := TInt(!char32Kind, []); char_is_unsigned := !M.theMachine.M.char_is_unsigned; little_endian := !M.theMachine.M.little_endian; underscore_name := !M.theMachine.M.underscore_name; diff --git a/src/cil.mli b/src/cil.mli index 3706634da..e8d5f977d 100644 --- a/src/cil.mli +++ b/src/cil.mli @@ -242,6 +242,7 @@ and typ = | TBuiltin_va_list of attributes (** This is the same as the gcc's type with the same name *) + | TDefault (** There are a number of functions for querying the kind of a type. These are @@ -296,6 +297,8 @@ and fkind = | FComplexFloat (** [float _Complex] *) | FComplexDouble (** [double _Complex] *) | FComplexLongDouble (** [long double _Complex]*) + | FFloat128 (** [__float128] *) + | FComplexFloat128 (** [__complex128] *) (** {b Attributes.} *) @@ -327,6 +330,9 @@ and attrparam = | AAlignOf of typ | AAlignOfE of attrparam | AAlignOfS of typsig + | AAlignOf_C11 of typ (* We differentiate between the C11 _Alignof and the GCC __alignof__ *) + | AAlignOfE_C11 of attrparam + | AAlignOfS_C11 of typsig | AUnOp of unop * attrparam | ABinOp of binop * attrparam * attrparam | ADot of attrparam * string (** a.foo **) @@ -492,6 +498,8 @@ and varinfo = { mutable vinline: bool; (** Whether this varinfo is for an inline function. *) + mutable vthreadlocal: bool; + mutable vdecl: location; (** Location of variable declaration. *) @@ -600,7 +608,9 @@ and exp = (** This corresponds to the GCC __alignof_. Has [unsigned int] type *) | AlignOfE of exp - + | AlignOf_C11 of typ + | AlignOfE_C11 of exp + | UnOp of unop * exp * typ (** Unary operation. Includes the type of the result. *) @@ -631,9 +641,14 @@ and exp = * not sure which one to use. In C this operation is implicit, the * [StartOf] operator is not printed. We have it in CIL because it makes * the typing rules simpler. *) + | Generic of exp * ((typ * exp) list) (** {b Constants.} *) +and wstring_type = | Wchar_t | Char16_t | Char32_t + +and encoding = No_encoding | Utf8 + (** Literal constants *) and constant = | CInt64 of int64 * ikind * string option @@ -642,13 +657,13 @@ and constant = * constant as, for example, 0xF instead of 15.) Use {!Cil.integer} or * {!Cil.kinteger} to create these. Watch out for integers that cannot be * represented on 64 bits. OCAML does not give Overflow exceptions. *) - | CStr of string + | CStr of string * encoding (** String constant. The escape characters inside the string have been * already interpreted. This constant has pointer to character type! The * only case when you would like a string literal to have an array type * is when it is an argument to sizeof. In that case you should use * SizeOfStr. *) - | CWStr of int64 list + | CWStr of int64 list * wstring_type (** Wide character string constant. Note that the local interpretation * of such a literal depends on {!Cil.wcharType} and {!Cil.wcharKind}. * Such a constant has type pointer to {!Cil.wcharType}. The @@ -1344,10 +1359,14 @@ val charType: typ (** char * *) val charPtrType: typ -(** wchar_t (depends on architecture) and is set when you call +(** wchar_t, char16_t and char32_t (depends on architecture) and is set when you call * {!Cil.initCIL}. *) val wcharKind: ikind ref val wcharType: typ ref +val char16Kind: ikind ref +val char16Type: typ ref +val char32Kind: ikind ref +val char32Type: typ ref (** char const * *) val charConstPtrType: typ diff --git a/src/ext/ccl/ccl.ml b/src/ext/ccl/ccl.ml index 861e74799..e637329d7 100644 --- a/src/ext/ccl/ccl.ml +++ b/src/ext/ccl/ccl.ml @@ -1055,7 +1055,7 @@ let rec evaluateExp (e : exp) (state : state) : summary = end; SFacts tFacts end - | Const (CStr s) -> + | Const (CStr (s, _)) -> SFacts (FactSet.singleton ("*", ANT 0)) | Const _ -> begin @@ -1074,12 +1074,15 @@ let rec evaluateExp (e : exp) (state : state) : summary = end; evaluateExp e' state | AlignOf _ - | AlignOfE _ -> SNone + | AlignOfE _ + | AlignOf_C11 _ + | AlignOfE_C11 _ -> SNone | StartOf lv -> evaluateLval lv state | Question _ -> E.s (E.unimp "ternary operator ?:") | AddrOfLabel _ -> E.s (E.unimp "address of label") | Real _ -> E.s (E.unimp "real") | Imag _ -> E.s (E.unimp "imag") + | Generic _ -> E.s (E.unimp "generic") and evaluateLval (lv : lval) (state : state) : summary = match lv with diff --git a/src/ext/cqualann/cqualann.ml b/src/ext/cqualann/cqualann.ml index 23b0cc3ba..36c775a67 100644 --- a/src/ext/cqualann/cqualann.ml +++ b/src/ext/cqualann/cqualann.ml @@ -300,10 +300,10 @@ class stringVisitor method! vexpr e = begin match e with - Const(CStr s) -> + Const(CStr (s, _)) -> (* ignore (E.log "String without cast: %a\n" d_plainexp e); *) ChangeTo(global4String s false) - | CastE(t, Const(CStr s)) -> + | CastE(t, Const(CStr (s, _))) -> let taint = baseTypeContainsSmallocAttribute t in (* ignore (E.log "%stainted String: %a\n" *) (* (if taint then "" else "Un") d_plainexp e); *) diff --git a/src/ext/llvm/llvmgen.ml b/src/ext/llvm/llvmgen.ml index 99c51fed8..aed1d9be3 100644 --- a/src/ext/llvm/llvmgen.ml +++ b/src/ext/llvm/llvmgen.ml @@ -589,8 +589,8 @@ class llvmGeneratorClass : llvmGenerator = object (self) method mkConstant (c:constant) : llvmValue = match c with | CInt64 (i, ik, _) -> LInt (i, ik) - | CStr s -> LGetelementptr [ LGlobal (self#addString s); lzerop; lzerop ] - | CWStr ws -> LGetelementptr [ LGlobal (self#addWString ws); lzerop; lzerop ] + | CStr (s, _) -> LGetelementptr [ LGlobal (self#addString s); lzerop; lzerop ] + | CWStr (ws,_) -> LGetelementptr [ LGlobal (self#addWString ws); lzerop; lzerop ] | CChr c -> LInt (Int64.of_int (Char.code c), IInt) | CReal (f, fk, _) -> LFloat (f, fk) | CEnum (e, _, ei) -> LInt (intConstValue e, ei.ekind) @@ -992,8 +992,8 @@ class llvmGeneratorClass : llvmGenerator = object (self) | SizeOf t -> iExp (sizeOf t) | SizeOfE e -> iExp (sizeOf (typeOf e)) | SizeOfStr s -> ([], LInt (Int64.of_int ((String.length s) + 1), !kindOfSizeOf)) - | AlignOf t -> ([], LInt (Int64.of_int (alignOf_int t), !kindOfSizeOf)) - | AlignOfE e -> ([], LInt (Int64.of_int (alignOf_int (typeOf e)), !kindOfSizeOf)) + | AlignOf t | AlignOf_C11 t-> ([], LInt (Int64.of_int (alignOf_int t), !kindOfSizeOf)) + | AlignOfE e | AlignOfE_C11 e -> ([], LInt (Int64.of_int (alignOf_int (typeOf e)), !kindOfSizeOf)) | Lval lv -> iRLval lv | UnOp (op, e, t) -> iUnop op e t | BinOp (op, e1, e2, t) -> iBinop op e1 e2 t @@ -1004,6 +1004,7 @@ class llvmGeneratorClass : llvmGenerator = object (self) | Real e -> raise (Unimplemented "Real") | AddrOfLabel _ -> raise (Unimplemented "AddrOfLabel") | Question _ -> raise (Unimplemented "Question") + | Generic _ -> raise (Unimplemented "Generic") and iUnop op (e:exp) (t:typ) : llvmInstruction list * llvmValue = let (il,v) = iExp e in diff --git a/src/ext/llvm/llvmutils.ml b/src/ext/llvm/llvmutils.ml index 2a4dec107..ada14577b 100644 --- a/src/ext/llvm/llvmutils.ml +++ b/src/ext/llvm/llvmutils.ml @@ -31,7 +31,6 @@ *) open Cil open Pretty -open List exception Unimplemented of string exception Bug @@ -146,6 +145,8 @@ and gType (t:typ) : doc = match t with | TFloat (FComplexFloat, _) -> text "float" (* TODO: Incorrect *) | TFloat (FComplexDouble, _) -> text "double" (* TODO: Incorrect *) | TFloat (FComplexLongDouble, _) -> text "fp128" (* TODO: Incorrect *) +| TFloat (FFloat128, _) -> text "__float128" (* TODO? *) +| TFloat (FComplexFloat128, _) -> text "__complex128" (* TODO? *) | TPtr (t, _) -> (* LLVM uses "i8 *" for 'void *' *) if isVoidType t then text "i8 *" @@ -159,6 +160,8 @@ and gType (t:typ) : doc = match t with | TComp (ci, _) -> (text "%struct.") ++ (text ci.cname) | TEnum (ei, _) -> dprintf "i%d" (bitsSizeOf t) | TBuiltin_va_list _ -> text "i8 *" +| TDefault -> text "default" (* TODO? *) + (* Convert a CIL type 't' to an LLVM type (as a doc string), for use with dprintf's %a *) and dgType () = gType diff --git a/src/ext/pta/ptranal.ml b/src/ext/pta/ptranal.ml index c9fe907d1..7eda9d3b6 100644 --- a/src/ext/pta/ptranal.ml +++ b/src/ext/pta/ptranal.ml @@ -231,7 +231,7 @@ and analyze_expr_as_lval (e : exp) : A.lvalue = and analyze_expr (e : exp ) : A.tau = let result = match e with - Const (CStr s) -> + Const (CStr (s, _)) -> if !model_strings then A.address (A.make_lvalue false @@ -257,6 +257,9 @@ and analyze_expr (e : exp ) : A.tau = | SizeOfE _ -> A.bottom () | Imag __ -> A.bottom () | Real __ -> A.bottom () + | AlignOf_C11 _ -> A.bottom () + | AlignOfE_C11 _ -> A.bottom () + | Generic (_, _) -> failwith "not implemented yet" in H.add expressions e result; result diff --git a/src/ext/simplify/simplify.ml b/src/ext/simplify/simplify.ml index b022ddda7..ecc057691 100644 --- a/src/ext/simplify/simplify.ml +++ b/src/ext/simplify/simplify.ml @@ -121,7 +121,7 @@ let rec makeThreeAddress * return that temp *) (e: exp) : taExp = match e with - SizeOf _ | SizeOfE _ | AlignOf _ | AlignOfE _ | SizeOfStr _ -> + SizeOf _ | SizeOfE _ | AlignOf _ | AlignOfE _ | SizeOfStr _ | AlignOf_C11 _ | AlignOfE_C11 _ -> constFold true e | Const _ -> e | AddrOf (Var _, NoOffset) -> e @@ -156,6 +156,7 @@ let rec makeThreeAddress | StartOf lv -> makeThreeAddress setTemp (AddrOf (addOffsetLval (Index(zero, NoOffset)) lv)) + | Generic (_, _) -> e (* TODO *) (* Make a basic expression *) and makeBasic (setTemp: taExp -> bExp) (e: exp) : bExp = diff --git a/src/formatparse.mly b/src/formatparse.mly index 34406bb3a..39109a1f4 100644 --- a/src/formatparse.mly +++ b/src/formatparse.mly @@ -560,11 +560,11 @@ constant: | ARG_g { let currentArg = $1 in ((fun args -> match getArg currentArg args with - Fg s -> Const(CStr s) + Fg s -> Const(CStr (s, No_encoding)) | a -> wrongArgType currentArg "string" a), fun e -> match e with - Const(CStr s) -> + Const(CStr (s, _)) -> Some [ Fg s ] | _ -> None) } diff --git a/src/frontc/cabs.ml b/src/frontc/cabs.ml index 04513c27c..a7278c42b 100644 --- a/src/frontc/cabs.ml +++ b/src/frontc/cabs.ml @@ -64,6 +64,7 @@ type typeSpecifier = (* Merge all specifiers into one type *) | Tint128 (* TODO needed? *) | Tfloat | Tfloat128 (* TODO needed? *) + | Tcomplex128 | Tdouble | Tsigned | Tsizet (* used temporarily to translate offsetof() *) @@ -79,12 +80,13 @@ type typeSpecifier = (* Merge all specifiers into one type *) | Tenum of string * enum_item list option * attribute list | TtypeofE of expression (* GCC __typeof__ *) | TtypeofT of specifier * decl_type (* GCC __typeof__ *) + | Tdefault and storage = NO_STORAGE | AUTO | STATIC | EXTERN | REGISTER and funspec = - INLINE | VIRTUAL | EXPLICIT + INLINE | VIRTUAL | EXPLICIT | NORETURN and cvspec = CV_CONST | CV_VOLATILE | CV_RESTRICT | CV_COMPLEX @@ -99,7 +101,9 @@ and spec_elem = | SpecCV of cvspec (* const/volatile *) | SpecAttr of attribute (* __attribute__ *) | SpecStorage of storage + | SpecFun of funspec | SpecInline + | SpecThreadLocal | SpecType of typeSpecifier | SpecPattern of string (* specifier pattern variable *) @@ -275,26 +279,32 @@ and expression = | TYPE_SIZEOF of specifier * decl_type | EXPR_ALIGNOF of expression | TYPE_ALIGNOF of specifier * decl_type + | EXPR_ALIGNOF_C11 of expression + | TYPE_ALIGNOF_C11 of specifier * decl_type | INDEX of expression * expression | MEMBEROF of expression * string | MEMBEROFPTR of expression * string | GNU_BODY of block | EXPR_PATTERN of string (* pattern variable, and name *) + | GENERIC of expression * ((specifier * expression) list) and constant = | CONST_INT of string (* the textual representation *) | CONST_FLOAT of string (* the textual representaton *) | CONST_COMPLEX of string (* the textual representation *) | CONST_CHAR of int64 list - | CONST_WCHAR of int64 list - | CONST_STRING of string - | CONST_WSTRING of int64 list + | CONST_WCHAR of int64 list * wchar_type + | CONST_STRING of string * encoding + | CONST_WSTRING of int64 list * wchar_type (* ww: wstrings are stored as an int64 list at this point because * we might need to feed the wide characters piece-wise into an * array initializer (e.g., wchar_t foo[] = L"E\xabcd";). If that * doesn't happen we will convert it to an (escaped) string before * passing it to Cil. *) +and wchar_type = WCHAR_T | CHAR16_T | CHAR32_T | CHAR | CHAR_UTF8 +and encoding = NO_ENCODING | UTF8 + and init_expression = | NO_INIT | SINGLE_INIT of expression diff --git a/src/frontc/cabs2cil.ml b/src/frontc/cabs2cil.ml index 9eef734ae..29d64a2c4 100644 --- a/src/frontc/cabs2cil.ml +++ b/src/frontc/cabs2cil.ml @@ -546,6 +546,9 @@ let docEnv () = H.iter (fun k d -> acc := (k, d) :: !acc) env; docList ~sep:line (fun (k, d) -> dprintf " %s -> %a" k doone d) () !acc + let rec stripParenLocal e = match e with + | A.PAREN e2 -> stripParenLocal e2 + | _ -> e (* Add a new variable. Do alpha-conversion if necessary *) @@ -603,6 +606,9 @@ let alphaConvertVarAndAddToEnv (addtoenv: bool) (vi: varinfo) : varinfo = addGlobalToEnv vi.vname (EnvVar newvi) else addLocalToEnv vi.vname (EnvVar newvi)); + + (if not vi.vglob && vi.vthreadlocal && vi.vstorage = NoStorage then + E.s (error "Declaration specifiers of %s in block scope include _Thread_local but do not include static or extern" vi.vname); ); (* ignore (E.log " new=%s\n" newvi.vname); *) @@ -669,6 +675,7 @@ let rec stripConstLocalType (t: typ) : typ = let a' = dc a in if a != a' then TVoid a' else t | TBuiltin_va_list a -> let a' = dc a in if a != a' then TBuiltin_va_list a' else t + | TDefault -> t let constFoldTypeVisitor = object (self) @@ -1268,8 +1275,12 @@ let arithmeticConversion (* c.f. ISO 6.3.1.8 *) (t2: typ) : typ = let resultingFType fkind1 t1 fkind2 t2 = (* t1 and t2 are the original types before unrollType, so TNamed is preserved if possible *) - let isComplex f = f = FComplexFloat || f = FComplexDouble || f = FComplexLongDouble in + let isComplex f = f = FComplexFloat || f = FComplexDouble || f = FComplexLongDouble || f = FComplexFloat128 in match fkind1, fkind2 with + | FComplexFloat128, _ -> t1 + | _, FComplexFloat128 -> t2 + | FFloat128, other -> if isComplex other then TFloat(FComplexFloat128, []) else t1 + | other, FFloat128 -> if isComplex other then TFloat(FComplexFloat128, []) else t2 | FComplexLongDouble, _ -> t1 | _, FComplexLongDouble -> t2 | FLongDouble, other -> if isComplex other then TFloat(FComplexLongDouble, []) else t1 @@ -1572,6 +1583,7 @@ let cabsTypeAddAttributes a0 t = | TComp (comp, a) -> TComp (comp, addA0To a) | TNamed (t, a) -> TNamed (t, addA0To a) | TBuiltin_va_list a -> TBuiltin_va_list (addA0To a) + | TDefault -> TDefault end @@ -1829,6 +1841,12 @@ let makeGlobalVarinfo (isadef: bool) (vi: varinfo) : varinfo * bool = (* This may throw an exception Not_found *) let oldvi, oldloc = lookupGlobalVar lookupname in + if oldvi.vthreadlocal <> vi.vthreadlocal then begin + ignore(warn + "_Thread_local appears in a declaration of '%s' but is not present in every declaration. Previous declaration: %a" + vi.vname d_loc oldloc); + oldvi.vthreadlocal <- false; + end; if debug then ignore (E.log " %s already in the env at loc %a\n" vi.vname d_loc oldloc); @@ -2317,9 +2335,10 @@ let rec doSpecList (suggestedAnonName: string) (* This string will be part of (specs: A.spec_elem list) (* Returns the base type, the storage, whether it is inline and the * (unprocessed) attributes *) - : typ * storage * bool * A.attribute list = + : typ * storage * bool * bool * A.attribute list = (* Do one element and collect the type specifiers *) let isinline = ref false in (* If inline appears *) + let isthreadlocal = ref false in (* The storage is placed here *) let storage : storage ref = ref NoStorage in @@ -2331,15 +2350,20 @@ let rec doSpecList (suggestedAnonName: string) (* This string will be part of * collected and processed separately. *) let attrs : A.attribute list ref = ref [] in (* __attribute__, etc. *) let cvattrs : A.cvspec list ref = ref [] in (* const/volatile *) + let funattrs : A.funspec list ref = ref [] in (* _Noreturn *) let doSpecElem (se: A.spec_elem) (acc: A.typeSpecifier list) : A.typeSpecifier list = match se with A.SpecTypedef -> acc - | A.SpecInline -> isinline := true; acc + | A.SpecInline -> isinline := true; acc + | A.SpecThreadLocal -> + if !storage <> NoStorage && !storage <> Extern && !storage <> Static then + E.s (error "Multiple storage specifiers"); + isthreadlocal := true; acc | A.SpecStorage st -> - if !storage <> NoStorage then + if !storage <> NoStorage || !isthreadlocal && st <> STATIC && st <> EXTERN then E.s (error "Multiple storage specifiers"); let sto' = match st with @@ -2353,6 +2377,7 @@ let rec doSpecList (suggestedAnonName: string) (* This string will be part of acc | A.SpecCV cv -> cvattrs := cv :: !cvattrs; acc + | A.SpecFun f -> funattrs := f :: !funattrs; acc | A.SpecAttr a -> attrs := a :: !attrs; acc | A.SpecType ts -> ts :: acc | A.SpecPattern _ -> E.s (E.bug "SpecPattern in cabs2cil input") @@ -2458,9 +2483,11 @@ let rec doSpecList (suggestedAnonName: string) (* This string will be part of | [A.Tdouble] -> TFloat(FDouble, []) | [A.Tlong; A.Tdouble] -> TFloat(FLongDouble, []) - | [A.Tfloat128] -> TFloat(FLongDouble, []) (* TODO: Correct? *) + | [A.Tfloat128] -> TFloat(FFloat128, []) + | [A.Tcomplex128] -> TFloat(FComplexFloat128, []) (* Now the other type specifiers *) + | [A.Tdefault] -> TDefault | [A.Tnamed n] -> begin if n = "__builtin_va_list" && !Machdep.theMachine.Machdep.__builtin_va_list then begin @@ -2622,7 +2649,7 @@ let rec doSpecList (suggestedAnonName: string) (* This string will be part of match e' with StartOf(lv) -> typeOfLval lv (* If this is a string literal, then we treat it as in sizeof*) - | Const (CStr s) -> begin + | Const (CStr (s, _)) -> begin match typeOf e' with TPtr(bt, _) -> (* This is the type of array elements *) TArray(bt, Some (SizeOfStr s), []) @@ -2642,7 +2669,7 @@ let rec doSpecList (suggestedAnonName: string) (* This string will be part of | _ -> E.s (error "Invalid combination of type specifiers") in - bt,!storage,!isinline,List.rev (!attrs @ (convertCVtoAttr !cvattrs)) + bt,!storage,!isinline, !isthreadlocal, List.rev (!attrs @ (convertCVtoAttr !cvattrs) @ (convertFuntoAttr !funattrs)) (* given some cv attributes, convert them into named attributes for * uniform processing *) @@ -2654,12 +2681,20 @@ and convertCVtoAttr (src: A.cvspec list) : A.attribute list = | CV_RESTRICT :: tl -> ("restrict",[]) :: (convertCVtoAttr tl) | CV_COMPLEX :: tl -> ("complex",[]) :: (convertCVtoAttr tl) +and convertFuntoAttr (src: A.funspec list) : A.attribute list = + match src with + | [] -> [] + | NORETURN :: tl -> ("c_noreturn", []) :: (convertFuntoAttr tl) + | INLINE :: tl + | VIRTUAL :: tl + | EXPLICIT :: tl -> [] (* TODO? *) + and makeVarInfoCabs ~(isformal: bool) ~(isglobal: bool) (ldecl : location) - (bt, sto, inline, attrs) + (bt, sto, inline, threadlocal, attrs) (n,ndt,a) : varinfo = let vtype, nattr = @@ -2682,6 +2717,7 @@ and makeVarInfoCabs vi.vstorage <- sto; vi.vattr <- nattr; vi.vdecl <- ldecl; + vi.vthreadlocal <- threadlocal; if false then ignore (E.log "Created varinfo %s : %a\n" vi.vname d_type vi.vtype); @@ -2757,7 +2793,7 @@ and doAttr (a: A.attribute) : attribute list = | _ -> ACons (n', []) with Not_found -> ACons(n', []) end - | A.CONSTANT (A.CONST_STRING s) -> AStr s + | A.CONSTANT (A.CONST_STRING (s, _)) -> AStr s | A.CONSTANT (A.CONST_INT str) -> begin match parseInt str with Const (CInt64 (v64,_,_)) -> @@ -2774,6 +2810,8 @@ and doAttr (a: A.attribute) : attribute list = | A.TYPE_SIZEOF (bt, dt) -> ASizeOf (doOnlyType bt dt) | A.EXPR_ALIGNOF e -> AAlignOfE (ae e) | A.TYPE_ALIGNOF (bt, dt) -> AAlignOf (doOnlyType bt dt) + | A.EXPR_ALIGNOF_C11 e -> AAlignOfE_C11 (ae e) + | A.TYPE_ALIGNOF_C11 (bt, dt) -> AAlignOf_C11 (doOnlyType bt dt) | A.BINARY(A.AND, aa1, aa2) -> ABinOp(LAnd, ae aa1, ae aa2) | A.BINARY(A.OR, aa1, aa2) -> @@ -3110,7 +3148,7 @@ and isVariableSizedArray (dt: A.decl_type): (A.decl_type * chunk * exp list) opt None and doOnlyType (specs: A.spec_elem list) (dt: A.decl_type) : typ = - let bt',sto,inl,attrs = doSpecList "" specs in + let bt',sto,inl,thrl,attrs = doSpecList "" specs in if sto <> NoStorage || inl then E.s (error "Storage or inline specifier in type only"); let tres, nattr = doType AttrType bt' (A.PARENTYPE(attrs, dt, [])) in @@ -3137,7 +3175,7 @@ and makeCompType (isstruct: bool) [] -> "" | ((n, _, _, _), _) :: _ -> n in - let bt, sto, inl, attrs = doSpecList sugg s in + let bt, sto, inl, thrl, attrs = doSpecList sugg s in (* Do the fields *) let makeFieldInfo (((n,ndt,a,cloc) : A.name), (widtho : A.expression option)) @@ -3361,7 +3399,7 @@ and doExp (asconst: bool) (* This expression is used as a constant *) | A.PAREN e -> E.s (bug "stripParen") | A.NOTHING when what = ADrop -> finishExp empty (integer 0) intType | A.NOTHING -> - let res = Const(CStr "exp_nothing") in + let res = Const(CStr ("exp_nothing", No_encoding)) in finishExp empty res (typeOf res) (* Do the potential lvalues first *) @@ -3526,11 +3564,16 @@ and doExp (asconst: bool) (* This expression is used as a constant *) (TPtr(wchar_t, [])) *) - | A.CONST_WSTRING (ws: int64 list) -> - let res = Const(CWStr ((* intlist_to_wstring *) ws)) in + | A.CONST_WSTRING (ws, wst) -> + let cil_wst = + match wst with + WCHAR_T -> Wchar_t | CHAR16_T -> Char16_t | CHAR32_T -> Char32_t + | _ -> E.s ("Error in CONST_WSTRING: Not a wchar type"); + in + let res = Const(CWStr ((* intlist_to_wstring *) ws, cil_wst)) in finishExp empty res (typeOf res) - | A.CONST_STRING s -> + | A.CONST_STRING (s, enc) -> (* Maybe we burried __FUNCTION__ in there *) let s' = try @@ -3547,14 +3590,15 @@ and doExp (asconst: bool) (* This expression is used as a constant *) s with Not_found -> s in - let res = Const(CStr s') in + let enc' = match enc with NO_ENCODING -> No_encoding | UTF8 -> Utf8 in + let res = Const(CStr (s', enc')) in finishExp empty res (typeOf res) | A.CONST_CHAR char_list -> let a, b = (interpret_character_constant char_list) in finishExp empty (Const a) b - | A.CONST_WCHAR char_list -> + | A.CONST_WCHAR (char_list, wct) -> (* matth: I can't see a reason for a list of more than one char * here, since the kinteger64 below will take only the lower 16 * bits of value. ('abc' makes sense, because CHAR constants have @@ -3562,10 +3606,17 @@ and doExp (asconst: bool) (* This expression is used as a constant *) * the value. But L'abc' has type wchar, and so is equivalent to * L'c'). But gcc allows L'abc', so I'll leave this here in case * I'm missing some architecture dependent behavior. *) - let value = reduce_multichar !wcharType char_list in - let result = kinteger64 !wcharKind value in - finishExp empty result (typeOf result) + let wcType, wcKind = match wct with + | WCHAR_T -> !wcharType, !wcharKind + | CHAR16_T -> !char16Type, !char16Kind + | CHAR32_T -> !char32Type, !char32Kind + | _ -> E.s ("Error in CONST_WCHAR: not a wchar type"); + in + let value = reduce_multichar wcType char_list in + let result = kinteger64 !wcharKind value in + finishExp empty result (typeOf result) + | A.CONST_FLOAT str -> begin (* Maybe it ends in U or UL. Strip those *) let l = String.length str in @@ -3576,10 +3627,12 @@ and doExp (asconst: bool) (* This expression is used as a constant *) String.sub str 0 (l - 1), FFloat else if hasSuffix str "D" then String.sub str 0 (l - 1), FDouble + else if hasSuffix str "Q" then + String.sub str 0 (l - 1), FFloat128 else str, FDouble in - if kind = FLongDouble then + if kind = FLongDouble || kind = FFloat128 then (* We only have 64-bit values in Ocaml *) E.log "treating long double constant %s as double constant at %a.\n" str d_loc !currentLoc; @@ -3592,7 +3645,7 @@ and doExp (asconst: bool) (* This expression is used as a constant *) ignore (E.log "float_of_string %s (%s)\n" str (Printexc.to_string e)); E.hadErrors := true; - let res = Const(CStr "booo CONS_FLOAT") in + let res = Const(CStr ("booo CONS_FLOAT", No_encoding)) in finishExp empty res (typeOf res) end end @@ -3606,6 +3659,8 @@ and doExp (asconst: bool) (* This expression is used as a constant *) String.sub str 0 (l - 2), FComplexFloat else if hasSuffix str "iD" || hasSuffix str "Di" then String.sub str 0 (l - 2), FComplexDouble + else if hasSuffix str "iQ" || hasSuffix str "Qi" then + String.sub str 0 (l - 2), FComplexFloat128 else (* A.CONST_COMPLEX always has the suffix i *) String.sub str 0 (l - 1), FComplexDouble in @@ -3622,7 +3677,7 @@ and doExp (asconst: bool) (* This expression is used as a constant *) ignore (E.log "float_of_string_2 %s (%s)\n" baseint (Printexc.to_string e)); E.hadErrors := true; - let res = Const(CStr "booo CONS_FLOAT") in + let res = Const(CStr ("booo CONS_FLOAT", No_encoding)) in finishExp empty res (typeOf res) end end @@ -3633,10 +3688,10 @@ and doExp (asconst: bool) (* This expression is used as a constant *) finishExp empty (SizeOf(typ)) !typeOfSizeOf (* Intercept the sizeof("string") *) - | A.EXPR_SIZEOF (A.CONSTANT (A.CONST_STRING s)) -> begin + | A.EXPR_SIZEOF (A.CONSTANT (A.CONST_STRING (s, enc))) -> begin (* Process the string first *) - match doExp asconst (A.CONSTANT (A.CONST_STRING s)) (AExp None) with - _, Const(CStr s), _ -> + match doExp asconst (A.CONSTANT (A.CONST_STRING (s, enc))) (AExp None) with + _, Const(CStr (s, enc)), _ -> finishExp empty (SizeOfStr s) !typeOfSizeOf | _ -> E.s (bug "cabs2cil: sizeOfStr") end @@ -3694,10 +3749,12 @@ and doExp (asconst: bool) (* This expression is used as a constant *) match fkind with | FFloat | FDouble - | FLongDouble -> 8 + | FLongDouble + | FFloat128 -> 8 | FComplexFloat | FComplexDouble - | FComplexLongDouble -> 9 + | FComplexLongDouble + | FComplexFloat128 -> 9 end | TEnum _ -> 3 | TPtr _ -> 5 @@ -3730,6 +3787,19 @@ and doExp (asconst: bool) (* This expression is used as a constant *) | _ -> e' in finishExp empty (AlignOfE(e'')) !typeOfSizeOf + | A.TYPE_ALIGNOF_C11 (bt, dt) -> + let typ = doOnlyType bt dt in + finishExp empty (AlignOf_C11(typ)) !typeOfSizeOf + | A.EXPR_ALIGNOF_C11 e -> + let (se, e', t) = doExp false e AExpLeaveArrayFun in + let e'' = + match e' with (* If we are taking the alignof an + * array we must drop the StartOf *) + StartOf(lv) -> Lval(lv) + + | _ -> e' + in + finishExp empty (AlignOfE_C11(e'')) !typeOfSizeOf | A.CAST ((specs, dt), ie) -> let s', dt', ie' = preprocessCast specs dt ie in @@ -3765,8 +3835,8 @@ and doExp (asconst: bool) (* This expression is used as a constant *) if !scopes == [] then begin (* This is a global. Mark the new vars as static *) let spec_res' = - let t, sto, inl, attrs = spec_res in - t, Static, inl, attrs + let t, sto, inl, thrl, attrs = spec_res in + t, Static, inl, thrl, attrs in ignore (createGlobal spec_res' ((newvar, dt', [], cabslu), ie')); @@ -4399,7 +4469,7 @@ and doExp (asconst: bool) (* This expression is used as a constant *) (* if the t we determined here is complex, but the return types of all the fptrs are not, the return *) (* type should not be complex *) let isComplex t = match t with - | TFloat(f, _) -> f = FComplexFloat || f = FComplexDouble || f = FComplexLongDouble + | TFloat(f, _) -> f = FComplexFloat || f = FComplexDouble || f = FComplexLongDouble || f = FComplexFloat128 | _ -> false in if List.for_all (fun x -> not (isComplex x)) retTypes then @@ -4847,6 +4917,31 @@ and doExp (asconst: bool) (* This expression is used as a constant *) | A.EXPR_PATTERN _ -> E.s (E.bug "EXPR_PATTERN in cabs2cil input") + | A.GENERIC (expr, lst) -> + let get_exp (_, e, _) = e in + let exp = get_exp (doExp false (stripParenLocal expr) (AExp None)) in + let cil_list = + let rec make_cil_list cabs_l cil_l = match cabs_l with + | [] -> cil_l + | (s, e) :: rest -> make_cil_list rest (((doOnlyType s JUSTBASE),get_exp (doExp false (stripParenLocal e) (AExp None))) :: cil_l) + in + make_cil_list lst [] + in + let exp_typ = typeOf exp in + let default_typ = ref voidType in + let typ = + let rec get_typ lst = match lst with + | (TDefault, e) :: rest -> default_typ := typeOf e; get_typ rest + | (t, e) :: rest -> if t = exp_typ then typeOf e else get_typ rest + | [] -> + if !default_typ = voidType then + E.s(error "Controlling expression of generic selection is not compatible with any association") + else !default_typ + in + get_typ cil_list + in + finishExp empty (Generic(exp, (cil_list))) typ + with e when continueOnError -> begin (*ignore (E.log "error in doExp (%s)" (Printexc.to_string e));*) E.hadErrors := true; @@ -5183,11 +5278,11 @@ and doInit * string into characters *) | TArray(bt, leno, _), (A.NEXT_INIT, - (A.SINGLE_INIT(A.CONSTANT (A.CONST_STRING s))| + (A.SINGLE_INIT(A.CONSTANT (A.CONST_STRING (s, enc)))| A.COMPOUND_INIT [(A.NEXT_INIT, A.SINGLE_INIT(A.CONSTANT - (A.CONST_STRING s)))])) :: restil + (A.CONST_STRING (s, enc))))])) :: restil when (match unrollType bt with TInt((IChar|IUChar|ISChar), _) -> true | TInt _ -> @@ -5235,11 +5330,11 @@ and doInit * important. *) | TArray(bt, leno, _), (A.NEXT_INIT, - (A.SINGLE_INIT(A.CONSTANT (A.CONST_WSTRING s)) | + (A.SINGLE_INIT(A.CONSTANT (A.CONST_WSTRING (s,_))) | A.COMPOUND_INIT [(A.NEXT_INIT, A.SINGLE_INIT(A.CONSTANT - (A.CONST_WSTRING s)))])) :: restil + (A.CONST_WSTRING (s, _))))])) :: restil when(let bt' = unrollType bt in match bt' with (* compare bt to wchar_t, ignoring signed vs. unsigned *) @@ -5525,7 +5620,7 @@ and doInit (* Create and add to the file (if not already added) a global. Return the * varinfo *) -and createGlobal (specs : (typ * storage * bool * A.attribute list)) +and createGlobal (specs : (typ * storage * bool * bool * A.attribute list)) (((n,ndt,a,cloc), inite) : A.init_name) : varinfo = try if debugGlobal then @@ -5536,6 +5631,7 @@ and createGlobal (specs : (typ * storage * bool * A.attribute list)) (* Add the variable to the environment before doing the initializer * because it might refer to the variable itself *) if isFunctionType vi.vtype then begin + if vi.vthreadlocal then ignore (error "Invalid storage class '_Thread_local' for function %s" vi.vname); if inite != A.NO_INIT then E.s (error "Function declaration with initializer (%s)" vi.vname); @@ -5638,7 +5734,7 @@ and createGlobal (specs : (typ * storage * bool * A.attribute list)) *) (* Must catch the Static local variables. Make them global *) -and createLocal ?allow_var_decl:(allow_var_decl=true) ((_, sto, _, _) as specs) +and createLocal ?allow_var_decl:(allow_var_decl=true) ((_, sto, _, _, _) as specs) ((((n, ndt, a, cloc) : A.name), (inite: A.init_expression)) as init_name) : chunk = @@ -5751,7 +5847,7 @@ and createLocal ?allow_var_decl:(allow_var_decl=true) ((_, sto, _, _) as specs) TArray(_,None, _), _, TArray(_, Some _, _) -> vi.vtype <- et (* Initializing a local array *) | TArray(TInt((IChar|IUChar|ISChar), _) as bt, None, a), - SingleInit(Const(CStr s)), _ -> + SingleInit(Const(CStr (s, enc))), _ -> vi.vtype <- TArray(bt, Some (integer (String.length s + 1)), a) @@ -5808,7 +5904,7 @@ and doDecl (isglobal: bool) : A.definition -> chunk = function let doOneDeclarator (acc: chunk) (name: init_name) = let (n,ndt,a,l),_ = name in if isglobal then begin - let bt,_,_,attrs = spec_res in + let bt,_,_,_,attrs = spec_res in let vtype, nattr = doType (AttrName false) bt (A.PARENTYPE(attrs, ndt, a)) in (match filterAttributes "alias" nattr with @@ -5935,7 +6031,7 @@ and doDecl (isglobal: bool) : A.definition -> chunk = function (* Fix the NAME and the STORAGE *) let _ = - let bt,sto,inl,attrs = doSpecList n specs in + let bt,sto,inl,thrl,attrs = doSpecList n specs in !currentFunctionFDEC.svar.vinline <- inl; let ftyp, funattr = @@ -6050,8 +6146,7 @@ and doDecl (isglobal: bool) : A.definition -> chunk = function end in let fmlocs = (match dt with PROTO(_, fml, _) -> fml | _ -> []) in - let formals = doFormals (argsToList formals_t) fmlocs in - + let formals = doFormals (argsToList formals_t) fmlocs in (* Recreate the type based on the formals. *) let ftype = TFun(returnType, Some (Util.list_map (fun f -> (f.vname, @@ -6214,7 +6309,8 @@ and doDecl (isglobal: bool) : A.definition -> chunk = function | Call (None, Lval (Var e, NoOffset), _, _) -> (* See if this is exit, or if it has the noreturn attribute *) if e.vname = "exit" then false - else if hasAttribute "noreturn" e.vattr then false + else if hasAttribute "noreturn" e.vattr + || hasAttribute "c_noreturn" (match !currentFunctionFDEC.svar.vtype with TFun(_,_,_,attr) -> attr | _ -> []) then false else true | Call _ -> true | Asm _ -> true @@ -6312,8 +6408,8 @@ and doDecl (isglobal: bool) : A.definition -> chunk = function ignore (warn "Body of function %s falls-through and cannot find an appropriate return value" !currentFunctionFDEC.svar.vname); None in - if not (hasAttribute "noreturn" - !currentFunctionFDEC.svar.vattr) then + if not (hasAttribute "noreturn" !currentFunctionFDEC.svar.vattr + || hasAttribute "c_noreturn" (match !currentFunctionFDEC.svar.vtype with TFun(_,_,_,attr) -> attr | _ -> []) ) then !currentFunctionFDEC.sbody.bstmts <- !currentFunctionFDEC.sbody.bstmts @ [mkStmt (Return(retval, endloc))] @@ -6352,7 +6448,7 @@ and doDecl (isglobal: bool) : A.definition -> chunk = function and doTypedef ((specs, nl): A.name_group) = try (* Do the specifiers exactly once *) - let bt, sto, inl, attrs = doSpecList (suggestAnonName nl) specs in + let bt, sto, inl, thrl, attrs = doSpecList (suggestAnonName nl) specs in if sto <> NoStorage || inl then E.s (error "Storage or inline specifier not allowed in typedef"); let createTypedef ((n,ndt,a,loc) : A.name) = @@ -6396,7 +6492,7 @@ and doTypedef ((specs, nl): A.name_group) = and doOnlyTypedef (specs: A.spec_elem list) : unit = try - let bt, sto, inl, attrs = doSpecList "" specs in + let bt, sto, inl, thrl, attrs = doSpecList "" specs in if sto <> NoStorage || inl then E.s (error "Storage or inline specifier not allowed in typedef"); let restyp, nattr = doType AttrType bt (A.PARENTYPE(attrs, @@ -6699,7 +6795,7 @@ and doStatement (s : A.statement) : chunk = (* Make a temporary variable, avoiding generation of VarDecl if possible *) (* as this is unsupported (see below) *) let vchunk = createLocal ~allow_var_decl:false - (!upointType, NoStorage, false, []) + (!upointType, NoStorage, false, false, []) (("__compgoto", A.JUSTBASE, [], loc), A.NO_INIT) in if not (isEmpty vchunk) then @@ -6814,11 +6910,6 @@ and doStatement (s : A.statement) : chunk = consLabel "booo_statement" empty (convLoc (C.get_statementloc s)) false end - -let rec stripParenLocal e = match e with - | A.PAREN e2 -> stripParenLocal e2 - | _ -> e - class stripParenClass : V.cabsVisitor = object (self) inherit V.nopCabsVisitor diff --git a/src/frontc/cabsvisit.ml b/src/frontc/cabsvisit.ml index 460dc3281..cdbb79921 100644 --- a/src/frontc/cabsvisit.ml +++ b/src/frontc/cabsvisit.ml @@ -220,8 +220,9 @@ and childrenTypeSpecifier vis ts = and childrenSpecElem (vis: cabsVisitor) (se: spec_elem) : spec_elem = match se with - SpecTypedef | SpecInline | SpecStorage _ | SpecPattern _ -> se + SpecTypedef | SpecInline | SpecStorage _ | SpecPattern _ | SpecThreadLocal-> se | SpecCV _ -> se (* cop out *) + | SpecFun _ -> se | SpecAttr a -> begin let al' = visitCabsAttribute vis a in match al' with @@ -524,6 +525,13 @@ and childrenExpression vis e = let s' = visitCabsSpecifier vis s in let dt' = visitCabsDeclType vis false dt in if s' != s || dt' != dt then TYPE_ALIGNOF (s' ,dt') else e + | EXPR_ALIGNOF_C11 (e1) -> + let e1' = ve e1 in + if e1' != e1 then EXPR_ALIGNOF_C11 (e1') else e + | TYPE_ALIGNOF_C11 (s, dt) -> + let s' = visitCabsSpecifier vis s in + let dt' = visitCabsDeclType vis false dt in + if s' != s || dt' != dt then TYPE_ALIGNOF_C11 (s' ,dt') else e | INDEX (e1, e2) -> let e1' = ve e1 in let e2' = ve e2 in @@ -538,6 +546,7 @@ and childrenExpression vis e = let b' = visitCabsBlock vis b in if b' != b then GNU_BODY b' else e | EXPR_PATTERN _ -> e + | GENERIC _ -> e (*TODO*) and visitCabsInitExpression vis (ie: init_expression) : init_expression = doVisit vis vis#vinitexpr childrenInitExpression ie diff --git a/src/frontc/clexer.mll b/src/frontc/clexer.mll index 3ba4d55c6..36f11348b 100644 --- a/src/frontc/clexer.mll +++ b/src/frontc/clexer.mll @@ -139,6 +139,7 @@ let init_lexicon _ = ("float", fun loc -> FLOAT loc); ("__float128", fun loc -> FLOAT128 loc); ("_Float128", fun loc -> FLOAT128 loc); + ("__complex128", fun loc -> COMPLEX128 loc); ("double", fun loc -> DOUBLE loc); ("void", fun loc -> VOID loc); ("enum", fun loc -> ENUM loc); @@ -167,6 +168,10 @@ let init_lexicon _ = INLINE loc else IDENT ("_inline", loc)); + ("_Noreturn", fun loc -> NORETURN loc); + ("_Thread_local", fun loc -> THREADLOCAL loc); + ("_Alignof", fun loc -> ALIGNOFC11 loc); + ("_Alignas", fun loc -> ALIGNAS loc); ("__attribute__", fun loc -> ATTRIBUTE loc); ("__attribute", fun loc -> ATTRIBUTE loc); (* @@ -225,6 +230,7 @@ let init_lexicon _ = THREAD loc else IDENT ("__thread", loc)); + ("_Generic", fun loc -> GENERIC loc); ] (* Mark an identifier as a type name. The old mapping is preserved and will @@ -338,6 +344,23 @@ let scan_oct_escape str = done; !the_value +(* For a given Unicode Code-point of type Int64, calculates the UTF-8 representation and returns the bytes + * in a list of 1-4 int64 values in reverse order, such that the first byte is the last element of the list *) +let utf8_representation value = + let generate_bytes n = + let first_byte = + let first_byte_prefix = match n with 1 -> 0L | 2 -> 0xC0L | 3 -> 0xE0L | 4 -> 0xF0L | _ -> E.s(error "error in utf8_representation"); in + Int64.logor first_byte_prefix (Int64.shift_right_logical value (6*(n-1))) + in + let rec generate_one bytes n = + if n = 1 then bytes + else generate_one ((Int64.logor 0x80L (Int64.logand (Int64.shift_right_logical value (6*(n-2))) 0x3FL)) :: bytes) (n-1) + in + generate_one [first_byte] n + in + let num_bytes = if value <= 127L then 1 else if value <= 2047L then 2 else if value <= 65535L then 3 else 4 in + generate_bytes num_bytes + let lex_hex_escape remainder lexbuf = let prefix = scan_hex_escape (Lexing.lexeme lexbuf) in prefix :: remainder lexbuf @@ -351,6 +374,14 @@ let lex_simple_escape remainder lexbuf = let prefix = scan_escape lexchar in prefix :: remainder lexbuf +let lex_universal_escape ischar remainder lexbuf = + let value = scan_hex_escape (Lexing.lexeme lexbuf) in + if ischar then + value :: remainder lexbuf + else + let prefix = utf8_representation value in + List.rev_append prefix (remainder lexbuf) + let lex_unescaped remainder lexbuf = let prefix = Int64.of_int (Char.code (Lexing.lexeme_char lexbuf 0)) in prefix :: remainder lexbuf @@ -434,17 +465,18 @@ let binexponent = ['p' 'P'] ['+' '-']? decdigit+ let hexfloat = hexprefix hexfraction binexponent | hexprefix hexdigit+ binexponent -let floatsuffix = ['f' 'F' 'l' 'L'] +let floatsuffix = ['f' 'F' 'l' 'L' 'q' 'Q'] let floatnum = (decfloat | hexfloat) floatsuffix? let complexnum = (decfloat | hexfloat) ((['i' 'I'] floatsuffix) | (floatsuffix? ['i' 'I'])) - -let ident = (letter|'_'|'$')(letter|decdigit|'_'|'$')* let blank = [' ' '\t' '\012' '\r']+ let escape = '\\' _ let hex_escape = '\\' ['x' 'X'] hexdigit+ let oct_escape = '\\' octdigit octdigit? octdigit? +let hexquad = hexdigit hexdigit hexdigit hexdigit +let universal_escape = '\\' ('u' hexquad | 'U' hexquad hexquad) +let ident = (letter|'_'|'$'|universal_escape)(letter|decdigit|'_'|'$'|universal_escape)* (* Pragmas that are not parsed by CIL. We lex them as PRAGMA_LINE tokens *) let no_parse_pragma = @@ -488,7 +520,9 @@ rule initial = | "_Pragma" { PRAGMA (currentLoc ()) } | '\'' { CST_CHAR (chr lexbuf, currentLoc ())} | "L'" { CST_WCHAR (chr lexbuf, currentLoc ()) } -| '"' { addLexeme lexbuf; (* '"' *) +| "u'" {CST_CHAR16 (chr lexbuf, currentLoc ())} +| "U'" {CST_CHAR32 (chr lexbuf, currentLoc ())} +| '"' { addLexeme lexbuf; (* '"' *) (* matth: BUG: this could be either a regular string or a wide string. * e.g. if it's the "world" in * L"Hello, " "world" @@ -499,12 +533,24 @@ rule initial = raise (InternalError ("str: " ^ Printexc.to_string e))} +| "u8\"" { addLexeme lexbuf; (* '"' *) + try CST_U8STRING (str lexbuf, currentLoc ()) + with e -> + raise (InternalError + ("str: " ^ + Printexc.to_string e))} | "L\"" { (* weimer: wchar_t string literal *) try CST_WSTRING(str lexbuf, currentLoc ()) with e -> raise (InternalError ("wide string: " ^ Printexc.to_string e))} +| "u\"" {try CST_STRING16(str lexbuf, currentLoc ()) + with e -> + raise (InternalError ("wide string: " ^ Printexc.to_string e))} +| "U\"" {try CST_STRING32(str lexbuf, currentLoc ()) + with e -> + raise (InternalError ("wide string: " ^ Printexc.to_string e))} | floatnum {CST_FLOAT (Lexing.lexeme lexbuf, currentLoc ())} | complexnum {CST_COMPLEX (Lexing.lexeme lexbuf, currentLoc ())} | hexnum {CST_INT (Lexing.lexeme lexbuf, currentLoc ())} @@ -668,6 +714,7 @@ and str = parse | hex_escape {addLexeme lexbuf; lex_hex_escape str lexbuf} | oct_escape {addLexeme lexbuf; lex_oct_escape str lexbuf} | escape {addLexeme lexbuf; lex_simple_escape str lexbuf} +| universal_escape {addLexeme lexbuf; lex_universal_escape false str lexbuf} | _ {addLexeme lexbuf; lex_unescaped str lexbuf} and chr = parse @@ -675,6 +722,7 @@ and chr = parse | hex_escape {lex_hex_escape chr lexbuf} | oct_escape {lex_oct_escape chr lexbuf} | escape {lex_simple_escape chr lexbuf} +| universal_escape {lex_universal_escape true chr lexbuf} | _ {lex_unescaped chr lexbuf} and msasm = parse diff --git a/src/frontc/cparser.mly b/src/frontc/cparser.mly index 3da7aba17..d3d2b26b4 100644 --- a/src/frontc/cparser.mly +++ b/src/frontc/cparser.mly @@ -238,12 +238,25 @@ let transformOffsetOf (speclist, dtype) member = let resultExpr = CAST (sizeofType, SINGLE_INIT addrExpr) in resultExpr +let queue_to_int64_list queue = + List.rev (Queue.fold (fun l e -> List.rev_append e l) [] queue) + +let queue_to_string queue = + let buffer = Buffer.create (Queue.length queue) in + Queue.iter + (List.iter + (fun value -> + let char = int64_to_char value in + Buffer.add_char buffer char)) + queue; + Buffer.contents buffer + %} %token IDENT %token QUALIFIER %token CST_CHAR -%token CST_WCHAR +%token CST_WCHAR CST_CHAR16 CST_CHAR32 %token CST_INT %token CST_FLOAT %token CST_COMPLEX @@ -252,11 +265,12 @@ let transformOffsetOf (speclist, dtype) member = /* Each character is its own list element, and the terminating nul is not included in this list. */ %token CST_STRING -%token CST_WSTRING +%token CST_WSTRING CST_STRING16 CST_STRING32 CST_U8STRING %token EOF %token CHAR INT BOOL DOUBLE FLOAT VOID INT64 INT32 -%token INT128 FLOAT128 COMPLEX /* C99 */ +%token INT128 FLOAT128 COMPLEX COMPLEX128 /* C99 */ +%token NORETURN THREADLOCAL GENERIC ALIGNOFC11 /* ALIGNOF is the GCC attribute */ ALIGNAS /* C11 */ %token ENUM STRUCT TYPEDEF UNION %token SIGNED UNSIGNED LONG SHORT %token VOLATILE EXTERN STATIC CONST RESTRICT AUTO REGISTER @@ -326,8 +340,8 @@ let transformOffsetOf (speclist, dtype) member = %left INF SUP INF_EQ SUP_EQ %left INF_INF SUP_SUP %left PLUS MINUS -%left STAR SLASH PERCENT CONST RESTRICT VOLATILE COMPLEX -%right EXCLAM TILDE PLUS_PLUS MINUS_MINUS CAST RPAREN ADDROF SIZEOF ALIGNOF IMAG REAL CLASSIFYTYPE +%left STAR SLASH PERCENT CONST RESTRICT VOLATILE COMPLEX HIDDEN +%right EXCLAM TILDE PLUS_PLUS MINUS_MINUS CAST RPAREN ADDROF SIZEOF ALIGNOF ALIGNOFC11 IMAG REAL CLASSIFYTYPE %left LBRACKET %left DOT ARROW LPAREN LBRACE %right NAMED_TYPE /* We'll use this to handle redefinitions of @@ -344,7 +358,7 @@ let transformOffsetOf (speclist, dtype) member = %type attributes attributes_with_asm asmattr %type statement %type constant -%type string_constant +%type string_constant %type expression %type opt_expression %type init_expression @@ -352,8 +366,8 @@ let transformOffsetOf (speclist, dtype) member = %type paren_comma_expression %type arguments %type bracket_comma_expression -%type string_list -%type wstring_list +/* %type string_list */ +/* %type wstring_list */ %type initializer %type <(Cabs.initwhat * Cabs.init_expression) list> initializer_list @@ -412,11 +426,11 @@ global: | function_def { $1 } /*(* Some C header files ar shared with the C++ compiler and have linkage * specification *)*/ -| EXTERN string_constant declaration { LINKAGE (fst $2, (*handleLoc*) (snd $2), [ $3 ]) } +| EXTERN string_constant declaration { let q,t,l = $2 in LINKAGE (queue_to_string q, (*handleLoc*) l, [ $3 ]) } | EXTERN string_constant LBRACE globals RBRACE - { LINKAGE (fst $2, (*handleLoc*) (snd $2), $4) } + { let q,t,l = $2 in LINKAGE (queue_to_string q, (*handleLoc*) l, $4) } | ASM LPAREN string_constant RPAREN SEMICOLON - { GLOBASM (fst $3, (*handleLoc*) $1) } + { let q,t,l = $3 in GLOBASM (queue_to_string q, (*handleLoc*) $1) } | pragma { $1 } /* (* Old-style function prototype. This should be somewhere else, like in * "declaration". For now we keep it at global scope only because in local @@ -475,8 +489,19 @@ primary_expression: /*(* 6.5.1. *)*/ /*(* Next is Scott's transformer *)*/ | AT_EXPR LPAREN IDENT RPAREN /* expression pattern variable */ { EXPR_PATTERN(fst $3), $1 } +| GENERIC LPAREN assignment_expression COMMA generic_assoc_list RPAREN {GENERIC ((fst $3), $5), $1} ; +/* (specifier, expression) list */ +generic_assoc_list: +| generic_association {[$1]} +| generic_assoc_list COMMA generic_association {$3 :: $1} + +/* specifier, expression */ +generic_association: +| type_name COLON assignment_expression {fst $1, fst $3} +| DEFAULT COLON assignment_expression {[SpecType(Tdefault)], fst $3} + postfix_expression: /*(* 6.5.2 *)*/ | primary_expression { $1 } @@ -538,6 +563,10 @@ unary_expression: /*(* 6.5.3 *)*/ {EXPR_ALIGNOF (fst $2), $1} | ALIGNOF LPAREN type_name RPAREN {let b, d = $3 in TYPE_ALIGNOF (b, d), $1} +| ALIGNOFC11 unary_expression + {EXPR_ALIGNOF_C11 (fst $2), $1} +| ALIGNOFC11 LPAREN type_name RPAREN + {let b, d = $3 in TYPE_ALIGNOF_C11 (b, d), $1} | PLUS cast_expression {UNARY (PLUS, fst $2), $1} | MINUS cast_expression @@ -696,55 +725,91 @@ constant: | CST_FLOAT {CONST_FLOAT (fst $1), snd $1} | CST_COMPLEX {CONST_COMPLEX (fst $1), snd $1} | CST_CHAR {CONST_CHAR (fst $1), snd $1} -| CST_WCHAR {CONST_WCHAR (fst $1), snd $1} -| string_constant {CONST_STRING (fst $1), snd $1} -| wstring_list {CONST_WSTRING (fst $1), snd $1} +| CST_WCHAR {CONST_WCHAR (fst $1, WCHAR_T), snd $1} +| CST_CHAR16 {CONST_WCHAR (fst $1, CHAR16_T), snd $1} +| CST_CHAR32 {CONST_WCHAR (fst $1, CHAR32_T), snd $1} +| string_constant { + let queue, typ, location = $1 in + match typ with + | CHAR -> CONST_STRING (queue_to_string queue, NO_ENCODING), location + | CHAR_UTF8 -> CONST_STRING (queue_to_string queue, UTF8), location + | _ -> CONST_WSTRING (queue_to_int64_list queue, typ), location + } ; -string_constant: -/* Now that we know this constant isn't part of a wstring, convert it - back to a string for easy viewing. */ - string_list { - let queue, location = $1 in - let buffer = Buffer.create (Queue.length queue) in - Queue.iter - (List.iter - (fun value -> - let char = int64_to_char value in - Buffer.add_char buffer char)) - queue; - Buffer.contents buffer, location - } -; one_string_constant: /* Don't concat multiple strings. For asm templates. */ CST_STRING {intlist_to_string (fst $1) } ; -string_list: +string_constant: one_string { + let queue = Queue.create () in + let str, typ, loc = $1 in + Queue.add str queue; + queue, typ, loc + } +| CST_WSTRING { let queue = Queue.create () in Queue.add (fst $1) queue; - queue, snd $1 + queue, WCHAR_T, snd $1 } -| string_list one_string { - Queue.add (fst $2) (fst $1); - $1 +| CST_STRING16 { + let queue = Queue.create () in + Queue.add (fst $1) queue; + queue, CHAR16_T, snd $1 + } +| CST_STRING32 { + let queue = Queue.create () in + Queue.add (fst $1) queue; + queue, CHAR32_T, snd $1 + } +| string_constant one_string { + let queue, typ, loc = $1 in + let str, typ2, _ = $2 in + Queue.add str queue; + if typ2 = CHAR_UTF8 && typ <> CHAR && typ <> CHAR_UTF8 then ( + parse_error "Incompatible string literals"; + raise Parsing.Parse_error) + else + let typ3 = if typ2 = CHAR_UTF8 then CHAR_UTF8 else typ in + queue, typ3, loc + } +| string_constant CST_WSTRING { + let queue, typ, loc = $1 in + Queue.add (fst $2) queue; + if typ <> CHAR && typ <> WCHAR_T then ( + parse_error "Incompatible string literals"; + raise Parsing.Parse_error) + else + queue, WCHAR_T, loc + } +| string_constant CST_STRING16 { + let queue, typ, loc = $1 in + Queue.add (fst $2) queue; + if typ <> CHAR && typ <> CHAR16_T then ( + parse_error "Incompatible string literals"; + raise Parsing.Parse_error) + else + queue, CHAR16_T, loc + } +| string_constant CST_STRING32 { + let queue, typ, loc = $1 in + Queue.add (fst $2) queue; + if typ <> CHAR && typ <> CHAR32_T then ( + parse_error "Incompatible string literals"; + raise Parsing.Parse_error) + else + queue, CHAR32_T, loc } ; -wstring_list: - CST_WSTRING { $1 } -| wstring_list one_string { (fst $1) @ (fst $2), snd $1 } -| wstring_list CST_WSTRING { (fst $1) @ (fst $2), snd $1 } -/* Only the first string in the list needs an L, so L"a" "b" is the same - * as L"ab" or L"a" L"b". */ - one_string: - CST_STRING {$1} + CST_STRING {fst $1, CHAR, snd $1} +| CST_U8STRING {fst $1, CHAR_UTF8, snd $1} | FUNCTION__ {(Cabshelper.explodeStringToInts - !currentFunctionName), $1} + !currentFunctionName), CHAR, $1} | PRETTY_FUNCTION__ {(Cabshelper.explodeStringToInts - !currentFunctionName), $1} + !currentFunctionName), CHAR, $1} ; init_expression: @@ -955,14 +1020,19 @@ decl_spec_list: /* ISO 6.7 */ | STATIC decl_spec_list_opt { SpecStorage STATIC :: $2, $1 } | AUTO decl_spec_list_opt { SpecStorage AUTO :: $2, $1 } | REGISTER decl_spec_list_opt { SpecStorage REGISTER :: $2, $1} +| THREADLOCAL decl_spec_list_opt { SpecThreadLocal :: $2, $1} /* ISO 6.7.2 */ | type_spec decl_spec_list_opt_no_named { SpecType (fst $1) :: $2, snd $1 } /* ISO 6.7.4 */ | INLINE decl_spec_list_opt { SpecInline :: $2, $1 } +| funspec decl_spec_list_opt { (fst $1) :: $2, snd $1 } | cvspec decl_spec_list_opt { (fst $1) :: $2, snd $1 } | attribute_nocv decl_spec_list_opt { SpecAttr (fst $1) :: $2, snd $1 } /* specifier pattern variable (must be last in spec list) */ | AT_SPECIFIER LPAREN IDENT RPAREN { [ SpecPattern(fst $3) ], $1 } + /* ISO 6.7.5 */ +| ALIGNAS unary_expression decl_spec_list_opt { SpecAttr ("alignas", [fst $2]) :: $3, $1 } +| ALIGNAS LPAREN type_name RPAREN decl_spec_list_opt { let (b, d) = $3 in ((SpecAttr ("alignas", [TYPE_ALIGNOF_C11 (b,d)]) :: $5), $1) } ; /* (* In most cases if we see a NAMED_TYPE we must shift it. Thus we declare * NAMED_TYPE to have right associativity *) */ @@ -989,6 +1059,7 @@ type_spec: /* ISO 6.7.2 */ | INT128 { Tint128, $1 } | FLOAT { Tfloat, $1 } | FLOAT128 { Tfloat128, $1 } +| COMPLEX128 { Tcomplex128, $1} | DOUBLE { Tdouble, $1 } /* | COMPLEX FLOAT { Tfloat, $2 } */ /* | COMPLEX FLOAT128{ Tfloat128, $2 } */ @@ -1297,6 +1368,11 @@ cvspec: | COMPLEX { SpecCV(CV_COMPLEX), $1 } ; +/* function specifiers */ +funspec: + NORETURN { SpecFun(NORETURN), $1 } +; + /*** GCC attributes ***/ attributes: /* empty */ { []} @@ -1309,8 +1385,8 @@ attributes_with_asm: /* empty */ { [] } | attribute attributes_with_asm { fst $1 :: $2 } | ASM LPAREN string_constant RPAREN attributes - { ("__asm__", - [CONSTANT(CONST_STRING (fst $3))]) :: $5 } + { let q,t,l = $3 in ("__asm__", + [CONSTANT(CONST_STRING (queue_to_string q, NO_ENCODING))]) :: $5 } ; /* things like __attribute__, but no const/volatile */ @@ -1375,7 +1451,7 @@ primary_attr: | LPAREN attr RPAREN { $2 } | IDENT IDENT { CALL(VARIABLE (fst $1), [VARIABLE (fst $2)]) } | CST_INT { CONSTANT(CONST_INT (fst $1)) } -| string_constant { CONSTANT(CONST_STRING (fst $1)) } +| string_constant { let q,t,l = $1 in CONSTANT(CONST_STRING (queue_to_string q, NO_ENCODING)) } /*(* Const when it appears in * attribute lists, is translated * to aconst *)*/ @@ -1421,6 +1497,8 @@ unary_attr: | ALIGNOF unary_expression {EXPR_ALIGNOF (fst $2) } | ALIGNOF LPAREN type_name RPAREN {let b, d = $3 in TYPE_ALIGNOF (b, d)} +| ALIGNOFC11 unary_expression {EXPR_ALIGNOF_C11 (fst $2) } +| ALIGNOFC11 LPAREN type_name RPAREN {let b, d = $3 in TYPE_ALIGNOF_C11 (b, d)} | PLUS cast_attr {UNARY (PLUS, $2)} | MINUS cast_attr {UNARY (MINUS, $2)} | STAR cast_attr {UNARY (MEMOF, $2)} @@ -1546,8 +1624,8 @@ asmoperandsne: | asmoperandsne COMMA asmoperand { $3 :: $1 } ; asmoperand: - asmopname string_constant LPAREN expression RPAREN { ($1, fst $2, fst $4) } -| asmopname string_constant LPAREN error RPAREN { ($1, fst $2, NOTHING ) } + asmopname string_constant LPAREN expression RPAREN { let q,t,l = $2 in ($1, queue_to_string q, fst $4) } +| asmopname string_constant LPAREN error RPAREN { let q,t,l = $2 in ($1, queue_to_string q, NOTHING ) } ; asminputs: /* empty */ { ([], []) } diff --git a/src/frontc/cprint.ml b/src/frontc/cprint.ml index c47e0ebe8..a22466363 100644 --- a/src/frontc/cprint.ml +++ b/src/frontc/cprint.ml @@ -133,8 +133,9 @@ let print_commas nl fct lst = let print_string (s:string) = print ("\"" ^ escape_string s ^ "\"") -let print_wstring (s: int64 list ) = - print ("L\"" ^ escape_wstring s ^ "\"") +let print_wstring (s: int64 list ) (wst: Cabs.wchar_type) = + let prefix = match wst with WCHAR_T -> "L" | CHAR16_T -> "u" | CHAR32_T -> "U" | _ -> Errormsg.s ("Error in print_wstring: not a wchar type") in + print (prefix ^ "\"" ^ escape_wstring s ^ "\"") (* ** Base Type Printing @@ -152,6 +153,13 @@ let rec print_specifiers (specs: spec_elem list) = | STATIC -> "static" | EXTERN -> "extern" | REGISTER -> "register") + | SpecThreadLocal -> printu "_Thread_local" + | SpecFun sf -> + printu (match sf with + INLINE -> "inline" + | VIRTUAL -> "virtual" + | EXPLICIT -> "explicit" + | NORETURN -> "_Noreturn") | SpecCV cv -> printu (match cv with | CV_CONST -> "const" @@ -177,6 +185,7 @@ and print_type_spec = function | Tint128 -> print "__int128 " | Tfloat -> print "float " | Tfloat128 -> print "__float128" + | Tcomplex128 -> print "__complex128" | Tdouble -> print "double " | Tsigned -> printu "signed" | Tunsigned -> print "unsigned " @@ -196,6 +205,7 @@ and print_type_spec = function (print_enum_items enum_items) | TtypeofE e -> printl ["__typeof__";"("]; print_expression e; print ") " | TtypeofT (s,d) -> printl ["__typeof__";"("]; print_onlytype (s, d); print ") " + | Tdefault -> print "default " (* print "struct foo", but with specified keyword and a list of @@ -403,6 +413,9 @@ and get_operator exp = | TYPE_SIZEOF _ -> ("", 16) | EXPR_ALIGNOF exp -> ("", 16) | TYPE_ALIGNOF _ -> ("", 16) + | EXPR_ALIGNOF_C11 exp -> ("", 16) + | TYPE_ALIGNOF_C11 _ -> ("", 16) + | GENERIC _ -> ("", 16) | IMAG exp -> ("", 16) | REAL exp -> ("", 16) | CLASSIFYTYPE exp -> ("", 16) @@ -517,9 +530,11 @@ and print_expression_level (lvl: int) (exp : expression) = | CONST_FLOAT r -> print r | CONST_COMPLEX r -> print r | CONST_CHAR c -> print ("'" ^ escape_wstring c ^ "'") - | CONST_WCHAR c -> print ("L'" ^ escape_wstring c ^ "'") - | CONST_STRING s -> print_string s - | CONST_WSTRING ws -> print_wstring ws) + | CONST_WCHAR (c, wct) -> + let prefix = match wct with WCHAR_T -> "L'" | CHAR16_T -> "u'" | CHAR32_T -> "U'" | CHAR_UTF8 -> "u8'" | CHAR -> "" in + print (prefix ^ escape_wstring c ^ "'") + | CONST_STRING (s, enc) -> print_string s + | CONST_WSTRING (ws, wst) -> print_wstring ws wst) | VARIABLE name -> comprint "variable"; print name @@ -538,6 +553,28 @@ and print_expression_level (lvl: int) (exp : expression) = printl ["__alignof__";"("]; print_onlytype (bt, dt); print ")" + | EXPR_ALIGNOF_C11 exp -> + printl ["_Alignof";"("]; + print_expression_level 0 exp; + print ")" + | TYPE_ALIGNOF_C11 (bt,dt) -> + printl ["_Alignof";"("]; + print_onlytype (bt, dt); + print ")" + | GENERIC (exp, lst) -> + let print_generic_list l = + match l with + [] -> () + | (s, e) :: tl -> + print ", "; + print_onlytype (s, JUSTBASE); + print ": "; + print_expression_level 0 e; + in + printl ["_Generic";"("]; + print_expression_level 0 exp; + print_generic_list lst; + print ")" | IMAG exp -> printl ["__imag__";"("]; print_expression_level 0 exp; diff --git a/src/machdep-ml.c.in b/src/machdep-ml.c.in index 2fb691d45..1e7d344e8 100644 --- a/src/machdep-ml.c.in +++ b/src/machdep-ml.c.in @@ -54,6 +54,12 @@ typedef int bool; #endif +#ifdef HAVE_QUADMATH_H +#include +#else +typedef long double _Complex __complex128; +#endif + #ifdef HAVE_INTTYPES_H #include #endif @@ -101,8 +107,8 @@ int main(int argc, char **argv) { int env = argc == 2 && !strcmp(argv[1], "--env"); int alignof_short, alignof_int, alignof_long, alignof_ptr, alignof_enum, - alignof_float, alignof_double, alignof_longdouble, - alignof_floatcomplex, alignof_doublecomplex, alignof_longdoublecomplex, + alignof_float, alignof_double, alignof_longdouble, alignof_float128, + alignof_floatcomplex, alignof_doublecomplex, alignof_longdoublecomplex, alignof_complex128, sizeof_fun, alignof_fun, alignof_str, alignof_aligned, alignof_longlong, little_endian, char_is_unsigned, alignof_bool; @@ -195,7 +201,7 @@ int main(int argc, char **argv) long double ld; }; alignof_longdouble = (intptr_t)(&((struct s1*)0)->ld); - } + } // The alignment of a float complex { @@ -224,12 +230,30 @@ int main(int argc, char **argv) alignof_longdoublecomplex = (intptr_t)(&((struct s1*)0)->ld); } + // The alignment of __complex128 + { + struct s1 { + char c; + __complex128 c1; + }; + alignof_complex128 = (intptr_t)(&((struct s1*)0)->c1); + } + alignof_str = __alignof("a string"); alignof_fun = __alignof(main); sizeof_fun = 0; + alignof_float128 = alignof_longdouble; #ifdef __GNUC__ sizeof_fun = sizeof(main); + // The alignment of __float128 + { + struct s1 { + char c; + __float128 f1; + }; + alignof_float128 = (intptr_t)(&((struct s1*)0)->f1); + } #endif // The alignment of anything with __attribute__((aligned)) @@ -260,20 +284,22 @@ int main(int argc, char **argv) { fprintf(stderr, "Generating CIL_MACHINE machine dependency information string (for CIL)\n"); printf("short=%d,%d int=%d,%d long=%d,%d long_long=%d,%d pointer=%d,%d " - "alignof_enum=%d float=%d,%d double=%d,%d long_double=%d,%d float_complex=%d,%d double_complex=%d,%d long_double_complex=%d,%d void=%d " - "bool=%d,%d fun=%d,%d alignof_string=%d max_alignment=%d size_t=%s " - "wchar_t=%s char_signed=%s const_string_literals=%s " + "alignof_enum=%d float=%d,%d double=%d,%d long_double=%d,%d float128=%d,%d " + "float_complex=%d,%d double_complex=%d,%d long_double_complex=%d,%d complex128=%d,%d " + "void=%d bool=%d,%d fun=%d,%d alignof_string=%d max_alignment=%d size_t=%s " + "wchar_t=%s char16_t=%s char32_t=%s char_signed=%s const_string_literals=%s " "big_endian=%s __thread_is_keyword=%s __builtin_va_list=%s " "underscore_name=%s\n", (int)sizeof(short), alignof_short, (int)sizeof(int), alignof_int, (int)sizeof(long), alignof_long, (int)sizeof(long long), alignof_longlong, (int)sizeof(int *), alignof_ptr, alignof_enum, (int)sizeof(float), alignof_float, (int)sizeof(double), alignof_double, - (int)sizeof(long double), alignof_longdouble, (int)sizeof(float _Complex), alignof_floatcomplex, (int)sizeof(double _Complex), alignof_doublecomplex, - (int)sizeof(long double _Complex), alignof_longdoublecomplex, (int)sizeof(void), - (int)sizeof(bool), alignof_bool, + (int)sizeof(long double), alignof_longdouble, (int)sizeof(__float128), alignof_float128, + (int)sizeof(float _Complex), alignof_floatcomplex, (int)sizeof(double _Complex), alignof_doublecomplex, + (int)sizeof(long double _Complex), alignof_longdoublecomplex, (int)sizeof(__complex128), alignof_complex128, + (int)sizeof(void), (int)sizeof(bool), alignof_bool, sizeof_fun, alignof_fun, alignof_str, alignof_aligned, - underscore(TYPE_SIZE_T), underscore(TYPE_WCHAR_T), + underscore(TYPE_SIZE_T), underscore(TYPE_WCHAR_T), underscore(TYPE_CHAR16_T), underscore(TYPE_CHAR32_T), char_is_unsigned ? "false" : "true", CONST_STRING_LITERALS, little_endian ? "false" : "true", THREAD_IS_KEYWORD, HAVE_BUILTIN_VA_LIST, UNDERSCORE_NAME); @@ -297,13 +323,17 @@ int main(int argc, char **argv) printf("\t sizeof_float = %d;\n", (int)sizeof(float)); printf("\t sizeof_double = %d;\n", (int)sizeof(double)); printf("\t sizeof_longdouble = %d;\n", (int)sizeof(long double)); + printf("\t sizeof_float128 = %d;\n", (int)sizeof(__float128)); printf("\t sizeof_floatcomplex = %d;\n", (int)sizeof(float _Complex)); printf("\t sizeof_doublecomplex = %d;\n", (int)sizeof(double _Complex)); printf("\t sizeof_longdoublecomplex = %d;\n", (int)sizeof(long double _Complex)); + printf("\t sizeof_complex128 = %d;\n", (int)sizeof(__complex128)); printf("\t sizeof_void = %d;\n", (int)sizeof(void)); printf("\t sizeof_fun = %d;\n", (int)sizeof_fun); printf("\t size_t = \"%s\";\n", TYPE_SIZE_T); printf("\t wchar_t = \"%s\";\n", TYPE_WCHAR_T); + printf("\t char16_t = \"%s\";\n", TYPE_CHAR16_T); + printf("\t char32_t = \"%s\";\n", TYPE_CHAR32_T); printf("\t alignof_short = %d;\n", alignof_short); printf("\t alignof_int = %d;\n", alignof_int); printf("\t alignof_bool = %d;\n", alignof_bool); @@ -314,9 +344,11 @@ int main(int argc, char **argv) printf("\t alignof_float = %d;\n", alignof_float); printf("\t alignof_double = %d;\n", alignof_double); printf("\t alignof_longdouble = %d;\n", alignof_longdouble); + printf("\t alignof_float128 = %d;\n", alignof_float128); printf("\t alignof_floatcomplex = %d;\n", alignof_floatcomplex); printf("\t alignof_doublecomplex = %d;\n", alignof_doublecomplex); printf("\t alignof_longdoublecomplex = %d;\n", alignof_longdoublecomplex); + printf("\t alignof_complex128 = %d;\n", alignof_complex128); printf("\t alignof_str = %d;\n", alignof_str); printf("\t alignof_fun = %d;\n", alignof_fun); printf("\t alignof_aligned = %d;\n", alignof_aligned); diff --git a/src/machdepenv.ml b/src/machdepenv.ml index 2707946b7..17590eae4 100644 --- a/src/machdepenv.ml +++ b/src/machdepenv.ml @@ -81,6 +81,10 @@ let modelParse (s:string) : mach = alignof_longdouble = getAlignof entries "long_double"; sizeof_longdoublecomplex = getSizeof entries "long_double_complex"; alignof_longdoublecomplex = getAlignof entries "long_double_complex"; + sizeof_float128 = getSizeof entries "float128"; + alignof_float128 = getAlignof entries "float128"; + sizeof_complex128 = getSizeof entries "complex128"; + alignof_complex128 = getAlignof entries "complex128"; sizeof_void = getSizeof entries "void"; sizeof_fun = getSizeof entries "fun"; alignof_fun = getAlignof entries "fun"; @@ -88,6 +92,8 @@ let modelParse (s:string) : mach = alignof_aligned = getInt entries "max_alignment"; size_t = respace (getNthString 0 entries "size_t"); wchar_t = respace (getNthString 0 entries "wchar_t"); + char16_t = respace (getNthString 0 entries "char16_t"); + char32_t = respace (getNthString 0 entries "char32_t"); char_is_unsigned = not (getBool entries "char_signed"); const_string_literals = getBool entries "const_string_literals"; little_endian = not (getBool entries "big_endian"); diff --git a/test/Makefile b/test/Makefile index 41e1e745b..99e386964 100644 --- a/test/Makefile +++ b/test/Makefile @@ -278,7 +278,7 @@ testrun/% : $(SMALL1)/%.ml combine%: $(SMALL1)/combine%_1.c cd $(SMALL1); \ - $(CILLY) $(CFLAGS) -std=gnu90 \ + $(CILLY) $(CFLAGS) -std=gnu90 -fcommon\ $(notdir $(wildcard $(SMALL1)/combine$*_[1-9].c)) \ $(EXEOUT)combine$*.exe cd $(SMALL1); ./combine$*.exe @@ -353,11 +353,11 @@ MYSAFECC := $(CILLY) comb: $(TESTDIR)/small2/comb1.c $(TESTDIR)/small2/comb2.c rm -f $(TESTDIR)/small2/comb.exe cd $(TESTDIR)/small2; \ - $(MYSAFECC) comb1.c $(CONLY) $(OBJOUT) comb1.o; \ - $(MYSAFECC) comb2.c $(CONLY) $(OBJOUT) comb2.o; \ - $(MYSAFECC) comb3.c $(CONLY) $(OBJOUT) comb3.o; \ - $(MYSAFECC) comb4.c $(CONLY) $(OBJOUT) comb4.o; \ - $(MYSAFECC) comb1.o comb2.o comb3.o comb4.o $(EXEOUT)comb.exe + $(MYSAFECC) -fcommon comb1.c $(CONLY) $(OBJOUT) comb1.o; \ + $(MYSAFECC) -fcommon comb2.c $(CONLY) $(OBJOUT) comb2.o; \ + $(MYSAFECC) -fcommon comb3.c $(CONLY) $(OBJOUT) comb3.o; \ + $(MYSAFECC) -fcommon comb4.c $(CONLY) $(OBJOUT) comb4.o; \ + $(MYSAFECC) -fcommon comb1.o comb2.o comb3.o comb4.o $(EXEOUT)comb.exe $(TESTDIR)/small2/comb.exe #call cilly on a .c file, a .i file, a .s file, and a .o file. @@ -368,13 +368,13 @@ mixedcomb: $(TESTDIR)/small2/comb1.c $(TESTDIR)/small2/comb2.c gcc -E -o comb2.i comb2.c; \ gcc -S -o comb3.s comb3.c; \ gcc -c -o comb4.o comb4.c; \ - $(MYSAFECC) comb1.c comb2.i comb3.s comb4.o $(EXEOUT)comb.exe + $(MYSAFECC) -fcommon comb1.c comb2.i comb3.s comb4.o $(EXEOUT)comb.exe $(TESTDIR)/small2/comb.exe # sm: another merger test mergestruct: $(TESTDIR)/small2/mergestruct1.c $(TESTDIR)/small2/mergestruct2.c cd $(TESTDIR)/small2; \ - $(CILLY) mergestruct1.c mergestruct2.c -o mergestruct.exe + $(CILLY) -fcommon mergestruct1.c mergestruct2.c -o mergestruct.exe $(TESTDIR)/small2/mergestruct.exe # sc: this tests for a merger bug in global variables initializations diff --git a/test/testcil.pl b/test/testcil.pl index b53075746..142050e21 100644 --- a/test/testcil.pl +++ b/test/testcil.pl @@ -714,7 +714,6 @@ sub addToGroup { addTest("testrunc99/c99-struct"); addTest("testrunc99/c99-complex"); addTest("testrunc99/c99-universal-character-names"); -addBadComment("testrunc99/c99-universal-character-names", "Universal character names are not yet supported"); addTest("testrunc99/c99-tgmath"); addTest("testrunc99/c99-float-pragma"); addTest("combinec99inline");