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]

Re: [PATCH] take 3: pragma FLOAT_CONST_DECIMAL64 for decimal float support


On Wed, 2009-05-06 at 20:11 +0000, Joseph S. Myers wrote:

Thanks once again for the very quick and valuable review.

> On Wed, 6 May 2009, Janis Johnson wrote:
> 
> > > > Index: gcc/c-cppbuiltin.c
> > > > ===================================================================
> > > > --- gcc/c-cppbuiltin.c	(revision 144896)
> > > > +++ gcc/c-cppbuiltin.c	(working copy)
> > > > @@ -626,7 +626,7 @@ c_cpp_builtins (cpp_reader *pfile)
> > > >    if (flag_single_precision_constant)
> > > >      builtin_define_float_constants ("DBL", "L", "((double)%s)", double_type_node);
> > > >    else
> > > > -    builtin_define_float_constants ("DBL", "", "%s", double_type_node);
> > > > +    builtin_define_float_constants ("DBL", "L", "((double)%s)", double_type_node);
> > > 
> > > The effect of this is to use the new definition unconditionally, in which 
> > > case you should remove the if and insert a comment explaining the use 
> > > cases (-fsingle-precision-constant and this pragma) needing the definition 
> > > as long double and the cast.
> > 
> > Fixed.
> > 
> > The comment says that the cast prevents the predefined macros from being
> > used in const expressions; if that's a problem we might just leave this
> > part out and force code that uses these macros to do so within code
> > blocks that turn off the pragma.
>
> This does not prevent them from being used in constant expressions; the 
> macros of floating-point type are only required to be usable in arithmetic 
> constant expressions, not integer constant expressions, and casts to 
> floating-point type are fine in arithmetic constant expressions.  So 
> remove that claim from the comment.

Done.

> > Index: gcc/c-common.c
> > ===================================================================
> > --- gcc/c-common.c	(revision 147110)
> > +++ gcc/c-common.c	(working copy)
> > @@ -416,6 +416,10 @@ int flag_signed_bitfields = 1;
> >  
> >  int warn_unknown_pragmas; /* Tri state variable.  */
> >  
> > +/* Warn about float constants with suffixes.  */
> > +
> > +int warn_unsuffixed_float_consts;
> 
> Unused variable (the one that is used, warn_unsuffixed_float_constants, 
> has an automatic definition).

Removed.

> > Index: gcc/c-parser.c
> > ===================================================================
> > --- gcc/c-parser.c	(revision 147110)
> > +++ gcc/c-parser.c	(working copy)
> > @@ -979,7 +979,9 @@ c_parser_translation_unit (c_parser *par
> >        do
> >  	{
> >  	  ggc_collect ();
> > +	  mark_valid_location_for_stdc_pragma (true);
> >  	  c_parser_external_declaration (parser);
> > +	  mark_valid_location_for_stdc_pragma (false);
> >  	  obstack_free (&parser_obstack, obstack_position);
> >  	}
> >        while (c_parser_next_token_is_not (parser, CPP_EOF));
> 
> What I think should be done here is marking it an invalid location before 
> c_parser_external_declaration and a valid location after, and just 
> allowing it in c_parser_external_declaration in the specific case that the 
> external declaration is a pragma.  Then you shouldn't need any special 
> code in c_parser_declspecs to mark it invalid there.

Instead, I marked it invalid before the loop; there's no reason to
mark it valid here.  The code that handles pragma in
c_parser_external_declaration now allows it, as you suggested.

> > @@ -3356,6 +3362,7 @@ c_parser_compound_statement_nostart (c_p
> >        c_parser_consume_token (parser);
> >        return;
> >      }
> > +  mark_valid_location_for_stdc_pragma (true);
> >    if (c_parser_next_token_is_keyword (parser, RID_LABEL))
> >      {
> >        location_t err_loc = c_parser_peek_token (parser)->location;
> 
> This looks right.
> 
> > @@ -3409,6 +3416,7 @@ c_parser_compound_statement_nostart (c_p
> >  	    label_loc = c_parser_peek_token (parser)->location;
> >  	  last_label = true;
> >  	  last_stmt = false;
> > +	  mark_valid_location_for_stdc_pragma (false);
> >  	  c_parser_label (parser);
> >  	}
> >        else if (!last_label
> > @@ -3416,6 +3424,7 @@ c_parser_compound_statement_nostart (c_p
> >  	{
> >  	  last_label = false;
> >  	  c_parser_declaration_or_fndef (parser, true, true, true, true);
> > +	  mark_valid_location_for_stdc_pragma (false);
> 
> I'd expect this to go before parsing the declaration, not after (thereby 
> ensuring that the pragma isn't allowed in struct definitions within a 
> function without needing anything in c_parser_declspecs).

Right.

> Don't you also need such calls in the __extension__ case?

Yes, and now there's a check for that in the pragma*-8 test.

> As this is a global flag, you really should be saving and restoring in 
> this function; it looks rather like it might allow
> 
> {
>   {
> #pragma
>   }
> #pragma
> }
> 
> at present because the flag gets cleared in the inner scope and not set 
> again.

Yes, the old value is now saved and restored, except when there's an
error and an early return.  If you want I can restore it in the error
cases as well.  I added this check and several more to pragma*-8.c in
gcc.dg/dfp.

2009-05-07  Janis Johnson  <janis187@us.ibm.com>

gcc/
	PR c/39037
	* c-common.h (mark_valid_location_for_stdc_pragma,
	valid_location_for_stdc_pragma_p, set_float_const_decimal64,
	clear_float_const_decimal64, float_const_decimal64_p): New.
	* c.opt (Wunsuffixed-float-constants): New.
	* c-lex.c (interpret_float): Use pragma FLOAT_CONST_DECIMAL64 for
	unsuffixed float constant, handle new warning.
	* c-cppbuiltin.c (c_cpp_builtins): Use cast for double constants.
	* c-decl.c (c_scope): New flag float_const_decimal64.
	(set_float_const_decimal64, clear_float_const_decimal64,
	float_const_decimal64_p): New.
	(push_scope): Set new flag.
	* c-parser.c (c_parser_translation_unit): Mark when it's valid
	to use STDC pragmas.
	(c_parser_external_declaration): Ditto.
	(c_parser_compound_statement_nostart): Ditto.
	* c-pragma.c (valid_location_for_stdc_pragma,
	mark_valid_location_for_stdc_pragma,
	valid_location_for_stdc_pragma_p, handle_stdc_pragma,
	handle_pragma_float_const_decimal64): New.
	(init_pragma): Register new pragma FLOAT_CONST_DECIMAL64.
	* cp/semantics.c (valid_location_for_stdc_pragma_p,
	set_float_const_decimal64, clear_float_const_decimal64,
	float_const_decimal64_p): New dummy functions.
	* doc/extend.texi (Decimal Float): Remove statement that the
	pragma, and suffix for double constants, are not supported.
	* doc/invoke.texi (Warning Options): List new option.
	(-Wunsuffixed-float-constants): New.

gcc/testsuite
	PR c/39037
	* gcc.dg/Wunsuffixed-float-constants-1.c: New test.
	* gcc.dg/cpp/pragma-float-const-decimal64-1.c: New test.
	* gcc.dg/dfp/float-constant-double.c: New test.
	* gcc.dg/dfp/pragma-float-const-decimal64-1.c: New test.
	* gcc.dg/dfp/pragma-float-const-decimal64-2.c: New test.
	* gcc.dg/dfp/pragma-float-const-decimal64-3.c: New test.
	* gcc.dg/dfp/pragma-float-const-decimal64-4.c: New test.
	* gcc.dg/dfp/pragma-float-const-decimal64-5.c: New test.
	* gcc.dg/dfp/pragma-float-const-decimal64-6.c: New test.
	* gcc.dg/dfp/pragma-float-const-decimal64-7.c: New test.
	* gcc.dg/dfp/pragma-float-const-decimal64-8.c: New test.
	* g++.dg/cpp/pragma-float-const-decimal64-1.C: New test.

Index: gcc/c-common.h
===================================================================
--- gcc/c-common.h	(revision 147209)
+++ gcc/c-common.h	(working copy)
@@ -809,6 +809,11 @@ extern void warn_logical_operator (locat
 extern void check_main_parameter_types (tree decl);
 extern bool c_determine_visibility (tree);
 extern bool same_scalar_type_ignoring_signedness (tree, tree);
+extern void mark_valid_location_for_stdc_pragma (bool);
+extern bool valid_location_for_stdc_pragma_p (void);
+extern void set_float_const_decimal64 (void);
+extern void clear_float_const_decimal64 (void);
+extern bool float_const_decimal64_p (void);
 
 #define c_sizeof(T)  c_sizeof_or_alignof_type (T, true, 1)
 #define c_alignof(T) c_sizeof_or_alignof_type (T, false, 1)
Index: gcc/c.opt
===================================================================
--- gcc/c.opt	(revision 147209)
+++ gcc/c.opt	(working copy)
@@ -476,6 +476,10 @@ Wunknown-pragmas
 C ObjC C++ ObjC++ Warning
 Warn about unrecognized pragmas
 
+Wunsuffixed-float-constants
+C ObjC Var(warn_unsuffixed_float_constants) Warning
+Warn about unsuffixed float constants
+
 Wunused-macros
 C ObjC C++ ObjC++ Warning
 Warn about macros defined in the main file that are not used
Index: gcc/c-lex.c
===================================================================
--- gcc/c-lex.c	(revision 147209)
+++ gcc/c-lex.c	(working copy)
@@ -617,11 +617,21 @@ interpret_float (const cpp_token *token,
   char *copy;
   size_t copylen;
 
-  /* Default (no suffix) is double.  */
+  /* Default (no suffix) depends on whether the FLOAT_CONST_DECIMAL64
+     pragma has been used and is either double or _Decimal64.  Types
+     that are not allowed with decimal float default to double.  */
   if (flags & CPP_N_DEFAULT)
     {
       flags ^= CPP_N_DEFAULT;
       flags |= CPP_N_MEDIUM;
+
+      if (((flags & CPP_N_HEX) == 0) && ((flags & CPP_N_IMAGINARY) == 0))
+	{
+	  warning (OPT_Wunsuffixed_float_constants,
+		   "unsuffixed float constant");
+	  if (float_const_decimal64_p ())
+	    flags |= CPP_N_DFLOAT;
+	}
     }
 
   /* Decode _Fract and _Accum.  */
Index: gcc/c-cppbuiltin.c
===================================================================
--- gcc/c-cppbuiltin.c	(revision 147209)
+++ gcc/c-cppbuiltin.c	(working copy)
@@ -619,14 +619,11 @@ c_cpp_builtins (cpp_reader *pfile)
                                  TARGET_DEC_EVAL_METHOD);
 
   builtin_define_float_constants ("FLT", "F", "%s", float_type_node);
-  /* Cast the double precision constants when single precision constants are
-     specified. The correct result is computed by the compiler when using 
-     macros that include a cast. This has the side-effect of making the value 
-     unusable in const expressions. */
-  if (flag_single_precision_constant)
-    builtin_define_float_constants ("DBL", "L", "((double)%s)", double_type_node);
-  else
-    builtin_define_float_constants ("DBL", "", "%s", double_type_node);
+  /* Cast the double precision constants.  This is needed when single
+     precision constants are specified or when pragma FLOAT_CONST_DECIMAL64
+     is used.  The correct result is computed by the compiler when using
+     macros that include a cast.  */
+  builtin_define_float_constants ("DBL", "L", "((double)%s)", double_type_node);
   builtin_define_float_constants ("LDBL", "L", "%s", long_double_type_node);
 
   /* For decfloat.h.  */
Index: gcc/c-decl.c
===================================================================
--- gcc/c-decl.c	(revision 147209)
+++ gcc/c-decl.c	(working copy)
@@ -342,6 +342,9 @@ struct GTY((chain_next ("%h.outer"))) c_
 
   /* True means make a BLOCK for this scope no matter what.  */
   BOOL_BITFIELD keep : 1;
+
+  /* True means that an unsuffixed float constant is _Decimal64.  */
+  BOOL_BITFIELD float_const_decimal64 : 1;
 };
 
 /* The scope currently in effect.  */
@@ -674,6 +677,30 @@ keep_next_level (void)
   keep_next_level_flag = true;
 }
 
+/* Set the flag for the FLOAT_CONST_DECIMAL64 pragma being ON.  */
+
+void
+set_float_const_decimal64 (void)
+{
+  current_scope->float_const_decimal64 = true;
+}
+
+/* Clear the flag for the FLOAT_CONST_DECIMAL64 pragma.  */
+
+void
+clear_float_const_decimal64 (void)
+{
+  current_scope->float_const_decimal64 = false;
+}
+
+/* Return nonzero if an unsuffixed float constant is _Decimal64.  */
+
+bool
+float_const_decimal64_p (void)
+{
+  return current_scope->float_const_decimal64;
+}
+
 /* Identify this scope as currently being filled with parameters.  */
 
 void
@@ -705,6 +732,13 @@ push_scope (void)
 
       keep_next_level_flag = false;
       next_is_function_body = false;
+
+      /* The FLOAT_CONST_DECIMAL64 pragma applies to nested scopes.  */
+      if (current_scope->outer)
+	current_scope->float_const_decimal64
+	  = current_scope->outer->float_const_decimal64;
+      else
+	current_scope->float_const_decimal64 = false;
     }
   else
     {
@@ -717,6 +751,12 @@ push_scope (void)
       else
 	scope = GGC_CNEW (struct c_scope);
 
+      /* The FLOAT_CONST_DECIMAL64 pragma applies to nested scopes.  */
+      if (current_scope)
+	scope->float_const_decimal64 = current_scope->float_const_decimal64;
+      else
+	scope->float_const_decimal64 = false;
+
       scope->keep          = keep_next_level_flag;
       scope->outer         = current_scope;
       scope->depth	   = current_scope ? (current_scope->depth + 1) : 0;
Index: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c	(revision 147209)
+++ gcc/c-parser.c	(working copy)
@@ -976,6 +976,7 @@ c_parser_translation_unit (c_parser *par
   else
     {
       void *obstack_position = obstack_alloc (&parser_obstack, 0);
+      mark_valid_location_for_stdc_pragma (false);
       do
 	{
 	  ggc_collect ();
@@ -1060,7 +1061,9 @@ c_parser_external_declaration (c_parser 
       c_parser_consume_token (parser);
       break;
     case CPP_PRAGMA:
+      mark_valid_location_for_stdc_pragma (true);
       c_parser_pragma (parser, pragma_external);
+      mark_valid_location_for_stdc_pragma (false);
       break;
     case CPP_PLUS:
     case CPP_MINUS:
@@ -3350,17 +3353,20 @@ c_parser_compound_statement_nostart (c_p
 {
   bool last_stmt = false;
   bool last_label = false;
+  bool save_valid_for_pragma = valid_location_for_stdc_pragma_p ();
   location_t label_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
   if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
     {
       c_parser_consume_token (parser);
       return;
     }
+  mark_valid_location_for_stdc_pragma (true);
   if (c_parser_next_token_is_keyword (parser, RID_LABEL))
     {
       location_t err_loc = c_parser_peek_token (parser)->location;
       /* Read zero or more forward-declarations for labels that nested
 	 functions can jump to.  */
+      mark_valid_location_for_stdc_pragma (false);
       while (c_parser_next_token_is_keyword (parser, RID_LABEL))
 	{
 	  c_parser_consume_token (parser);
@@ -3409,12 +3415,14 @@ c_parser_compound_statement_nostart (c_p
 	    label_loc = c_parser_peek_token (parser)->location;
 	  last_label = true;
 	  last_stmt = false;
+	  mark_valid_location_for_stdc_pragma (false);
 	  c_parser_label (parser);
 	}
       else if (!last_label
 	       && c_parser_next_token_starts_declspecs (parser))
 	{
 	  last_label = false;
+	  mark_valid_location_for_stdc_pragma (false);
 	  c_parser_declaration_or_fndef (parser, true, true, true, true);
 	  if (last_stmt)
 	    pedwarn_c90 (loc, 
@@ -3441,6 +3449,7 @@ c_parser_compound_statement_nostart (c_p
 	      ext = disable_extension_diagnostics ();
 	      c_parser_consume_token (parser);
 	      last_label = false;
+	      mark_valid_location_for_stdc_pragma (false);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true);
 	      /* Following the old parser, __extension__ does not
 		 disable this diagnostic.  */
@@ -3489,6 +3498,7 @@ c_parser_compound_statement_nostart (c_p
 	statement:
 	  last_label = false;
 	  last_stmt = true;
+	  mark_valid_location_for_stdc_pragma (false);
 	  c_parser_statement_after_labels (parser);
 	}
 
@@ -3497,6 +3507,8 @@ c_parser_compound_statement_nostart (c_p
   if (last_label)
     error_at (label_loc, "label at end of compound statement");
   c_parser_consume_token (parser);
+  /* Restore the value we started with.  */
+  mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
 }
 
 /* Parse a label (C90 6.6.1, C99 6.8.1).
Index: gcc/c-pragma.c
===================================================================
--- gcc/c-pragma.c	(revision 147209)
+++ gcc/c-pragma.c	(working copy)
@@ -1162,6 +1162,116 @@ handle_pragma_message (cpp_reader *ARG_U
     inform (input_location, "#pragma message: %s", TREE_STRING_POINTER (message));
 }
 
+/* Mark whether the current location is valid for a STDC pragma.  */
+
+static bool valid_location_for_stdc_pragma;
+
+void
+mark_valid_location_for_stdc_pragma (bool flag)
+{
+  valid_location_for_stdc_pragma = flag;
+}
+
+/* Return true if the current location is valid for a STDC pragma.  */
+
+bool
+valid_location_for_stdc_pragma_p (void)
+{
+  return valid_location_for_stdc_pragma;
+}
+
+enum pragma_switch_t { ON, OFF, DEFAULT, BAD };
+
+/* A STDC pragma must appear outside of external declarations or
+   preceding all explicit declarations and statements inside a compound
+   statement; its behavior is undefined if used in any other context.
+   It takes a switch of ON, OFF, or DEFAULT.  */
+
+static enum pragma_switch_t
+handle_stdc_pragma (const char *pname)
+{
+  const char *arg;
+  tree t;
+  enum pragma_switch_t ret;
+
+  if (!valid_location_for_stdc_pragma_p ())
+    {
+      warning (OPT_Wpragmas, "invalid location for %<pragma %s%>, ignored",
+	       pname);
+      return BAD;
+    }
+
+  if (pragma_lex (&t) != CPP_NAME)
+    {
+      warning (OPT_Wpragmas, "malformed %<#pragma %s%>, ignored", pname);
+      return BAD;
+    }
+
+  arg = IDENTIFIER_POINTER (t);
+
+  if (!strcmp (arg, "ON"))
+    ret = ON;
+  else if (!strcmp (arg, "OFF"))
+    ret = OFF;
+  else if (!strcmp (arg, "DEFAULT"))
+    ret = DEFAULT;
+  else
+    {
+      warning (OPT_Wpragmas, "malformed %<#pragma %s%>, ignored", pname);
+      return BAD;
+    }
+
+  if (pragma_lex (&t) != CPP_EOF)
+    {
+      warning (OPT_Wpragmas, "junk at end of %<#pragma %s%>", pname);
+      return BAD;
+    }
+
+  return ret;
+}
+
+/* #pragma STDC FLOAT_CONST_DECIMAL64 ON
+   #pragma STDC FLOAT_CONST_DECIMAL64 OFF
+   #pragma STDC FLOAT_CONST_DECIMAL64 DEFAULT */
+
+static void
+handle_pragma_float_const_decimal64 (cpp_reader *ARG_UNUSED (dummy))
+{
+  if (c_dialect_cxx ())
+    {
+      if (warn_unknown_pragmas > in_system_header)
+	warning (OPT_Wunknown_pragmas,
+		 "%<#pragma STDC FLOAT_CONST_DECIMAL64%> is not supported"
+		 " for C++");
+      return;
+    }
+
+  if (!targetm.decimal_float_supported_p ())
+    {
+      if (warn_unknown_pragmas > in_system_header)
+	warning (OPT_Wunknown_pragmas,
+		 "%<#pragma STDC FLOAT_CONST_DECIMAL64%> is not supported"
+		 " on this target");
+      return;
+    }
+
+  pedwarn (input_location, OPT_pedantic,
+	   "ISO C does not support %<#pragma STDC FLOAT_CONST_DECIMAL64%>");
+
+  switch (handle_stdc_pragma ("STDC FLOAT_CONST_DECIMAL64"))
+    {
+    case ON:
+      set_float_const_decimal64 ();
+      break;
+    case OFF:
+    case DEFAULT:
+      clear_float_const_decimal64 ();
+      break;
+    case BAD:
+      break;
+    }
+}
+
 /* A vector of registered pragma callbacks.  */
 
 DEF_VEC_O (pragma_handler);
@@ -1330,6 +1440,9 @@ init_pragma (void)
   c_register_pragma ("GCC", "pop_options", handle_pragma_pop_options);
   c_register_pragma ("GCC", "reset_options", handle_pragma_reset_options);
 
+  c_register_pragma ("STDC", "FLOAT_CONST_DECIMAL64",
+		     handle_pragma_float_const_decimal64);
+
   c_register_pragma_with_expansion (0, "redefine_extname", handle_pragma_redefine_extname);
   c_register_pragma (0, "extern_prefix", handle_pragma_extern_prefix);
 
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(revision 147209)
+++ gcc/cp/semantics.c	(working copy)
@@ -5050,4 +5050,23 @@ finish_trait_expr (cp_trait_kind kind, t
 	  ? boolean_true_node : boolean_false_node);
 }
 
+/* Do-nothing variants of functions to handle pragma FLOAT_CONST_DECIMAL64,
+   which is ignored for C++.  */
+
+void
+set_float_const_decimal64 (void)
+{
+}
+
+void
+clear_float_const_decimal64 (void)
+{
+}
+
+bool
+float_const_decimal64_p (void)
+{
+  return 0;
+}
+
 #include "gt-cp-semantics.h"
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 147209)
+++ gcc/doc/extend.texi	(working copy)
@@ -958,10 +958,6 @@ is incomplete:
 
 @itemize @bullet
 @item
-Pragma @code{FLOAT_CONST_DECIMAL64} is not supported, nor is the @samp{d}
-suffix for literal constants of type @code{double}.
-
-@item
 When the value of a decimal floating type cannot be represented in the
 integer type to which it is being converted, the result is undefined
 rather than the result value specified by the draft technical report.
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 147209)
+++ gcc/doc/invoke.texi	(working copy)
@@ -259,8 +259,8 @@ Objective-C and Objective-C++ Dialects}.
 -Wswitch  -Wswitch-default  -Wswitch-enum -Wsync-nand @gol
 -Wsystem-headers  -Wtrigraphs  -Wtype-limits  -Wundef  -Wuninitialized @gol
 -Wunknown-pragmas  -Wno-pragmas -Wunreachable-code @gol
--Wunused  -Wunused-function  -Wunused-label  -Wunused-parameter @gol
--Wunused-value  -Wunused-variable @gol
+-Wunsuffixed-float-constants  -Wunused  -Wunused-function @gol
+-Wunused-label  -Wunused-parameter  -Wunused-value  -Wunused-variable @gol
 -Wvariadic-macros -Wvla @gol
 -Wvolatile-register-var  -Wwrite-strings}
 
@@ -4218,6 +4218,15 @@ minimum maximum, so we do not diagnose o
 
 This option is implied by @option{-pedantic}, and can be disabled with
 @option{-Wno-overlength-strings}.
+
+@item -Wunsuffixed-float-constants
+@opindex Wunsuffixed-float-constants
+
+GCC will issue a warning for any floating constant that does not have
+a suffix.  When used together with @option{-Wsystem-headers} it will
+warn about such constants in system header files.  This can be useful
+when preparing code to use with the @code{FLOAT_CONST_DECIMAL64} pragma
+from the decimal floating-point extension to C99.
 @end table
 
 @node Debugging Options
Index: gcc/testsuite/gcc.dg/Wunsuffixed-float-constants-1.c
===================================================================
--- gcc/testsuite/gcc.dg/Wunsuffixed-float-constants-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/Wunsuffixed-float-constants-1.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99 -Wunsuffixed-float-constants" } */
+
+#define VAL 0.5;
+
+double a = 1.1d;
+
+/* With FLOAT_CONST_DECIMAL64 switched to ON these would have type
+   _Decimal64.  */
+
+double b = VAL;		/* { dg-warning "unsuffixed float constant" } */
+double c = 1.2;		/* { dg-warning "unsuffixed float constant" } */
+
+/* With FLOAT_CONST_DECIMAL64 switched to ON these are still binary.  */
+
+double d = 0x5.0p1;	/* No warning for hex constant.  */
+double e = 3.1i;	/* No warning for imaginary constant.  */
Index: gcc/testsuite/gcc.dg/cpp/pragma-float-const-decimal64-1.c
===================================================================
--- gcc/testsuite/gcc.dg/cpp/pragma-float-const-decimal64-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/cpp/pragma-float-const-decimal64-1.c	(revision 0)
@@ -0,0 +1,5 @@
+/* { dg-do compile { target { ! dfp } } } */
+/* { dg-options "-std=gnu99 -Wunknown-pragmas" } */
+
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-warning "not supported on this target" } */
+double d = 1.0;
Index: gcc/testsuite/gcc.dg/dfp/float-constant-double.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/float-constant-double.c	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/float-constant-double.c	(revision 0)
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+/* Constant float values of type double in <float.h> are suffixed with L
+   and cast to double so they can be used within code that uses pragma
+   FLOAT_CONST_DECIMAL64.  If they were not suffixed then use of the macro
+   would have them interpreted as _Decimal64, leading to errors when used
+   in expressions with other operands of type double.  */
+
+#include <float.h>
+
+extern double a, b, c, d;
+
+void
+foo ()
+{
+  _Pragma ("STDC FLOAT_CONST_DECIMAL64 ON")
+  a = 0.1d * DBL_MAX;
+  b = DBL_EPSILON * 10.0d;
+  c = DBL_MIN * 200.0d;
+}
Index: gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-1.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-1.c	(revision 0)
@@ -0,0 +1,85 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99 -Wall" } */
+
+/* N1312 7.1.1: The FLOAT_CONST_DECIMAL64 pragma.
+   C99 6.4.4.2a (New).
+
+   Verify that the pragma has the expected result by using unsuffixed
+   float constants as operands in expressions that would mix binary and
+   decimal operands if the pragma had no effect, or the wrong effect.  */
+
+#pragma STDC FLOAT_CONST_DECIMAL64 ON
+double a = 1.0 * 2.0dd;
+
+double
+f1 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF
+  double b = 2.0 * 3.0d;
+
+  {
+    double c = 3.0 * 4.0d;
+    b = b + c;
+  }
+
+  {
+#pragma STDC FLOAT_CONST_DECIMAL64 ON
+    double d = 4.0 * 5.0dd;
+
+    b = b + d;
+  }
+
+  {
+     /* Default is OFF.  */
+#pragma STDC FLOAT_CONST_DECIMAL64 DEFAULT
+     double e = 5.0 * 6.0d;
+     b = b + e;
+  }
+
+  return b;
+}
+
+double
+f2 (void)
+{
+  /* Use value from outer scope, which is ON.  */
+  double b = 2.0 * 3.0dd;
+
+  {
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF
+    double c = 3.0 * 4.0d;
+
+    {
+#pragma STDC FLOAT_CONST_DECIMAL64 ON
+      double d = 4.0 * 5.0dd;
+
+      {
+#pragma STDC FLOAT_CONST_DECIMAL64 DEFAULT
+	double e = 5.0 * 6.0d;
+
+	{
+#pragma STDC FLOAT_CONST_DECIMAL64 ON
+	  double f = 6.0 * 7.0dd;
+
+	  b = a + b + c + d + e + f;
+	}
+      }
+    }
+  }
+  return b;
+}
+
+/* Use previous value from this scope, which is ON.  */
+double f = 6.0 * 7.0dd;
+
+double
+f3 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF
+  double b = 2.0 * 3.0d;
+
+  return b + f;
+}
+
+/* Return to the state from this scope, which is ON.  */
+double g = 7.0 + 8.0dd;
Index: gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-2.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-2.c	(revision 0)
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99 -Wall" } */
+
+/* N1312 7.1.1: The FLOAT_CONST_DECIMAL64 pragma.
+   C99 6.4.4.2a (New).
+
+   Verify that the pragma has the expected result by using unsuffixed
+   float constants as operands in expressions that would mix binary and
+   decimal operands if the pragma had no effect, or the wrong effect.
+   Use _Pragma rather than #pragma.  */
+
+_Pragma ("STDC FLOAT_CONST_DECIMAL64 ON")
+double a = 1.0 * 2.0dd;
+
+double
+f1 (void)
+{
+_Pragma ("STDC FLOAT_CONST_DECIMAL64 OFF")
+  double b = 2.0 * 3.0d;
+
+  {
+    double c = 3.0 * 4.0d;
+    b = b + c;
+  }
+
+  {
+_Pragma ("STDC FLOAT_CONST_DECIMAL64 ON")
+    double d = 4.0 * 5.0dd;
+
+    b = b + d;
+  }
+
+  {
+     /* Default is OFF.  */
+_Pragma ("STDC FLOAT_CONST_DECIMAL64 DEFAULT")
+     double e = 5.0 * 6.0d;
+     b = b + e;
+  }
+
+  return b;
+}
+
+double
+f2 (void)
+{
+  /* Use value from outer scope, which is ON.  */
+  double b = 2.0 * 3.0dd;
+
+  {
+_Pragma ("STDC FLOAT_CONST_DECIMAL64 OFF")
+    double c = 3.0 * 4.0d;
+
+    {
+_Pragma ("STDC FLOAT_CONST_DECIMAL64 ON")
+      double d = 4.0 * 5.0dd;
+
+      {
+_Pragma ("STDC FLOAT_CONST_DECIMAL64 DEFAULT")
+	double e = 5.0 * 6.0d;
+
+	{
+_Pragma ("STDC FLOAT_CONST_DECIMAL64 ON")
+	  double f = 6.0 * 7.0dd;
+
+	  b = a + b + c + d + e + f;
+	}
+      }
+    }
+  }
+  return b;
+}
+
+/* Use previous value from this scope, which is ON.  */
+double f = 6.0 * 7.0dd;
+
+double
+f3 (void)
+{
+_Pragma ("STDC FLOAT_CONST_DECIMAL64 OFF")
+  double b = 2.0 * 3.0d;
+
+  return b + f;
+}
+
+/* Return to the state from this scope, which is ON.  */
+double g = 7.0 + 8.0dd;
Index: gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-3.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-3.c	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-3.c	(revision 0)
@@ -0,0 +1,83 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99 -Wall" } */
+
+/* N1312 7.1.1: The FLOAT_CONST_DECIMAL64 pragma.
+   C99 6.4.4.2a (New).  */
+
+/* Check that defining macros whose names are the same as the tokens used
+   in the pragma doesn't affect use of the pragma.  */
+
+#define ON YES
+#define OFF NO
+#define DEFAULT NOPE
+#define STDC OFFICIAL
+#define FLOAT_CONST_DECIMAL64 NEW_PRAGMA
+
+double a;
+
+void
+f1a (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 ON
+  a = 1.0dd + 2.0;
+}
+
+void
+f1b (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF
+  a = 2.0d + 3.0;
+}
+
+void
+f1c (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 DEFAULT
+  a = 3.0d + 4.0;
+}
+
+/* Check that a macro can be used for the entire pragma.  */
+
+#define PRAGMA(x) _Pragma (#x)
+#define DEFAULT_FLOAT_IS_DECIMAL PRAGMA(STDC FLOAT_CONST_DECIMAL64 ON)
+#define DEFAULT_FLOAT_IS_BINARY PRAGMA(STDC FLOAT_CONST_DECIMAL64 OFF)
+
+void
+f2a (void)
+{
+  DEFAULT_FLOAT_IS_DECIMAL
+  a = 5.0 * 6.0dd;
+}
+
+void
+f2b (void)
+{
+  DEFAULT_FLOAT_IS_BINARY
+  a = 6.0 * 7.0d;
+}
+
+/* _Pragma can be used with macros, including the use of a macro for the
+    switch.  */
+
+#undef ON
+#undef OFF
+#undef DEFAULT
+#undef STDC
+#undef FLOAT_CONST_DECIMAL64
+
+#define SWITCH ON
+#define FLOAT_CONST_DECIMAL64(x) PRAGMA(STDC FLOAT_CONST_DECIMAL64 x)
+
+void
+f3a (void)
+{
+  FLOAT_CONST_DECIMAL64(SWITCH)
+  a = 1.0 * 7.0dd;
+}
+
+void
+f3b (void)
+{
+  FLOAT_CONST_DECIMAL64(OFF)
+  a = 1.0 + 2.0d;
+}
Index: gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-4.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-4.c	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-4.c	(revision 0)
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+/* N1312 7.1.1: The FLOAT_CONST_DECIMAL64 pragma.
+   C99 6.4.4.2a (New).
+
+   Check that malformed versions of pragma STDC FLOAT_CONST_DECIMAL64
+   are detected.  */
+
+double a;
+
+void f1 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64	/* { dg-warning "malformed" } */
+  a = 1.0;
+}
+
+void f2 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 DFP	/* { dg-warning "malformed" } */
+  a = 2.0;
+}
+
+void f3 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 ON DFP /* { dg-warning "junk at end" } */
+  a = 3.0;
+}
+
+void f4 (void)
+{
+  _Pragma ( "STDC FLOAT_CONST_DECIMAL64" )	/* { dg-warning "malformed" } */
+  a = 1.0;
+}
+
+void f5 (void)
+{
+  _Pragma ( "STDC FLOAT_CONST_DECIMAL64 DFP" )	/* { dg-warning "malformed" } */
+  a = 2.0;
+}
+
+void f6 (void)
+{
+  _Pragma ( "STDC FLOAT_CONST_DECIMAL64 ON DFP" ) /* { dg-warning "junk at end" } */
+  a = 3.0;
+}
Index: gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-5.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-5.c	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-5.c	(revision 0)
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c99 -pedantic" } */
+
+/* N1312 7.1.1: The FLOAT_CONST_DECIMAL64 pragma.
+   C99 6.4.4.2a (New).
+
+   Check that there is a pedantic warning for the use of pragma
+   STD FLOAT_CONST_DECIMAL64.  */
+
+double a;
+
+void f1 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 ON		/* { dg-warning "ISO C" } */
+  a = 1.0;
+}
+
+void f2 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF		/* { dg-warning "ISO C" } */
+  a = 2.0;
+}
+
+void f3 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 DEFAULT	/* { dg-warning "ISO C" } */
+  a = 3.0;
+}
+
+void f4 (void)
+{
+  _Pragma ("STDC FLOAT_CONST_DECIMAL64 ON")	/* { dg-warning "ISO C" } */
+  a = 1.0;
+}
+
+void f5 (void)
+{
+  _Pragma ("STDC FLOAT_CONST_DECIMAL64 OFF")	/* { dg-warning "ISO C" } */
+  a = 2.0;
+}
+
+void f6 (void)
+{
+  _Pragma ("STDC FLOAT_CONST_DECIMAL64 DEFAULT")	/* { dg-warning "ISO C" } */
+  a = 3.0;
+}
Index: gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-6.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-6.c	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-6.c	(revision 0)
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c99 -pedantic-errors" } */
+
+/* N1312 7.1.1: The FLOAT_CONST_DECIMAL64 pragma.
+   C99 6.4.4.2a (New).
+
+   Check that there is a pedantic error for the use of pragma
+   STD FLOAT_CONST_DECIMAL64.  */
+
+double a;
+
+void f1 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 ON		/* { dg-error "ISO C" } */
+  a = 1.0;
+}
+
+void f2 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF		/* { dg-error "ISO C" } */
+  a = 2.0;
+}
+
+void f3 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 DEFAULT	/* { dg-error "ISO C" } */
+  a = 3.0;
+}
+
+void f4 (void)
+{
+  _Pragma ("STDC FLOAT_CONST_DECIMAL64 ON")	/* { dg-error "ISO C" } */
+  a = 1.0;
+}
+
+void f5 (void)
+{
+  _Pragma ("STDC FLOAT_CONST_DECIMAL64 OFF")	/* { dg-error "ISO C" } */
+  a = 2.0;
+}
+
+void f6 (void)
+{
+  _Pragma ("STDC FLOAT_CONST_DECIMAL64 DEFAULT") /* { dg-error "ISO C" } */
+  a = 3.0;
+}
Index: gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-7.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-7.c	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-7.c	(revision 0)
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99 -Wall" } */
+
+/* N1312 7.1.1: The FLOAT_CONST_DECIMAL64 pragma.
+   C99 6.4.4.2a (New).
+
+   Check that when pragma FLOAT_CONST_DECIMAL64 is in effect so that
+   unsuffixed constants are _Decimal64, invalid types are still reported
+   as invalid.  */
+
+double
+f1 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF
+  double a = 0x1.0p1;
+  double b = 1.0i;
+
+  return a + b;
+}
+
+double
+f2 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF
+  double a = 0x1.0p1dd;		/* { dg-error "with hex" } */
+  double b = 1.0idd;		/* { dg-error "invalid suffix" } */
+
+  return a + b;
+}
+
+double
+f3 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 ON
+  double a = 0x1.0p1;	/* Hex constant is not affected by pragma.  */
+  double b = 1.0i;	/* Imaginary constant is not affected by pragma.  */
+
+  return a + b;
+}
Index: gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-8.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-8.c	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-8.c	(revision 0)
@@ -0,0 +1,174 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99 -Wall" } */
+
+/* N1312 7.1.1: The FLOAT_CONST_DECIMAL64 pragma.
+   C99 6.4.4.2a (New).
+
+   Pragma STDC FLOAT_CONST_DECIMAL64 "shall occur either outside external
+   declarations or preceding all explicit declarations and statements
+   inside a compound statement." */
+
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF
+
+#define MAX 200
+
+#pragma STDC FLOAT_CONST_DECIMAL64 ON
+
+double a;
+
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF
+
+struct S1 {
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-warning "invalid location" } */
+  int i;
+  int j;
+};
+
+struct S2 {
+  int i;
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-warning "invalid location" } */
+  int j;
+};
+
+struct S3 {
+  int i;
+  int j;
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-warning "invalid location" } */
+};
+
+enum E1 {
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-error "#pragma" } */
+  one,
+  two
+};
+
+enum E2 {
+  red,
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-error "#pragma" } */
+  blue
+};
+
+enum E3 {
+  cat,
+  dog
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-error "#pragma" } */
+};
+
+double
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF	/* { dg-error "#pragma" } */
+b;
+
+double
+f1 (void)
+{
+#pragma STDC FLOAT_CONST_DECIMAL64 ON
+  return a;
+}
+
+double
+f2 (void)
+{
+  double b;
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-warning "invalid location" } */
+  b = 0.5;
+  return a + b;
+}
+
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF
+
+double
+f3 (void)
+{
+  typedef double b32;
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-warning "invalid location" } */
+  b32 b = 0.5;
+  return b;
+}
+
+double
+f4 (int i)
+{
+top:
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF	/* { dg-warning "invalid location" } */
+  if (i == 0)
+    return a;  
+  a *= 2.;
+  i = 0;
+  goto top;
+}
+
+double
+f5 (int i)
+{
+  a = a * i;
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF	/* { dg-warning "invalid location" } */
+  return a * 2.;
+}
+
+double
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-error "#pragma" } */
+f6 (void)
+{
+  return a;
+}
+
+double
+f7
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-error "#pragma" } */
+(void)					/* { dg-error "before" } */
+{
+  return a;
+}
+
+double
+f8 (void)
+{
+  {
+#pragma STDC FLOAT_CONST_DECIMAL64 OFF
+  }
+#pragma STDC FLOAT_CONST_DECIMAL64 ON   /* { dg-warning "invalid location" } */
+  return a;
+}
+
+extern void foo9 (void *);
+
+double
+f9 (void)
+{
+  __label__ here;
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-warning "invalid location" } */
+  foo9 (&&here);
+here:
+  return a;
+}
+
+double
+f10 (void)
+{
+  void foo10 (void)
+  {
+    a = 1.0;
+  }
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-warning "invalid location" } */
+  return a;
+}
+
+double
+f11 (void)
+{
+  __extension__
+   struct A {
+    struct { char a; };
+    char b;
+  };
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-warning "invalid location" } */
+  return a;
+}
+
+double
+f12 (void)
+{
+  __extension__ ({ a = 0.5; });
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	/* { dg-warning "invalid location" } */
+  return a;
+}
Index: gcc/testsuite/g++.dg/cpp/pragma-float-const-decimal64-1.C
===================================================================
--- gcc/testsuite/g++.dg/cpp/pragma-float-const-decimal64-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp/pragma-float-const-decimal64-1.C	(revision 0)
@@ -0,0 +1,5 @@
+// { dg-do compile }
+// { dg-options "-Wunknown-pragmas" }
+
+#pragma STDC FLOAT_CONST_DECIMAL64 ON	// { dg-warning "not supported for C\\\+\\\+" }
+double d = 1.0;


> > Index: gcc/doc/invoke.texi
> > ===================================================================
> > --- gcc/doc/invoke.texi	(revision 147110)
> > +++ gcc/doc/invoke.texi	(working copy)
> > @@ -4218,6 +4218,15 @@ minimum maximum, so we do not diagnose o
> >  
> >  This option is implied by @option{-pedantic}, and can be disabled with
> >  @option{-Wno-overlength-strings}.
> > +
> > +@item -Wunsuffixed-float-constants
> > +@opindex Wunsuffixed-float-constants
> > +
> > +GCC will issue a warning for any floating constant that does not have
> > +a suffix.  When used together with @option{-Wsystem-headers} it will
> > +warn about such constants in system header files.  This can be useful
> > +when preparing code to use with the @code{FLOAT_CONST_DECIMAL64} pragma
> > +from the decimal floating-point extension to C99.
> >  @end table
> 
> There are summary tables of options earlier in invoke.texi that need the 
> new option added somewhere.

Added.

Tested, once again, with bootstrap and regression test on
powerpc64-linux, -m32/-m64.




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