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. From-SVN: r180536
This commit is contained in:
parent
7f808cadda
commit
3ce4f9e4d2
57 changed files with 1714 additions and 51 deletions
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
395
gcc/cp/parser.c
395
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 (type != tok->type)
|
||||
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 != 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)
|
||||
|
|
|
@ -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:
|
||||
|
|
118
gcc/cp/typeck.c
118
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
10
gcc/testsuite/g++.dg/cpp0x/udlit-addr.C
Normal file
10
gcc/testsuite/g++.dg/cpp0x/udlit-addr.C
Normal file
|
@ -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);
|
38
gcc/testsuite/g++.dg/cpp0x/udlit-args-neg.C
Normal file
38
gcc/testsuite/g++.dg/cpp0x/udlit-args-neg.C
Normal file
|
@ -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" }
|
38
gcc/testsuite/g++.dg/cpp0x/udlit-args.C
Normal file
38
gcc/testsuite/g++.dg/cpp0x/udlit-args.C
Normal file
|
@ -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);
|
8
gcc/testsuite/g++.dg/cpp0x/udlit-clink-neg.C
Normal file
8
gcc/testsuite/g++.dg/cpp0x/udlit-clink-neg.C
Normal file
|
@ -0,0 +1,8 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
extern "C" {
|
||||
|
||||
int
|
||||
operator"" _badclinkage(unsigned long long); // { dg-error "operator with C linkage" }
|
||||
|
||||
}
|
9
gcc/testsuite/g++.dg/cpp0x/udlit-concat-neg.C
Normal file
9
gcc/testsuite/g++.dg/cpp0x/udlit-concat-neg.C
Normal file
|
@ -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" }
|
24
gcc/testsuite/g++.dg/cpp0x/udlit-concat.C
Normal file
24
gcc/testsuite/g++.dg/cpp0x/udlit-concat.C
Normal file
|
@ -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;
|
7
gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C
Normal file
7
gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C
Normal file
|
@ -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];
|
17
gcc/testsuite/g++.dg/cpp0x/udlit-cpp98-neg.C
Normal file
17
gcc/testsuite/g++.dg/cpp0x/udlit-cpp98-neg.C
Normal file
|
@ -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 }
|
15
gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C
Normal file
15
gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C
Normal file
|
@ -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" }
|
34
gcc/testsuite/g++.dg/cpp0x/udlit-embed-quote.C
Normal file
34
gcc/testsuite/g++.dg/cpp0x/udlit-embed-quote.C
Normal file
|
@ -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();
|
||||
}
|
28
gcc/testsuite/g++.dg/cpp0x/udlit-friend.C
Normal file
28
gcc/testsuite/g++.dg/cpp0x/udlit-friend.C
Normal file
|
@ -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;
|
52
gcc/testsuite/g++.dg/cpp0x/udlit-general.C
Normal file
52
gcc/testsuite/g++.dg/cpp0x/udlit-general.C
Normal file
|
@ -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); }
|
22
gcc/testsuite/g++.dg/cpp0x/udlit-inline.C
Normal file
22
gcc/testsuite/g++.dg/cpp0x/udlit-inline.C
Normal file
|
@ -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;
|
7
gcc/testsuite/g++.dg/cpp0x/udlit-linkage-neg.C
Normal file
7
gcc/testsuite/g++.dg/cpp0x/udlit-linkage-neg.C
Normal file
|
@ -0,0 +1,7 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
extern "C"_badlinkage { // { dg-error "expected unqualified-id before" }
|
||||
|
||||
int foo();
|
||||
|
||||
}
|
15
gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C
Normal file
15
gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C
Normal file
|
@ -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; }
|
43
gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C
Normal file
43
gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C
Normal file
|
@ -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; }
|
||||
}
|
9
gcc/testsuite/g++.dg/cpp0x/udlit-nofunc-neg.C
Normal file
9
gcc/testsuite/g++.dg/cpp0x/udlit-nofunc-neg.C
Normal file
|
@ -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" }
|
6
gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C
Normal file
6
gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C
Normal file
|
@ -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" }
|
3
gcc/testsuite/g++.dg/cpp0x/udlit-nospace-neg.C
Normal file
3
gcc/testsuite/g++.dg/cpp0x/udlit-nospace-neg.C
Normal file
|
@ -0,0 +1,3 @@
|
|||
// { dg-options "-std=c++0x" }
|
||||
|
||||
float operator ""_abc(const char*); // { dg-error "missing space between|and suffix identifier" }
|
5
gcc/testsuite/g++.dg/cpp0x/udlit-nosuffix-neg.C
Normal file
5
gcc/testsuite/g++.dg/cpp0x/udlit-nosuffix-neg.C
Normal file
|
@ -0,0 +1,5 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
char32_t
|
||||
operator"" (char32_t C) // { dg-error "expected suffix identifier" }
|
||||
{ return C; }
|
9
gcc/testsuite/g++.dg/cpp0x/udlit-nounder-neg.C
Normal file
9
gcc/testsuite/g++.dg/cpp0x/udlit-nounder-neg.C
Normal file
|
@ -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" }
|
42
gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C
Normal file
42
gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C
Normal file
|
@ -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;
|
||||
}
|
9
gcc/testsuite/g++.dg/cpp0x/udlit-preproc-neg.C
Normal file
9
gcc/testsuite/g++.dg/cpp0x/udlit-preproc-neg.C
Normal file
|
@ -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
|
8
gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C
Normal file
8
gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C
Normal file
|
@ -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" }
|
21
gcc/testsuite/g++.dg/cpp0x/udlit-raw-op.C
Normal file
21
gcc/testsuite/g++.dg/cpp0x/udlit-raw-op.C
Normal file
|
@ -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 );
|
||||
}
|
15
gcc/testsuite/g++.dg/cpp0x/udlit-raw-str.C
Normal file
15
gcc/testsuite/g++.dg/cpp0x/udlit-raw-str.C
Normal file
|
@ -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;
|
49
gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C
Normal file
49
gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C
Normal file
|
@ -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 }
|
5
gcc/testsuite/g++.dg/cpp0x/udlit-suffix-neg.C
Normal file
5
gcc/testsuite/g++.dg/cpp0x/udlit-suffix-neg.C
Normal file
|
@ -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" }
|
3
gcc/testsuite/g++.dg/cpp0x/udlit-systemheader.C
Normal file
3
gcc/testsuite/g++.dg/cpp0x/udlit-systemheader.C
Normal file
|
@ -0,0 +1,3 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
#include "udlit_system_header"
|
51
gcc/testsuite/g++.dg/cpp0x/udlit-template.C
Normal file
51
gcc/testsuite/g++.dg/cpp0x/udlit-template.C
Normal file
|
@ -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); }
|
4
gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg-neg.C
Normal file
4
gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg-neg.C
Normal file
|
@ -0,0 +1,4 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
template<char...>
|
||||
int operator"" _xyz(unsigned long long); // { dg-error "has invalid argument list" }
|
4
gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg.C
Normal file
4
gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg.C
Normal file
|
@ -0,0 +1,4 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
template<char...>
|
||||
int operator"" _abc();
|
12
gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C
Normal file
12
gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C
Normal file
|
@ -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" }
|
6
gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms.C
Normal file
6
gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms.C
Normal file
|
@ -0,0 +1,6 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
class Foo { };
|
||||
|
||||
template<char...>
|
||||
Foo operator"" _Foo();
|
6
gcc/testsuite/g++.dg/cpp0x/udlit_system_header
Normal file
6
gcc/testsuite/g++.dg/cpp0x/udlit_system_header
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
#pragma GCC system_header
|
||||
|
||||
char
|
||||
operator"" stdsuffix(char __c)
|
||||
{ return __c/2; }
|
|
@ -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.
|
||||
|
|
189
libcpp/expr.c
189
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:
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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. */
|
||||
|
|
25
libcpp/lex.c
25
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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue