gcc's <stdbool.h> is broken

Zack Weinberg zackw@stanford.edu
Mon Feb 5 12:28:00 GMT 2001


On Mon, Feb 05, 2001 at 07:03:33PM +0000, Joseph S. Myers wrote:
> On Mon, 5 Feb 2001, Bruno Haible wrote:
> 
> > ISO C 99 section 7.16 specifies that the macros 'false' and 'true'
> > shall be usable in preprocessor expressions. But gcc 2.95.2/2.95.3
> > gets this wrong.
> 
> Don't use the 2.95.2/2.95.3 <stdbool.h> - 2.95.2 predates the publication
> of C99, and its <stdbool.h> was based on an old draft (although it doesn't
> conform to the oldest draft I have around - from before the _Bool builtin
> type was added).  The GCC 3.0 release notes clearly note (or will when
> they're written) that the conforming _Bool and <stdbool.h> in 3.0 is not
> binary compatible with the 2.95.2 boolean type (though it is compatible
> with C++ bool in the new ABI).

There is a real bug in this area, though: in C++, after including
stdbool.h, you still can't use 'true' and 'false' in #if.  They are
defined to themselves, and the preprocessor doesn't know the
keywords.

The appended patch makes them acceptable to the preprocessor in C++
mode always.  We pedwarn before stdbool.h is included, because C++98
2.11 does not expect them to work at all in preprocessor expressions.
We don't afterward, because then they are (as if) integer constant
expressions, which is fine.

I'm bootstrapping now.  Is this extension acceptable to the C++ folks?
Should I wait till after the branch?  When is the branch, anyway? :-)

zw

	* cpphash.h (struct spec_nodes): Add n_true and n_false.
	* cppinit.c (cpp_create_reader): Initialize them.
	(append_include_chain): cxx_aware arg might be unused.
	* cppexp.c (lex): In C++ mode, recognize 'true' and 'false'
	keywords and give them their phase 7 meaning.  Pedwarn about
	this unless '__bool_true_false_are_defined' is defined.

	* g++.dg/stdbool-if.C: New test.

===================================================================
Index: cppexp.c
--- cppexp.c	2001/01/28 01:50:05	1.85
+++ cppexp.c	2001/02/05 20:23:46
@@ -413,18 +413,36 @@ lex (pfile, skip_evaluation, token)
 
 	  return parse_defined (pfile);
 	}
-      /* Controlling #if expressions cannot contain identifiers (they
-	 could become macros in the future).  */
-      pfile->mi_state = MI_FAILED;
+      else if (CPP_OPTION (pfile, cplusplus)
+	       && (token->val.node == pfile->spec_nodes.n_true
+		   || token->val.node == pfile->spec_nodes.n_false))
+	{
+	  op.op = CPP_INT;
+	  op.unsignedp = 0;
+	  op.value = (token->val.node == pfile->spec_nodes.n_true);
 
-      op.op = CPP_INT;
-      op.unsignedp = 0;
-      op.value = 0;
+	  /* Warn about use of true or false in #if when pedantic
+	     and stdbool.h has not been included.  */
+	  if (CPP_PEDANTIC (pfile)
+	      && ! cpp_defined (pfile, DSC("__bool_true_false_are_defined")))
+	    cpp_pedwarn (pfile, "ISO C++ does not permit \"%s\" in #if",
+			 token->val.node->name);
+	  return op;
+	}
+      else
+	{
+	  /* Controlling #if expressions cannot contain identifiers (they
+	     could become macros in the future).  */
+	  pfile->mi_state = MI_FAILED;
 
-      if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation)
-	cpp_warning (pfile, "\"%s\" is not defined", token->val.node->name);
+	  op.op = CPP_INT;
+	  op.unsignedp = 0;
+	  op.value = 0;
 
-      return op;
+	  if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation)
+	    cpp_warning (pfile, "\"%s\" is not defined", token->val.node->name);
+	  return op;
+	}
 
     case CPP_HASH:
       {
===================================================================
Index: cpphash.h
--- cpphash.h	2001/02/03 18:21:34	1.96
+++ cpphash.h	2001/02/05 20:23:46
@@ -156,6 +156,8 @@ struct spec_nodes
 {
   cpp_hashnode *n_L;			/* L"str" */
   cpp_hashnode *n_defined;		/* defined operator */
+  cpp_hashnode *n_true;			/* C++ keyword true */
+  cpp_hashnode *n_false;		/* C++ keyword false */
   cpp_hashnode *n__Pragma;		/* _Pragma operator */
   cpp_hashnode *n__STRICT_ANSI__;	/* STDC_0_IN_SYSTEM_HEADERS */
   cpp_hashnode *n__CHAR_UNSIGNED__;	/* plain char is unsigned */
===================================================================
Index: cppinit.c
--- cppinit.c	2001/02/04 08:29:46	1.146
+++ cppinit.c	2001/02/05 20:23:46
@@ -203,7 +203,7 @@ append_include_chain (pfile, dir, path, 
      cpp_reader *pfile;
      char *dir;
      int path;
-     int cxx_aware;
+     int cxx_aware ATTRIBUTE_UNUSED;
 {
   struct cpp_pending *pend = CPP_OPTION (pfile, pending);
   struct file_name_list *new;
@@ -554,6 +554,8 @@ cpp_create_reader (lang)
   s = &pfile->spec_nodes;
   s->n_L                = cpp_lookup (pfile, DSC("L"));
   s->n_defined		= cpp_lookup (pfile, DSC("defined"));
+  s->n_true		= cpp_lookup (pfile, DSC("true"));
+  s->n_false		= cpp_lookup (pfile, DSC("false"));
   s->n__Pragma		= cpp_lookup (pfile, DSC("_Pragma"));
   s->n__STRICT_ANSI__   = cpp_lookup (pfile, DSC("__STRICT_ANSI__"));
   s->n__CHAR_UNSIGNED__ = cpp_lookup (pfile, DSC("__CHAR_UNSIGNED__"));
===================================================================
Index: testsuite/g++.dg/stdbool-if.C
--- testsuite/g++.dg/stdbool-if.C	Tue May  5 13:32:27 1998
+++ testsuite/g++.dg/stdbool-if.C	Mon Feb  5 12:23:46 2001
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options -pedantic } */
+
+/* test of 'true' and 'false' in #if.  this is accepted with a pedwarn
+   before stdbool.h is included, silently afterward.  */
+
+/* Make sure they're viable keywords.  */
+bool a = true;
+bool b = false;
+
+#if true		/* { dg-warning "true" "true in #if pedwarn" } */
+#else
+#error true is false	/* { dg-bogus "true" "true is false" } */
+#endif
+
+#if false		/* { dg-warning "false" "false in #if pedwarn" } */
+#error false is true	/* { dg-bogus "false" "false is true" } */
+#endif
+
+#include <stdbool.h>
+
+/* Must still be viable keywords.  */
+bool c = true;
+bool d = false;
+
+#if true		/* { dg-bogus "true" "true in #if with stdbool.h" } */
+#else
+#error true is false	/* { dg-bogus "true" "true is false" } */
+#endif
+
+#if false		/* { dg-bogus "false" "false in #if with stdbool.h" } */
+#error false is true	/* { dg-bogus "false" "false is true" } */
+#endif


More information about the Gcc-bugs mailing list