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]
Other format: [Raw text]

C/C++ PATCH to smarten up -Wswitch-bool (PR c/66322)


Linus's kind words here <https://lkml.org/lkml/2015/5/27/941> prodded
me to improving the -Wswitch-bool warning.  In particular, this patch
makes the warning not warn when the case values aren't outside bool
range.  But it will still warn about

  switch (boolean)
    {
    case false ... true: ...
    default: ...
    }

That of course means that the warning must be delayed to the point where
all the case labels have been parsed.  Then there are these annoying
differences between C and C++ (type of a comparison), which means some
splay trees fun.  Another problem stems from the fact that case labels
that are outside the range of the original type of the switch controlling
expression are dropped on the floor, so I had to add the OUTSIDE_RANGE_P
flag.  Case ranges are fun as well.

If this patch is approved, I'd like to backport it even to 5 branch after
some time so it's fixed in 5.2.

There's also the possibility to add -Wswitch-bool=2 that would warn every
time the compiler sees a switch with a boolean controlling expr, i.e. do
what we're doing now.  But that would be something for trunk only.

Thoughts?

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2015-06-10  Marek Polacek  <polacek@redhat.com>

	PR c/66322
	* c-common.c (check_case_bounds): Add bool * parameter.  Set
	OUTSIDE_RANGE_P.
	(c_add_case_label): Add bool * parameter.  Pass it down to
	check_case_bounds.
	(c_do_switch_warnings): Add bool parameters.  Implement -Wswitch-bool
	warning here.
	* c-common.h (c_add_case_label, c_do_switch_warnings): Update
	declarations.

	* c-typeck.c (struct c_switch): Add BOOL_COND_P and OUTSIDE_RANGE_P.
	(c_start_case): Set BOOL_COND_P and OUTSIDE_RANGE_P.  Don't warn
	about -Wswitch-bool here.
	(do_case): Update c_add_case_label call.
	(c_finish_case): Update c_do_switch_warnings call.

	* decl.c (struct cp_switch): Add OUTSIDE_RANGE_P.
	(push_switch): Set OUTSIDE_RANGE_P.
	(pop_switch): Update c_do_switch_warnings call.
	(finish_case_label): Update c_add_case_label call.
	* semantics.c (finish_switch_cond): Don't warn about -Wswitch-bool
	here.

	* function.c (stack_protect_epilogue): Remove a cast to int.
	* doc/invoke.texi: Update -Wswitch-bool description.

	* c-c++-common/pr60439.c: Add dg-prune-output and add switch cases.
	* c-c++-common/pr66322.c: New test.
	* g++.dg/eh/scope1.C: Remove dg-warning.

diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index 5903c75..3746de7 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -4012,7 +4012,8 @@ warning about an omitted enumeration code even if there is a
 @item -Wswitch-bool
 @opindex Wswitch-bool
 @opindex Wno-switch-bool
-Warn whenever a @code{switch} statement has an index of boolean type.
+Warn whenever a @code{switch} statement has an index of boolean type
+and the case values are outside the range of a boolean type.
 It is possible to suppress this warning by casting the controlling
 expression to a type other than @code{bool}.  For example:
 @smallexample
diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c
index 5b76567..6f9f056 100644
--- gcc/c-family/c-common.c
+++ gcc/c-family/c-common.c
@@ -312,7 +312,8 @@ struct visibility_flags visibility_options;
 
 static tree c_fully_fold_internal (tree expr, bool, bool *, bool *, bool);
 static tree check_case_value (location_t, tree);
-static bool check_case_bounds (location_t, tree, tree, tree *, tree *);
+static bool check_case_bounds (location_t, tree, tree, tree *, tree *,
+			       bool *);
 
 static tree handle_packed_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *);
@@ -3639,13 +3640,15 @@ check_case_value (location_t loc, tree value)
    bound of the case label, and CASE_HIGH_P is the upper bound or NULL
    if the case is not a case range.
    The caller has to make sure that we are not called with NULL for
-   CASE_LOW_P (i.e. the default case).
+   CASE_LOW_P (i.e. the default case).  OUTSIDE_RANGE_P says whether there
+   was a case value that doesn't fit into the range of the ORIG_TYPE.
    Returns true if the case label is in range of ORIG_TYPE (saturated or
    untouched) or false if the label is out of range.  */
 
 static bool
 check_case_bounds (location_t loc, tree type, tree orig_type,
-		   tree *case_low_p, tree *case_high_p)
+		   tree *case_low_p, tree *case_high_p,
+		   bool *outside_range_p)
 {
   tree min_value, max_value;
   tree case_low = *case_low_p;
@@ -3664,6 +3667,7 @@ check_case_bounds (location_t loc, tree type, tree orig_type,
     {
       warning_at (loc, 0, "case label value is less than minimum value "
 		  "for type");
+      *outside_range_p = true;
       return false;
     }
 
@@ -3672,6 +3676,7 @@ check_case_bounds (location_t loc, tree type, tree orig_type,
       && tree_int_cst_compare (case_high, max_value) > 0)
     {
       warning_at (loc, 0, "case label value exceeds maximum value for type");
+      *outside_range_p = true;
       return false;
     }
 
@@ -3681,6 +3686,7 @@ check_case_bounds (location_t loc, tree type, tree orig_type,
     {
       warning_at (loc, 0, "lower value in case label range"
 		  " less than minimum value for type");
+      *outside_range_p = true;
       case_low = min_value;
     }
 
@@ -3690,6 +3696,7 @@ check_case_bounds (location_t loc, tree type, tree orig_type,
     {
       warning_at (loc, 0, "upper value in case label range"
 		  " exceeds maximum value for type");
+      *outside_range_p = true;
       case_high = max_value;
     }
 
@@ -6383,13 +6390,14 @@ case_compare (splay_tree_key k1, splay_tree_key k2)
    HIGH_VALUE is NULL_TREE, then case label was declared using the
    usual C/C++ syntax, rather than the GNU case range extension.
    CASES is a tree containing all the case ranges processed so far;
-   COND is the condition for the switch-statement itself.  Returns the
-   CASE_LABEL_EXPR created, or ERROR_MARK_NODE if no CASE_LABEL_EXPR
-   is created.  */
+   COND is the condition for the switch-statement itself.
+   OUTSIDE_RANGE_P says whether there was a case value that doesn't
+   fit into the range of the ORIG_TYPE.  Returns the CASE_LABEL_EXPR
+   created, or ERROR_MARK_NODE if no CASE_LABEL_EXPR is created.  */
 
 tree
 c_add_case_label (location_t loc, splay_tree cases, tree cond, tree orig_type,
-		  tree low_value, tree high_value)
+		  tree low_value, tree high_value, bool *outside_range_p)
 {
   tree type;
   tree label;
@@ -6450,7 +6458,8 @@ c_add_case_label (location_t loc, splay_tree cases, tree cond, tree orig_type,
      don't insert the case label and return NULL_TREE.  */
   if (low_value
       && !check_case_bounds (loc, type, orig_type,
-			     &low_value, high_value ? &high_value : NULL))
+			     &low_value, high_value ? &high_value : NULL,
+			     outside_range_p))
     return NULL_TREE;
 
   /* Look up the LOW_VALUE in the table of case labels we already
@@ -6611,13 +6620,15 @@ match_case_to_enum (splay_tree_node node, void *data)
 
 void
 c_do_switch_warnings (splay_tree cases, location_t switch_location,
-		      tree type, tree cond)
+		      tree type, tree cond, bool bool_cond_p,
+		      bool outside_range_p)
 {
   splay_tree_node default_node;
   splay_tree_node node;
   tree chain;
 
-  if (!warn_switch && !warn_switch_enum && !warn_switch_default)
+  if (!warn_switch && !warn_switch_enum && !warn_switch_default
+      && !warn_switch_bool)
     return;
 
   default_node = splay_tree_lookup (cases, (splay_tree_key) NULL);
@@ -6625,6 +6636,52 @@ c_do_switch_warnings (splay_tree cases, location_t switch_location,
     warning_at (switch_location, OPT_Wswitch_default,
 		"switch missing default case");
 
+  /* There are certain cases where -Wswitch-bool warnings aren't
+     desirable, such as
+     switch (boolean)
+       {
+       case true: ...
+       case false: ...
+       }
+     so be careful here.  */
+  if (warn_switch_bool && bool_cond_p)
+    {
+      splay_tree_node min_node;
+      /* If there's a default node, it's also the value with the minimal
+	 key.  So look at the penultimate key (if any).  */
+      if (default_node)
+	min_node = splay_tree_successor (cases, (splay_tree_key) NULL);
+      else
+	min_node = splay_tree_min (cases);
+      tree min = min_node ? (tree) min_node->key : NULL_TREE;
+
+      splay_tree_node max_node = splay_tree_max (cases);
+      /* This might be a case range, so look at the value with the
+	 maximal key and then check CASE_HIGH.  */
+      tree max = max_node ? (tree) max_node->value : NULL_TREE;
+      if (max)
+	max = CASE_HIGH (max) ? CASE_HIGH (max) : CASE_LOW (max);
+
+      /* If there's a case value > 1 or < 0, that is outside bool
+	 range, warn.  */
+      if (outside_range_p
+	  || (max && wi::gts_p (max, 1))
+	  || (min && wi::lts_p (min, 0))
+	  /* And handle the
+	     switch (boolean)
+	       {
+	       case true: ...
+	       case false: ...
+	       default: ...
+	       }
+	     case, where we want to warn.  */
+	  || (default_node
+	      && max && wi::eq_p (max, 1)
+	      && min && wi::eq_p (min, 0)))
+	warning_at (switch_location, OPT_Wswitch_bool,
+		    "switch condition has boolean value");
+    }
+
   /* From here on, we only care about about enumerated types.  */
   if (!type || TREE_CODE (type) != ENUMERAL_TYPE)
     return;
diff --git gcc/c-family/c-common.h gcc/c-family/c-common.h
index 7ba81c4..3578929 100644
--- gcc/c-family/c-common.h
+++ gcc/c-family/c-common.h
@@ -947,9 +947,11 @@ extern tree boolean_increment (enum tree_code, tree);
 
 extern int case_compare (splay_tree_key, splay_tree_key);
 
-extern tree c_add_case_label (location_t, splay_tree, tree, tree, tree, tree);
+extern tree c_add_case_label (location_t, splay_tree, tree, tree, tree, tree,
+			      bool *);
 
-extern void c_do_switch_warnings (splay_tree, location_t, tree, tree);
+extern void c_do_switch_warnings (splay_tree, location_t, tree, tree, bool,
+				  bool);
 
 extern tree build_function_call (location_t, tree, tree);
 
diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index 636e0bb..04a50c7 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -9529,6 +9529,14 @@ struct c_switch {
 
   /* The next node on the stack.  */
   struct c_switch *next;
+
+  /* Remember whether the controlling expression had boolean type
+     before integer promotions for the sake of -Wswitch-bool.  */
+  bool bool_cond_p;
+
+  /* Remember whether there was a case value that is outside the
+     range of the ORIG_TYPE.  */
+  bool outside_range_p;
 };
 
 /* A stack of the currently active switch statements.  The innermost
@@ -9542,7 +9550,7 @@ struct c_switch *c_switch_stack;
 /* Start a C switch statement, testing expression EXP.  Return the new
    SWITCH_EXPR.  SWITCH_LOC is the location of the `switch'.
    SWITCH_COND_LOC is the location of the switch's condition.
-   EXPLICIT_CAST_P is true if the expression EXP has explicit cast.  */
+   EXPLICIT_CAST_P is true if the expression EXP has an explicit cast.  */
 
 tree
 c_start_case (location_t switch_loc,
@@ -9550,6 +9558,7 @@ c_start_case (location_t switch_loc,
 	      tree exp, bool explicit_cast_p)
 {
   tree orig_type = error_mark_node;
+  bool bool_cond_p = false;
   struct c_switch *cs;
 
   if (exp != error_mark_node)
@@ -9579,8 +9588,7 @@ c_start_case (location_t switch_loc,
 	      /* Explicit cast to int suppresses this warning.  */
 	      && !(TREE_CODE (type) == INTEGER_TYPE
 		   && explicit_cast_p))
-	    warning_at (switch_cond_loc, OPT_Wswitch_bool,
-			"switch condition has boolean value");
+	    bool_cond_p = true;
 
 	  if (!in_system_header_at (input_location)
 	      && (type == long_integer_type_node
@@ -9604,6 +9612,8 @@ c_start_case (location_t switch_loc,
   cs->orig_type = orig_type;
   cs->cases = splay_tree_new (case_compare, NULL, NULL);
   cs->bindings = c_get_switch_bindings ();
+  cs->bool_cond_p = bool_cond_p;
+  cs->outside_range_p = false;
   cs->next = c_switch_stack;
   c_switch_stack = cs;
 
@@ -9650,7 +9660,8 @@ do_case (location_t loc, tree low_value, tree high_value)
   label = c_add_case_label (loc, c_switch_stack->cases,
 			    SWITCH_COND (c_switch_stack->switch_expr),
 			    c_switch_stack->orig_type,
-			    low_value, high_value);
+			    low_value, high_value,
+			    &c_switch_stack->outside_range_p);
   if (label == error_mark_node)
     label = NULL_TREE;
   return label;
@@ -9671,7 +9682,8 @@ c_finish_case (tree body, tree type)
   switch_location = EXPR_LOCATION (cs->switch_expr);
   c_do_switch_warnings (cs->cases, switch_location,
 			type ? type : TREE_TYPE (cs->switch_expr),
-			SWITCH_COND (cs->switch_expr));
+			SWITCH_COND (cs->switch_expr),
+			cs->bool_cond_p, cs->outside_range_p);
 
   /* Pop the stack.  */
   c_switch_stack = cs->next;
diff --git gcc/cp/decl.c gcc/cp/decl.c
index 3bed538..c7b27ff 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -3212,6 +3212,9 @@ struct cp_switch
      label.  We need a tree, rather than simply a hash table, because
      of the GNU case range extension.  */
   splay_tree cases;
+  /* Remember whether there was a case value that is outside the
+     range of the original type of the controlling expression.  */
+  bool outside_range_p;
 };
 
 /* A stack of the currently active switch statements.  The innermost
@@ -3233,6 +3236,7 @@ push_switch (tree switch_stmt)
   p->next = switch_stack;
   p->switch_stmt = switch_stmt;
   p->cases = splay_tree_new (case_compare, NULL, NULL);
+  p->outside_range_p = false;
   switch_stack = p;
 }
 
@@ -3244,10 +3248,14 @@ pop_switch (void)
 
   /* Emit warnings as needed.  */
   switch_location = EXPR_LOC_OR_LOC (cs->switch_stmt, input_location);
+  const bool bool_cond_p
+    = (SWITCH_STMT_TYPE (cs->switch_stmt)
+       && TREE_CODE (SWITCH_STMT_TYPE (cs->switch_stmt)) == BOOLEAN_TYPE);
   if (!processing_template_decl)
     c_do_switch_warnings (cs->cases, switch_location,
 			  SWITCH_STMT_TYPE (cs->switch_stmt),
-			  SWITCH_STMT_COND (cs->switch_stmt));
+			  SWITCH_STMT_COND (cs->switch_stmt),
+			  bool_cond_p, cs->outside_range_p);
 
   splay_tree_delete (cs->cases);
   switch_stack = switch_stack->next;
@@ -3312,7 +3320,8 @@ finish_case_label (location_t loc, tree low_value, tree high_value)
   high_value = case_conversion (type, high_value);
 
   r = c_add_case_label (loc, switch_stack->cases, cond, type,
-			low_value, high_value);
+			low_value, high_value,
+			&switch_stack->outside_range_p);
 
   /* After labels, make any new cleanups in the function go into their
      own new (temporary) binding contour.  */
diff --git gcc/cp/semantics.c gcc/cp/semantics.c
index 59ec9047..aa43022 100644
--- gcc/cp/semantics.c
+++ gcc/cp/semantics.c
@@ -1161,11 +1161,6 @@ finish_switch_cond (tree cond, tree switch_stmt)
 	orig_type = TREE_TYPE (cond);
       if (cond != error_mark_node)
 	{
-	  /* Warn if the condition has boolean value.  */
-	  if (TREE_CODE (orig_type) == BOOLEAN_TYPE)
-	    warning_at (input_location, OPT_Wswitch_bool,
-			"switch condition has type bool");
-
 	  /* [stmt.switch]
 
 	     Integral promotions are performed.  */
diff --git gcc/function.c gcc/function.c
index 8baaed7..0b45abf 100644
--- gcc/function.c
+++ gcc/function.c
@@ -4934,7 +4934,7 @@ stack_protect_epilogue (void)
 
   /* Allow the target to compare Y with X without leaking either into
      a register.  */
-  switch ((int) (HAVE_stack_protect_test != 0))
+  switch (HAVE_stack_protect_test != 0)
     {
     case 1:
       tmp = gen_stack_protect_test (x, y, label);
diff --git gcc/testsuite/c-c++-common/pr60439.c gcc/testsuite/c-c++-common/pr60439.c
index 3368a0b..68bd33c 100644
--- gcc/testsuite/c-c++-common/pr60439.c
+++ gcc/testsuite/c-c++-common/pr60439.c
@@ -1,5 +1,6 @@
 /* PR c/60439 */
 /* { dg-do compile } */
+/* { dg-prune-output "case label value exceeds" } */
 
 #ifndef __cplusplus
 # define bool _Bool
@@ -11,18 +12,30 @@ void
 f1 (bool b)
 {
   switch (b) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
 }
 
 void
 f2 (int a, int b)
 {
   switch (a && b) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
   switch ((bool) (a && b)) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
   switch ((a && b) || a) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
   /* No warnings on following.  */
   switch ((int) (a && b))
     break;
@@ -38,35 +51,65 @@ void
 f3 (int a)
 {
   switch (!!a) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
   switch (!a) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
 }
 
 void
 f4 (void)
 {
   switch (foo ()) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
 }
 
 void
 f5 (int a)
 {
   switch (a == 3) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
   switch (a != 3) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
   switch (a > 3) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
   switch (a < 3) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
   switch (a <= 3) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
   switch (a >= 3) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
   switch (foo (), foo (), a >= 42) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
   switch (a == 3, a & 4, a ^ 5, a)
     break;
   switch ((int) (a == 3))
@@ -79,11 +122,20 @@ void
 f6 (bool b)
 {
   switch (b) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
   switch (!b) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
   switch (b++) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
 }
 
 void
@@ -91,7 +143,10 @@ f7 (void)
 {
   bool b;
   switch (b = 1) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 3:
+      break;
+    }
 }
 
 void
@@ -104,5 +159,8 @@ f8 (int i)
   switch ((unsigned int) i)
     break;
   switch ((bool) i) /* { dg-warning "switch condition has" } */
-    break;
+    {
+    case 11:
+      break;
+    }
 }
diff --git gcc/testsuite/c-c++-common/pr66322.c gcc/testsuite/c-c++-common/pr66322.c
index e69de29..eb1e9e4 100644
--- gcc/testsuite/c-c++-common/pr66322.c
+++ gcc/testsuite/c-c++-common/pr66322.c
@@ -0,0 +1,144 @@
+/* PR c/66322 */
+/* { dg-do compile } */
+
+#ifndef __cplusplus
+# define bool _Bool
+# define true 1
+# define false 0
+#endif
+
+void
+nowarn (bool b)
+{
+  switch (b)
+    ;
+
+  switch (b)
+    {
+    case true:
+    case false:
+      break;
+    }
+
+  switch (b)
+    {
+    case true:
+      break;
+    }
+
+  switch (b)
+    {
+    case true:
+    default:
+      break;
+    }
+
+  switch (b)
+    {
+    case false:
+      break;
+    }
+
+  switch (b)
+    {
+    case false:
+    default:
+      break;
+    }
+
+  switch (b)
+    {
+    default:
+      break;
+    }
+
+  switch (b)
+    {
+    case false ... true:
+      break;
+    }
+
+  switch (b)
+    {
+    case 1:
+      switch (b)
+	{
+	case true:
+	default:
+	  break;
+	}
+      default:
+	break;
+    }
+}
+
+void
+warn (bool b)
+{
+  switch (b)  /* { dg-warning "switch condition has" } */
+    {
+    case true:
+    case false:
+    default:
+      break;
+    }
+
+  switch (b)  /* { dg-warning "switch condition has" } */
+    {
+    case false ... true:
+    default:
+      break;
+    }
+}
+
+void
+warn2 (int n)
+{
+  switch (n == 2)  /* { dg-warning "switch condition has" } */
+    {
+    case 0 ... 2: /* { dg-warning "upper value" "" { target c++ } } */
+    default:
+      break;
+    }
+
+  switch (n == 2)  /* { dg-warning "switch condition has" } */
+    {
+    case 1 ... 10: /* { dg-warning "upper value" "" { target c++ } } */
+    default:
+      break;
+    }
+
+  switch (n == 2) /* { dg-warning "switch condition has" } */
+    {
+      case 2: /* { dg-warning "case label" "" { target c++ } } */
+	break;
+    }
+
+  switch (n == 2) /* { dg-warning "switch condition has" } */
+    {
+      case 0:
+      case 1:
+      case -1: /* { dg-warning "case label" "" { target c++ } } */
+	break;
+    }
+
+  switch (n == 2) /* { dg-warning "switch condition has" } */
+    {
+      case -1 ... 1: /* { dg-warning "lower value" "" { target c++ } } */
+	break;
+    }
+
+  switch (n == 2) /* { dg-warning "switch condition has" } */
+    {
+      case -1 ... 0: /* { dg-warning "lower value" "" { target c++ } } */
+      default:
+	break;
+    }
+
+  switch (n == 2) /* { dg-warning "switch condition has" } */
+    {
+      case -10 ... -1: /* { dg-warning "case label" "" { target c++ } } */
+      default:
+	break;
+    }
+}
diff --git gcc/testsuite/g++.dg/eh/scope1.C gcc/testsuite/g++.dg/eh/scope1.C
index 8d553d8..276e0d6 100644
--- gcc/testsuite/g++.dg/eh/scope1.C
+++ gcc/testsuite/g++.dg/eh/scope1.C
@@ -31,7 +31,7 @@ void f3 ()
 
 void f4 ()
 {
-  switch (C br = C()) /* { dg-warning "switch condition has" } */
+  switch (C br = C())
     {
     default:
       abort ();

	Marek


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