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
This commit is contained in:
Edward Smith-Rowland 2013-10-31 14:01:23 +00:00 committed by Edward Smith-Rowland
parent b63cb15373
commit 7057e6452b
14 changed files with 187 additions and 31 deletions

View File

@ -1,3 +1,9 @@
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.
2013-10-30 Jakub Jelinek <jakub@redhat.com> 2013-10-30 Jakub Jelinek <jakub@redhat.com>
* cilk.c (create_cilk_helper_decl): Use HOST_WIDE_INT_PRINT_DEC. * cilk.c (create_cilk_helper_decl): Use HOST_WIDE_INT_PRINT_DEC.

View File

@ -774,8 +774,19 @@ interpret_float (const cpp_token *token, unsigned int flags,
} }
copy = (char *) alloca (copylen + 1); copy = (char *) alloca (copylen + 1);
memcpy (copy, token->val.str.text, copylen); if (cxx_dialect > cxx11)
copy[copylen] = '\0'; {
size_t maxlen = 0;
for (size_t i = 0; i < copylen; ++i)
if (token->val.str.text[i] != '\'')
copy[maxlen++] = token->val.str.text[i];
copy[maxlen] = '\0';
}
else
{
memcpy (copy, token->val.str.text, copylen);
copy[copylen] = '\0';
}
real_from_string3 (&real, copy, TYPE_MODE (const_type)); real_from_string3 (&real, copy, TYPE_MODE (const_type));
if (const_type != type) if (const_type != type)

View File

@ -1,3 +1,10 @@
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.
2013-10-31 Jakub Jelinek <jakub@redhat.com> 2013-10-31 Jakub Jelinek <jakub@redhat.com>
* gcc.dg/vect/vect-align-3.c: New test. * gcc.dg/vect/vect-align-3.c: New test.

View File

@ -0,0 +1,12 @@
// { dg-options -std=c++11 }
#define assert(E) if(!(E))__builtin_abort();
#define m(x) 0
int
main()
{
int i = m(1'2)+(3'4);
assert(i == 0);
}

View File

@ -0,0 +1,26 @@
// { dg-options -std=c++1y }
int
main()
{
int i = 0;
i = 1048''576; // { dg-error "adjacent digit separators" }
i = 0X'100000; // { dg-error "digit separator after base indicator" }
i = 0x'100000; // { dg-error "digit separator after base indicator" }
i = 0004''000'000); // { dg-error "adjacent digit separators" }
i = 0B1'0'0'0'0'0'0'0'0'0'0'0'0'0'0'0'0'0'0'0'0; // OK
i = 0b'0001'0000'0000'0000'0000'0000; // { dg-error "digit separator after base indicator" }
i = 0b0001'0000'0000'0000'0000'0000'; // { dg-error "digit separator outside digit sequence" }
unsigned u = 0b0001'0000'0000'0000'0000'0000'U; // { dg-error "digit separator outside digit sequence" }
double d = 0.0;
d = 1'.602'176'565e-19; // { dg-error "digit separator adjacent to decimal point" }
d = 1.'602'176'565e-19; // { dg-error "digit separator adjacent to decimal point" }
d = 1.602''176'565e-19; // { dg-error "adjacent digit separators" }
d = 1.602'176'565'e-19; // { dg-error "digit separator adjacent to exponent" }
d = 1.602'176'565e'-19; // { dg-error "digit separator adjacent to exponent" }
d = 1.602'176'565e-'19; // { dg-error "digit separator adjacent to exponent" }
d = 1.602'176'565e-1'9; // OK
d = 1.602'176'565e-19'; // { dg-error "digit separator outside digit sequence" }
float f = 1.602'176'565e-19'F; // { dg-error "digit separator outside digit sequence" }
}

View File

@ -0,0 +1,22 @@
// { dg-options -std=c++1y }
#define assert(E) if(!(E))__builtin_abort();
#define m(x) 0
int
main()
{
assert(1048576 == 1'048'576);
assert(1048576 == 0X100000);
assert(1048576 == 0x10'0000);
assert(1048576 == 0'004'000'000);
assert(1048576 == 0B100000000000000000000);
assert(1048576 == 0b0001'0000'0000'0000'0000'0000);
assert(1.602'176'565e-19 == 1.602176565e-19);
assert(1.602'176'565e-1'9 == 1.602176565e-19);
int i = m(1'2)+(3'4);
assert(i == 34);
}

View File

@ -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> 2013-10-15 David Malcolm <dmalcolm@redhat.com>
* Makefile.in (PICFLAG): New. * Makefile.in (PICFLAG): New.

View File

@ -394,6 +394,7 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
unsigned int max_digit, result, radix; unsigned int max_digit, result, radix;
enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag; enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag;
bool seen_digit; bool seen_digit;
bool seen_digit_sep;
if (ud_suffix) if (ud_suffix)
*ud_suffix = NULL; *ud_suffix = NULL;
@ -408,6 +409,7 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
max_digit = 0; max_digit = 0;
radix = 10; radix = 10;
seen_digit = false; seen_digit = false;
seen_digit_sep = false;
/* First, interpret the radix. */ /* First, interpret the radix. */
if (*str == '0') if (*str == '0')
@ -416,16 +418,27 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
str++; str++;
/* Require at least one hex digit to classify it as hex. */ /* Require at least one hex digit to classify it as hex. */
if ((*str == 'x' || *str == 'X') if (*str == 'x' || *str == 'X')
&& (str[1] == '.' || ISXDIGIT (str[1])))
{ {
radix = 16; if (str[1] == '.' || ISXDIGIT (str[1]))
str++; {
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; if (str[1] == '0' || str[1] == '1')
str++; {
radix = 2;
str++;
}
else if (DIGIT_SEP (str[1]))
SYNTAX_ERROR_AT (virtual_location,
"digit separator after base indicator");
} }
} }
@ -436,13 +449,24 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16)) if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16))
{ {
seen_digit_sep = false;
seen_digit = true; seen_digit = true;
c = hex_value (c); c = hex_value (c);
if (c > max_digit) if (c > max_digit)
max_digit = c; 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 == '.') 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) if (float_flag == NOT_FLOAT)
float_flag = AFTER_POINT; float_flag = AFTER_POINT;
else else
@ -452,6 +476,9 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
else if ((radix <= 10 && (c == 'e' || c == 'E')) else if ((radix <= 10 && (c == 'e' || c == 'E'))
|| (radix == 16 && (c == 'p' || c == 'P'))) || (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; float_flag = AFTER_EXPON;
break; break;
} }
@ -463,6 +490,10 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
} }
} }
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. */ /* The suffix may be for decimal fixed-point constants without exponent. */
if (radix != 16 && float_flag == NOT_FLOAT) if (radix != 16 && float_flag == NOT_FLOAT)
{ {
@ -520,16 +551,28 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
/* Exponent is decimal, even if string is a hex float. */ /* Exponent is decimal, even if string is a hex float. */
if (!ISDIGIT (*str)) 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 do
str++; {
while (ISDIGIT (*str)); seen_digit_sep = DIGIT_SEP (*str);
str++;
}
while (ISDIGIT (*str) || DIGIT_SEP (*str));
} }
else if (radix == 16) else if (radix == 16)
SYNTAX_ERROR_AT (virtual_location, SYNTAX_ERROR_AT (virtual_location,
"hexadecimal floating constants require an exponent"); "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); result = interpret_float_suffix (pfile, str, limit - str);
if (result == 0) if (result == 0)
{ {
@ -723,6 +766,8 @@ cpp_interpret_integer (cpp_reader *pfile, const cpp_token *token,
if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c))) if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c)))
c = hex_value (c); c = hex_value (c);
else if (DIGIT_SEP (c))
continue;
else else
break; break;

View File

@ -437,6 +437,9 @@ struct cpp_options
/* Nonzero for C++ 2014 Standard binary constants. */ /* Nonzero for C++ 2014 Standard binary constants. */
unsigned char 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. */ /* Holds the name of the target (execution) character set. */
const char *narrow_charset; const char *narrow_charset;

View File

@ -84,24 +84,25 @@ struct lang_flags
char rliterals; char rliterals;
char user_literals; char user_literals;
char binary_constants; char binary_constants;
char digit_separators;
}; };
static const struct lang_flags lang_defaults[] = static const struct lang_flags lang_defaults[] =
{ /* c99 c++ xnum xid std // digr ulit rlit udlit bin_cst */ { /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 } /* ASM */ { 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 }
/* xid should be 1 for GNUC99, STDC99, GNUCXX, CXX98, GNUCXX11, CXX11, /* xid should be 1 for GNUC99, STDC99, GNUCXX, CXX98, GNUCXX11, CXX11,
GNUCXX1Y, and CXX1Y when no longer experimental (when all uses of GNUCXX1Y, and CXX1Y when no longer experimental (when all uses of
identifiers in the compiler have been audited for correct handling identifiers in the compiler have been audited for correct handling
@ -128,6 +129,7 @@ cpp_set_lang (cpp_reader *pfile, enum c_lang lang)
CPP_OPTION (pfile, rliterals) = l->rliterals; CPP_OPTION (pfile, rliterals) = l->rliterals;
CPP_OPTION (pfile, user_literals) = l->user_literals; CPP_OPTION (pfile, user_literals) = l->user_literals;
CPP_OPTION (pfile, binary_constants) = l->binary_constants; CPP_OPTION (pfile, binary_constants) = l->binary_constants;
CPP_OPTION (pfile, digit_separators) = l->digit_separators;
} }
/* Initialize library global state. */ /* Initialize library global state. */

View File

@ -59,6 +59,8 @@ struct cset_converter
|| (((prevc) == 'p' || (prevc) == 'P') \ || (((prevc) == 'p' || (prevc) == 'P') \
&& CPP_OPTION (pfile, extended_numbers)))) && 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_OPTION(PFILE, OPTION) ((PFILE)->opts.OPTION)
#define CPP_BUFFER(PFILE) ((PFILE)->buffer) #define CPP_BUFFER(PFILE) ((PFILE)->buffer)
#define CPP_BUF_COLUMN(BUF, CUR) ((CUR) - (BUF)->line_base) #define CPP_BUF_COLUMN(BUF, CUR) ((CUR) - (BUF)->line_base)

View File

@ -1274,7 +1274,8 @@ lex_number (cpp_reader *pfile, cpp_string *number,
cur = pfile->buffer->cur; cur = pfile->buffer->cur;
/* N.B. ISIDNUM does not include $. */ /* 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++; cur++;
NORMALIZE_STATE_UPDATE_IDNUM (nst); NORMALIZE_STATE_UPDATE_IDNUM (nst);

View File

@ -1,3 +1,9 @@
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, '\''>.
2013-10-31 Paolo Carlini <paolo.carlini@oracle.com> 2013-10-31 Paolo Carlini <paolo.carlini@oracle.com>
* testsuite/20_util/default_delete/48631_neg.cc: Tweak dg-prune. * testsuite/20_util/default_delete/48631_neg.cc: Tweak dg-prune.

View File

@ -32,7 +32,7 @@
#pragma GCC system_header #pragma GCC system_header
// From n3642.pdf except I added binary literals and digit separator '`'. // From n3642.pdf except I added binary literals and digit separator '\''.
#if __cplusplus > 201103L #if __cplusplus > 201103L
@ -221,7 +221,7 @@ namespace __parse_int {
// Digit separator // Digit separator
template<unsigned _Base> template<unsigned _Base>
struct _Digit<_Base, '`'> struct _Digit<_Base, '\''>
{ {
static constexpr bool valid{false}; static constexpr bool valid{false};
static constexpr unsigned value{0}; static constexpr unsigned value{0};