Implement C++14 digit separators.

libcpp:

2013-10-31  Edward Smith-Rowland  <3dw4rd@verizon.net>

        Implement C++14 digit separators.
	* include/cpplib.h (cpp_options): Add digit_separators flag.
	* internal.h (DIGIT_SEP(c)): New macro.
	* expr.c (cpp_classify_number): Check improper placement of digit sep;
	(cpp_interpret_integer): Skip over digit separators.
	* init.c (lang_flags): Add digit_separators flag; (lang_defaults): Add
	digit separator flags per language; (cpp_set_lang): Set
	digit_separators
	* lex.c (lex_number): Add digits separator to allowable characters for
	C++14.


gcc/c-family:

2013-10-31  Edward Smith-Rowland  <3dw4rd@verizon.net>

        Implement C++14 digit separators.
	* c-lex.c (interpret_float): Remove digit separators from scratch string
	before building real literal.


gcc/testsuite:

2013-10-31  Edward Smith-Rowland  <3dw4rd@verizon.net>

        Implement C++14 digit separators.
	* g++.dg/cpp1y/digit-sep.C: New.
	* g++.dg/cpp1y/digit-sep-neg.C: New.
	* g++.dg/cpp1y/digit-sep-cxx11-neg.C: New.


libstdc++-v3:

2013-10-31  Edward Smith-Rowland  <3dw4rd@verizon.net>

        Implement C++14 digit separators.
	* include/include/bits/parse_numbers.h: Change struct _Digit<_Base, '`'>
	to struct _Digit<_Base, '\''>.

From-SVN: r204260
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index b4de4f5..2e98e34 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,16 @@
+2013-10-31  Edward Smith-Rowland  <3dw4rd@verizon.net>
+
+        Implement C++14 digit separators.
+	* include/cpplib.h (cpp_options): Add digit_separators flag.
+	* internal.h (DIGIT_SEP(c)): New macro.
+	* expr.c (cpp_classify_number): Check improper placement of digit sep;
+	(cpp_interpret_integer): Skip over digit separators.
+	* init.c (lang_flags): Add digit_separators flag; (lang_defaults): Add
+	digit separator flags per language; (cpp_set_lang): Set
+	digit_separators
+	* lex.c (lex_number): Add digits separator to allowable characters for
+	C++14.
+
 2013-10-15  David Malcolm  <dmalcolm@redhat.com>
 
 	* Makefile.in (PICFLAG): New.
diff --git a/libcpp/expr.c b/libcpp/expr.c
index 0eb6c13..c009807 100644
--- a/libcpp/expr.c
+++ b/libcpp/expr.c
@@ -394,6 +394,7 @@
   unsigned int max_digit, result, radix;
   enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag;
   bool seen_digit;
+  bool seen_digit_sep;
 
   if (ud_suffix)
     *ud_suffix = NULL;
@@ -408,6 +409,7 @@
   max_digit = 0;
   radix = 10;
   seen_digit = false;
+  seen_digit_sep = false;
 
   /* First, interpret the radix.  */
   if (*str == '0')
@@ -416,16 +418,27 @@
       str++;
 
       /* Require at least one hex digit to classify it as hex.  */
-      if ((*str == 'x' || *str == 'X')
-	  && (str[1] == '.' || ISXDIGIT (str[1])))
+      if (*str == 'x' || *str == 'X')
 	{
-	  radix = 16;
-	  str++;
+	  if (str[1] == '.' || ISXDIGIT (str[1]))
+	    {
+	      radix = 16;
+	      str++;
+	    }
+	  else if (DIGIT_SEP (str[1]))
+	    SYNTAX_ERROR_AT (virtual_location,
+			     "digit separator after base indicator");
 	}
-      else if ((*str == 'b' || *str == 'B') && (str[1] == '0' || str[1] == '1'))
+      else if (*str == 'b' || *str == 'B')
 	{
-	  radix = 2;
-	  str++;
+	  if (str[1] == '0' || str[1] == '1')
+	    {
+	      radix = 2;
+	      str++;
+	    }
+	  else if (DIGIT_SEP (str[1]))
+	    SYNTAX_ERROR_AT (virtual_location,
+			     "digit separator after base indicator");
 	}
     }
 
@@ -436,13 +449,24 @@
 
       if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16))
 	{
+	  seen_digit_sep = false;
 	  seen_digit = true;
 	  c = hex_value (c);
 	  if (c > max_digit)
 	    max_digit = c;
 	}
+      else if (DIGIT_SEP (c))
+	{
+	  if (seen_digit_sep)
+	    SYNTAX_ERROR_AT (virtual_location, "adjacent digit separators");
+	  seen_digit_sep = true;
+	}
       else if (c == '.')
 	{
+	  if (seen_digit_sep || DIGIT_SEP (*str))
+	    SYNTAX_ERROR_AT (virtual_location,
+			     "digit separator adjacent to decimal point");
+	  seen_digit_sep = false;
 	  if (float_flag == NOT_FLOAT)
 	    float_flag = AFTER_POINT;
 	  else
@@ -452,6 +476,9 @@
       else if ((radix <= 10 && (c == 'e' || c == 'E'))
 	       || (radix == 16 && (c == 'p' || c == 'P')))
 	{
+	  if (seen_digit_sep || DIGIT_SEP (*str))
+	    SYNTAX_ERROR_AT (virtual_location,
+			     "digit separator adjacent to exponent");
 	  float_flag = AFTER_EXPON;
 	  break;
 	}
@@ -463,6 +490,10 @@
 	}
     }
 
+  if (seen_digit_sep && float_flag != AFTER_EXPON)
+    SYNTAX_ERROR_AT (virtual_location,
+		     "digit separator outside digit sequence");
+
   /* The suffix may be for decimal fixed-point constants without exponent.  */
   if (radix != 16 && float_flag == NOT_FLOAT)
     {
@@ -520,16 +551,28 @@
 
 	  /* Exponent is decimal, even if string is a hex float.  */
 	  if (!ISDIGIT (*str))
-	    SYNTAX_ERROR_AT (virtual_location, "exponent has no digits");
-
+	    {
+	      if (DIGIT_SEP (*str))
+		SYNTAX_ERROR_AT (virtual_location,
+				 "digit separator adjacent to exponent");
+	      else
+		SYNTAX_ERROR_AT (virtual_location, "exponent has no digits");
+	    }
 	  do
-	    str++;
-	  while (ISDIGIT (*str));
+	    {
+	      seen_digit_sep = DIGIT_SEP (*str);
+	      str++;
+	    }
+	  while (ISDIGIT (*str) || DIGIT_SEP (*str));
 	}
       else if (radix == 16)
 	SYNTAX_ERROR_AT (virtual_location,
 			 "hexadecimal floating constants require an exponent");
 
+      if (seen_digit_sep)
+	SYNTAX_ERROR_AT (virtual_location,
+			 "digit separator outside digit sequence");
+
       result = interpret_float_suffix (pfile, str, limit - str);
       if (result == 0)
 	{
@@ -723,6 +766,8 @@
 
 	  if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c)))
 	    c = hex_value (c);
+	  else if (DIGIT_SEP (c))
+	    continue;
 	  else
 	    break;
 
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 6c4225c..34ad6c3 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -437,6 +437,9 @@
   /* Nonzero for C++ 2014 Standard binary constants.  */
   unsigned char binary_constants;
 
+  /* Nonzero for C++ 2014 Standard digit separators.  */
+  unsigned char digit_separators;
+
   /* Holds the name of the target (execution) character set.  */
   const char *narrow_charset;
 
diff --git a/libcpp/init.c b/libcpp/init.c
index 9751000..97aa6cd 100644
--- a/libcpp/init.c
+++ b/libcpp/init.c
@@ -84,24 +84,25 @@
   char rliterals;
   char user_literals;
   char binary_constants;
+  char digit_separators;
 };
 
 static const struct lang_flags lang_defaults[] =
-{ /*              c99 c++ xnum xid std  //   digr ulit rlit udlit bin_cst */
-  /* GNUC89   */  { 0,  0,  1,   0,  0,   1,   1,   0,   0,   0,    0 },
-  /* GNUC99   */  { 1,  0,  1,   0,  0,   1,   1,   1,   1,   0,    0 },
-  /* GNUC11   */  { 1,  0,  1,   0,  0,   1,   1,   1,   1,   0,    0 },
-  /* STDC89   */  { 0,  0,  0,   0,  1,   0,   0,   0,   0,   0,    0 },
-  /* STDC94   */  { 0,  0,  0,   0,  1,   0,   1,   0,   0,   0,    0 },
-  /* STDC99   */  { 1,  0,  1,   0,  1,   1,   1,   0,   0,   0,    0 },
-  /* STDC11   */  { 1,  0,  1,   0,  1,   1,   1,   1,   0,   0,    0 },
-  /* GNUCXX   */  { 0,  1,  1,   0,  0,   1,   1,   0,   0,   0,    0 },
-  /* CXX98    */  { 0,  1,  1,   0,  1,   1,   1,   0,   0,   0,    0 },
-  /* GNUCXX11 */  { 1,  1,  1,   0,  0,   1,   1,   1,   1,   1,    0 },
-  /* CXX11    */  { 1,  1,  1,   0,  1,   1,   1,   1,   1,   1,    0 },
-  /* GNUCXX1Y */  { 1,  1,  1,   0,  0,   1,   1,   1,   1,   1,    1 },
-  /* CXX1Y    */  { 1,  1,  1,   0,  1,   1,   1,   1,   1,   1,    1 },
-  /* ASM      */  { 0,  0,  1,   0,  0,   1,   0,   0,   0,   0,    0 }
+{ /*              c99 c++ xnum xid std  //   digr ulit rlit udlit bin_cst dig_sep */
+  /* GNUC89   */  { 0,  0,  1,   0,  0,   1,   1,   0,   0,   0,    0,      0 },
+  /* GNUC99   */  { 1,  0,  1,   0,  0,   1,   1,   1,   1,   0,    0,      0 },
+  /* GNUC11   */  { 1,  0,  1,   0,  0,   1,   1,   1,   1,   0,    0,      0 },
+  /* STDC89   */  { 0,  0,  0,   0,  1,   0,   0,   0,   0,   0,    0,      0 },
+  /* STDC94   */  { 0,  0,  0,   0,  1,   0,   1,   0,   0,   0,    0,      0 },
+  /* STDC99   */  { 1,  0,  1,   0,  1,   1,   1,   0,   0,   0,    0,      0 },
+  /* STDC11   */  { 1,  0,  1,   0,  1,   1,   1,   1,   0,   0,    0,      0 },
+  /* GNUCXX   */  { 0,  1,  1,   0,  0,   1,   1,   0,   0,   0,    0,      0 },
+  /* CXX98    */  { 0,  1,  1,   0,  1,   1,   1,   0,   0,   0,    0,      0 },
+  /* GNUCXX11 */  { 1,  1,  1,   0,  0,   1,   1,   1,   1,   1,    0,      0 },
+  /* CXX11    */  { 1,  1,  1,   0,  1,   1,   1,   1,   1,   1,    0,      0 },
+  /* GNUCXX1Y */  { 1,  1,  1,   0,  0,   1,   1,   1,   1,   1,    1,      1 },
+  /* CXX1Y    */  { 1,  1,  1,   0,  1,   1,   1,   1,   1,   1,    1,      1 },
+  /* ASM      */  { 0,  0,  1,   0,  0,   1,   0,   0,   0,   0,    0,      0 }
   /* xid should be 1 for GNUC99, STDC99, GNUCXX, CXX98, GNUCXX11, CXX11,
      GNUCXX1Y, and CXX1Y when no longer experimental (when all uses of
      identifiers in the compiler have been audited for correct handling
@@ -128,6 +129,7 @@
   CPP_OPTION (pfile, rliterals)			 = l->rliterals;
   CPP_OPTION (pfile, user_literals)		 = l->user_literals;
   CPP_OPTION (pfile, binary_constants)		 = l->binary_constants;
+  CPP_OPTION (pfile, digit_separators)		 = l->digit_separators;
 }
 
 /* Initialize library global state.  */
diff --git a/libcpp/internal.h b/libcpp/internal.h
index 1226dbd..6de44ed 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -59,6 +59,8 @@
     || (((prevc) == 'p' || (prevc) == 'P') \
         && CPP_OPTION (pfile, extended_numbers))))
 
+#define DIGIT_SEP(c) ((c) == '\'' && CPP_OPTION (pfile, digit_separators))
+
 #define CPP_OPTION(PFILE, OPTION) ((PFILE)->opts.OPTION)
 #define CPP_BUFFER(PFILE) ((PFILE)->buffer)
 #define CPP_BUF_COLUMN(BUF, CUR) ((CUR) - (BUF)->line_base)
diff --git a/libcpp/lex.c b/libcpp/lex.c
index ed794d5..95995ed 100644
--- a/libcpp/lex.c
+++ b/libcpp/lex.c
@@ -1274,7 +1274,8 @@
       cur = pfile->buffer->cur;
 
       /* N.B. ISIDNUM does not include $.  */
-      while (ISIDNUM (*cur) || *cur == '.' || VALID_SIGN (*cur, cur[-1]))
+      while (ISIDNUM (*cur) || *cur == '.' || DIGIT_SEP (*cur)
+	     || VALID_SIGN (*cur, cur[-1]))
 	{
 	  cur++;
 	  NORMALIZE_STATE_UPDATE_IDNUM (nst);