diff options
author | jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-10-26 19:30:59 +0000 |
---|---|---|
committer | jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-10-26 19:30:59 +0000 |
commit | 244db24d8ddff5d5788dc1f10c971d815c9b4388 (patch) | |
tree | 1d0c22775480b21a84a6024b85f12710e67dd587 | |
parent | a60a96f62b663b8dc609fa90feb808ca74956a03 (diff) | |
download | gcc-244db24d8ddff5d5788dc1f10c971d815c9b4388.tar.gz |
Implement C++11 user-defined literals.
libcpp/
* expr.c: (cpp_interpret_float_suffix, cpp_interpret_int_suffix,
cpp_userdef_string_remove_type, cpp_userdef_string_add_type,
cpp_userdef_char_remove_type, cpp_userdef_char_add_type,
cpp_userdef_string_p, cpp_userdef_char_p, cpp_get_userdef_suffix): New.
(cpp_classify_number): Classify unrecognized tokens as user-defined
literals.
* include/cpplib.h: Add new tokens for user-defined literals.
* init.c: Add new preprocessor flag (cxx11).
* lex.c: (lex_string, lex_raw_string): Handle user-defined literals
including concatenation and promotion with suffixes.
c-family/
* c-common.c (build_userdef_literal): New.
* c-common.def: New tree code.
* c-common.h (tree_userdef_literal): New tree struct and accessors.
* c-lex.c (interpret_float): Add suffix parm.
(c_lex_with_flags): Build literal tokens.
cp/
* cp-objcp-common.c: (cp_tree_size) Return size of USERDEF_LITERAL tree.
* cp-tree.h: (UDLIT_OP_*, UDLIT_OPER_P): Literal operator
name tools. New tree code for user-defined literals.
* cxx-pretty-print.h: (pp_cxx_userdef_literal) New.
* cxx-pretty-print.c: (pp_cxx_userdef_literal) New.
(pp_cxx_primary_expression, pp_cxx_expression): Use it.
* decl.c: (cp_tree_node_structure): Return new tree code.
(duplicate_decls): Check for raw vs. template operator conflicts.
(grokfndecl, grokdeclarator): New checks for literal operators.
* error.c: (dump_expr): Warn about user-defined literals
in C++98 mode. (dump_function_name): Pretty printing.
* mangle.c: (write_literal_operator_name): New.
(write_unqualified_id, write_unqualified_name): Use it.
* parser.c: (cp_parser_operator): Handle operator"".
(cp_parser_userdef_char_literal, cp_parser_userdef_numeric_literal,
cp_parser_userdef_string_literal): New.
(cp_parser_primary_expression): Handle new user-defined literal tokens
with new functions.
* semantics.c: (potential_constant_expression_1): Add
user-defined literals.
* typeck.c (check_raw_literal_operator,
check_literal_operator_args): New.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@180536 138bc75d-0d04-0410-961f-82ee72b054a4
57 files changed, 1714 insertions, 51 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index d1c2c49ac85..b49e827866b 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,12 @@ +2011-10-26 Ed Smith-Rowland <3dw4rd@verizon.net> + + Implement C++11 user-defined literals. + * c-common.c (build_userdef_literal): New. + * c-common.def: New tree code. + * c-common.h (tree_userdef_literal): New tree struct and accessors. + * c-lex.c (interpret_float): Add suffix parm. + (c_lex_with_flags): Build literal tokens. + 2011-10-23 Paolo Carlini <paolo.carlini@oracle.com> PR c++/50841 diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index ae18de3929c..2eefe03f390 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -9912,4 +9912,17 @@ c_common_init_ts (void) MARK_TS_TYPED (EXCESS_PRECISION_EXPR); } +/* Build a user-defined numeric literal out of an integer constant type VALUE + with identifier SUFFIX. */ + +tree +build_userdef_literal (tree suffix_id, tree value, tree num_string) +{ + tree literal = make_node (USERDEF_LITERAL); + USERDEF_LITERAL_SUFFIX_ID (literal) = suffix_id; + USERDEF_LITERAL_VALUE (literal) = value; + USERDEF_LITERAL_NUM_STRING (literal) = num_string; + return literal; +} + #include "gt-c-family-c-common.h" diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def index c7e01b693ca..2a7df882d0a 100644 --- a/gcc/c-family/c-common.def +++ b/gcc/c-family/c-common.def @@ -47,6 +47,12 @@ DEFTREECODE (C_MAYBE_CONST_EXPR, "c_maybe_const_expr", tcc_expression, 2) evaluated. */ DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1) +/* Used to represent a user-defined literal. + The operands are an IDENTIFIER for the suffix, the VALUE of the literal, + and for numeric literals the original string representation of the + number. */ +DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3) + /* Local variables: mode:c diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 9818c9ca682..be9d7295b2a 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1067,4 +1067,27 @@ c_tree_chain_next (tree t) return NULL; } +/* A suffix-identifier value doublet that represents user-defined literals + for C++-0x. */ +struct GTY(()) tree_userdef_literal { + struct tree_base base; + tree suffix_id; + tree value; + tree num_string; +}; + +#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_NUM_STRING(NODE) \ + (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->num_string) + +#define USERDEF_LITERAL_TYPE(NODE) \ + (TREE_TYPE (USERDEF_LITERAL_VALUE (NODE))) + +extern tree build_userdef_literal (tree suffix_id, tree value, tree num_string); + #endif /* ! GCC_C_COMMON_H */ diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c index b151564000c..baee8eb9799 100644 --- a/gcc/c-family/c-lex.c +++ b/gcc/c-family/c-lex.c @@ -45,7 +45,7 @@ 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_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 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags, case CPP_NUMBER: { - unsigned int flags = cpp_classify_number (parse_in, tok); + const char *suffix = NULL; + unsigned int flags = cpp_classify_number (parse_in, tok, &suffix); switch (flags & CPP_N_CATEGORY) { @@ -332,12 +333,27 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags, 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 suffix_id = get_identifier (suffix); + int len = tok->val.str.len - strlen (suffix); + tree num_string = build_string (len + 1, + (const char *) tok->val.str.text); + TREE_TYPE (num_string) = char_array_type_node; + num_string = fix_string_type (num_string); + char *str = CONST_CAST (char *, TREE_STRING_POINTER (num_string)); + str[len] = '\0'; + tree literal = build_userdef_literal (suffix_id, *value, + num_string); + *value = literal; + } } break; @@ -415,6 +431,22 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags, } 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; + const char *suffix = cpp_get_userdef_suffix (tok); + temp_tok.val.str.len -= strlen (suffix); + temp_tok.type = cpp_userdef_char_remove_type (type); + literal = build_userdef_literal (get_identifier (suffix), + lex_charconst (&temp_tok), NULL_TREE); + *value = literal; + } + break; + case CPP_CHAR: case CPP_WCHAR: case CPP_CHAR16: @@ -422,6 +454,22 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags, *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, string; + const char *suffix = cpp_get_userdef_suffix (tok); + string = build_string (tok->val.str.len - strlen (suffix), + (const char *) tok->val.str.text); + literal = build_userdef_literal (get_identifier (suffix), + string, NULL_TREE); + *value = literal; + } + break; + case CPP_STRING: case CPP_WSTRING: case CPP_STRING16: @@ -621,9 +669,10 @@ interpret_integer (const cpp_token *token, unsigned int flags) } /* 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 +751,9 @@ interpret_float (const cpp_token *token, unsigned int flags) 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 { diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e6a9a90affe..ee942cab6d6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,29 @@ +2011-10-26 Ed Smith-Rowland <3dw4rd@verizon.net> + + Implement C++11 user-defined literals. + * cp-objcp-common.c: (cp_tree_size) Return size of USERDEF_LITERAL tree. + * cp-tree.h: (UDLIT_OP_*, UDLIT_OPER_P): Literal operator + name tools. New tree code for user-defined literals. + * cxx-pretty-print.h: (pp_cxx_userdef_literal) New. + * cxx-pretty-print.c: (pp_cxx_userdef_literal) New. + (pp_cxx_primary_expression, pp_cxx_expression): Use it. + * decl.c: (cp_tree_node_structure): Return new tree code. + (duplicate_decls): Check for raw vs. template operator conflicts. + (grokfndecl, grokdeclarator): New checks for literal operators. + * error.c: (dump_expr): Warn about user-defined literals + in C++98 mode. (dump_function_name): Pretty printing. + * mangle.c: (write_literal_operator_name): New. + (write_unqualified_id, write_unqualified_name): Use it. + * parser.c: (cp_parser_operator): Handle operator"". + (cp_parser_userdef_char_literal, cp_parser_userdef_numeric_literal, + cp_parser_userdef_string_literal): New. + (cp_parser_primary_expression): Handle new user-defined literal tokens + with new functions. + * semantics.c: (potential_constant_expression_1): Add + user-defined literals. + * typeck.c (check_raw_literal_operator, + check_literal_operator_args): New. + 2011-10-26 Paolo Carlini <paolo.carlini@oracle.com> * typeck.c (cp_build_addr_expr_1): Use BASELINK_P. diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 035fdcd2f4e..a957a0303ac 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -100,6 +100,8 @@ cp_tree_size (enum tree_code code) case TEMPLATE_INFO: return sizeof (struct tree_template_info); + case USERDEF_LITERAL: return sizeof (struct tree_userdef_literal); + default: gcc_unreachable (); } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b20e7d1aac5..cc12d154a22 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -400,7 +400,9 @@ typedef enum cpp0x_warn_str /* override controls, override/final */ CPP0X_OVERRIDE_CONTROLS, /* non-static data member initializers */ - CPP0X_NSDMI + CPP0X_NSDMI, + /* user defined literals */ + CPP0X_USER_DEFINED_LITERALS } cpp0x_warn_str; /* The various kinds of operation used by composite_pointer_type. */ @@ -740,6 +742,7 @@ enum cp_tree_node_structure_enum { TS_CP_TRAIT_EXPR, TS_CP_LAMBDA_EXPR, TS_CP_TEMPLATE_INFO, + TS_CP_USERDEF_LITERAL, LAST_TS_CP_ENUM }; @@ -765,6 +768,8 @@ union GTY((desc ("cp_tree_node_structure (&%h)"), lambda_expression; struct tree_template_info GTY ((tag ("TS_CP_TEMPLATE_INFO"))) template_info; + struct tree_userdef_literal GTY ((tag ("TS_CP_USERDEF_LITERAL"))) + userdef_literal; }; @@ -4228,6 +4233,17 @@ extern GTY(()) VEC(tree,gc) *local_classes; 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 "li" +#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)) +#define UDLIT_OP_SUFFIX(ID_NODE) \ + (IDENTIFIER_POINTER (ID_NODE) + 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' \ @@ -5759,6 +5775,8 @@ extern tree convert_ptrmem (tree, tree, bool, bool, extern int lvalue_or_else (tree, enum lvalue_use, tsubst_flags_t); extern void check_template_keyword (tree); +extern bool check_raw_literal_operator (const_tree decl); +extern bool check_literal_operator_args (const_tree, bool *, bool *); /* in typeck2.c */ extern void require_complete_eh_spec_types (tree, tree); diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 708afc8cdc2..55cb64b21e4 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -367,6 +367,17 @@ pp_cxx_id_expression (cxx_pretty_printer *pp, tree t) pp_cxx_unqualified_id (pp, t); } +/* user-defined literal: + literal ud-suffix */ + +void +pp_cxx_userdef_literal (cxx_pretty_printer *pp, tree t) +{ + pp_cxx_constant (pp, USERDEF_LITERAL_VALUE (t)); + pp_cxx_id_expression (pp, USERDEF_LITERAL_SUFFIX_ID (t)); +} + + /* primary-expression: literal this @@ -413,6 +424,10 @@ pp_cxx_primary_expression (cxx_pretty_printer *pp, tree t) pp_cxx_constant (pp, t); break; + case USERDEF_LITERAL: + pp_cxx_userdef_literal (pp, t); + break; + case BASELINK: t = BASELINK_FUNCTIONS (t); case VAR_DECL: @@ -1024,6 +1039,10 @@ pp_cxx_expression (cxx_pretty_printer *pp, tree t) pp_cxx_constant (pp, t); break; + case USERDEF_LITERAL: + pp_cxx_userdef_literal (pp, t); + break; + case RESULT_DECL: pp_cxx_unqualified_id (pp, t); break; diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h index d12506e62fe..bb9fec1c1bd 100644 --- a/gcc/cp/cxx-pretty-print.h +++ b/gcc/cp/cxx-pretty-print.h @@ -74,5 +74,7 @@ void pp_cxx_canonical_template_parameter (cxx_pretty_printer *, tree); void pp_cxx_trait_expression (cxx_pretty_printer *, tree); void pp_cxx_va_arg_expression (cxx_pretty_printer *, tree); void pp_cxx_offsetof_expression (cxx_pretty_printer *, tree); +void pp_cxx_userdef_literal (cxx_pretty_printer *, tree); + #endif /* GCC_CXX_PRETTY_PRINT_H */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 26e9847f4fd..5ba50088684 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1203,6 +1203,21 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) || TREE_TYPE (olddecl) == error_mark_node) return error_mark_node; + if (UDLIT_OPER_P (DECL_NAME (newdecl)) + && UDLIT_OPER_P (DECL_NAME (olddecl))) + { + if (TREE_CODE (newdecl) == TEMPLATE_DECL + && TREE_CODE (olddecl) != TEMPLATE_DECL + && check_raw_literal_operator (olddecl)) + error ("literal operator template %q+D conflicts with" + " raw literal operator %qD", newdecl, olddecl); + else if (TREE_CODE (newdecl) != TEMPLATE_DECL + && TREE_CODE (olddecl) == TEMPLATE_DECL + && check_raw_literal_operator (newdecl)) + error ("raw literal operator %q+D conflicts with" + " literal operator template %qD", newdecl, olddecl); + } + if (DECL_P (olddecl) && TREE_CODE (newdecl) == FUNCTION_DECL && TREE_CODE (olddecl) == FUNCTION_DECL @@ -7345,6 +7360,47 @@ grokfndecl (tree ctype, if (IDENTIFIER_OPNAME_P (DECL_NAME (decl)) && !grok_op_properties (decl, /*complain=*/true)) return NULL_TREE; + else if (UDLIT_OPER_P (DECL_NAME (decl))) + { + bool long_long_unsigned_p; + bool long_double_p; + const char *suffix = NULL; + /* [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 (decl, &long_long_unsigned_p, + &long_double_p)) + { + error ("%qD has invalid argument list", decl); + return NULL_TREE; + } + + suffix = UDLIT_OP_SUFFIX (DECL_NAME (decl)); + if (long_long_unsigned_p) + { + if (cpp_interpret_int_suffix (suffix, strlen (suffix))) + warning (0, "integer suffix %<%s%>" + " shadowed by implementation", suffix); + } + else if (long_double_p) + { + if (cpp_interpret_float_suffix (suffix, strlen (suffix))) + warning (0, "floating point suffix %<%s%>" + " shadowed by implementation", suffix); + } + } + 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 @@ -8536,6 +8592,15 @@ grokdeclarator (const cp_declarator *declarator, 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) + { + error ("declaration of %qD as non-function", dname); + return error_mark_node; + } if (dname && IDENTIFIER_OPNAME_P (dname)) { @@ -13754,6 +13819,7 @@ cp_tree_node_structure (union lang_tree_node * t) case TRAIT_EXPR: return TS_CP_TRAIT_EXPR; case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR; case TEMPLATE_INFO: return TS_CP_TEMPLATE_INFO; + case USERDEF_LITERAL: return TS_CP_USERDEF_LITERAL; default: return TS_CP_GENERIC; } } diff --git a/gcc/cp/error.c b/gcc/cp/error.c index c6110b220fa..544c4d1b7ac 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1534,6 +1534,8 @@ dump_function_name (tree t, int flags) } 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); @@ -1756,6 +1758,10 @@ dump_expr (tree t, int flags) pp_constant (cxx_pp, t); break; + case USERDEF_LITERAL: + pp_cxx_userdef_literal (cxx_pp, t); + break; + case THROW_EXPR: /* While waiting for caret diagnostics, avoid printing __cxa_allocate_exception, __cxa_throw, and the like. */ @@ -3233,7 +3239,7 @@ maybe_warn_cpp0x (cpp0x_warn_str str) pedwarn (input_location, OPT_pedantic, "inline namespaces " "only available with -std=c++0x or -std=gnu++0x"); - break; + break; case CPP0X_OVERRIDE_CONTROLS: pedwarn (input_location, 0, "override controls (override/final) " @@ -3244,8 +3250,13 @@ maybe_warn_cpp0x (cpp0x_warn_str str) "non-static data member initializers " "only available with -std=c++0x or -std=gnu++0x"); 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(); + gcc_unreachable (); } } diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 55851e646b2..8bc26d8b34f 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -181,6 +181,7 @@ static void write_template_prefix (const tree); 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 *, @@ -1174,6 +1175,8 @@ write_unqualified_id (tree identifier) } write_string (mangled_name); } + else if (UDLIT_OPER_P (identifier)) + write_literal_operator_name (identifier); else write_source_name (identifier); } @@ -1227,6 +1230,8 @@ write_unqualified_name (const tree decl) 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; @@ -1286,6 +1291,21 @@ write_source_name (tree identifier) 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) +{ + const char* suffix = UDLIT_OP_SUFFIX (identifier); + char* buffer = XNEWVEC (char, strlen (UDLIT_OP_MANGLED_PREFIX) + + strlen (suffix) + 10); + 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 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index a762d9d9184..840a30ddf65 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -225,6 +225,9 @@ static cp_token_cache *cp_token_cache_new static void cp_parser_initial_pragma (cp_token *); +static tree cp_literal_operator_id + (const char *); + /* Manifest constants. */ #define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token)) #define CP_SAVED_TOKEN_STACK 5 @@ -1762,6 +1765,12 @@ static tree cp_parser_identifier (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_token *); +static tree cp_parser_userdef_numeric_literal + (cp_parser *); /* Basic concepts [gram.basic] */ @@ -2270,6 +2279,8 @@ static bool cp_parser_error_occurred (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 @@ -2290,7 +2301,7 @@ cp_parser_parsing_tentatively (cp_parser* parser) /* 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 || @@ -2299,6 +2310,20 @@ cp_parser_is_string_literal (cp_token* token) 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 @@ -3338,7 +3363,11 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok) struct obstack str_ob; cpp_string str, istr, *strs; cp_token *tok; - enum cpp_ttype type; + enum cpp_ttype type, curr_type; + int have_suffix_p = 0; + tree string_tree; + tree suffix_id = NULL_TREE; + bool curr_tok_is_userdef_p = false; tok = cp_lexer_peek_token (parser->lexer); if (!cp_parser_is_string_literal (tok)) @@ -3347,7 +3376,18 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok) return error_mark_node; } - type = tok->type; + if (cpp_userdef_string_p (tok->type)) + { + string_tree = USERDEF_LITERAL_VALUE (tok->u.value); + curr_type = cpp_userdef_string_remove_type (tok->type); + curr_tok_is_userdef_p = true; + } + else + { + string_tree = tok->u.value; + curr_type = tok->type; + } + type = curr_type; /* Try to avoid the overhead of creating and destroying an obstack for the common case of just one string. */ @@ -3356,10 +3396,19 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok) { 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) + { + suffix_id = USERDEF_LITERAL_SUFFIX_ID (tok->u.value); + have_suffix_p = 1; + curr_type = cpp_userdef_string_remove_type (tok->type); + } + else + curr_type = tok->type; + strs = &str; } else @@ -3371,14 +3420,35 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok) { 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 curr_suffix_id = USERDEF_LITERAL_SUFFIX_ID (tok->u.value); + if (have_suffix_p == 0) + { + suffix_id = curr_suffix_id; + have_suffix_p = 1; + } + else if (have_suffix_p == 1 + && curr_suffix_id != suffix_id) + { + error ("inconsistent user-defined literal suffixes" + " %qD and %qD in string literal", + suffix_id, curr_suffix_id); + have_suffix_p = -1; + } + curr_type = cpp_userdef_string_remove_type (tok->type); + } + else + curr_type = tok->type; - if (type != tok->type) + if (type != curr_type) { if (type == CPP_STRING) - type = tok->type; - else if (tok->type != CPP_STRING) + type = curr_type; + else if (curr_type != CPP_STRING) error_at (tok->location, "unsupported non-standard concatenation " "of string literals"); @@ -3387,6 +3457,18 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok) 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); + curr_type = cpp_userdef_string_remove_type (tok->type); + curr_tok_is_userdef_p = true; + } + else + { + string_tree = tok->u.value; + curr_type = tok->type; + curr_tok_is_userdef_p = false; + } } while (cp_parser_is_string_literal (tok)); @@ -3424,6 +3506,13 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok) } value = fix_string_type (value); + + if (have_suffix_p) + { + tree literal = build_userdef_literal (suffix_id, value, NULL_TREE); + tok->u.value = literal; + return cp_parser_userdef_string_literal (tok); + } } else /* cpp_interpret_string has issued an error. */ @@ -3435,6 +3524,186 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok) 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; + 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. */ + vec = make_tree_vector (); + VEC_safe_push (tree, gc, vec, value); + decl = lookup_function_nonclass (name, vec, /*block_p=*/false); + if (!decl || decl == error_mark_node) + { + error ("unable to find user-defined character literal operator %qD", + name); + release_tree_vector (vec); + return error_mark_node; + } + result = finish_call_expr (decl, &vec, false, true, tf_warning_or_error); + release_tree_vector (vec); + + return result; +} + +/* A subroutine of cp_parser_userdef_numeric_literal to + create a char... template parameter pack from a string node. */ + +static tree +make_char_string_pack (tree value) +{ + tree charvec; + tree argpack = make_node (NONTYPE_ARGUMENT_PACK); + const char *str = TREE_STRING_POINTER (value); + int i, len = TREE_STRING_LENGTH (value) - 1; + tree argvec = make_tree_vec (1); + + /* Fill in CHARVEC with all of the parameters. */ + charvec = make_tree_vec (len); + for (i = 0; i < len; ++i) + TREE_VEC_ELT (charvec, i) = build_int_cst (char_type_node, str[i]); + + /* Build the argument packs. */ + SET_ARGUMENT_PACK_ARGS (argpack, charvec); + TREE_TYPE (argpack) = char_type_node; + + TREE_VEC_ELT (argvec, 0) = argpack; + + return argvec; +} + +/* 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, num_string; + tree name, decl; + tree result = error_mark_node; + 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. */ + args = make_tree_vector (); + VEC_safe_push (tree, gc, args, value); + decl = lookup_function_nonclass (name, args, /*block_p=*/false); + if (decl && decl != error_mark_node) + { + result = finish_call_expr (decl, &args, false, true, tf_none); + if (result != error_mark_node) + { + release_tree_vector (args); + return result; + } + } + release_tree_vector (args); + + /* 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. */ + args = make_tree_vector (); + VEC_safe_push (tree, gc, args, num_string); + decl = lookup_function_nonclass (name, args, /*block_p=*/false); + if (decl && decl != error_mark_node) + { + result = finish_call_expr (decl, &args, false, true, tf_none); + if (result != error_mark_node) + { + release_tree_vector (args); + return result; + } + } + release_tree_vector (args); + + /* If the raw literal didn't work, look for a non-type template + 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); + if (decl && decl != error_mark_node) + { + tree tmpl_args = make_char_string_pack (num_string); + decl = lookup_template_function (decl, tmpl_args); + result = finish_call_expr (decl, &args, false, true, tf_none); + if (result != error_mark_node) + { + release_tree_vector (args); + return result; + } + } + release_tree_vector (args); + + if (result == error_mark_node) + error ("unable to find user-defined numeric literal operator %qD", name); + + 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_token *token) +{ + tree literal, suffix_id, value; + tree name, decl; + 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. */ + 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); + if (!decl || decl == error_mark_node) + { + error ("unable to find user-defined string literal operator %qD", name); + release_tree_vector (vec); + 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); + + return result; +} + /* Basic concepts [gram.basic] */ @@ -3578,12 +3847,16 @@ cp_parser_primary_expression (cp_parser *parser, 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) { @@ -3637,11 +3910,22 @@ cp_parser_primary_expression (cp_parser *parser, } 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. */ @@ -4477,6 +4761,14 @@ cp_parser_unqualified_id (cp_parser* parser, /* If that didn't work, try a conversion-function-id. */ if (!cp_parser_parse_definitely (parser)) id = cp_parser_conversion_function_id (parser); + else if (UDLIT_OPER_P (id)) + { + /* 17.6.3.3.5 */ + const char *name = UDLIT_OP_SUFFIX (id); + if (name[0] != '_' && !in_system_header) + warning (0, "literal operator suffixes not preceded by %<_%>" + " are reserved for future standardization"); + } return id; } @@ -5119,7 +5411,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, /* Restore the saved message. */ parser->type_definition_forbidden_message = saved_message; /* `typeid' may not appear in an integral constant expression. */ - if (cp_parser_non_integral_constant_expression(parser, NIC_TYPEID)) + if (cp_parser_non_integral_constant_expression (parser, NIC_TYPEID)) return error_mark_node; } break; @@ -9739,7 +10031,7 @@ cp_parser_declaration (cp_parser* parser) /* 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 @@ -11170,6 +11462,22 @@ cp_parser_operator_function_id (cp_parser* parser) 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 = XNEWVEC (char, strlen (UDLIT_OP_ANSI_PREFIX) + + strlen (name) + 10); + sprintf (buffer, UDLIT_OP_ANSI_FORMAT, name); + identifier = get_identifier (buffer); + /*IDENTIFIER_UDLIT_OPNAME_P (identifier) = 1; If we get a flag someday. */ + + return identifier; +} + /* Parse an operator. operator: @@ -11389,6 +11697,37 @@ cp_parser_operator (cp_parser* parser) 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 %<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 + { + error ("expected suffix identifier"); + return error_mark_node; + } + + case CPP_STRING_USERDEF: + error ("missing space between %<\"\"%> and suffix identifier"); + return error_mark_node; + default: /* Anything else is an error. */ break; @@ -20583,6 +20922,33 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p) /* Finish up. */ finish_template_decl (parameter_list); + /* Check the template arguments for a literal operator template. */ + if (decl + && (TREE_CODE (decl) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (decl)) + && UDLIT_OPER_P (DECL_NAME (decl))) + { + bool ok = true; + if (parameter_list == NULL_TREE) + ok = false; + else + { + int num_parms = TREE_VEC_LENGTH (parameter_list); + if (num_parms != 1) + ok = false; + else + { + tree parm_list = TREE_VEC_ELT (parameter_list, 0); + tree parm = INNERMOST_TEMPLATE_PARMS (parm_list); + if (TREE_TYPE (parm) != char_type_node + || !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))) + ok = false; + } + } + if (!ok) + error ("literal operator template %qD has invalid parameter list." + " Expected non-type template argument pack <char...>", + decl); + } /* Register member declarations. */ if (member_p && !friend_p && decl && !DECL_CLASS_TEMPLATE_P (decl)) finish_member_declaration (decl); @@ -22891,7 +23257,8 @@ cp_parser_objc_interstitial_code (cp_parser* parser) /* 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) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index ec38a473715..fa8ab9914c3 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7865,6 +7865,7 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags) case TEMPLATE_PARM_INDEX: case TRAIT_EXPR: case IDENTIFIER_NODE: + case USERDEF_LITERAL: /* We can see a FIELD_DECL in a pointer-to-member expression. */ case FIELD_DECL: case PARM_DECL: diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 068819ebe87..59e1357cb0b 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -8356,3 +8356,121 @@ lvalue_or_else (tree ref, enum lvalue_use use, tsubst_flags_t complain) return 1; } +/* Return true if a user-defined literal operator is a raw operator. */ + +bool +check_raw_literal_operator (const_tree decl) +{ + tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl)); + tree argtype; + int arity; + bool maybe_raw_p = false; + + /* Count the number and type of arguments and check for ellipsis. */ + for (argtype = argtypes, arity = 0; + argtype && argtype != void_list_node; + ++arity, argtype = TREE_CHAIN (argtype)) + { + tree t = TREE_VALUE (argtype); + + if (same_type_p (t, const_string_type_node)) + maybe_raw_p = true; + } + if (!argtype) + return false; /* Found ellipsis. */ + + if (!maybe_raw_p || arity != 1) + return false; + + return true; +} + + +/* Return true if a user-defined literal operator has one of the allowed + argument types. */ + +bool +check_literal_operator_args (const_tree decl, + bool *long_long_unsigned_p, bool *long_double_p) +{ + tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl)); + if (processing_template_decl) + return (argtypes == NULL_TREE + || same_type_p (TREE_VALUE (argtypes), void_type_node)); + else + { + tree argtype; + int arity; + int max_arity = 2; + bool found_string_p = false; + bool maybe_raw_p = false; + bool found_size_p = false; + 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)); + + *long_long_unsigned_p = false; + *long_double_p = false; + + /* Count the number and type of arguments and check for ellipsis. */ + for (argtype = argtypes, arity = 0; + argtype && argtype != void_list_node; + argtype = TREE_CHAIN (argtype)) + { + tree t = TREE_VALUE (argtype); + ++arity; + + if (same_type_p (t, const_string_type_node)) + { + found_string_p = true; + maybe_raw_p = true; + } + else if (same_type_p (t, const_wchar_ptr_type_node)) + found_string_p = true; + else if (same_type_p (t, const_char16_ptr_type_node)) + found_string_p = true; + else if (same_type_p (t, const_char32_ptr_type_node)) + found_string_p = true; + else if (same_type_p (t, size_type_node)) + { + if (!found_string_p) + return false; + found_size_p = true; + } + else if (same_type_p (t, long_long_unsigned_type_node)) + { + max_arity = 1; + *long_long_unsigned_p = true; + } + else if (same_type_p (t, long_double_type_node)) + { + max_arity = 1; + *long_double_p = true; + } + else if (same_type_p (t, char_type_node)) + max_arity = 1; + else if (same_type_p (t, wchar_type_node)) + max_arity = 1; + else if (same_type_p (t, char16_type_node)) + max_arity = 1; + else if (same_type_p (t, char32_type_node)) + max_arity = 1; + else + return false; + } + if (!argtype) + return false; /* Found ellipsis. */ + + if (arity > max_arity) + return false; + + if (found_string_p && !maybe_raw_p && !found_size_p) + return false; + + return true; + } +} + diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 868e4b0d204..e702ae907c2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,38 @@ +2011-10-26 Ed Smith-Rowland <3dw4rd@verizon.net> + + Implement C++11 user-defined literals. + * g++.dg/cpp0x/udlit-addr.C: New. + * g++.dg/cpp0x/udlit-args.C: New. + * g++.dg/cpp0x/udlit-args-neg.C: New. + * g++.dg/cpp0x/udlit-clink-neg.C: New. + * g++.dg/cpp0x/udlit-concat.C: New. + * g++.dg/cpp0x/udlit-concat-neg.C: New. + * g++.dg/cpp0x/udlit-constexpr.C: New. + * g++.dg/cpp0x/udlit-cpp98-neg.C: New. + * g++.dg/cpp0x/udlit-declare-neg.C: New. + * g++.dg/cpp0x/udlit-friend.C: New. + * g++.dg/cpp0x/udlit-general.C: New. + * g++.dg/cpp0x/udlit-inline.C: New. + * g++.dg/cpp0x/udlit-linkage-neg.C: New. + * g++.dg/cpp0x/udlit-member-neg.C: New. + * g++.dg/cpp0x/udlit-namespace.C: New. + * g++.dg/cpp0x/udlit-nofunc-neg.C: New. + * g++.dg/cpp0x/udlit-nonempty-str-neg.C: New. + * g++.dg/cpp0x/udlit-nospace-neg.C: New. + * g++.dg/cpp0x/udlit-nosuffix-neg.C: New. + * g++.dg/cpp0x/udlit-nounder-neg.C: New. + * g++.dg/cpp0x/udlit-operator-neg.C: New. + * g++.dg/cpp0x/udlit-raw-str.C: New. + * g++.dg/cpp0x/udlit-shadow-neg.C: New. + * g++.dg/cpp0x/udlit-suffix-neg.C: New. + * g++.dg/cpp0x/udlit-systemheader.C: New. + * g++.dg/cpp0x/udlit-template.C: New. + * g++.dg/cpp0x/udlit-tmpl-arg.C: New. + * g++.dg/cpp0x/udlit-tmpl-arg-neg.C: New. + * g++.dg/cpp0x/udlit-tmpl-parms.C: New. + * g++.dg/cpp0x/udlit-tmpl-parms-neg.C: New. + * g++.dg/cpp0x/udlit_system_header: New. + 2011-10-26 Paolo Carlini <paolo.carlini@oracle.com> PR c++/50870 diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-addr.C b/gcc/testsuite/g++.dg/cpp0x/udlit-addr.C new file mode 100644 index 00000000000..7d3286e007b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-addr.C @@ -0,0 +1,10 @@ +// { dg-options "-std=c++0x" } + +#include <cstddef> + +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); diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-args-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-args-neg.C new file mode 100644 index 00000000000..cb924a249bf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-args-neg.C @@ -0,0 +1,38 @@ +// { dg-options -std=c++0x } + +#include <cstddef> + +class Foo { }; + +Foo +operator"" _Foo(int *); // { dg-error "has invalid argument list" } + +Foo +operator"" _Foo(unsigned long int); // { dg-error "has invalid argument list" } + +Foo +operator"" _Foo(double); // { dg-error "has invalid argument list" } + +Foo +operator"" _Foo(const float *, std::size_t); // { dg-error "has invalid argument list" } + +Foo +operator"" _Foo(const wchar_t *, int); // { dg-error "has invalid argument list" } + +Foo +operator"" _Foo(const char16_t *); // { dg-error "has invalid argument list" } + +Foo +operator"" _Foo(char...); // { dg-error "has invalid argument list" } + +Foo +operator"" _Foo(unsigned long long int, char); // { dg-error "has invalid argument list" } + +Foo +operator"" _Foo(const char *, std::size_t, int); // { dg-error "has invalid argument list" } + +Foo +operator"" _Foo(long double &); // { dg-error "has invalid argument list" } + +Foo +operator"" _Foo(std::size_t, const char16_t *); // { dg-error "has invalid argument list" } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-args.C b/gcc/testsuite/g++.dg/cpp0x/udlit-args.C new file mode 100644 index 00000000000..ca2039c59d3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-args.C @@ -0,0 +1,38 @@ +// { dg-options -std=c++0x } + +#include <cstddef> + +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); diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-clink-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-clink-neg.C new file mode 100644 index 00000000000..a80e7244afd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-clink-neg.C @@ -0,0 +1,8 @@ +// { dg-options -std=c++0x } + +extern "C" { + +int +operator"" _badclinkage(unsigned long long); // { dg-error "operator with C linkage" } + +} diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-concat-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-concat-neg.C new file mode 100644 index 00000000000..61dc2ab02c6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-concat-neg.C @@ -0,0 +1,9 @@ +// { dg-options "-std=c++0x" } + +#include <string> + +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" } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-concat.C b/gcc/testsuite/g++.dg/cpp0x/udlit-concat.C new file mode 100644 index 00000000000..612bc1d1116 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-concat.C @@ -0,0 +1,24 @@ +// { dg-options "-std=c++0x" } + +#include <string> + +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; diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C b/gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C new file mode 100644 index 00000000000..40b0dfac531 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C @@ -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]; diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-cpp98-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-cpp98-neg.C new file mode 100644 index 00000000000..cb78a2c9c3e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-cpp98-neg.C @@ -0,0 +1,17 @@ +// { dg-options "-std=c++98" } + +#include <cstddef> + +int +operator"" _mm(long double m) // { dg-warning "user-defined literals only available with" } +{ return int(1000.0L * m); } + +int in = 0.0254_mm; // { dg-error "invalid suffix" } + +int +operator"" _Q(const char *, std::size_t) // { dg-warning "user-defined literals only available with" } +{ return 42; } + +int x = "Hello"_Q; // { dg-error "invalid conversion from" } + +// { dg-error "expected" "" { target *-*-* } 15 } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C new file mode 100644 index 00000000000..7b50c017f01 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C @@ -0,0 +1,15 @@ +// { dg-options "-std=c++0x" } + +// 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 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" } + +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" } + +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" } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-embed-quote.C b/gcc/testsuite/g++.dg/cpp0x/udlit-embed-quote.C new file mode 100644 index 00000000000..48a2a1b171d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-embed-quote.C @@ -0,0 +1,34 @@ +// { dg-do run } +// { dg-options "-std=c++0x" } + +// Make sure embedded quotes are not a problem for string and char literals. + +#include <cstdint> +#include <cassert> + +int operator"" _embedchar(char) +{ return 41; }; + +int operator"" _embedstr(const char*, std::size_t len) +{ return 42 + len; }; + +void +test() +{ + int i = '\''_embedchar; + + int j = "\""_embedstr; + assert(j == 43); + + int k = "foo\""_embedstr; + assert(k == 46); + + int l = "\"bar"_embedstr; + assert(l == 46); +} + +int +main() +{ + test(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-friend.C b/gcc/testsuite/g++.dg/cpp0x/udlit-friend.C new file mode 100644 index 00000000000..b3f3ef8a604 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-friend.C @@ -0,0 +1,28 @@ +// { dg-options -std=c++0x } + +long double +operator"" _Hertz(long double); + +class Foo +{ +public: + Foo() { } + + friend Foo operator"" _Bar(char); + + friend long double + operator"" _Hertz(long double omega) + { return omega / 6.28318530717958648; } +}; + +Foo +operator"" _Bar(char) +{ return Foo(); } + +Foo f1 = operator"" _Bar('x'); + +Foo f2 = 'x'_Bar; + +long double fm1 = operator"" _Hertz(552.92L); + +long double fm2 = 552.92_Hertz; diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-general.C b/gcc/testsuite/g++.dg/cpp0x/udlit-general.C new file mode 100644 index 00000000000..9e448ac8050 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-general.C @@ -0,0 +1,52 @@ +// { dg-do run } +// { dg-options "-std=c++0x" } + +// Test user-defined literals. +// Test simple operator declaration and definition. + +#include <cstring> +#include <string> +#include <complex> +#include <cassert> + +long double operator"" _v(long double); +std::string operator"" _w(const char16_t*, size_t); +unsigned operator"" _w(const char*); + +std::complex<double> +operator"" _i(long double y) +{ return std::complex<double>(0.0L, y); } + +void +test1() +{ + long double x = operator"" _v(1.2L); + assert(x == 2.2L); + + std::string s = operator"" _w(u"one", 3); + assert(s == "boo"); + + unsigned u = operator"" _w("Hello, World!"); + assert(u == 13U); + + std::complex<double> i = operator"" _i(2.0); + assert(i == std::complex<double>(0.0, 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* str) +{ return strlen(str); } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-inline.C b/gcc/testsuite/g++.dg/cpp0x/udlit-inline.C new file mode 100644 index 00000000000..75032c57679 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-inline.C @@ -0,0 +1,22 @@ +// { dg-options "-std=c++0x" } + +// Literal operators can be inline. + +inline int +operator"" _thing1(char cc) +{ return 42 * cc; } + +int operator"" _thing2(char cc); + +class Foo +{ + int + friend operator"" _thing2(char cc) + { return 42 * cc; } +}; + +int i = operator"" _thing1('x'); +int j = 'x'_thing1; + +int iF = operator"" _thing2('x'); +int jF = 'x'_thing2; diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-linkage-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-linkage-neg.C new file mode 100644 index 00000000000..c2ecede8d48 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-linkage-neg.C @@ -0,0 +1,7 @@ +// { dg-options -std=c++0x } + +extern "C"_badlinkage { // { dg-error "expected unqualified-id before" } + +int foo(); + +} diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C new file mode 100644 index 00000000000..809df254c0e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C @@ -0,0 +1,15 @@ +// { dg-options -std=c++0x } + +class Foo +{ +public: + Foo() { } + int operator"" _Bar(char32_t); // { dg-error "must be a non-member function" } +}; + +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 +Foo::operator"" _Bar(char32_t) // { dg-error "must be a non-member function" } +{ return 42; } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C b/gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C new file mode 100644 index 00000000000..e5d54e51900 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C @@ -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 <cmath> +#include <limits> + +namespace Long +{ + long double operator"" _LL(long double); +} + +namespace Short +{ + short + operator"" _SS(long double x) + { return std::fmod(x, static_cast<long double>(std::numeric_limits<short>::max())); } +} + +void +test1() +{ + long double x = Long::operator "" _LL(1.2L); + + using namespace Short; + short s = operator"" _SS(1.2L); + short s2 = 1.2_SS; +} + +int +main() +{ + test1(); +} + +namespace Long +{ + long double + operator"" _LL(long double x) + { return x + 2.0L; } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-nofunc-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-nofunc-neg.C new file mode 100644 index 00000000000..6ad79b85b1d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-nofunc-neg.C @@ -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<char...> + int operator"" _badtmpldecl; // { dg-error "as non-function" } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C new file mode 100644 index 00000000000..981865f1526 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C @@ -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" } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-nospace-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-nospace-neg.C new file mode 100644 index 00000000000..2b57637a916 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-nospace-neg.C @@ -0,0 +1,3 @@ +// { dg-options "-std=c++0x" } + +float operator ""_abc(const char*); // { dg-error "missing space between|and suffix identifier" } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-nosuffix-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-nosuffix-neg.C new file mode 100644 index 00000000000..b90635cd0fc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-nosuffix-neg.C @@ -0,0 +1,5 @@ +// { dg-options -std=c++0x } + +char32_t +operator"" (char32_t C) // { dg-error "expected suffix identifier" } +{ return C; } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-nounder-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-nounder-neg.C new file mode 100644 index 00000000000..2067bbe561f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-nounder-neg.C @@ -0,0 +1,9 @@ +// { dg-options "-std=c++0x" } + +// Test user-defined literals. +// Test warning on declaration without leading underscore. + +long double operator"" nounder(long double); // { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" } + +template<char...> + int operator"" nounder(); // { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C new file mode 100644 index 00000000000..27fdedec766 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C @@ -0,0 +1,42 @@ +// { dg-options "-std=c++0x" } + +// Can't have *both* literal operator template and raw literal operator. + +int +operator"" _abc(const char*) + { + return 42; + } + +template<char...> + int + operator"" _abc() // { dg-error "literal operator template|conflicts with raw literal operator" } + { + return 13; + } + +template<char...> + int + operator"" _def() + { + return 12; + } + +int +operator"" _def(const char*) // { dg-error "raw literal operator|conflicts with literal operator template" } + { + return 43; + } + +int +operator"" _ghi(long double) + { + return 42; + } + +template<char...> + int + operator"" _ghi() // OK + { + return 13; + } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-preproc-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-preproc-neg.C new file mode 100644 index 00000000000..23633390cf0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-preproc-neg.C @@ -0,0 +1,9 @@ +// { dg-options "-std=c++0x" } + +int +operator"" _badpreproc(const char *str) +{ return 0; } + +#if 123_badpreproc // { dg-error "user-defined literal in preprocessor expression" } +# error ("user-defined literal in preprocessor expression") // { dg-error "user-defined literal in preprocessor expression" } +#endif diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C new file mode 100644 index 00000000000..5c399aff599 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C @@ -0,0 +1,8 @@ +// { dg-options "-std=c++0x" } + +// Make sure handing a string to a raw literal generates a sensible error message. + +int operator"" _embedraw(const char*) +{ return 41; }; + +int k = "Boo!"_embedraw; // { dg-error "unable to find valid user-defined string literal operator" } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-raw-op.C b/gcc/testsuite/g++.dg/cpp0x/udlit-raw-op.C new file mode 100644 index 00000000000..3bbf19cb05c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-raw-op.C @@ -0,0 +1,21 @@ +// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+#include <cassert>
+#include <cstring>
+
+int
+operator"" _raw_umber(const char * str)
+{
+ return strlen(str);
+}
+
+int
+main()
+{
+ int i = 0123012301230123012301230123012301230123012301230123012301230123_raw_umber;
+ assert( i == 64 );
+
+ int j = 90123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789_raw_umber;
+ assert( j == 101 );
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-raw-str.C b/gcc/testsuite/g++.dg/cpp0x/udlit-raw-str.C new file mode 100644 index 00000000000..e94410fd061 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-raw-str.C @@ -0,0 +1,15 @@ +// { dg-options -std=c++0x } + +#include <string> + +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; diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C new file mode 100644 index 00000000000..6d38252ff2a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C @@ -0,0 +1,49 @@ +// { dg-options -std=c++0x } + +// Test that the standard suffixes shadow any user-defined suffixes of the same name. +long double +operator"" L(long double x) // { dg-warning "floating point suffix|shadowed by implementation" } +{ return x; } + +unsigned long long int +operator"" ULL(unsigned long long int k) // { dg-warning "integer suffix|shadowed by implementation" } +{ return k; } + +long double +operator"" l(long double x) // { dg-warning "floating point suffix|shadowed by implementation" } +{ return x; } + +unsigned long long int +operator"" ull(unsigned long long int k) // { dg-warning "integer suffix|shadowed by implementation" } +{ return k; } + +// Namespaces are no hiding place. +namespace Long +{ + +long double +operator"" L(long double x) // { dg-warning "integer suffix|shadowed by implementation" } +{ return x; } + +unsigned long long int +operator"" ULL(unsigned long long int k) // { dg-warning "integer suffix|shadowed by implementation" } +{ return k; } + +long double +operator"" l(long double x) // { dg-warning "integer suffix|shadowed by implementation" } +{ return x; } + +unsigned long long int +operator"" ull(unsigned long long int k) // { dg-warning "integer suffix|shadowed by implementation" } +{ return k; } + +} + +// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 5 } +// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 9 } +// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 13 } +// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 17 } +// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 25 } +// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 29 } +// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 33 } +// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 37 } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-suffix-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-suffix-neg.C new file mode 100644 index 00000000000..56eab01d736 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-suffix-neg.C @@ -0,0 +1,5 @@ +// { dg-options -std=c++0x } + +#include <string> + +std::string operator"" 5X(const char*, std::size_t); // { dg-error "expected suffix identifier" } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-systemheader.C b/gcc/testsuite/g++.dg/cpp0x/udlit-systemheader.C new file mode 100644 index 00000000000..599c8652a14 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-systemheader.C @@ -0,0 +1,3 @@ +// { dg-options -std=c++0x } + +#include "udlit_system_header" diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-template.C b/gcc/testsuite/g++.dg/cpp0x/udlit-template.C new file mode 100644 index 00000000000..6a28f74a22b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-template.C @@ -0,0 +1,51 @@ +// { dg-do run } +// { dg-options "-std=c++0x" } + +// Test user-defined literals. +// Test template operator declaration and definition. + +#include <cassert> + +template<char...> + int operator"" _abc(); + +template<> + int + operator"" _abc<>() + { return -1; } + +template<> + int + operator"" _abc<'L','U','E'>() + { return 42; } + +template<> + int + operator"" _abc<'6','6','6'>() + { return 21; } + +int +test1() +{ + int i = operator"" _abc<'1','2','3'>(); + assert(i == 45); + int universal_meaning = operator"" _abc<'L','U','E'>(); + assert(universal_meaning == 42); + int b = operator"" _abc<'6','6','6'>(); + int z = operator"" _abc<>(); + assert(z == -1); + int j = 123_abc; + assert(j == i); + int jb = 666_abc; + assert(jb == b); +} + +int +main() +{ + test1(); +} + +template<char... Chars> + int operator"" _abc() + { return 42 + sizeof...(Chars); } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg-neg.C new file mode 100644 index 00000000000..e8ccb6f545d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg-neg.C @@ -0,0 +1,4 @@ +// { dg-options -std=c++0x } + +template<char...> + int operator"" _xyz(unsigned long long); // { dg-error "has invalid argument list" } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg.C new file mode 100644 index 00000000000..6324823fabb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg.C @@ -0,0 +1,4 @@ +// { dg-options -std=c++0x } + +template<char...> + int operator"" _abc(); diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C new file mode 100644 index 00000000000..4dab4d2f6f0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C @@ -0,0 +1,12 @@ +// { dg-options -std=c++0x } + +class Foo { }; + +template<wchar_t...> + Foo operator"" _Foo(); // { dg-error "literal operator template|has invalid parameter list" } + +template<char> + Foo operator"" _Bar(); // { dg-error "literal operator template|has invalid parameter list" } + +template<typename... Type> + Foo operator"" _Bar(); // { dg-error "literal operator template|has invalid parameter list" } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms.C b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms.C new file mode 100644 index 00000000000..77456737c70 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms.C @@ -0,0 +1,6 @@ +// { dg-options -std=c++0x } + +class Foo { }; + +template<char...> + Foo operator"" _Foo(); diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit_system_header b/gcc/testsuite/g++.dg/cpp0x/udlit_system_header new file mode 100644 index 00000000000..d541f24f62a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit_system_header @@ -0,0 +1,6 @@ + +#pragma GCC system_header + +char +operator"" stdsuffix(char __c) +{ return __c/2; } diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index 918b8af1dad..5be923ea1f6 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,17 @@ +2011-10-26 Ed Smith-Rowland <3dw4rd@verizon.net> + + Implement C++11 user-defined literals. + * expr.c: (cpp_interpret_float_suffix, cpp_interpret_int_suffix, + cpp_userdef_string_remove_type, cpp_userdef_string_add_type, + cpp_userdef_char_remove_type, cpp_userdef_char_add_type, + cpp_userdef_string_p, cpp_userdef_char_p, cpp_get_userdef_suffix): New. + (cpp_classify_number): Classify unrecognized tokens as user-defined + literals. + * include/cpplib.h: Add new tokens for user-defined literals. + * init.c: Add new preprocessor flag (cxx11). + * lex.c: (lex_string, lex_raw_string): Handle user-defined literals + including concatenation and promotion with suffixes. + 2011-10-24 Dodji Seketeli <dodji@redhat.com> * line-map.c (linemap_macro_map_lookup): Fix logic. diff --git a/libcpp/expr.c b/libcpp/expr.c index 3c36127b54f..7bbc72d6f26 100644 --- a/libcpp/expr.c +++ b/libcpp/expr.c @@ -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 @@ interpret_float_suffix (const uchar *s, size_t len) 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,143 @@ interpret_int_suffix (const uchar *s, size_t len) : (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. */ +const char * +cpp_get_userdef_suffix (const cpp_token *tok) +{ + unsigned int len = tok->val.str.len; + const char *text = (const char *)tok->val.str.text; + char delim; + unsigned int i; + for (i = 0; i < len; ++i) + if (text[i] == '\'' || text[i] == '"') + break; + if (i == len) + return text + len; + delim = text[i]; + for (i = len; i > 0; --i) + if (text[i - 1] == delim) + break; + return text + i; +} + /* 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, + const char **ud_suffix) { const uchar *str = token->val.str.text; const uchar *limit; @@ -231,6 +370,9 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token) 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 +503,19 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token) 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, user_literals)) + { + if (ud_suffix) + *ud_suffix = (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 +557,19 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token) 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, user_literals)) + { + if (ud_suffix) + *ud_suffix = (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. @@ -539,7 +699,7 @@ cpp_interpret_integer (cpp_reader *pfile, const cpp_token *token, } } - if (overflow) + if (overflow && !(type & CPP_N_USERDEF)) cpp_error (pfile, CPP_DL_PEDWARN, "integer constant is too large for its type"); /* If too big to be signed, consider it unsigned. Only warn for @@ -748,7 +908,10 @@ eval_token (cpp_reader *pfile, const cpp_token *token) switch (token->type) { case CPP_NUMBER: - temp = cpp_classify_number (pfile, token); + temp = cpp_classify_number (pfile, token, NULL); + if (temp & CPP_N_USERDEF) + cpp_error (pfile, CPP_DL_ERROR, + "user-defined literal in preprocessor expression"); switch (temp & CPP_N_CATEGORY) { case CPP_N_FLOATING: diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 825bf2fc6ff..9582b621ab5 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -131,6 +131,16 @@ struct _cpp_file; TK(OBJC_STRING, LITERAL) /* @"string" - Objective-C */ \ TK(HEADER_NAME, LITERAL) /* <stdio.h> 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. */ \ @@ -414,6 +424,9 @@ struct cpp_options /* True for traditional preprocessing. */ unsigned char traditional; + /* Nonzero for C++ 2011 Standard user-defnied literals. */ + unsigned char user_literals; + /* Holds the name of the target (execution) character set. */ const char *narrow_charset; @@ -829,13 +842,22 @@ struct cpp_num #define CPP_N_FRACT 0x100000 /* Fract types. */ #define CPP_N_ACCUM 0x200000 /* Accum types. */ +#define CPP_N_USERDEF 0x1000000 /* C++0x user-defined 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 *, + const char **); + +/* Return the classification flags for a float suffix. */ +extern unsigned int cpp_interpret_float_suffix (const char *, size_t); + +/* Return the classification flags for an int suffix. */ +extern unsigned int cpp_interpret_int_suffix (const char *, size_t); /* Evaluate a token classified as category CPP_N_INTEGER. */ extern cpp_num cpp_interpret_integer (cpp_reader *, const cpp_token *, - unsigned int type); + unsigned int); /* Sign extend a number, with PRECISION significant bits and all others assumed clear, to fill out a cpp_num structure. */ @@ -1005,4 +1027,20 @@ extern int cpp_read_state (cpp_reader *, const char *, FILE *, extern void cpp_force_token_locations (cpp_reader *, source_location *); extern void cpp_stop_forcing_token_locations (cpp_reader *); +/* 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 const char * cpp_get_userdef_suffix + (const cpp_token *); + #endif /* ! LIBCPP_CPPLIB_H */ diff --git a/libcpp/init.c b/libcpp/init.c index 6771e638970..99b65ba339e 100644 --- a/libcpp/init.c +++ b/libcpp/init.c @@ -80,22 +80,23 @@ struct lang_flags char digraphs; char uliterals; char rliterals; + char user_literals; }; static const struct lang_flags lang_defaults[] = -{ /* c99 c++ xnum xid std // digr ulit rlit */ - /* GNUC89 */ { 0, 0, 1, 0, 0, 1, 1, 0, 0 }, - /* GNUC99 */ { 1, 0, 1, 0, 0, 1, 1, 1, 1 }, - /* GNUC1X */ { 1, 0, 1, 0, 0, 1, 1, 1, 1 }, - /* STDC89 */ { 0, 0, 0, 0, 1, 0, 0, 0, 0 }, - /* STDC94 */ { 0, 0, 0, 0, 1, 0, 1, 0, 0 }, - /* STDC99 */ { 1, 0, 1, 0, 1, 1, 1, 0, 0 }, - /* STDC1X */ { 1, 0, 1, 0, 1, 1, 1, 1, 0 }, - /* GNUCXX */ { 0, 1, 1, 0, 0, 1, 1, 0, 0 }, - /* CXX98 */ { 0, 1, 1, 0, 1, 1, 1, 0, 0 }, - /* GNUCXX0X */ { 1, 1, 1, 0, 0, 1, 1, 1, 1 }, - /* CXX0X */ { 1, 1, 1, 0, 1, 1, 1, 1, 1 }, - /* ASM */ { 0, 0, 1, 0, 0, 1, 0, 0, 0 } +{ /* c99 c++ xnum xid std // digr ulit rlit user_literals */ + /* GNUC89 */ { 0, 0, 1, 0, 0, 1, 1, 0, 0, 0 }, + /* GNUC99 */ { 1, 0, 1, 0, 0, 1, 1, 1, 1, 0 }, + /* GNUC1X */ { 1, 0, 1, 0, 0, 1, 1, 1, 1, 0 }, + /* STDC89 */ { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, + /* STDC94 */ { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0 }, + /* STDC99 */ { 1, 0, 1, 0, 1, 1, 1, 0, 0, 0 }, + /* STDC1X */ { 1, 0, 1, 0, 1, 1, 1, 1, 0, 0 }, + /* GNUCXX */ { 0, 1, 1, 0, 0, 1, 1, 0, 0, 0 }, + /* CXX98 */ { 0, 1, 1, 0, 1, 1, 1, 0, 0, 0 }, + /* GNUCXX0X */ { 1, 1, 1, 0, 0, 1, 1, 1, 1, 1 }, + /* CXX0X */ { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 }, + /* ASM */ { 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 } /* xid should be 1 for GNUC99, STDC99, GNUCXX, CXX98, GNUCXX0X, and CXX0X when no longer experimental (when all uses of identifiers in the compiler have been audited for correct handling of @@ -120,6 +121,7 @@ cpp_set_lang (cpp_reader *pfile, enum c_lang lang) CPP_OPTION (pfile, digraphs) = l->digraphs; CPP_OPTION (pfile, uliterals) = l->uliterals; CPP_OPTION (pfile, rliterals) = l->rliterals; + CPP_OPTION (pfile, user_literals) = l->user_literals; } /* Initialize library global state. */ diff --git a/libcpp/lex.c b/libcpp/lex.c index 896a3bef2c2..fcec329d8b4 100644 --- a/libcpp/lex.c +++ b/libcpp/lex.c @@ -1478,6 +1478,18 @@ lex_raw_string (cpp_reader *pfile, cpp_token *token, const uchar *base, } break_outer_loop: + if (CPP_OPTION (pfile, user_literals)) + { + /* Grab user defined literal suffix. */ + if (ISIDST (*cur)) + { + 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); @@ -1581,6 +1593,19 @@ lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base) cpp_error (pfile, CPP_DL_PEDWARN, "missing terminating %c character", (int) terminator); + if (CPP_OPTION (pfile, user_literals)) + { + /* 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); } |