Ping... Sorry I forgot to cc you. I needed rebase anyhow after all the churn recently.
Also, I started a food fight with http://gcc.gnu.org/ml/gcc/2011-11/msg00124.html. My idea was that if C++ explicitly does not use the fixed point suffixes then, in C++11 mode, we should pass them along as user-defined literals. I think the point was lost ;-). But what would you say to a three-liner and a test case? And the idea?
Ed
Index: gcc/testsuite/g++.dg/cpp0x/udlit-raw-length.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-raw-length.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-raw-length.C (revision 0) @@ -0,0 +1,27 @@ +// { dg-options "-std=c++0x" } +// PR c++/50958 + +typedef decltype(sizeof(0)) size_type; + +constexpr size_type +cstrlen_impl(const char* s, size_type i) +{ + return s[i] ? cstrlen_impl(s, i + 1) : i; +} + +constexpr size_type +cstrlen(const char* s) +{ + return s ? cstrlen_impl(s, 0) : throw 0; +} + +constexpr size_type +operator "" _lenraw(const char* digits) +{ + return cstrlen(digits); +} + +static_assert(123_lenraw == 3, "Ouch"); +static_assert(1_lenraw == 1, "Ouch"); +static_assert(012_lenraw == 3, "Ouch"); +static_assert(0_lenraw == 1, "Ouch"); Index: gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C (revision 181180) +++ gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C (working copy) @@ -5,4 +5,4 @@ int operator"" _embedraw(const char*) { return 41; }; -int k = "Boo!"_embedraw; // { dg-error "unable to find valid user-defined string literal operator" } +int k = "Boo!"_embedraw; // { dg-error "unable to find valid string literal operator" } Index: gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C (revision 181180) +++ gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C (working copy) @@ -8,7 +8,7 @@ }; int i = operator"" _Bar(U'x'); // { dg-error "was not declared in this scope" } -int j = U'x'_Bar; // { dg-error "unable to find user-defined character literal operator" } +int j = U'x'_Bar; // { dg-error "unable to find character literal operator" } int Foo::operator"" _Bar(char32_t) // { dg-error "must be a non-member function" } Index: gcc/testsuite/g++.dg/cpp0x/udlit-implicit-conv-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-implicit-conv-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-implicit-conv-neg.C (revision 0) @@ -0,0 +1,63 @@ +// { dg-options -std=c++0x } + +#include <cstdint> + +int operator"" _bar (long double); + +double operator"" _foo (long long unsigned); + +int i = 12_bar; // { dg-error "unable to find numeric literal operator|with|argument" } + +double d = 1.2_foo; // { dg-error "unable to find numeric literal operator|with|argument" } + +int operator"" _char(char); + +int operator"" _wchar_t(wchar_t); + +int operator"" _char16_t(char16_t); + +int operator"" _char32_t(char32_t); + +int cwcx = 'c'_wchar_t; // { dg-error "unable to find character literal operator|with|argument" } +int cc16 = 'c'_char16_t; // { dg-error "unable to find character literal operator|with|argument" } +int cc32 = 'c'_char32_t; // { dg-error "unable to find character literal operator|with|argument" } + +int wccx = L'c'_char; // { dg-error "unable to find character literal operator|with|argument" } +int wcc16 = L'c'_char16_t; // { dg-error "unable to find character literal operator|with|argument" } +int wcc32 = L'c'_char32_t; // { dg-error "unable to find character literal operator|with|argument" } + +int c16c = u'c'_char; // { dg-error "unable to find character literal operator|with|argument" } +int c16wc = u'c'_wchar_t; // { dg-error "unable to find character literal operator|with|argument" } +int c16c32 = u'c'_char32_t; // { dg-error "unable to find character literal operator|with|argument" } + +int c32c = U'c'_char; // { dg-error "unable to find character literal operator|with|argument" } +int c32wc = U'c'_wchar_t; // { dg-error "unable to find character literal operator|with|argument" } +int c32c16 = U'c'_char16_t; // { dg-error "unable to find character literal operator|with|argument" } + +int operator"" _char_str(const char*, std::size_t); + +int operator"" _wchar_t_str(const wchar_t*, std::size_t); + +int operator"" _char16_t_str(const char16_t*, std::size_t); + +int operator"" _char32_t_str(const char32_t*, std::size_t); + +int strwstr = "str"_wchar_t_str; // { dg-error "unable to find string literal operator|with|arguments" } +int strstr16 = "str"_char16_t_str; // { dg-error "unable to find string literal operator|with|arguments" } +int strstr32 = "str"_char32_t_str; // { dg-error "unable to find string literal operator|with|arguments" } + +int str8wstr = u8"str"_wchar_t_str; // { dg-error "unable to find string literal operator|with|arguments" } +int str8str16 = u8"str"_char16_t_str; // { dg-error "unable to find string literal operator|with|arguments" } +int str8str32 = u8"str"_char32_t_str; // { dg-error "unable to find string literal operator|with|arguments" } + +int wstrstr = L"str"_char_str; // { dg-error "unable to find string literal operator|with|arguments" } +int wstrstr16 = L"str"_char16_t_str; // { dg-error "unable to find string literal operator|with|arguments" } +int wstrstr32 = L"str"_char32_t_str; // { dg-error "unable to find string literal operator|with|arguments" } + +int str16str = u"str"_char_str; // { dg-error "unable to find string literal operator|with|arguments" } +int str16wstr = u"str"_wchar_t_str; // { dg-error "unable to find string literal operator|with|arguments" } +int str16str32 = u"str"_char32_t_str; // { dg-error "unable to find string literal operator|with|arguments" } + +int str32str = U"str"_char_str; // { dg-error "unable to find string literal operator|with|arguments" } +int str32wstr = U"str"_wchar_t_str; // { dg-error "unable to find string literal operator|with|arguments" } +int str32str16 = U"str"_char16_t_str; // { dg-error "unable to find string literal operator string operator|with|arguments" } Index: gcc/testsuite/g++.dg/cpp0x/udlit-resolve.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-resolve.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-resolve.C (revision 0) @@ -0,0 +1,43 @@ +// { dg-do run } +// { dg-options "-std=c++0x" } + +#include <cstdint> +#include <cassert> + +int operator"" _foo(const char*) { return 0; } +int operator"" _foo(unsigned long long int) { return 1; } +int operator"" _foo(long double) { return 2; } +int operator"" _foo(char) { return 3; } +int operator"" _foo(wchar_t) { return 4; } +int operator"" _foo(char16_t) { return 5; } +int operator"" _foo(char32_t) { return 6; } +int operator"" _foo(const char*, std::size_t) { return 7; } +int operator"" _foo(const wchar_t*, std::size_t) { return 8; } +int operator"" _foo(const char16_t*, std::size_t) { return 9; } +int operator"" _foo(const char32_t*, std::size_t) { return 10; } +template<char...> int operator"" _foo2() { return 20; } +int operator"" _foo2(unsigned long long int) { return 21; } + +namespace bar { +int operator"" _foo(unsigned long long int) { return 101; } +} +using namespace bar; + +int +main() +{ + //assert(123_foo == 0); + //assert(123_foo == 1); + assert(123_foo == 101); + assert(0.123_foo == 2); + assert('c'_foo == 3); + assert(L'c'_foo == 4); + assert(u'c'_foo == 5); + assert(U'c'_foo == 6); + assert("abc"_foo == 7); + assert(L"abc"_foo == 8); + assert(u"abc"_foo == 9); + assert(U"abc"_foo == 10); + assert(123_foo2 == 21); + //assert(_foo == ); +} Index: gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C (revision 181180) +++ gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C (working copy) @@ -3,13 +3,13 @@ // Check that undeclared literal operator calls and literals give appropriate errors. int i = operator"" _Bar('x'); // { dg-error "was not declared in this scope" } -int j = 'x'_Bar; // { dg-error "unable to find user-defined character literal operator" } +int j = 'x'_Bar; // { dg-error "unable to find character literal operator" } int ii = operator"" _BarCharStr("Howdy, Pardner!"); // { dg-error "was not declared in this scope" } -int jj = "Howdy, Pardner!"_BarCharStr; // { dg-error "unable to find user-defined string literal operator" } +int jj = "Howdy, Pardner!"_BarCharStr; // { dg-error "unable to find valid string literal operator" } unsigned long long iULL = operator"" _BarULL(666ULL); // { dg-error "was not declared in this scope" } -unsigned long long jULL = 666_BarULL; // { dg-error "unable to find user-defined numeric literal operator" } +unsigned long long jULL = 666_BarULL; // { dg-error "unable to find numeric literal operator" } long double iLD = operator"" _BarLD(666.0L); // { dg-error "was not declared in this scope" } -long double jLD = 666.0_BarLD; // { dg-error "unable to find user-defined numeric literal operator" } +long double jLD = 666.0_BarLD; // { dg-error "unable to find numeric literal operator" } Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 181180) +++ gcc/cp/parser.c (working copy) @@ -3547,40 +3547,86 @@ return value; } +/* Look up a literal operator with the name and the exact arguments. */ + +static tree +lookup_literal_operator(tree name, VEC(tree,gc) *args, bool *have_size) +{ + tree decl, fns; + if (have_size) + *have_size = false; + decl = lookup_name (name); + if (!decl || decl == error_mark_node) + return error_mark_node; + + for (fns = decl; fns; fns = OVL_NEXT (fns)) + { + unsigned int ix; + bool found = true; + tree fn = OVL_CURRENT (fns); + tree argtypes = NULL_TREE; + if (TREE_CODE (TREE_TYPE (fn)) != LANG_TYPE) + argtypes = TYPE_ARG_TYPES (TREE_TYPE (fn)); + if (argtypes != NULL_TREE) + { + for (ix = 0; ix < VEC_length (tree, args) && argtypes != NULL_TREE; + ++ix, argtypes = TREE_CHAIN (argtypes)) + { + bool ptr = TREE_CODE (TREE_VALUE (argtypes)) == POINTER_TYPE; + bool arr = TREE_CODE (TREE_TYPE (VEC_index (tree, args, ix))) + == ARRAY_TYPE; + if ((ptr || arr + || !same_type_p (TREE_VALUE (argtypes), + TREE_TYPE (VEC_index (tree, args, ix)))) + && (!ptr || !arr + || !same_type_p (TREE_TYPE (TREE_VALUE (argtypes)), + TREE_TYPE (TREE_TYPE (VEC_index (tree, args, ix)))))) + found = false; + if (have_size && ix == 1 + && same_type_p (TREE_VALUE (argtypes), size_type_node)) + *have_size = true; + } + if (found) + return fn; + } + } + + return error_mark_node; +} + /* Parse a user-defined char constant. Returns a call to a user-defined literal operator taking the character as an argument. */ static tree cp_parser_userdef_char_literal (cp_parser *parser) { - cp_token *token = NULL; - tree literal, suffix_id, value; - tree name, decl; - tree result; - VEC(tree,gc) *vec; + cp_token *token = cp_lexer_consume_token (parser->lexer); + tree literal = token->u.value; + tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal); + tree value = USERDEF_LITERAL_VALUE (literal); + tree name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id)); + tree decl, result; - token = cp_lexer_consume_token (parser->lexer); - literal = token->u.value; - suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal); - value = USERDEF_LITERAL_VALUE (literal); - name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id)); - /* Build up a call to the user-defined operator */ /* Lookup the name we got back from the id-expression. */ - vec = make_tree_vector (); - VEC_safe_push (tree, gc, vec, value); - decl = lookup_function_nonclass (name, vec, /*block_p=*/false); + VEC(tree,gc) *args = make_tree_vector (); + VEC_safe_push (tree, gc, args, value); + decl = lookup_literal_operator(name, args, NULL); if (!decl || decl == error_mark_node) { - error ("unable to find user-defined character literal operator %qD", - name); - release_tree_vector (vec); + error ("unable to find character literal operator %qD with %qT argument", + name, TREE_TYPE (value)); + release_tree_vector (args); return error_mark_node; } - result = finish_call_expr (decl, &vec, false, true, tf_warning_or_error); - release_tree_vector (vec); + result = finish_call_expr (decl, &args, false, true, tf_warning_or_error); + release_tree_vector (args); + if (result != error_mark_node) + return result; - return result; + error ("unable to find character literal operator %qD with %qT argument", + name, TREE_TYPE (value)); + return error_mark_node; } /* A subroutine of cp_parser_userdef_numeric_literal to @@ -3615,26 +3661,20 @@ static tree cp_parser_userdef_numeric_literal (cp_parser *parser) { - cp_token *token = NULL; - tree literal, suffix_id, value, num_string; - tree name, decl; - tree result = error_mark_node; + cp_token *token = cp_lexer_consume_token (parser->lexer); + tree literal = token->u.value; + tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal); + tree value = USERDEF_LITERAL_VALUE (literal); + tree num_string = USERDEF_LITERAL_NUM_STRING (literal); + tree name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id)); + tree decl, result; VEC(tree,gc) *args; - token = cp_lexer_consume_token (parser->lexer); - literal = token->u.value; - suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal); - value = USERDEF_LITERAL_VALUE (literal); - num_string = USERDEF_LITERAL_NUM_STRING (literal); - name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id)); - - /* Build up a call to the user-defined operator */ - /* Lookup the name we got back from the id-expression. */ - /* Try to find the literal operator by finishing the call expression - with the numeric argument. */ + /* Look for a literal operator taking the exact type of numeric argument + as the literal value. */ args = make_tree_vector (); VEC_safe_push (tree, gc, args, value); - decl = lookup_function_nonclass (name, args, /*block_p=*/false); + decl = lookup_literal_operator (name, args, NULL); if (decl && decl != error_mark_node) { result = finish_call_expr (decl, &args, false, true, tf_none); @@ -3651,7 +3691,7 @@ in string format. */ args = make_tree_vector (); VEC_safe_push (tree, gc, args, num_string); - decl = lookup_function_nonclass (name, args, /*block_p=*/false); + decl = lookup_literal_operator (name, args, NULL); if (decl && decl != error_mark_node) { result = finish_call_expr (decl, &args, false, true, tf_none); @@ -3667,7 +3707,7 @@ function with parameter pack char.... Call the function with template parameter characters representing the number. */ args = make_tree_vector (); - decl = lookup_function_nonclass (name, args, /*block_p=*/false); + decl = lookup_literal_operator (name, args, NULL); if (decl && decl != error_mark_node) { tree tmpl_args = make_char_string_pack (num_string); @@ -3681,10 +3721,8 @@ } release_tree_vector (args); - if (result == error_mark_node) - error ("unable to find user-defined numeric literal operator %qD", name); - - return result; + error ("unable to find numeric literal operator %qD", name); + return error_mark_node; } /* Parse a user-defined string constant. Returns a call to a user-defined @@ -3694,38 +3732,41 @@ static tree cp_parser_userdef_string_literal (cp_token *token) { - tree literal, suffix_id, value; - tree name, decl; - tree result; - VEC(tree,gc) *vec; - int len; + tree literal = token->u.value; + tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal); + tree name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id)); + tree value = USERDEF_LITERAL_VALUE (literal); + int len = TREE_STRING_LENGTH (value) + / TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (value)))) - 1; + bool have_size = false; + tree decl, result; - literal = token->u.value; - suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal); - name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id)); - value = USERDEF_LITERAL_VALUE (literal); - len = TREE_STRING_LENGTH (value) - / TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (value)))) - 1; /* Build up a call to the user-defined operator */ /* Lookup the name we got back from the id-expression. */ - vec = make_tree_vector (); - VEC_safe_push (tree, gc, vec, value); - VEC_safe_push (tree, gc, vec, build_int_cst (size_type_node, len)); - decl = lookup_function_nonclass (name, vec, /*block_p=*/false); + VEC(tree,gc) *args = make_tree_vector (); + VEC_safe_push (tree, gc, args, value); + VEC_safe_push (tree, gc, args, build_int_cst (size_type_node, len)); + decl = lookup_literal_operator (name, args, &have_size); if (!decl || decl == error_mark_node) { - error ("unable to find user-defined string literal operator %qD", name); - release_tree_vector (vec); + if (have_size) + error ("unable to find string literal operator %qD with %qT, %qT" + " arguments", name, TREE_TYPE (value), size_type_node); + else + error ("unable to find valid string literal operator %qD." + " Possible missing length argument in string literal operator.", + name); + release_tree_vector (args); return error_mark_node; } - result = finish_call_expr (decl, &vec, false, true, tf_none); - if (result == error_mark_node) - error ("unable to find valid user-defined string literal operator %qD." - " Possible missing length argument in string literal operator.", - name); - release_tree_vector (vec); + result = finish_call_expr (decl, &args, false, true, tf_none); + release_tree_vector (args); + if (result != error_mark_node) + return result; - return result; + error ("unable to find string literal operator %qD with %qT, %qT arguments", + name, TREE_TYPE (value), size_type_node); + return error_mark_node; } Index: libcpp/expr.c =================================================================== --- libcpp/expr.c (revision 181180) +++ libcpp/expr.c (working copy) @@ -284,9 +284,9 @@ else if (type == CPP_WCHAR_USERDEF) return CPP_WCHAR; else if (type == CPP_CHAR16_USERDEF) - return CPP_STRING16; + return CPP_CHAR16; else if (type == CPP_CHAR32_USERDEF) - return CPP_STRING32; + return CPP_CHAR32; else return type; }
2011-10-30 Ed Smith-Rowland <3dw...@verizon.net> * gcc/testsuite/g++.dg/cpp0x/udlit-raw-length.C: New. * gcc/testsuite/g++.dg/cpp0x/udlit-implicit-conv-neg.C: New. * gcc/testsuite/g++.dg/cpp0x/udlit-resolve.C: New. * gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C: Adjust error message. * gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C: Ditto. * gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C: Ditto. * gcc/cp/parser.c: (lookup_literal_operator): New to correct lookup of literal operators. (cp_parser_userdef_char_literal, cp_parser_userdef_numeric_literal, cp_parser_userdef_string_literal): Use it. * libcpp/expr.c: (cpp_userdef_char_remove_type): Fix boneheaded paste-o.