On Thu, Jan 11, 2018 at 02:06:06PM +0000, Joseph Myers wrote: > On Thu, 11 Jan 2018, David Brown wrote: > > > Maybe it is easier to say "gcc supports <=> in C++2a, and as an > > extension also supports it in C and C++ of any standard" ? I don't > > believe there is any way for it to conflict with existing valid code, so > > it would do no harm as a gcc extension like that - and C users can then > > use it too. > > As per previous IRC discussion, changing the lexing to support this > pp-token can break valid code in previous standards, e.g. code > concatenating <=> and >, then stringizing the result (the C++ proposal for > adding this feature also notes some obscure cases where the character > sequence <=> can actually occur as tokens, not just pp-tokens - > "X<&Y::operator<=>" and "x+&operator<=>y" - so of course patches adding > this feature should add testcases using such cases with older -std= > options). > > Changes to cpp_avoid_paste (so that preprocessed output does not put a > pp-token starting with > immediately after <=) do not need to be > conditional on the standard version, however.
Here is a patch that attempts to implement this (in libcpp + gcc/testsuite only so far). It needs to be parsed and handled in the C++ FE obviously, which is missing. 2018-08-30 Jakub Jelinek <ja...@redhat.com> P0515R3 - Consistent comparison * include/cpplib.h (TTYPE_TABLE): Add CPP_SPACESHIP. (struct cpp_options): Add spaceship field. * init.c (struct lang_flags): Add spaceship field. (lang_defaults): Add spaceship column. (cpp_set_lang): Initialize CPP_OPTION (pfile, spaceship). * lex.c (_cpp_lex_direct): Lex CPP_SPACESHIP. (cpp_avoid_paste): Avoid pasting <= with >. * c-c++-common/cpp/spaceship-1.c: New test. * g++.dg/cpp/spaceship-1.C: New test. --- libcpp/include/cpplib.h.jj 2018-08-26 22:43:12.510939169 +0200 +++ libcpp/include/cpplib.h 2018-08-30 18:55:55.483035882 +0200 @@ -91,6 +91,7 @@ struct _cpp_file; OP(XOR_EQ, "^=") \ OP(RSHIFT_EQ, ">>=") \ OP(LSHIFT_EQ, "<<=") \ + OP(SPACESHIP, "<=>") \ /* Digraphs together, beginning with CPP_FIRST_DIGRAPH. */ \ OP(HASH, "#") /* digraphs */ \ OP(PASTE, "##") \ @@ -480,6 +481,9 @@ struct cpp_options /* Nonzero for C++2a __VA_OPT__ feature. */ unsigned char va_opt; + /* Nonzero for C++2a <=> operator. */ + unsigned char spaceship; + /* Holds the name of the target (execution) character set. */ const char *narrow_charset; --- libcpp/init.c.jj 2018-08-26 22:43:13.760918150 +0200 +++ libcpp/init.c 2018-08-30 18:57:41.479297007 +0200 @@ -92,30 +92,31 @@ struct lang_flags char trigraphs; char utf8_char_literals; char va_opt; + char spaceship; }; static const struct lang_flags lang_defaults[] = -{ /* c99 c++ xnum xid c11 std digr ulit rlit udlit bincst digsep trig u8chlit vaopt */ - /* GNUC89 */ { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 }, - /* GNUC99 */ { 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 }, - /* GNUC11 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 }, - /* GNUC17 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 }, - /* STDC89 */ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, - /* STDC94 */ { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 }, - /* STDC99 */ { 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 }, - /* STDC11 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0 }, - /* STDC17 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0 }, - /* GNUCXX */ { 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 }, - /* CXX98 */ { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 }, - /* GNUCXX11 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1 }, - /* CXX11 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0 }, - /* GNUCXX14 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1 }, - /* CXX14 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, - /* GNUCXX17 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, - /* CXX17 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0 }, - /* GNUCXX2A */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, - /* CXX2A */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, - /* ASM */ { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +{ /* c99 c++ xnum xid c11 std digr ulit rlit udlit bincst digsep trig u8chlit vaopt spaceship */ + /* GNUC89 */ { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + /* GNUC99 */ { 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0 }, + /* GNUC11 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0 }, + /* GNUC17 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0 }, + /* STDC89 */ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, + /* STDC94 */ { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, + /* STDC99 */ { 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, + /* STDC11 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0 }, + /* STDC17 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0 }, + /* GNUCXX */ { 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + /* CXX98 */ { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, + /* GNUCXX11 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0 }, + /* CXX11 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 }, + /* GNUCXX14 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, + /* CXX14 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, + /* GNUCXX17 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0 }, + /* CXX17 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0 }, + /* GNUCXX2A */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1 }, + /* CXX2A */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1 }, + /* ASM */ { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; /* Sets internal flags correctly for a given language. */ @@ -141,6 +142,7 @@ cpp_set_lang (cpp_reader *pfile, enum c_ CPP_OPTION (pfile, trigraphs) = l->trigraphs; CPP_OPTION (pfile, utf8_char_literals) = l->utf8_char_literals; CPP_OPTION (pfile, va_opt) = l->va_opt; + CPP_OPTION (pfile, spaceship) = l->spaceship; } /* Initialize library global state. */ --- libcpp/lex.c.jj 2018-08-26 22:43:14.784900935 +0200 +++ libcpp/lex.c 2018-08-30 19:02:43.261340974 +0200 @@ -2963,7 +2963,11 @@ _cpp_lex_direct (cpp_reader *pfile) result->type = CPP_LESS; if (*buffer->cur == '=') - buffer->cur++, result->type = CPP_LESS_EQ; + { + buffer->cur++, result->type = CPP_LESS_EQ; + if (*buffer->cur == '>' && CPP_OPTION (pfile, spaceship)) + buffer->cur++, result->type = CPP_SPACESHIP; + } else if (*buffer->cur == '<') { buffer->cur++; @@ -3466,6 +3470,7 @@ cpp_avoid_paste (cpp_reader *pfile, cons || (CPP_OPTION (pfile, objc) && token1->val.str.text[0] == '@' && (b == CPP_NAME || b == CPP_STRING))); + case CPP_LESS_EQ: return c == '>'; case CPP_STRING: case CPP_WSTRING: case CPP_UTF8STRING: --- gcc/testsuite/c-c++-common/cpp/spaceship-1.c.jj 2018-08-30 19:41:13.762257530 +0200 +++ gcc/testsuite/c-c++-common/cpp/spaceship-1.c 2018-08-30 19:49:09.338386388 +0200 @@ -0,0 +1,6 @@ +/* { dg-do preprocess } */ +/* { dg-options "-std=c11" { target c } } */ + +#define A(x, y) x##y +A(<=, >) /* { dg-error "does not give a valid preprocessing token" "" { target { ! c++2a } } } */ +A(<=>, >) /* { dg-error "does not give a valid preprocessing token" "" { target c++2a } } */ --- gcc/testsuite/g++.dg/cpp/spaceship-1.C.jj 2018-08-30 19:58:56.152695104 +0200 +++ gcc/testsuite/g++.dg/cpp/spaceship-1.C 2018-08-30 19:59:20.802288063 +0200 @@ -0,0 +1,8 @@ +// { dg-do compile { target c++17_down } } +// { dg-options "-Wno-pointer-arith" } + +struct X {}; +bool operator<= (X, X); +template<bool (X, X)> struct Y {}; +Y<&operator<=> y; +bool foo (bool (*fn) (X, X), int n) { return n+&operator<=> fn; } Jakub