From patchwork Wed Oct 30 22:53:07 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ed Smith-Rowland <3dw4rd@verizon.net> X-Patchwork-Id: 287361 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id E0AE72C037D for ; Thu, 31 Oct 2013 09:53:43 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; q=dns; s=default; b=R30KrAsVBpg7UkpyQ 9ApUwlKUazv2EcNz3RjXuRXQOT5TbRrf79q0Uo5R0kbmr2JHKoafqL89FYCN6W5O 1ygzHyW1ZcIFSNs1YCDRgzmviU7Qj7gHbgi7Uhd2pfXCqVxhADwXpyPez5aEgpqX YvzDEuZVgHXJRNMr364bc5nAVI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; s=default; bh=bz5V3gb2Qh53UiPhkoTmMrB cVcE=; b=RUWmDt4bavbSIkOTcuL3NFHtBOtj4ehFdPe9PMfqQSD9dctCaIRqCFe K17bQQMKeeiTGs/GPTCS34x0geFKXsZ3ykR9bJK579BOZS/NDDurW7tYw2hoP0Rb lCt5B/dV6oNSXm7KwQh6/og4wNWSeUu73iLw069ADh1t1X4JkZS0= Received: (qmail 10991 invoked by alias); 30 Oct 2013 22:53:37 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 10981 invoked by uid 89); 30 Oct 2013 22:53:37 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.0 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 X-HELO: vms173007pub.verizon.net Received: from vms173007pub.verizon.net (HELO vms173007pub.verizon.net) (206.46.173.7) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 30 Oct 2013 22:53:27 +0000 Received: from [192.168.1.13] ([unknown] [74.103.25.251]) by vms173007.mailsrvcs.net (Sun Java(tm) System Messaging Server 7u2-7.02 32bit (built Apr 16 2009)) with ESMTPA id <0MVI00MPO7KJHN90@vms173007.mailsrvcs.net> for gcc-patches@gcc.gnu.org; Wed, 30 Oct 2013 17:53:08 -0500 (CDT) Message-id: <52718DD3.3020700@verizon.net> Date: Wed, 30 Oct 2013 18:53:07 -0400 From: Ed Smith-Rowland <3dw4rd@verizon.net> User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.0 MIME-version: 1.0 To: Jason Merrill , "Joseph S. Myers" Cc: gcc-patches Subject: Re: C++14 digit separators.. References: <526DD13C.2080400@verizon.net> <526E6A4B.5000207@redhat.com> In-reply-to: <526E6A4B.5000207@redhat.com> Content-type: multipart/mixed; boundary=------------010707040208090906080309 On 10/28/2013 09:44 AM, Jason Merrill wrote: > On 10/28/2013 09:10 AM, Joseph S. Myers wrote: >> On Sun, 27 Oct 2013, Ed Smith-Rowland wrote: >> >>> Here is an implementation for C++14 digit separators (single quote). >> >> I tend to think that such features should come with a test that the >> feature is not enabled for language / standard versions for which it >> shouldn't be. That is, something like >> >> #define m(x) 0 >> int i = m(1'2)+(3'4); > > Good idea. Other than that, the patch looks good to me. > > Jason > > OK, I had to add some more checks in libcpp. After reading the standard a few times i figured out the magic words are "digit separators" - must have digit on both sides. I also put in the suggested check above. bootstrapped and fully tested on x86_64-linux. Still OK? Ed libcpp: 2013-10-30 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-30 Edward Smith-Rowland <3dw4rd@verizon.net> * c-lex.c (interpret_float): Remove digit separators from scratch string before building real literal. gcc/testsuite: 2013-10-30 Edward Smith-Rowland <3dw4rd@verizon.net> * 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-30 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, '\''>. Index: libcpp/include/cpplib.h =================================================================== --- libcpp/include/cpplib.h (revision 204189) +++ libcpp/include/cpplib.h (working copy) @@ -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; Index: libcpp/internal.h =================================================================== --- libcpp/internal.h (revision 204189) +++ libcpp/internal.h (working copy) @@ -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) Index: libcpp/expr.c =================================================================== --- libcpp/expr.c (revision 204189) +++ libcpp/expr.c (working copy) @@ -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; Index: libcpp/init.c =================================================================== --- libcpp/init.c (revision 204189) +++ libcpp/init.c (working copy) @@ -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. */ Index: libcpp/lex.c =================================================================== --- libcpp/lex.c (revision 204189) +++ libcpp/lex.c (working copy) @@ -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); Index: gcc/c-family/c-lex.c =================================================================== --- gcc/c-family/c-lex.c (revision 204189) +++ gcc/c-family/c-lex.c (working copy) @@ -774,8 +774,19 @@ } copy = (char *) alloca (copylen + 1); - memcpy (copy, token->val.str.text, copylen); - copy[copylen] = '\0'; + if (cxx_dialect > cxx11) + { + 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)); if (const_type != type) Index: libstdc++-v3/include/bits/parse_numbers.h =================================================================== --- libstdc++-v3/include/bits/parse_numbers.h (revision 204189) +++ libstdc++-v3/include/bits/parse_numbers.h (working copy) @@ -32,7 +32,7 @@ #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 @@ -221,7 +221,7 @@ // Digit separator template - struct _Digit<_Base, '`'> + struct _Digit<_Base, '\''> { static constexpr bool valid{false}; static constexpr unsigned value{0}; Index: gcc/testsuite/g++.dg/cpp1y/digit-sep.C =================================================================== --- gcc/testsuite/g++.dg/cpp1y/digit-sep.C (revision 0) +++ gcc/testsuite/g++.dg/cpp1y/digit-sep.C (working copy) @@ -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); +} Index: gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C (working copy) @@ -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" } +} Index: gcc/testsuite/g++.dg/cpp1y/digit-sep-cxx11-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp1y/digit-sep-cxx11-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp1y/digit-sep-cxx11-neg.C (working copy) @@ -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); +}