PING! Support operator"" ""(...) per CWG 1473. This brings full string parsing to literal operator declarations including string chunk concatenation and appropriate errors.
Bootstrapped and tested on x86_64-linux. OK? I'm less sure if this is appropriate for 4.9 even when it opens.
cp/ 2014-07-12 Edward Smith-Rowland <3dw...@verizon.net> PR C++/60209 - Declaration of user-defined literal operator cause error * cp/parser.c (cp_parser_operator()): Fold treatment of strings and user-defined string literals. Use the full string parser. (cp_parser_string_literal()): Add flag to not look for literal operator. testsuite/ 2014-07-12 Edward Smith-Rowland <3dw...@verizon.net> PR C++/60209 - Declaration of user-defined literal operator cause error * g++.dg/cpp0x/pr60209-neg.C: New. * g++.dg/cpp0x/pr60209.C: New. * g++.dg/cpp1y/udlit-empty-string-neg.C: Adjust messages.
Index: cp/parser.c =================================================================== --- cp/parser.c (revision 212479) +++ cp/parser.c (working copy) @@ -1895,7 +1895,7 @@ static tree cp_parser_identifier (cp_parser *); static tree cp_parser_string_literal - (cp_parser *, bool, bool); + (cp_parser *, bool, bool, bool); static tree cp_parser_userdef_char_literal (cp_parser *); static tree cp_parser_userdef_string_literal @@ -3566,7 +3566,8 @@ FUTURE: ObjC++ will need to handle @-strings here. */ static tree -cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok) +cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok, + bool lookup_udlit = true) { tree value; size_t count; @@ -3721,7 +3722,10 @@ { tree literal = build_userdef_literal (suffix_id, value, OT_NONE, NULL_TREE); - value = cp_parser_userdef_string_literal (literal); + if (lookup_udlit) + value = cp_parser_userdef_string_literal (literal); + else + value = literal; } } else @@ -12636,7 +12640,7 @@ { tree id = NULL_TREE; cp_token *token; - bool bad_encoding_prefix = false; + bool utf8 = false; /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); @@ -12836,83 +12840,73 @@ cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); return ansi_opname (ARRAY_REF); + case CPP_UTF8STRING: + case CPP_UTF8STRING_USERDEF: + utf8 = true; + case CPP_STRING: case CPP_WSTRING: case CPP_STRING16: case CPP_STRING32: - case CPP_UTF8STRING: - bad_encoding_prefix = true; - /* Fall through. */ - - case CPP_STRING: - if (cxx_dialect == cxx98) - maybe_warn_cpp0x (CPP0X_USER_DEFINED_LITERALS); - if (bad_encoding_prefix) - { - error ("invalid encoding prefix in literal operator"); - return error_mark_node; - } - if (TREE_STRING_LENGTH (token->u.value) > 2) - { - error ("expected empty string after %<operator%> keyword"); - return error_mark_node; - } - /* Consume the string. */ - cp_lexer_consume_token (parser->lexer); - /* Look for the suffix identifier. */ - token = cp_lexer_peek_token (parser->lexer); - if (token->type == CPP_NAME) - { - id = cp_parser_identifier (parser); - if (id != error_mark_node) - { - const char *name = IDENTIFIER_POINTER (id); - return cp_literal_operator_id (name); - } - } - else if (token->type == CPP_KEYWORD) - { - error ("unexpected keyword;" - " remove space between quotes and suffix identifier"); - return error_mark_node; - } - else - { - error ("expected suffix identifier"); - return error_mark_node; - } - + case CPP_STRING_USERDEF: case CPP_WSTRING_USERDEF: case CPP_STRING16_USERDEF: case CPP_STRING32_USERDEF: - case CPP_UTF8STRING_USERDEF: - bad_encoding_prefix = true; - /* Fall through. */ + { + tree str, string_tree; + int sz, len; - case CPP_STRING_USERDEF: - if (cxx_dialect == cxx98) - maybe_warn_cpp0x (CPP0X_USER_DEFINED_LITERALS); - if (bad_encoding_prefix) - { - error ("invalid encoding prefix in literal operator"); + if (cxx_dialect == cxx98) + maybe_warn_cpp0x (CPP0X_USER_DEFINED_LITERALS); + + /* Consume the string. */ + str = cp_parser_string_literal (parser, /*translate=*/true, + /*wide_ok=*/true, /*lookup_udlit=*/false); + if (str == error_mark_node) return error_mark_node; - } - { - tree string_tree = USERDEF_LITERAL_VALUE (token->u.value); - if (TREE_STRING_LENGTH (string_tree) > 2) + else if (TREE_CODE (str) == USERDEF_LITERAL) { + string_tree = USERDEF_LITERAL_VALUE (str); + id = USERDEF_LITERAL_SUFFIX_ID (str); + } + else + { + string_tree = str; + /* Look for the suffix identifier. */ + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_NAME) + id = cp_parser_identifier (parser); + else if (token->type == CPP_KEYWORD) + { + error ("unexpected keyword;" + " remove space between quotes and suffix identifier"); + return error_mark_node; + } + else + { + error ("expected suffix identifier"); + return error_mark_node; + } + } + sz = TREE_INT_CST_LOW (TYPE_SIZE_UNIT + (TREE_TYPE (TREE_TYPE (string_tree)))); + len = TREE_STRING_LENGTH (string_tree) / sz - 1; + if (len != 0) + { error ("expected empty string after %<operator%> keyword"); return error_mark_node; } - id = USERDEF_LITERAL_SUFFIX_ID (token->u.value); - /* Consume the user-defined string literal. */ - cp_lexer_consume_token (parser->lexer); + if (utf8 || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (string_tree))) + != char_type_node) + { + error ("invalid encoding prefix in literal operator"); + return error_mark_node; + } if (id != error_mark_node) { const char *name = IDENTIFIER_POINTER (id); - return cp_literal_operator_id (name); + id = cp_literal_operator_id (name); } - else - return error_mark_node; + return id; } default: Index: testsuite/g++.dg/cpp0x/pr60209-neg.C =================================================================== --- testsuite/g++.dg/cpp0x/pr60209-neg.C (revision 0) +++ testsuite/g++.dg/cpp0x/pr60209-neg.C (working copy) @@ -0,0 +1,28 @@ +// PR c++/60209 +// { dg-do compile { target c++11 } } + +// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1473 + +void operator "" "boo" _ya(unsigned long long); // { dg-error "expected empty string after" } + +void operator "" "boo"_ya(unsigned long long); // { dg-error "expected empty string after" } + +void operator "" u"" _u(unsigned long long); // { dg-error "invalid encoding prefix in literal operator" } + +void operator u"" "" _v(unsigned long long); // { dg-error "invalid encoding prefix in literal operator" } + +void operator U"" "" _w(unsigned long long); // { dg-error "invalid encoding prefix in literal operator" } + +void operator L"" "" _x(unsigned long long); // { dg-error "invalid encoding prefix in literal operator" } + +void operator u8"" "" _y(unsigned long long); // { dg-error "invalid encoding prefix in literal operator" } + +void operator u"" L"" _z(unsigned long long); // { dg-error "unsupported non-standard concatenation of string literals" } + +void operator ""_p ""_q(unsigned long long); // { dg-error "inconsistent user-defined literal suffixes" } + +void operator "" "" while(unsigned long long); // { dg-error "unexpected keyword; remove space between quotes and suffix identifier" } + +void operator "" ""(unsigned long long); // { dg-error "expected suffix identifier" } + +// { dg-error "invalid encoding prefix in literal operator" "invalid" { target *-*-* } 20 } Index: testsuite/g++.dg/cpp0x/pr60209.C =================================================================== --- testsuite/g++.dg/cpp0x/pr60209.C (revision 0) +++ testsuite/g++.dg/cpp0x/pr60209.C (working copy) @@ -0,0 +1,12 @@ +// PR c++/60209 +// { dg-do compile { target c++11 } } + +// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1473 + +void operator "" "" _x(unsigned long long); + +void operator "" "" "" _x(unsigned long long); + +void operator "" ""_w(unsigned long long); + +void operator "" ""_w ""(unsigned long long); Index: testsuite/g++.dg/cpp1y/udlit-empty-string-neg.C =================================================================== --- testsuite/g++.dg/cpp1y/udlit-empty-string-neg.C (revision 212479) +++ testsuite/g++.dg/cpp1y/udlit-empty-string-neg.C (working copy) @@ -5,17 +5,17 @@ { return 0; } int -operator L"*"_Ls(unsigned long long) // { dg-error "invalid encoding prefix in literal operator" } +operator L"*"_Ls(unsigned long long) // { dg-error "expected empty string after 'operator'" } { return 0; } int -operator u"*"_s16(unsigned long long) // { dg-error "invalid encoding prefix in literal operator" } +operator u"*"_s16(unsigned long long) // { dg-error "expected empty string after 'operator'" } { return 0; } int -operator U"*"_s32(unsigned long long) // { dg-error "invalid encoding prefix in literal operator" } +operator U"*"_s32(unsigned long long) // { dg-error "expected empty string after 'operator'" } { return 0; } int -operator u8"*"_u8s(unsigned long long) // { dg-error "invalid encoding prefix in literal operator" } +operator u8"*"_u8s(unsigned long long) // { dg-error "expected empty string after 'operator'" } { return 0; }