This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Patch to add intmax_t support


This patch adds an internal notion of intmax_t and uintmax_t to GCC.
It ignores the problem of when and how GCC should provide <stdint.h>
(as required for conforming freestanding implementations of C99).
Pedantic warnings are added if a `mode' attribute is used to create a
type larger than intmax_t, since such a type cannot be an integer type
within the meaning of C99; the warning for integer constants being too
large for unsigned long is adjusted to compare against long long types
for C99.  (A constant that is too large for a long long type is
allowed to have an extended integer type, but this is not required
even if a suitable type exists.)

This should complete the implementation of C99 format checking.  I
believe the internal defaults for intmax_t agree with glibc.  If some
target uses a different intmax_t (e.g. long long when that is the same
size as long) then as well as the target headers, the testcases will
need adjusting until GCC has a <stdint.h> to cleanly communicate its
type choice to programs.

Note: the default definitions of the various types (SIZE_TYPE,
INTMAX_TYPE, etc.) really belong in a separate header included where
required, but the duplication in this patch follows existing practice.
The tree node initialisation would also best go in a shared function,
but so would that of many of the existing tree nodes that is
duplicated; maybe c_common_nodes_and_builtins is suitable, maybe not,
but this is probably best left to any subsequent work on code sharing
between the C and C++ compilers.

Bootstrapped with no regressions on i686-pc-linux-gnu.  OK to commit?

gcc/ChangeLog:
2000-09-19  Joseph S. Myers  <jsm28@cam.ac.uk>

	* tm.texi (INTMAX_TYPE, UINTMAX_TYPE): Define.
	* c-common.h (enum c_tree_index): Add CTI_INTMAX_TYPE and
	CTI_UINTMAX_TYPE.
	(intmax_type_node, uintmax_type_node): Define.
	* c-common.c (decl_attributes): If pedantic, warn if `mode'
	attributes create a type wider than intmax_t.
	(T_IM, T_UIM): Define properly.
	* c-decl.c (INTMAX_TYPE, UINTMAX_TYPE): Define if not already
	defined.
	(init_decl_processing): Initialize intmax_type_node and
	uintmax_type_node.
	* c-lex.c (lex_number): When pedantic and warning for integer
	constants that are too large, in C99 mode warn for those that have
	a type wider than long long.

gcc/cp/ChangeLog:
2000-09-19  Joseph S. Myers  <jsm28@cam.ac.uk>

	* decl.c (INTMAX_TYPE, UINTMAX_TYPE): Define if not already
	defined.
	(init_decl_processing): Initialize intmax_type_node and
	uintmax_type_node.

gcc/testsuite/ChangeLog:
2000-09-19  Joseph S. Myers  <jsm28@cam.ac.uk>

	* gcc.dg/c99-printf-1.c, gcc.dg/c99-scanf-1.c,
	gcc.dg/c90-printf-2.c, gcc.dg/c90-scanf-2.c: Define intmax_t and
	uintmax_t using <limits.h> to emulate the compiler's internal
	logic.  No longer XFAIL %j tests.

--- tm.texi.orig	Thu Sep  7 23:11:11 2000
+++ tm.texi	Mon Sep 18 22:15:40 2000
@@ -1305,6 +1305,29 @@
 
 If you don't define this macro, the default is @code{"unsigned int"}.
 
+@findex INTMAX_TYPE
+@item INTMAX_TYPE
+A C expression for a string describing the name of the data type that
+can represent any value of any standard or extended signed integer type.
+The typedef name @code{intmax_t} is defined using the contents of the
+string.  See @code{SIZE_TYPE} above for more information.
+
+If you don't define this macro, the default is the first of
+@code{"int"}, @code{"long int"}, or @code{"long long int"} that has as
+much precision as @code{long long int}.
+
+@findex UINTMAX_TYPE
+@item UINTMAX_TYPE
+A C expression for a string describing the name of the data type that
+can represent any value of any standard or extended unsigned integer
+type.  The typedef name @code{uintmax_t} is defined using the contents
+of the string.  See @code{SIZE_TYPE} above for more information.
+
+If you don't define this macro, the default is the first of
+@code{"unsigned int"}, @code{"long unsigned int"}, or @code{"long long
+unsigned int"} that has as much precision as @code{long long unsigned
+int}.
+
 @findex OBJC_INT_SELECTORS
 @item OBJC_INT_SELECTORS
 Define this macro if the type of Objective C selectors should be
--- c-common.h.orig	Sun Sep 17 15:39:57 2000
+++ c-common.h	Mon Sep 18 22:17:37 2000
@@ -119,6 +119,8 @@ enum c_tree_index
     CTI_C_SIZE_TYPE, /* For format checking only.  */
     CTI_SIGNED_SIZE_TYPE, /* For format checking only.  */
     CTI_UNSIGNED_PTRDIFF_TYPE, /* For format checking only.  */
+    CTI_INTMAX_TYPE,
+    CTI_UINTMAX_TYPE,
     CTI_WIDEST_INT_LIT_TYPE,
     CTI_WIDEST_UINT_LIT_TYPE,
 
@@ -161,6 +163,8 @@ enum c_tree_index
 #define c_size_type_node		c_global_trees[CTI_C_SIZE_TYPE]
 #define signed_size_type_node		c_global_trees[CTI_SIGNED_SIZE_TYPE]
 #define unsigned_ptrdiff_type_node	c_global_trees[CTI_UNSIGNED_PTRDIFF_TYPE]
+#define intmax_type_node		c_global_trees[CTI_INTMAX_TYPE]
+#define uintmax_type_node		c_global_trees[CTI_UINTMAX_TYPE]
 #define widest_integer_literal_type_node c_global_trees[CTI_WIDEST_INT_LIT_TYPE]
 #define widest_unsigned_literal_type_node c_global_trees[CTI_WIDEST_UINT_LIT_TYPE]
 
--- c-common.c.orig	Mon Sep 18 16:31:23 2000
+++ c-common.c	Mon Sep 18 22:32:20 2000
@@ -761,6 +761,12 @@ decl_attributes (node, attributes, prefi
 		error ("no data type for mode `%s'", p);
 	      else
 		{
+		  if (TYPE_PRECISION (typefm) > (TREE_UNSIGNED (type)
+						 ? TYPE_PRECISION(uintmax_type_node)
+						 : TYPE_PRECISION(intmax_type_node))
+		      && pedantic)
+		    pedwarn ("type with more precision than %s",
+			     TREE_UNSIGNED (type) ? "uintmax_t" : "intmax_t");
 		  TREE_TYPE (decl) = type = typefm;
 		  DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0;
 		  layout_decl (decl, 0);
@@ -1429,9 +1435,9 @@ static const format_length_info scanf_le
 #define T99_PD	{ STD_C99, "ptrdiff_t", T_PD }
 #define T_UPD   &unsigned_ptrdiff_type_node
 #define T99_UPD	{ STD_C99, "unsigned ptrdiff_t", T_UPD }
-#define T_IM    NULL /* intmax_t not yet implemented.  */
+#define T_IM    &intmax_type_node
 #define T99_IM	{ STD_C99, "intmax_t", T_IM }
-#define T_UIM   NULL /* uintmax_t not yet implemented.  */
+#define T_UIM   &uintmax_type_node
 #define T99_UIM	{ STD_C99, "uintmax_t", T_UIM }
 
 static const format_char_info print_char_table[] =
--- c-decl.c.orig	Sun Sep 17 19:37:05 2000
+++ c-decl.c	Mon Sep 18 22:21:22 2000
@@ -77,6 +77,22 @@ enum decl_context
 #ifndef WINT_TYPE
 #define WINT_TYPE "unsigned int"
 #endif
+
+#ifndef INTMAX_TYPE
+#define INTMAX_TYPE ((INT_TYPE_SIZE == LONG_LONG_TYPE_SIZE)	\
+		     ? "int"					\
+		     : ((LONG_TYPE_SIZE == LONG_LONG_TYPE_SIZE)	\
+			? "long int"				\
+			: "long long int"))
+#endif
+
+#ifndef UINTMAX_TYPE
+#define UINTMAX_TYPE ((INT_TYPE_SIZE == LONG_LONG_TYPE_SIZE)	\
+		     ? "unsigned int"				\
+		     : ((LONG_TYPE_SIZE == LONG_LONG_TYPE_SIZE)	\
+			? "long unsigned int"			\
+			: "long long unsigned int"))
+#endif
 
 /* Do GC.  */
 int ggc_p = 1;
@@ -3075,6 +3091,11 @@ init_decl_processing ()
 
   wint_type_node =
     TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (WINT_TYPE)));
+
+  intmax_type_node =
+    TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (INTMAX_TYPE)));
+  uintmax_type_node =
+    TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (UINTMAX_TYPE)));
 
   boolean_type_node = integer_type_node;
   boolean_true_node = integer_one_node;
--- c-lex.c.orig	Sun Sep 17 15:40:10 2000
+++ c-lex.c	Mon Sep 18 22:50:26 2000
@@ -2279,11 +2279,19 @@ lex_number (str, len)
 	    warning ("width of integer constant may change on other systems with -traditional");
 	}
 
-      if (pedantic && !flag_traditional && !spec_long_long && !warn
-	  && (TYPE_PRECISION (long_integer_type_node) < TYPE_PRECISION (type)))
+      if (pedantic && !flag_traditional && (flag_isoc99 || !spec_long_long)
+	  && !warn
+	  && ((flag_isoc99
+	       ? TYPE_PRECISION (long_long_integer_type_node)
+	       : TYPE_PRECISION (long_integer_type_node)) < TYPE_PRECISION (type)))
 	{
 	  warn = 1;
-	  pedwarn ("integer constant larger than the maximum value of an unsigned long int");
+	  pedwarn ("integer constant larger than the maximum value of %s",
+		   (flag_isoc99
+		    ? (TREE_UNSIGNED (type)
+		       ? "an unsigned long long int"
+		       : "a long long int")
+		    : "an unsigned long int"));
 	}
 
       if (base == 10 && ! spec_unsigned && TREE_UNSIGNED (type))
--- cp/decl.c.orig	Sun Sep 17 15:40:16 2000
+++ cp/decl.c	Mon Sep 18 22:52:49 2000
@@ -83,6 +83,22 @@ int ggc_p = 1;
 #define WCHAR_TYPE "int"
 #endif
 
+#ifndef INTMAX_TYPE
+#define INTMAX_TYPE ((INT_TYPE_SIZE == LONG_LONG_TYPE_SIZE)	\
+		     ? "int"					\
+		     : ((LONG_TYPE_SIZE == LONG_LONG_TYPE_SIZE)	\
+			? "long int"				\
+			: "long long int"))
+#endif
+
+#ifndef UINTMAX_TYPE
+#define UINTMAX_TYPE ((INT_TYPE_SIZE == LONG_LONG_TYPE_SIZE)	\
+		     ? "unsigned int"				\
+		     : ((LONG_TYPE_SIZE == LONG_LONG_TYPE_SIZE)	\
+			? "long unsigned int"			\
+			: "long long unsigned int"))
+#endif
+
 static tree grokparms				PARAMS ((tree, int));
 static const char *redeclaration_error_message	PARAMS ((tree, tree));
 
@@ -6541,6 +6557,11 @@ init_decl_processing ()
   /* This is for wide string constants.  */
   wchar_array_type_node
     = build_array_type (wchar_type_node, array_domain_type);
+
+  intmax_type_node =
+    TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (INTMAX_TYPE)));
+  uintmax_type_node =
+    TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (UINTMAX_TYPE)));
 
   if (flag_vtable_thunks)
     {
--- testsuite/gcc.dg/c99-printf-1.c.orig	Fri Aug 25 21:55:00 2000
+++ testsuite/gcc.dg/c99-printf-1.c	Mon Sep 18 22:37:05 2000
@@ -16,13 +16,24 @@
 typedef __SIZE_TYPE__ signed_size_t;
 #undef unsigned
 
-/* These next definitions are broken.  When GCC has a <stdint.h> and
-   an internal understanding of intmax_t and uintmax_t, they should be
-   replaced by an include of <stdint.h> or by definitions for internal
-   macros or typedefs, and the corresponding xfails removed.
+/* These next definitions are kludges.  When GCC has a <stdint.h> it
+   should be used.
 */
-typedef long long int intmax_t;
-typedef unsigned long long int uintmax_t;
+#include <limits.h>
+#if INT_MAX == LLONG_MAX
+typedef int intmax_t;
+#elif LONG_MAX == LLONG_MAX
+typedef long intmax_t;
+#else
+typedef long long intmax_t;
+#endif
+#if UINT_MAX == ULLONG_MAX
+typedef unsigned int uintmax_t;
+#elif ULONG_MAX == ULLONG_MAX
+typedef unsigned long uintmax_t;
+#else
+typedef unsigned long long uintmax_t;
+#endif
 
 extern int printf (const char *, ...);
 
@@ -82,8 +93,8 @@
   printf ("%llc", i); /* { dg-warning "length" "bad use of %ll" } */
   printf ("%lls", s); /* { dg-warning "length" "bad use of %ll" } */
   printf ("%llp", p); /* { dg-warning "length" "bad use of %ll" } */
-  printf ("%jd%ji%jo%ju%jx%jX", j, j, uj, uj, uj, uj); /* { dg-bogus "length" "bogus %j warning" { xfail *-*-* } } */
-  printf ("%jn", jn); /* { dg-bogus "length" "bogus %j warning" { xfail *-*-* } } */
+  printf ("%jd%ji%jo%ju%jx%jX", j, j, uj, uj, uj, uj); /* { dg-bogus "length" "bogus %j warning" { target *-*-* } } */
+  printf ("%jn", jn); /* { dg-bogus "length" "bogus %j warning" { target *-*-* } } */
   printf ("%jf", d); /* { dg-warning "length" "bad use of %j" } */
   printf ("%jF", d); /* { dg-warning "length" "bad use of %j" } */
   printf ("%je", d); /* { dg-warning "length" "bad use of %j" } */
--- testsuite/gcc.dg/c99-scanf-1.c.orig	Fri Aug 25 21:55:00 2000
+++ testsuite/gcc.dg/c99-scanf-1.c	Mon Sep 18 22:42:14 2000
@@ -18,13 +18,24 @@
 typedef unsigned __PTRDIFF_TYPE__ unsigned_ptrdiff_t;
 #undef signed
 
-/* These next definitions are broken.  When GCC has a <stdint.h> and
-   an internal understanding of intmax_t and uintmax_t, they should be
-   replaced by an include of <stdint.h> or by definitions for internal
-   macros or typedefs, and the corresponding xfails removed.
+/* These next definitions are kludges.  When GCC has a <stdint.h> it
+   should be used.
 */
-typedef long long int intmax_t;
-typedef unsigned long long int uintmax_t;
+#include <limits.h>
+#if INT_MAX == LLONG_MAX
+typedef int intmax_t;
+#elif LONG_MAX == LLONG_MAX
+typedef long intmax_t;
+#else
+typedef long long intmax_t;
+#endif
+#if UINT_MAX == ULLONG_MAX
+typedef unsigned int uintmax_t;
+#elif ULONG_MAX == ULLONG_MAX
+typedef unsigned long uintmax_t;
+#else
+typedef unsigned long long uintmax_t;
+#endif
 
 extern int scanf (const char *, ...);
 
@@ -102,7 +113,7 @@
   scanf ("%ll[ac]", s); /* { dg-warning "length" "bad use of %ll" } */
   scanf ("%llc", s); /* { dg-warning "length" "bad use of %ll" } */
   scanf ("%llp", pp); /* { dg-warning "length" "bad use of %ll" } */
-  scanf ("%jd%ji%jo%ju%jx%jX%jn", jp, jp, ujp, ujp, ujp, ujp, jn); /* { dg-bogus "length" "bogus %j warning" { xfail *-*-* } } */
+  scanf ("%jd%ji%jo%ju%jx%jX%jn", jp, jp, ujp, ujp, ujp, ujp, jn); /* { dg-bogus "length" "bogus %j warning" { target *-*-* } } */
   scanf ("%ja", fp); /* { dg-warning "length" "bad use of %j" } */
   scanf ("%jA", fp); /* { dg-warning "length" "bad use of %j" } */
   scanf ("%je", fp); /* { dg-warning "length" "bad use of %j" } */
--- testsuite/gcc.dg/c90-printf-2.c.orig	Fri Aug 25 21:55:00 2000
+++ testsuite/gcc.dg/c90-printf-2.c	Mon Sep 18 22:38:29 2000
@@ -10,12 +10,17 @@
 
 __extension__ typedef long long int llong;
 
-/* This next definition is broken.  When GCC has a <stdint.h> and
-   an internal understanding of intmax_t, it should be
-   replaced by an include of <stdint.h> or by a definition for internal
-   macros or typedefs.
+/* This next definition is a kludge.  When GCC has a <stdint.h> it
+   should be used.
 */
-__extension__ typedef long long int intmax_t;
+#include <limits.h>
+#if INT_MAX == LLONG_MAX
+typedef int intmax_t;
+#elif LONG_MAX == LLONG_MAX
+typedef long intmax_t;
+#else
+__extension__ typedef long long intmax_t;
+#endif
 
 extern int printf (const char *, ...);
 
--- testsuite/gcc.dg/c90-scanf-2.c.orig	Fri Aug 25 21:55:00 2000
+++ testsuite/gcc.dg/c90-scanf-2.c	Mon Sep 18 22:39:36 2000
@@ -10,12 +10,17 @@
 
 __extension__ typedef long long int llong;
 
-/* This next definition is broken.  When GCC has a <stdint.h> and
-   an internal understanding of intmax_t, it should be
-   replaced by an include of <stdint.h> or by a definition for internal
-   macros or typedefs.
+/* This next definition is a kludge.  When GCC has a <stdint.h> it
+   should be used.
 */
-__extension__ typedef long long int intmax_t;
+#include <limits.h>
+#if INT_MAX == LLONG_MAX
+typedef int intmax_t;
+#elif LONG_MAX == LLONG_MAX
+typedef long intmax_t;
+#else
+__extension__ typedef long long intmax_t;
+#endif
 
 extern int scanf (const char *, ...);
 

-- 
Joseph S. Myers
jsm28@cam.ac.uk


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]