Index: gcc/c-family/c-lex.c =================================================================== --- gcc/c-family/c-lex.c (revision 172287) +++ gcc/c-family/c-lex.c (working copy) @@ -44,8 +44,8 @@ int pending_lang_change; /* If we need to switch languages - C++ only */ int c_header_level; /* depth in C headers - C++ only */ -static tree interpret_integer (const cpp_token *, unsigned int); -static tree interpret_float (const cpp_token *, unsigned int); +static tree interpret_integer (const cpp_token *, unsigned int, const char *); +static tree interpret_float (const cpp_token *, unsigned int, const char *); static tree interpret_fixed (const cpp_token *, unsigned int); static enum integer_type_kind narrowest_unsigned_type (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned int); @@ -314,7 +314,8 @@ case CPP_NUMBER: { - unsigned int flags = cpp_classify_number (parse_in, tok); + char *suffix = NULL; + unsigned int flags = cpp_classify_number (parse_in, tok, &suffix); switch (flags & CPP_N_CATEGORY) { @@ -328,16 +329,24 @@ Set PURE_ZERO to pass this information to the C++ parser. */ if (tok->val.str.len == 1 && *tok->val.str.text == '0') add_flags = PURE_ZERO; - *value = interpret_integer (tok, flags); + *value = interpret_integer (tok, flags, suffix); break; case CPP_N_FLOATING: - *value = interpret_float (tok, flags); + *value = interpret_float (tok, flags, suffix); break; default: gcc_unreachable (); } + + if (flags & CPP_N_USERDEF) + { + tree literal = build_userdef_literal (); + USERDEF_LITERAL_SUFFIX_ID (literal) = get_identifier (suffix); + USERDEF_LITERAL_VALUE (literal) = *value; + *value = literal; + } } break; @@ -415,6 +424,24 @@ } goto retry; + case CPP_CHAR_USERDEF: + case CPP_WCHAR_USERDEF: + case CPP_CHAR16_USERDEF: + case CPP_CHAR32_USERDEF: + { + tree literal; + cpp_token temp_tok = *tok; + char suffix[256] = ""; + cpp_get_userdef_suffix (tok->val.str, '\'', suffix); + temp_tok.val.str.len -= strlen (suffix); + temp_tok.type = cpp_userdef_char_remove_type (type); + literal = build_userdef_literal (); + USERDEF_LITERAL_SUFFIX_ID (literal) = get_identifier (suffix); + USERDEF_LITERAL_VALUE (literal) = lex_charconst (&temp_tok); + *value = literal; + } + break; + case CPP_CHAR: case CPP_WCHAR: case CPP_CHAR16: @@ -422,6 +449,23 @@ *value = lex_charconst (tok); break; + case CPP_STRING_USERDEF: + case CPP_WSTRING_USERDEF: + case CPP_STRING16_USERDEF: + case CPP_STRING32_USERDEF: + case CPP_UTF8STRING_USERDEF: + { + tree literal; + char suffix[256] = ""; + cpp_get_userdef_suffix (tok->val.str, '"', suffix); + literal = build_userdef_literal (); + USERDEF_LITERAL_SUFFIX_ID (literal) = get_identifier (suffix); + USERDEF_LITERAL_VALUE (literal) + = build_string (tok->val.str.len - strlen (suffix), tok->val.str.text); + *value = literal; + } + break; + case CPP_STRING: case CPP_WSTRING: case CPP_STRING16: @@ -536,9 +580,11 @@ return itk_none; } -/* Interpret TOKEN, an integer with FLAGS as classified by cpplib. */ +/* Interpret TOKEN, an integer with FLAGS as classified by cpplib. + For C++0X SUFFIX may contain a user-defined literal suffix. */ static tree -interpret_integer (const cpp_token *token, unsigned int flags) +interpret_integer (const cpp_token *token, unsigned int flags, + const char *suffix) { tree value, type; enum integer_type_kind itk; @@ -621,9 +667,10 @@ } /* Interpret TOKEN, a floating point number with FLAGS as classified - by cpplib. */ + by cpplib. For C++0X SUFFIX may contain a user-defined literal suffix. */ static tree -interpret_float (const cpp_token *token, unsigned int flags) +interpret_float (const cpp_token *token, unsigned int flags, + const char *suffix) { tree type; tree const_type; @@ -702,7 +749,9 @@ has any suffixes, cut them off; REAL_VALUE_ATOF/ REAL_VALUE_HTOF can't handle them. */ copylen = token->val.str.len; - if (flags & CPP_N_DFLOAT) + if (flags & CPP_N_USERDEF) + copylen -= strlen(suffix); + else if (flags & CPP_N_DFLOAT) copylen -= 2; else { Index: gcc/tree.c =================================================================== --- gcc/tree.c (revision 172287) +++ gcc/tree.c (working copy) @@ -337,6 +337,7 @@ case OMP_CLAUSE: return TS_OMP_CLAUSE; case OPTIMIZATION_NODE: return TS_OPTIMIZATION; case TARGET_OPTION_NODE: return TS_TARGET_OPTION; + case USERDEF_LITERAL: return TS_USERDEF_LITERAL; default: gcc_unreachable (); @@ -431,6 +432,7 @@ case TS_OMP_CLAUSE: case TS_OPTIMIZATION: case TS_TARGET_OPTION: + case TS_USERDEF_LITERAL: MARK_TS_COMMON (code); break; @@ -727,6 +729,8 @@ case OPTIMIZATION_NODE: return sizeof (struct tree_optimization_option); case TARGET_OPTION_NODE: return sizeof (struct tree_target_option); + case USERDEF_LITERAL: return sizeof (struct tree_userdef_literal); + default: return lang_hooks.tree_size (code); } @@ -1671,7 +1675,19 @@ } } +/* Build a user-defined numeric literal out of an integer constant type VALUE + with identifier SUFFIX. */ +tree +build_userdef_literal (void) +{ + tree literal = make_node (USERDEF_LITERAL); + USERDEF_LITERAL_SUFFIX_ID (literal) = NULL_TREE; + USERDEF_LITERAL_VALUE (literal) = NULL_TREE; + return literal; +} + + /* Build a BINFO with LEN language slots. */ tree Index: gcc/tree.h =================================================================== --- gcc/tree.h (revision 172287) +++ gcc/tree.h (working copy) @@ -3497,6 +3497,25 @@ /* Return a tree node that encapsulates the current target options. */ extern tree build_target_option_node (void); +/* A suffix-identifier value doublet that represents user-defined literals + for C++-0x. */ +struct GTY(()) tree_userdef_literal { + struct tree_common common; + tree suffix_id; + tree value; +}; + +#define USERDEF_LITERAL_SUFFIX_ID(NODE) \ + (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->suffix_id) + +#define USERDEF_LITERAL_VALUE(NODE) \ + (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->value) + +#define USERDEF_LITERAL_TYPE(NODE) \ + (TREE_TYPE (USERDEF_LITERAL_VALUE (NODE))) + +extern tree build_userdef_literal (void); + /* Define the overall contents of a tree node. It may be any of the structures declared above @@ -3540,6 +3559,7 @@ struct tree_omp_clause GTY ((tag ("TS_OMP_CLAUSE"))) omp_clause; struct tree_optimization_option GTY ((tag ("TS_OPTIMIZATION"))) optimization; struct tree_target_option GTY ((tag ("TS_TARGET_OPTION"))) target_option; + struct tree_userdef_literal GTY ((tag ("TS_USERDEF_LITERAL"))) userdef_literal; }; /* Standard named or nameless data types of the C compiler. */ Index: gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg-neg.C (revision 0) @@ -0,0 +1,4 @@ +// { dg-options -std=c++0x } + +template + int operator"" _xyz(unsigned long long); // { dg-error "has illegal argument list" } Index: gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C (revision 0) @@ -0,0 +1,16 @@ +// { dg-options "-std=c++0x" } + +// Both of these can't have *both* of these. + +int +operator"" abc(const char*) + { + return 42; + } + +template + int + operator"" abc() + { + return 13; + } Index: gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C (revision 0) @@ -0,0 +1,43 @@ +// { dg-do run } +// { dg-options "-std=c++0x" } + +// Test user-defined literals. +// Test simple operator declaration and definition in namespaces. + +#include +#include + +namespace Long +{ + long double operator"" LL(long double); +} + +namespace Short +{ + short + operator"" SS(long double x) + { return std::fmod(x, static_cast(std::numeric_limits::max())); } +} + +void +test1() +{ + long double x = Long::operator "" LL(1.2L); + + using namespace Short; + short s = operator"" SS(1.2L); + short s2 = 1.2SS; +} + +int +main() +{ + test1(); +} + +namespace Long +{ + long double + operator"" LL(long double x) + { return x + 2.0L; } +} Index: gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C (revision 0) @@ -0,0 +1,10 @@ +// { dg-options -std=c++0x } + +class Foo +{ +public: + Foo() { } + int operator"" _Bar(char32_t) { return 42; } // { dg-error "must be a non-member function" } +}; + +int n = 'x'_Bar; // { dg-error "unable to find user-defined literal operator declaration" } Index: gcc/testsuite/g++.dg/cpp0x/udlit-args-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-args-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-args-neg.C (revision 0) @@ -0,0 +1,23 @@ +// { dg-options -std=c++0x } + +#include + +class Foo { }; + +Foo +operator"" _Foo(int *); // { dg-error "has illegal argument list" } + +Foo +operator"" _Foo(unsigned long int); // { dg-error "has illegal argument list" } + +Foo +operator"" _Foo(double); // { dg-error "has illegal argument list" } + +Foo +operator"" _Foo(const float *, std::size_t); // { dg-error "has illegal argument list" } + +Foo +operator"" _Foo(const wchar_t *, int); // { dg-error "has illegal argument list" } + +Foo +operator"" _Foo(const char16_t *); // { dg-error "has illegal argument list" } Index: gcc/testsuite/g++.dg/cpp0x/udlit-nounder-pedwarn.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-nounder-pedwarn.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-nounder-pedwarn.C (revision 0) @@ -0,0 +1,6 @@ +// { dg-options "-std=c++0x -pedantic" } + +// Test user-defined literals. +// Test warning on declaration without leading underscore. + +long double operator"" nounder(long double); // { dg-warning "suffixes not preceded by|are reserved for future standardization" } Index: gcc/testsuite/g++.dg/cpp0x/udlit-suffix-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-suffix-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-suffix-neg.C (revision 0) @@ -0,0 +1,5 @@ +// { dg-options -std=c++0x } + +#include + +std::string operator"" 5X(const char*, std::size_t); // { dg-error "expected suffix identifier" } Index: gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C (revision 0) @@ -0,0 +1,7 @@ +// { dg-options -std=c++0x } + +constexpr unsigned long long +operator"" _grow(unsigned long long n) +{ return 2 * n; } + +double buffer[25_grow]; Index: gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C (revision 0) @@ -0,0 +1,9 @@ +// { dg-options -std=c++0x } + +long double +operator"" L(long double x) +{ return x; } // { dg-error "floating point suffix shadowed by implementation" } + +unsigned long long int +operator"" ULL(unsigned long long int k) +{ return k; } // { dg-error "integer suffix shadowed by implementation" } Index: gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C (revision 0) @@ -0,0 +1,6 @@ +// { dg-options -std=c++0x } + +class Foo { }; + +template // { dg-error "" } + Foo operator"" _Foo(); Index: gcc/testsuite/g++.dg/cpp0x/udlit-general.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-general.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-general.C (revision 0) @@ -0,0 +1,47 @@ +// { dg-do run } +// { dg-options "-std=c++0x" } + +// Test user-defined literals. +// Test simple operator declaration and definition. + +#include +#include + +long double operator"" v(long double); +std::string operator"" w(const char16_t*, size_t); +unsigned operator"" w(const char*); + +std::complex +operator"" _i(long double y) +{ return std::complex(0.0L, y); } + +void +test1() +{ + long double x = operator"" v(1.2L); + + std::string s = operator"" w(u"one", 3); + + unsigned u = operator"" w("Hello, World!"); + unsigned u2 = operator"" w("Hello, World!"); + + std::complex i = operator"" _i(2.0); +} + +int +main() +{ + test1(); +} + +long double +operator"" v(long double x) +{ return x + 1.0L; } + +std::string +operator"" w(const char16_t*, size_t) +{ return std::string("boo"); } + +unsigned +operator"" w(const char*) +{ return 0U; } Index: gcc/testsuite/g++.dg/cpp0x/udlit-raw-str.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-raw-str.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-raw-str.C (revision 0) @@ -0,0 +1,15 @@ +// { dg-options -std=c++0x } + +#include + +std::string operator"" _i18n(const char*, std::size_t); + +std::string vogon_poem = R"V0G0N( + O freddled gruntbuggly thy micturations are to me + As plured gabbleblochits on a lurgid bee. + Groop, I implore thee my foonting turlingdromes. + And hooptiously drangle me with crinkly bindlewurdles, + Or I will rend thee in the gobberwarts with my blurlecruncheon, see if I don't. + + (by Prostetnic Vogon Jeltz; see p. 56/57) +)V0G0N"_i18n; Index: gcc/testsuite/g++.dg/cpp0x/udlit-nofunc-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-nofunc-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-nofunc-neg.C (revision 0) @@ -0,0 +1,9 @@ +// { dg-options "-std=c++0x" } + +// Test user-defined literals. +// Test error on non-function declaration. + +double operator"" _baddecl; // { dg-error "as non-function" } + +template + int operator"" _badtmpldecl; // { dg-error "as non-function" } Index: gcc/testsuite/g++.dg/cpp0x/udlit-addr.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-addr.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-addr.C (revision 0) @@ -0,0 +1,10 @@ +// { dg-options "-std=c++0x" } + +#include + +bool operator"" yn(const char*, size_t); + +typedef bool (*pfunk)(const char*, size_t); +pfunk p = &operator"" yn; + +bool tf = p("Hello,\0 World!", 14); Index: gcc/testsuite/g++.dg/cpp0x/udlit-noshadow.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-noshadow.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-noshadow.C (revision 0) @@ -0,0 +1,14 @@ +// { dg-options -std=c++0x } + +namespace Long +{ + +long double +operator"" L(long double x) +{ return x; } + +unsigned long long int +operator"" ULL(unsigned long long int k) +{ return k; } + +} Index: gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg.C (revision 0) @@ -0,0 +1,4 @@ +// { dg-options -std=c++0x } + +template + int operator"" _abc(); Index: gcc/testsuite/g++.dg/cpp0x/udlit-clink-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-clink-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-clink-neg.C (revision 0) @@ -0,0 +1,8 @@ +// { dg-options -std=c++0x } + +extern "C" { + +int +operator"" _badclinkage(unsigned long long); // { dg-error "operator with C linkage" } + +} Index: gcc/testsuite/g++.dg/cpp0x/udlit-template.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-template.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-template.C (revision 0) @@ -0,0 +1,25 @@ +// { dg-do run } +// { dg-options "-std=c++0x" } + +// Test user-defined literals. +// Test template operator declaration and definition. + +template + int operator"" _abc(); + +int +test1() +{ + int universal_meaning = operator"" _abc<'L','U','E'>(); +} + +int +main() +{ + test1(); + int j = 1234567890_abc; +} + +template + int operator"" _abc() + { return 42; } Index: gcc/testsuite/g++.dg/cpp0x/udlit-args.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-args.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-args.C (revision 0) @@ -0,0 +1,38 @@ +// { dg-options -std=c++0x } + +#include + +class Foo { }; + +Foo +operator"" _Foo(const char *); + +Foo +operator"" _Foo(unsigned long long int); + +Foo +operator"" _Foo(long double); + +Foo +operator"" _Foo(char); + +Foo +operator"" _Foo(wchar_t); + +Foo +operator"" _Foo(char16_t); + +Foo +operator"" _Foo(char32_t); + +Foo +operator"" _Foo(const char *, std::size_t); + +Foo +operator"" _Foo(const wchar_t *, std::size_t); + +Foo +operator"" _Foo(const char16_t *, std::size_t); + +Foo +operator"" _Foo(const char32_t *, std::size_t); Index: gcc/testsuite/g++.dg/cpp0x/udlit-nosuffix-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-nosuffix-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-nosuffix-neg.C (revision 0) @@ -0,0 +1,5 @@ +// { dg-options -std=c++0x } + +char32_t +operator"" (char32_t C) +{ return C; } // { dg-error "expected suffix identifier" } Index: gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C (revision 0) @@ -0,0 +1,6 @@ +// { dg-options "-std=c++0x" } + +// Test user-defined literals. +// Test error on non-empty string after 'operator' keyword. + +double operator"hi" _badword(long double); // { dg-error "expected empty string after" } Index: gcc/testsuite/g++.dg/cpp0x/udlit-linkage-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-linkage-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-linkage-neg.C (revision 0) @@ -0,0 +1,7 @@ +// { dg-options -std=c++0x } + +extern "C"_badlinkage { // { dg-error "expected unqualified-id before" } + +int foo(); + +} Index: gcc/testsuite/g++.dg/cpp0x/udlit-friend.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-friend.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-friend.C (revision 0) @@ -0,0 +1,10 @@ +// { dg-options -std=c++0x } + +class Foo +{ +public: + Foo() { } + friend Foo operator"" _Bar(char) { return Foo(); } +}; + +Foo f = 'x'_Bar; Index: gcc/testsuite/g++.dg/cpp0x/udlit-concat-neg.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-concat-neg.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-concat-neg.C (revision 0) @@ -0,0 +1,9 @@ +// { dg-options "-std=c++0x" } + +#include + +std::string operator"" xxx(const char*, size_t); + +std::string operator"" yyy(const char*, size_t); + +std::string concat = "Hello, "xxx "World!"yyy; // { dg-error "inconsistent user-defined literal suffixes" } Index: gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms.C (revision 0) @@ -0,0 +1,6 @@ +// { dg-options -std=c++0x } + +class Foo { }; + +template + Foo operator"" _Foo(); Index: gcc/testsuite/g++.dg/cpp0x/udlit-concat.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/udlit-concat.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/udlit-concat.C (revision 0) @@ -0,0 +1,24 @@ +// { dg-options "-std=c++0x" } + +#include + +std::string operator"" www(const char*, size_t); + +std::string concat01 = "Hello, " "World!"www; + +std::string concat10 = "Hello, "www "World!"; + +std::string concat11 = "Hello, "www "World!"www; + + +class Tachyon { }; + +Tachyon operator"" fast(const char*, size_t); + +int operator"" fast(const char32_t*, size_t); + +int speedy01 = "Hello, " U"World!"fast; + +int speedy10 = "Hello, "fast U"World!"; + +int speedy11 = "Hello, "fast U"World!"fast; Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c (revision 172287) +++ gcc/cp/typeck.c (working copy) @@ -8262,3 +8262,33 @@ return 1; } + +/* Return true if a user-defined literal operator has one of the allowed + argument types. */ + +bool +check_literal_operator_args(const_tree decl, int * type_index) +{ + const_tree type1 = decl; + const_tree args1 = TYPE_ARG_TYPES (type1); + + if (!processing_template_decl) + { + int start = (int) CPTI_USERDEF_LIT_CHAR_PTR_TYPE; + int i; + for (i = 0; i < 11; ++i) + { + const_tree type2 = cp_global_trees[start + i]; + const_tree args2 = TYPE_ARG_TYPES (type2); + if (compparms (args1, args2)) + { + *type_index = start + i; + return true; + } + } + return false; + } + else + return (args1 == NULL_TREE || TREE_VALUE (args1) == void_type_node); +} + Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c (revision 172287) +++ gcc/cp/decl.c (working copy) @@ -3610,6 +3610,45 @@ SET_TYPE_MODE (nullptr_type_node, Pmode); record_builtin_type (RID_MAX, "decltype(nullptr)", nullptr_type_node); nullptr_node = build_int_cst (nullptr_type_node, 0); +{ +tree const_char_ptr_type_node = build_pointer_type(build_type_variant(char_type_node, 1, 0)); +tree const_wchar_ptr_type_node = build_pointer_type(build_type_variant(wchar_type_node, 1, 0)); +tree const_char16_ptr_type_node = build_pointer_type(build_type_variant(char16_type_node, 1, 0)); +tree const_char32_ptr_type_node = build_pointer_type(build_type_variant(char32_type_node, 1, 0)); + + userdef_lit_char_ptr_type + = build_function_type_list (void_type_node, + const_char_ptr_type_node, NULL_TREE); + + userdef_lit_ull_type + = build_function_type_list (void_type_node, long_long_unsigned_type_node, + NULL_TREE); + userdef_lit_ldbl_type + = build_function_type_list (void_type_node, long_double_type_node, + NULL_TREE); + + userdef_lit_char_type + = build_function_type_list (void_type_node, char_type_node, NULL_TREE); + userdef_lit_wchar_type + = build_function_type_list (void_type_node, wchar_type_node, NULL_TREE); + userdef_lit_char16_type + = build_function_type_list (void_type_node, char16_type_node, NULL_TREE); + userdef_lit_char32_type + = build_function_type_list (void_type_node, char32_type_node, NULL_TREE); + + userdef_lit_char_str_type + = build_function_type_list (void_type_node, const_char_ptr_type_node, + size_type_node, NULL_TREE); + userdef_lit_wchar_str_type + = build_function_type_list (void_type_node, const_wchar_ptr_type_node, + size_type_node, NULL_TREE); + userdef_lit_char16_str_type + = build_function_type_list (void_type_node, const_char16_ptr_type_node, + size_type_node, NULL_TREE); + userdef_lit_char32_str_type + = build_function_type_list (void_type_node, const_char32_ptr_type_node, + size_type_node, NULL_TREE); +} } abort_fndecl @@ -7121,7 +7160,49 @@ if (IDENTIFIER_OPNAME_P (DECL_NAME (decl)) && !grok_op_properties (decl, /*complain=*/true)) return NULL_TREE; + else if (UDLIT_OPER_P (DECL_NAME (decl))) + { + int type_index = -1; + /* [over.literal]/6: Literal operators shall not have C linkage. */ + if (DECL_LANGUAGE(decl) == lang_c) + { + error ("literal operator with C linkage"); + return NULL_TREE; + } + if (DECL_NAMESPACE_SCOPE_P (decl)) + { + if (! check_literal_operator_args(TREE_TYPE (decl), &type_index)) + { + error ("%qD has illegal argument list", decl); + return NULL_TREE; + } + + if (CP_DECL_CONTEXT (decl) == global_namespace) + { + const char *name = IDENTIFIER_POINTER (DECL_NAME (decl)); + char suffix[256] = ""; + sscanf(name, UDLIT_OP_ANSI_FORMAT, suffix); + if (type_index == CPTI_USERDEF_LIT_ULL_TYPE) + { + if (cpp_interpret_int_suffix (suffix, strlen (suffix))) + warning (0, "integer suffix shadowed by implementation"); + } + else if (type_index == CPTI_USERDEF_LIT_LDBL_TYPE) + { + if (cpp_interpret_float_suffix (suffix, strlen (suffix))) + warning (0, "floating point suffix" + " shadowed by implementation"); + } + } + } + else + { + error ("%qD must be a non-member function", decl); + return NULL_TREE; + } + } + if (funcdef_flag) /* Make the init_value nonzero so pushdecl knows this is not tentative. error_mark_node is replaced later with the BLOCK. */ @@ -8220,6 +8301,16 @@ error ("declaration of %qD as non-function", dname); return error_mark_node; } + + if (dname + && TREE_CODE (dname) == IDENTIFIER_NODE + && UDLIT_OPER_P (dname) + && innermost_code != cdk_function + && ! (ctype && !declspecs->any_specifiers_p)) + { + error ("declaration of %qD as non-function", dname); + return error_mark_node; + } /* Anything declared one level down from the top level must be one of the parameters of a function Index: gcc/cp/error.c =================================================================== --- gcc/cp/error.c (revision 172287) +++ gcc/cp/error.c (working copy) @@ -1,7 +1,7 @@ /* Call-backs for C++ error reporting. This code is non-reentrant. Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, - 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify @@ -1493,6 +1493,8 @@ } else if (name && IDENTIFIER_OPNAME_P (name)) pp_cxx_tree_identifier (cxx_pp, name); + else if (name && UDLIT_OPER_P (name)) + pp_cxx_tree_identifier (cxx_pp, name); else dump_decl (name, flags); @@ -1713,6 +1715,11 @@ pp_constant (cxx_pp, t); break; + case USERDEF_LITERAL: + pp_constant (cxx_pp, USERDEF_LITERAL_VALUE (t)); + dump_decl (USERDEF_LITERAL_SUFFIX_ID (t), flags); + break; + case THROW_EXPR: /* While waiting for caret diagnostics, avoid printing __cxa_allocate_exception, __cxa_throw, and the like. */ @@ -3142,7 +3149,12 @@ pedwarn (input_location, OPT_pedantic, "inline namespaces " "only available with -std=c++0x or -std=gnu++0x"); - break; + break; + case CPP0X_USER_DEFINED_LITERALS: + pedwarn (input_location, 0, + "user-defined literals " + "only available with -std=c++0x or -std=gnu++0x"); + break; default: gcc_unreachable(); } Index: gcc/cp/operators.def =================================================================== --- gcc/cp/operators.def (revision 172287) +++ gcc/cp/operators.def (working copy) @@ -153,3 +153,6 @@ /* Variadic templates extension. */ DEF_SIMPLE_OPERATOR ("...", EXPR_PACK_EXPANSION, "sp", 1) + +/* User-defined literal operator. +DEF_SIMPLE_OPERATOR ("\"\"", USERDEF_LITERAL_EXPR, "ud", 1) */ Index: gcc/cp/cxx-pretty-print.c =================================================================== --- gcc/cp/cxx-pretty-print.c (revision 172287) +++ gcc/cp/cxx-pretty-print.c (working copy) @@ -1,6 +1,6 @@ /* Implementation of subroutines for the GNU C++ pretty-printer. Copyright (C) 2003, 2004, 2005, 2007, 2008, - 2009, 2010 Free Software Foundation, Inc. + 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Gabriel Dos Reis This file is part of GCC. @@ -327,6 +327,10 @@ { switch (TREE_CODE (t)) { + case USERDEF_LITERAL: + pp_c_constant (pp_c_base (pp), USERDEF_LITERAL_VALUE (t)); + break; + case STRING_CST: { const bool in_parens = PAREN_STRING_LITERAL_P (t); @@ -407,6 +411,7 @@ case REAL_CST: case COMPLEX_CST: case STRING_CST: + case USERDEF_LITERAL: pp_cxx_constant (pp, t); break; @@ -1017,6 +1022,7 @@ case INTEGER_CST: case REAL_CST: case COMPLEX_CST: + case USERDEF_LITERAL: pp_cxx_constant (pp, t); break; Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 172287) +++ gcc/cp/semantics.c (working copy) @@ -7367,6 +7367,7 @@ case TEMPLATE_PARM_INDEX: case TRAIT_EXPR: case IDENTIFIER_NODE: + case USERDEF_LITERAL: return true; case PARM_DECL: Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 172287) +++ gcc/cp/parser.c (working copy) @@ -1,6 +1,6 @@ /* C++ Parser. Copyright (C) 2000, 2001, 2002, 2003, 2004, - 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + 2005, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Written by Mark Mitchell . This file is part of GCC. @@ -209,6 +209,8 @@ (cp_lexer *); static void cp_lexer_rollback_tokens (cp_lexer *); +static tree cp_literal_operator_id + (const char *); #ifdef ENABLE_CHECKING static void cp_lexer_print_token (FILE *, cp_token *); @@ -500,20 +502,20 @@ } else { - if (warn_cxx0x_compat - && C_RID_CODE (token->u.value) >= RID_FIRST_CXX0X - && C_RID_CODE (token->u.value) <= RID_LAST_CXX0X) - { - /* Warn about the C++0x keyword (but still treat it as - an identifier). */ - warning (OPT_Wc__0x_compat, - "identifier %qE will become a keyword in C++0x", - token->u.value); + if (warn_cxx0x_compat + && C_RID_CODE (token->u.value) >= RID_FIRST_CXX0X + && C_RID_CODE (token->u.value) <= RID_LAST_CXX0X) + { + /* Warn about the C++0x keyword (but still treat it as + an identifier). */ + warning (OPT_Wc__0x_compat, + "identifier %qE will become a keyword in C++0x", + token->u.value); - /* Clear out the C_RID_CODE so we don't warn about this - particular identifier-turned-keyword again. */ - C_SET_RID_CODE (token->u.value, RID_MAX); - } + /* Clear out the C_RID_CODE so we don't warn about this + particular identifier-turned-keyword again. */ + C_SET_RID_CODE (token->u.value, RID_MAX); + } token->ambiguous_p = false; token->keyword = RID_MAX; @@ -1506,6 +1508,12 @@ (cp_parser *); static tree cp_parser_string_literal (cp_parser *, bool, bool); +static tree cp_parser_userdef_char_literal + (cp_parser *); +static tree cp_parser_userdef_string_literal + (cp_parser *, cp_token *); +static tree cp_parser_userdef_numeric_literal + (cp_parser *); /* Basic concepts [gram.basic] */ @@ -2000,6 +2008,8 @@ (cp_parser *); static bool cp_parser_allow_gnu_extensions_p (cp_parser *); +static bool cp_parser_is_pure_string_literal + (cp_token *); static bool cp_parser_is_string_literal (cp_token *); static bool cp_parser_is_keyword @@ -2020,7 +2030,7 @@ /* Returns nonzero if TOKEN is a string literal. */ static bool -cp_parser_is_string_literal (cp_token* token) +cp_parser_is_pure_string_literal (cp_token* token) { return (token->type == CPP_STRING || token->type == CPP_STRING16 || @@ -2029,6 +2039,20 @@ token->type == CPP_UTF8STRING); } +/* Returns nonzero if TOKEN is a string literal + of a user-defined string literal. */ + +static bool +cp_parser_is_string_literal (cp_token* token) +{ + return (cp_parser_is_pure_string_literal (token) || + token->type == CPP_STRING_USERDEF || + token->type == CPP_STRING16_USERDEF || + token->type == CPP_STRING32_USERDEF || + token->type == CPP_WSTRING_USERDEF || + token->type == CPP_UTF8STRING_USERDEF); +} + /* Returns nonzero if TOKEN is the indicated KEYWORD. */ static bool @@ -3069,6 +3093,10 @@ cpp_string str, istr, *strs; cp_token *tok; enum cpp_ttype type; + char suffix[256] = "", curr_suffix[256] = ""; + int have_suffix_p = 0; + tree string_tree; + bool curr_tok_is_userdef_p = false; tok = cp_lexer_peek_token (parser->lexer); if (!cp_parser_is_string_literal (tok)) @@ -3077,6 +3105,14 @@ return error_mark_node; } + if (cpp_userdef_string_p (tok->type)) + { + string_tree = USERDEF_LITERAL_VALUE (tok->u.value); + tok->type = cpp_userdef_string_remove_type (tok->type); + curr_tok_is_userdef_p = true; + } + else + string_tree = tok->u.value; type = tok->type; /* Try to avoid the overhead of creating and destroying an obstack @@ -3086,10 +3122,18 @@ { cp_lexer_consume_token (parser->lexer); - str.text = (const unsigned char *)TREE_STRING_POINTER (tok->u.value); - str.len = TREE_STRING_LENGTH (tok->u.value); + str.text = (const unsigned char *)TREE_STRING_POINTER (string_tree); + str.len = TREE_STRING_LENGTH (string_tree); count = 1; + if (curr_tok_is_userdef_p) + { + tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (tok->u.value); + strcpy (suffix, IDENTIFIER_POINTER (suffix_id)); + have_suffix_p = 1; + tok->type = cpp_userdef_string_remove_type (tok->type); + } + strs = &str; } else @@ -3101,9 +3145,26 @@ { cp_lexer_consume_token (parser->lexer); count++; - str.text = (const unsigned char *)TREE_STRING_POINTER (tok->u.value); - str.len = TREE_STRING_LENGTH (tok->u.value); + str.text = (const unsigned char *)TREE_STRING_POINTER (string_tree); + str.len = TREE_STRING_LENGTH (string_tree); + if (curr_tok_is_userdef_p) + { + tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (tok->u.value); + strcpy (curr_suffix, IDENTIFIER_POINTER (suffix_id)); + if (have_suffix_p == 0) + { + strcpy(suffix, curr_suffix); + have_suffix_p = 1; + } + else if (have_suffix_p == 1 && strcmp (suffix, curr_suffix) != 0) + { + error ("inconsistent user-defined literal suffixes"); + have_suffix_p = -1; + } + tok->type = cpp_userdef_string_remove_type (tok->type); + } + if (type != tok->type) { if (type == CPP_STRING) @@ -3117,6 +3178,17 @@ obstack_grow (&str_ob, &str, sizeof (cpp_string)); tok = cp_lexer_peek_token (parser->lexer); + if (cpp_userdef_string_p (tok->type)) + { + string_tree = USERDEF_LITERAL_VALUE (tok->u.value); + tok->type = cpp_userdef_string_remove_type (tok->type); + curr_tok_is_userdef_p = true; + } + else + { + string_tree = tok->u.value; + curr_tok_is_userdef_p = false; + } } while (cp_parser_is_string_literal (tok)); @@ -3154,6 +3226,15 @@ } value = fix_string_type (value); + + if (have_suffix_p) + { + tree literal = build_userdef_literal(); + USERDEF_LITERAL_SUFFIX_ID (literal) = get_identifier (suffix); + USERDEF_LITERAL_VALUE (literal) = value; + tok->u.value = literal; + return cp_parser_userdef_string_literal (parser, tok); + } } else /* cpp_interpret_string has issued an error. */ @@ -3165,7 +3246,166 @@ return value; } +/* 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, ambig_decls; + tree result; + VEC(tree,gc) *vec; + 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. */ + decl = cp_parser_lookup_name (parser, name, + none_type, + /*is_template=*/false, + /*is_namespace=*/false, + /*check_dependency=*/true, + /*ambig_decls=*/&ambig_decls, + token->location); + if (decl == error_mark_node) + { + error ("unable to find user-defined literal operator declaration"); + return error_mark_node; + } + vec = make_tree_vector (); + VEC_safe_push (tree, gc, vec, value); + result = finish_call_expr (decl, &vec, false, true, tf_warning_or_error); + release_tree_vector (vec); + + return result; +} + +/* Parse a user-defined numeric constant. returns a call to a user-defined + literal operator. */ +static tree +cp_parser_userdef_numeric_literal (cp_parser *parser) +{ + cp_token *token = NULL; + tree literal, suffix_id, value; + tree name, decl, ambig_decls; + tree result = error_mark_node; + VEC(tree,gc) *vec; + + 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. */ + decl = cp_parser_lookup_name (parser, name, + none_type, + /*is_template=*/false, + /*is_namespace=*/false, + /*check_dependency=*/true, + /*ambig_decls=*/&ambig_decls, + token->location); + if (decl == error_mark_node) + { + error ("unable to find user-defined literal operator declaration"); + return error_mark_node; + } + else + { + /* Try to find the literal operator by finishing the call expression + with the numeric argument. */ + vec = make_tree_vector (); + VEC_safe_push (tree, gc, vec, value); + result = finish_call_expr (decl, &vec, false, true, tf_none); + release_tree_vector (vec); + + if (result == error_mark_node) + { + /* If the numeric argument didn't work, look for a raw literal + operator taking a const char* argument consisting of the number + in string format. */ + char str[256] = ""; + tree newval = error_mark_node; + vec = make_tree_vector (); + /* Cast VALUE as a string. */ + if (TREE_CODE (value) == INTEGER_CST) + { + HOST_WIDEST_INT i = TREE_INT_CST_LOW (value); + sprintf (str, HOST_WIDEST_INT_PRINT_DEC, i); + newval = build_string (strlen(str), str); + } + else if (TREE_CODE (value) == REAL_CST) + { + REAL_VALUE_TYPE d; + d = TREE_REAL_CST (value); + real_to_decimal (str, &d, 256, + /*digits=*/18, + /*crop_trailing_zeros=*/1); /* TODO: Get the right number of DIGITS! */ + newval = build_string (strlen(str), str); + } + else + gcc_unreachable (); + TREE_TYPE (newval) = char_array_type_node; + VEC_safe_push (tree, gc, vec, newval); + result = finish_call_expr (decl, &vec, false, true, tf_none); + release_tree_vector (vec); + } + } + + if (result == error_mark_node) + error ("unable to find appropriate call for user-defined literal"); + + return result; +} + +/* Parse a user-defined string constant. Returns a call to a user-defined + literal operator taking a character pointer and the length of the string + as arguments. */ +static tree +cp_parser_userdef_string_literal (cp_parser *parser, cp_token *token) +{ + tree literal, suffix_id, value; + tree name, decl, ambig_decls; + tree result; + VEC(tree,gc) *vec; + int len; + + 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) - 1; + + /* Build up a call to the user-defined operator */ + /* Lookup the name we got back from the id-expression. */ + decl = cp_parser_lookup_name (parser, name, + none_type, + /*is_template=*/false, + /*is_namespace=*/false, + /*check_dependency=*/true, + /*ambig_decls=*/&ambig_decls, + token->location); + if (decl == error_mark_node) + { + error ("unable to find user-defined literal operator declaration"); + return error_mark_node; + } + vec = make_tree_vector (); + VEC_safe_push (tree, gc, vec, value); + VEC_safe_push (tree, gc, vec, build_int_cst (size_type_node, len)); + result = finish_call_expr (decl, &vec, false, true, tf_warning_or_error); + release_tree_vector (vec); + + return result; +} + + /* Basic concepts [gram.basic] */ /* Parse a translation-unit. @@ -3305,12 +3545,16 @@ character-literal floating-literal string-literal - boolean-literal */ + boolean-literal + pointer-literal + user-defined-literal */ case CPP_CHAR: case CPP_CHAR16: case CPP_CHAR32: case CPP_WCHAR: case CPP_NUMBER: + if (TREE_CODE (token->u.value) == USERDEF_LITERAL) + return cp_parser_userdef_numeric_literal (parser); token = cp_lexer_consume_token (parser->lexer); if (TREE_CODE (token->u.value) == FIXED_CST) { @@ -3364,11 +3608,22 @@ } return token->u.value; + case CPP_CHAR_USERDEF: + case CPP_CHAR16_USERDEF: + case CPP_CHAR32_USERDEF: + case CPP_WCHAR_USERDEF: + return cp_parser_userdef_char_literal (parser); + case CPP_STRING: case CPP_STRING16: case CPP_STRING32: case CPP_WSTRING: case CPP_UTF8STRING: + case CPP_STRING_USERDEF: + case CPP_STRING16_USERDEF: + case CPP_STRING32_USERDEF: + case CPP_WSTRING_USERDEF: + case CPP_UTF8STRING_USERDEF: /* ??? Should wide strings be allowed when parser->translate_strings_p is false (i.e. in attributes)? If not, we can kill the third argument to cp_parser_string_literal. */ @@ -9181,7 +9436,7 @@ /* If the next token is `extern' and the following token is a string literal, then we have a linkage specification. */ if (token1.keyword == RID_EXTERN - && cp_parser_is_string_literal (&token2)) + && cp_parser_is_pure_string_literal (&token2)) cp_parser_linkage_specification (parser); /* If the next token is `template', then we have either a template declaration, an explicit instantiation, or an explicit @@ -10603,6 +10858,25 @@ return cp_parser_operator (parser); } +/* Return an identifier node for a user-defined literal operator. + The suffix identifier is chained to the operator name identifier. */ + +static tree +cp_literal_operator_id (const char* name) +{ + tree identifier; + char buffer[256]; + + sprintf (buffer, UDLIT_OP_ANSI_FORMAT, name); + identifier = get_identifier (buffer); + /*IDENTIFIER_UDLIT_OPNAME_P (identifier) = 1; If we get a flag someday. */ + + /* Add the suffix identifier. */ + TREE_CHAIN (identifier) = get_identifier (name); + + return identifier; +} + /* Parse an operator. operator: @@ -10822,6 +11096,36 @@ cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); return ansi_opname (ARRAY_REF); + case CPP_STRING: + if (cxx_dialect == cxx98) + maybe_warn_cpp0x (CPP0X_USER_DEFINED_LITERALS); + if (TREE_STRING_LENGTH (token->u.value) > 2) + { + error ("expected empty string after % keyword"); + return error_mark_node; + } + /* Consume the string. */ + cp_lexer_consume_token (parser->lexer); + /* Look for an identifier. */ + id = cp_parser_identifier (parser); + if (id != error_mark_node) + { + const char *name = IDENTIFIER_POINTER (id); + + /* 17.6.3.3.5 */ + if (name[0] != '_') + pedwarn (token->location, OPT_pedantic, + "suffixes not preceded by %<_%> " + "are reserved for future standardization"); + + return cp_literal_operator_id(name); + } + else + { + error ("expected suffix identifier"); + return error_mark_node; + } + default: /* Anything else is an error. */ break; @@ -21946,7 +22250,8 @@ /* If the next token is `extern' and the following token is a string literal, then we have a linkage specification. */ if (token->keyword == RID_EXTERN - && cp_parser_is_string_literal (cp_lexer_peek_nth_token (parser->lexer, 2))) + && cp_parser_is_pure_string_literal + (cp_lexer_peek_nth_token (parser->lexer, 2))) cp_parser_linkage_specification (parser); /* Handle #pragma, if any. */ else if (token->type == CPP_PRAGMA) Index: gcc/cp/mangle.c =================================================================== --- gcc/cp/mangle.c (revision 172287) +++ gcc/cp/mangle.c (working copy) @@ -181,6 +181,7 @@ static void write_unqualified_name (const tree); static void write_conversion_operator_name (const tree); static void write_source_name (tree); +static void write_literal_operator_name (tree); static void write_unnamed_type_name (const tree); static void write_closure_type_name (const tree); static int hwint_to_ascii (unsigned HOST_WIDE_INT, const unsigned int, char *, @@ -1162,6 +1163,8 @@ } write_string (mangled_name); } + else if (UDLIT_OPER_P (identifier)) + write_literal_operator_name (identifier); else write_source_name (identifier); } @@ -1215,6 +1218,8 @@ write_string (oni[DECL_OVERLOADED_OPERATOR_P (decl)].mangled_name); } + else if (UDLIT_OPER_P (DECL_NAME (decl))) + write_literal_operator_name (DECL_NAME (decl)); else found = false; @@ -1274,6 +1279,23 @@ write_identifier (IDENTIFIER_POINTER (identifier)); } +/* Write a user-defined literal operator. + IDENTIFIER is an LITERAL_IDENTIFIER_NODE. */ + +static void +write_literal_operator_name (tree identifier) +{ + tree suffix_id; + char buffer[256]; + const char* suffix; + suffix_id = TREE_CHAIN (identifier); + suffix = IDENTIFIER_POINTER (suffix_id); + sprintf (buffer, UDLIT_OP_MANGLED_FORMAT, suffix); + + write_unsigned_number (strlen(buffer)); + write_identifier (buffer); +} + /* Encode 0 as _, and 1+ as n-1_. */ static void Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 172287) +++ gcc/cp/cp-tree.h (working copy) @@ -395,7 +395,9 @@ /* defaulted and deleted functions */ CPP0X_DEFAULTED_DELETED, /* inline namespaces */ - CPP0X_INLINE_NAMESPACES + CPP0X_INLINE_NAMESPACES, + /* user defined literals */ + CPP0X_USER_DEFINED_LITERALS } cpp0x_warn_str; /* The various kinds of operation used by composite_pointer_type. */ @@ -794,6 +796,18 @@ CPTI_NULLPTR, CPTI_NULLPTR_TYPE, + CPTI_USERDEF_LIT_CHAR_PTR_TYPE, + CPTI_USERDEF_LIT_ULL_TYPE, + CPTI_USERDEF_LIT_LDBL_TYPE, + CPTI_USERDEF_LIT_CHAR_TYPE, + CPTI_USERDEF_LIT_WCHAR_TYPE, + CPTI_USERDEF_LIT_CHAR16_TYPE, + CPTI_USERDEF_LIT_CHAR32_TYPE, + CPTI_USERDEF_LIT_CHAR_STR_TYPE, + CPTI_USERDEF_LIT_WCHAR_STR_TYPE, + CPTI_USERDEF_LIT_CHAR16_STR_TYPE, + CPTI_USERDEF_LIT_CHAR32_STR_TYPE, + CPTI_MAX }; @@ -831,6 +845,18 @@ #define nullptr_node cp_global_trees[CPTI_NULLPTR] #define nullptr_type_node cp_global_trees[CPTI_NULLPTR_TYPE] +#define userdef_lit_char_ptr_type cp_global_trees[CPTI_USERDEF_LIT_CHAR_PTR_TYPE] +#define userdef_lit_ull_type cp_global_trees[CPTI_USERDEF_LIT_ULL_TYPE] +#define userdef_lit_ldbl_type cp_global_trees[CPTI_USERDEF_LIT_LDBL_TYPE] +#define userdef_lit_char_type cp_global_trees[CPTI_USERDEF_LIT_CHAR_TYPE] +#define userdef_lit_wchar_type cp_global_trees[CPTI_USERDEF_LIT_WCHAR_TYPE] +#define userdef_lit_char16_type cp_global_trees[CPTI_USERDEF_LIT_CHAR16_TYPE] +#define userdef_lit_char32_type cp_global_trees[CPTI_USERDEF_LIT_CHAR32_TYPE] +#define userdef_lit_char_str_type cp_global_trees[CPTI_USERDEF_LIT_CHAR_STR_TYPE] +#define userdef_lit_wchar_str_type cp_global_trees[CPTI_USERDEF_LIT_WCHAR_STR_TYPE] +#define userdef_lit_char16_str_type cp_global_trees[CPTI_USERDEF_LIT_CHAR16_STR_TYPE] +#define userdef_lit_char32_str_type cp_global_trees[CPTI_USERDEF_LIT_CHAR32_STR_TYPE] + /* We cache these tree nodes so as to call get_identifier less frequently. */ @@ -4131,6 +4157,15 @@ LAMBDANAME_PREFIX, \ sizeof (LAMBDANAME_PREFIX) - 1)) +#define UDLIT_OP_ANSI_PREFIX "operator\"\" " +#define UDLIT_OP_ANSI_FORMAT UDLIT_OP_ANSI_PREFIX "%s" +#define UDLIT_OP_MANGLED_PREFIX "__udlit" +#define UDLIT_OP_MANGLED_FORMAT UDLIT_OP_MANGLED_PREFIX "%s" +#define UDLIT_OPER_P(ID_NODE) \ + (!strncmp (IDENTIFIER_POINTER (ID_NODE), \ + UDLIT_OP_ANSI_PREFIX, \ + sizeof (UDLIT_OP_ANSI_PREFIX) - 1)) + #if !defined(NO_DOLLAR_IN_LABEL) || !defined(NO_DOT_IN_LABEL) #define VTABLE_NAME_P(ID_NODE) (IDENTIFIER_POINTER (ID_NODE)[1] == 'v' \ @@ -5587,6 +5622,7 @@ extern int lvalue_or_else (tree, enum lvalue_use, tsubst_flags_t); extern void check_template_keyword (tree); +extern bool check_literal_operator_args (const_tree, int *); /* in typeck2.c */ extern void require_complete_eh_spec_types (tree, tree); Index: gcc/lto-streamer-out.c =================================================================== --- gcc/lto-streamer-out.c (revision 172287) +++ gcc/lto-streamer-out.c (working copy) @@ -1,6 +1,6 @@ /* Write the GIMPLE representation to a file stream. - Copyright 2009, 2010 Free Software Foundation, Inc. + Copyright 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Kenneth Zadeck Re-implemented by Diego Novillo @@ -1145,6 +1145,15 @@ lto_output_string (ob, ob->main_stream, TRANSLATION_UNIT_LANGUAGE (expr)); } +/* Write a TS_USERDEF_LITERAL tree in EXPR to OB. */ + +static void +lto_output_ts_userdef_literal_tree_pointers (struct output_block *ob, tree expr) +{ + lto_output_tree (ob, USERDEF_LITERAL_SUFFIX_ID (expr), false); + lto_output_tree (ob, USERDEF_LITERAL_VALUE (expr), false); +} + /* Helper for lto_output_tree. Write all pointer fields in EXPR to output block OB. If REF_P is true, the leaves of EXPR are emitted as references. */ @@ -1230,6 +1239,9 @@ if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL)) lto_output_ts_translation_unit_decl_tree_pointers (ob, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_USERDEF_LITERAL)) + lto_output_ts_userdef_literal_tree_pointers (ob, expr); } Index: gcc/treestruct.def =================================================================== --- gcc/treestruct.def (revision 172287) +++ gcc/treestruct.def (working copy) @@ -65,3 +65,4 @@ DEFTREESTRUCT(TS_OMP_CLAUSE, "omp clause") DEFTREESTRUCT(TS_OPTIMIZATION, "optimization options") DEFTREESTRUCT(TS_TARGET_OPTION, "target options") +DEFTREESTRUCT(TS_USERDEF_LITERAL, "user defined literal") Index: gcc/lto-streamer-in.c =================================================================== --- gcc/lto-streamer-in.c (revision 172287) +++ gcc/lto-streamer-in.c (working copy) @@ -1,6 +1,6 @@ /* Read the GIMPLE representation from a file stream. - Copyright 2009, 2010 Free Software Foundation, Inc. + Copyright 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Kenneth Zadeck Re-implemented by Diego Novillo @@ -2325,6 +2325,16 @@ VEC_safe_push (tree, gc, all_translation_units, expr); } +/* Input a TS_USERDEF_LITERAL tree from IB to DATA_IN into EXPR. */ + +static void +lto_input_ts_userdef_literal_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + USERDEF_LITERAL_SUFFIX_ID (expr) = lto_input_tree (ib, data_in); + USERDEF_LITERAL_VALUE (expr) = lto_input_tree (ib, data_in); +} + /* Helper for lto_input_tree. Read all pointer fields in EXPR from input block IB. DATA_IN contains tables and descriptors for the file being read. */ @@ -2413,6 +2423,9 @@ if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL)) lto_input_ts_translation_unit_decl_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_USERDEF_LITERAL)) + lto_input_ts_userdef_literal_tree_pointers (ib, data_in, expr); } Index: gcc/tree.def =================================================================== --- gcc/tree.def (revision 172287) +++ gcc/tree.def (working copy) @@ -1160,6 +1160,10 @@ /* TARGET_OPTION_NODE. Node to store the target specific options. */ DEFTREECODE (TARGET_OPTION_NODE, "target_option_node", tcc_exceptional, 0) +/* Used to represent a user-defined literal. + The operands are an IDENTIFIER for the suffix and the VALUE of the literal. */ +DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 2) + /* Local variables: mode:c Index: gcc/lto-streamer.c =================================================================== --- gcc/lto-streamer.c (revision 172287) +++ gcc/lto-streamer.c (working copy) @@ -1,7 +1,7 @@ /* Miscellaneous utilities for GIMPLE streaming. Things that are used in both input and output are here. - Copyright 2009, 2010 Free Software Foundation, Inc. + Copyright 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Doug Kwan This file is part of GCC. @@ -304,6 +304,7 @@ handled_p[TS_OPTIMIZATION] = true; handled_p[TS_TARGET_OPTION] = true; handled_p[TS_TRANSLATION_UNIT_DECL] = true; + handled_p[TS_USERDEF_LITERAL] = true; /* Anything not marked above will trigger the following assertion. If this assertion triggers, it means that there is a new TS_* Index: libcpp/include/cpplib.h =================================================================== --- libcpp/include/cpplib.h (revision 172287) +++ libcpp/include/cpplib.h (working copy) @@ -1,6 +1,6 @@ /* Definitions for CPP library. Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2007, 2008, 2009, 2010 + 2004, 2005, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Written by Per Bothner, 1994-95. @@ -131,6 +131,16 @@ TK(OBJC_STRING, LITERAL) /* @"string" - Objective-C */ \ TK(HEADER_NAME, LITERAL) /* in #include */ \ \ + TK(CHAR_USERDEF, LITERAL) /* 'char'_suffix - C++-0x */ \ + TK(WCHAR_USERDEF, LITERAL) /* L'char'_suffix - C++-0x */ \ + TK(CHAR16_USERDEF, LITERAL) /* u'char'_suffix - C++-0x */ \ + TK(CHAR32_USERDEF, LITERAL) /* U'char'_suffix - C++-0x */ \ + TK(STRING_USERDEF, LITERAL) /* "string"_suffix - C++-0x */ \ + TK(WSTRING_USERDEF, LITERAL) /* L"string"_suffix - C++-0x */ \ + TK(STRING16_USERDEF, LITERAL) /* u"string"_suffix - C++-0x */ \ + TK(STRING32_USERDEF, LITERAL) /* U"string"_suffix - C++-0x */ \ + TK(UTF8STRING_USERDEF,LITERAL) /* u8"string"_suffix - C++-0x */ \ + \ TK(COMMENT, LITERAL) /* Only if output comments. */ \ /* SPELL_LITERAL happens to DTRT. */ \ TK(MACRO_ARG, NONE) /* Macro argument. */ \ @@ -813,10 +823,19 @@ #define CPP_N_FRACT 0x100000 /* Fract types. */ #define CPP_N_ACCUM 0x200000 /* Accum types. */ +#define CPP_N_USERDEF 0x1000000 /* C++0x user-defned literal. */ + /* Classify a CPP_NUMBER token. The return value is a combination of the flags from the above sets. */ -extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *); +extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *, + char **ud_suffix); +/* Return the classification flags for a float suffix. */ +unsigned int cpp_interpret_float_suffix (const char *s, size_t len); + +/* Return the classification flags for an int suffix. */ +unsigned int cpp_interpret_int_suffix (const char *s, size_t len); + /* Evaluate a token classified as category CPP_N_INTEGER. */ extern cpp_num cpp_interpret_integer (cpp_reader *, const cpp_token *, unsigned int type); @@ -985,4 +1004,20 @@ extern int cpp_read_state (cpp_reader *, const char *, FILE *, struct save_macro_data *); +/* In expr.c */ +extern enum cpp_ttype cpp_userdef_string_remove_type + (enum cpp_ttype type); +extern enum cpp_ttype cpp_userdef_string_add_type + (enum cpp_ttype type); +extern enum cpp_ttype cpp_userdef_char_remove_type + (enum cpp_ttype type); +extern enum cpp_ttype cpp_userdef_char_add_type + (enum cpp_ttype type); +extern bool cpp_userdef_string_p + (enum cpp_ttype type); +extern bool cpp_userdef_char_p + (enum cpp_ttype type); +extern void cpp_get_userdef_suffix + (cpp_string, char, char *); + #endif /* ! LIBCPP_CPPLIB_H */ Index: libcpp/expr.c =================================================================== --- libcpp/expr.c (revision 172287) +++ libcpp/expr.c (working copy) @@ -1,6 +1,6 @@ /* Parse C expressions for cpplib. Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001, - 2002, 2004, 2008, 2009, 2010 Free Software Foundation. + 2002, 2004, 2008, 2009, 2010, 2011 Free Software Foundation. Contributed by Per Bothner, 1994. This program is free software; you can redistribute it and/or modify it @@ -185,6 +185,13 @@ q ? CPP_N_MD_Q : CPP_N_DEFAULT)); } +/* Return the classification flags for a float suffix. */ +unsigned int +cpp_interpret_float_suffix (const char *s, size_t len) +{ + return interpret_float_suffix ((const unsigned char *)s, len); +} + /* Subroutine of cpp_classify_number. S points to an integer suffix of length LEN, possibly zero. Returns 0 for an invalid suffix, or a flag vector describing the suffix. */ @@ -219,11 +226,139 @@ : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE)); } +/* Return the classification flags for an int suffix. */ +unsigned int +cpp_interpret_int_suffix (const char *s, size_t len) +{ + return interpret_int_suffix ((const unsigned char *)s, len); +} + +/* Return the string type corresponding to the the input user-defined string + literal type. If the input type is not a user-defined string literal + type return the input type. */ +enum cpp_ttype +cpp_userdef_string_remove_type (enum cpp_ttype type) +{ + if (type == CPP_STRING_USERDEF ) + return CPP_STRING; + else if (type == CPP_WSTRING_USERDEF ) + return CPP_WSTRING; + else if (type == CPP_STRING16_USERDEF ) + return CPP_STRING16; + else if (type == CPP_STRING32_USERDEF ) + return CPP_STRING32; + else if (type == CPP_UTF8STRING_USERDEF ) + return CPP_UTF8STRING; + else + return type; +} + +/* Return the user-defined string literal type corresponding to the input + string type. If the input type is not a string type return the input + type. */ +enum cpp_ttype +cpp_userdef_string_add_type (enum cpp_ttype type) +{ + if (type == CPP_STRING ) + return CPP_STRING_USERDEF; + else if (type == CPP_WSTRING ) + return CPP_WSTRING_USERDEF; + else if (type == CPP_STRING16 ) + return CPP_STRING16_USERDEF; + else if (type == CPP_STRING32 ) + return CPP_STRING32_USERDEF; + else if (type == CPP_UTF8STRING ) + return CPP_UTF8STRING_USERDEF; + else + return type; +} + +/* Return the char type corresponding to the the input user-defined char + literal type. If the input type is not a user-defined char literal + type return the input type. */ +enum cpp_ttype +cpp_userdef_char_remove_type (enum cpp_ttype type) +{ + if (type == CPP_CHAR_USERDEF ) + return CPP_CHAR; + else if (type == CPP_WCHAR_USERDEF ) + return CPP_WCHAR; + else if (type == CPP_CHAR16_USERDEF ) + return CPP_STRING16; + else if (type == CPP_CHAR32_USERDEF ) + return CPP_STRING32; + else + return type; +} + +/* Return the user-defined char literal type corresponding to the input + char type. If the input type is not a char type return the input + type. */ +enum cpp_ttype +cpp_userdef_char_add_type (enum cpp_ttype type) +{ + if (type == CPP_CHAR ) + return CPP_CHAR_USERDEF; + else if (type == CPP_WCHAR ) + return CPP_WCHAR_USERDEF; + else if (type == CPP_CHAR16 ) + return CPP_CHAR16_USERDEF; + else if (type == CPP_CHAR32 ) + return CPP_CHAR32_USERDEF; + else + return type; +} + +/* Return true if the token type is a user-defined string literal. */ +bool +cpp_userdef_string_p (enum cpp_ttype type) +{ + if (type == CPP_STRING_USERDEF + || type == CPP_WSTRING_USERDEF + || type == CPP_STRING16_USERDEF + || type == CPP_STRING32_USERDEF + || type == CPP_UTF8STRING_USERDEF ) + return true; + else + return false; +} + +/* Return true if the token type is a user-defined char literal. */ +bool +cpp_userdef_char_p (enum cpp_ttype type) +{ + if (type == CPP_CHAR_USERDEF + || type == CPP_WCHAR_USERDEF + || type == CPP_CHAR16_USERDEF + || type == CPP_CHAR32_USERDEF ) + return true; + else + return false; +} + +/* Extract the suffix from a user-defined literal string or char. */ +void +cpp_get_userdef_suffix (cpp_string string, char delim, char *suffix) +{ + unsigned int len = string.len; + const char *text = (const char *)string.text; + int i; + for (i = len; i > 0; --i) + { + if (text[i - 1] == delim) + break; + } + strncpy(suffix, text + i, len - i); + suffix[len - i + 1] = '\0'; +} + /* Categorize numeric constants according to their field (integer, floating point, or invalid), radix (decimal, octal, hexadecimal), - and type suffixes. */ + and type suffixes. In C++0X if UD_SUFFIX is non null it will be + assigned any unrecognized suffix for a user-defined literal. */ unsigned int -cpp_classify_number (cpp_reader *pfile, const cpp_token *token) +cpp_classify_number (cpp_reader *pfile, const cpp_token *token, + char **ud_suffix) { const uchar *str = token->val.str.text; const uchar *limit; @@ -231,6 +366,9 @@ enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag; bool seen_digit; + if (ud_suffix) + *ud_suffix = NULL; + /* If the lexer has done its job, length one can only be a single digit. Fast-path this very common case. */ if (token->val.str.len == 1) @@ -361,10 +499,20 @@ result = interpret_float_suffix (str, limit - str); if (result == 0) { - cpp_error (pfile, CPP_DL_ERROR, - "invalid suffix \"%.*s\" on floating constant", - (int) (limit - str), str); - return CPP_N_INVALID; + if (CPP_OPTION (pfile, lang) == CLK_CXX0X + || CPP_OPTION (pfile, lang) == CLK_GNUCXX0X) + { + if (ud_suffix) + *ud_suffix = xstrdup((const char *)str); + result = CPP_N_LARGE | CPP_N_USERDEF; + } + else + { + cpp_error (pfile, CPP_DL_ERROR, + "invalid suffix \"%.*s\" on floating constant", + (int) (limit - str), str); + return CPP_N_INVALID; + } } /* Traditional C didn't accept any floating suffixes. */ @@ -406,10 +554,20 @@ result = interpret_int_suffix (str, limit - str); if (result == 0) { - cpp_error (pfile, CPP_DL_ERROR, - "invalid suffix \"%.*s\" on integer constant", - (int) (limit - str), str); - return CPP_N_INVALID; + if (CPP_OPTION (pfile, lang) == CLK_CXX0X + || CPP_OPTION (pfile, lang) == CLK_GNUCXX0X) + { + if (ud_suffix) + *ud_suffix = xstrdup((const char *)str); + result = CPP_N_UNSIGNED | CPP_N_LARGE | CPP_N_USERDEF; + } + else + { + cpp_error (pfile, CPP_DL_ERROR, + "invalid suffix \"%.*s\" on integer constant", + (int) (limit - str), str); + return CPP_N_INVALID; + } } /* Traditional C only accepted the 'L' suffix. @@ -748,7 +906,7 @@ switch (token->type) { case CPP_NUMBER: - temp = cpp_classify_number (pfile, token); + temp = cpp_classify_number (pfile, token, NULL); switch (temp & CPP_N_CATEGORY) { case CPP_N_FLOATING: Index: libcpp/lex.c =================================================================== --- libcpp/lex.c (revision 172287) +++ libcpp/lex.c (working copy) @@ -1226,6 +1226,7 @@ token->type = type; token->val.str.len = len; token->val.str.text = dest; +/*printf("\ntoken: %s", token->val.str.text);*/ } /* Subroutine of lex_raw_string: Append LEN chars from BASE to the buffer @@ -1483,6 +1484,22 @@ cpp_error_with_line (pfile, CPP_DL_WARNING, saw_NUL, 0, "null character(s) preserved in literal"); + if (CPP_OPTION(pfile, lang) == CLK_CXX0X + || CPP_OPTION(pfile, lang) == CLK_GNUCXX0X) + { + /* Grab user defined literal suffix. */ + if (ISIDST(*cur)) + { + type = cpp_userdef_char_add_type (type); + type = cpp_userdef_string_add_type (type); + ++cur; + } + while (ISIDNUM(*cur)) + { + ++cur; + } + } + pfile->buffer->cur = cur; if (first_buff == NULL) create_literal (pfile, token, base, cur - base, type); @@ -1586,6 +1603,22 @@ cpp_error (pfile, CPP_DL_PEDWARN, "missing terminating %c character", (int) terminator); + if (CPP_OPTION(pfile, lang) == CLK_CXX0X + || CPP_OPTION(pfile, lang) == CLK_GNUCXX0X) + { + /* Grab user defined literal suffix. */ + if (ISIDST(*cur)) + { + type = cpp_userdef_char_add_type (type); + type = cpp_userdef_string_add_type (type); + ++cur; + } + while (ISIDNUM(*cur)) + { + ++cur; + } + } + pfile->buffer->cur = cur; create_literal (pfile, token, base, cur - base, type); }