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:
Ed Smith-Rowland 2011-10-26 19:30:59 +00:00 committed by Jason Merrill
parent 7f808cadda
commit 3ce4f9e4d2
57 changed files with 1714 additions and 51 deletions

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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 */

View file

@ -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
{

View file

@ -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.

View file

@ -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 ();
}

View file

@ -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);

View file

@ -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;

View file

@ -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 */

View file

@ -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;
}
}

View file

@ -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 ();
}
}

View file

@ -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

View file

@ -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)

View file

@ -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:

View file

@ -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;
}
}

View file

@ -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

View 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);

View 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" }

View 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);

View file

@ -0,0 +1,8 @@
// { dg-options -std=c++0x }
extern "C" {
int
operator"" _badclinkage(unsigned long long); // { dg-error "operator with C linkage" }
}

View 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" }

View 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;

View 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];

View 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 }

View 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" }

View 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();
}

View 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;

View 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); }

View 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;

View file

@ -0,0 +1,7 @@
// { dg-options -std=c++0x }
extern "C"_badlinkage { // { dg-error "expected unqualified-id before" }
int foo();
}

View 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; }

View 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; }
}

View 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" }

View 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" }

View file

@ -0,0 +1,3 @@
// { dg-options "-std=c++0x" }
float operator ""_abc(const char*); // { dg-error "missing space between|and suffix identifier" }

View file

@ -0,0 +1,5 @@
// { dg-options -std=c++0x }
char32_t
operator"" (char32_t C) // { dg-error "expected suffix identifier" }
{ return C; }

View 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" }

View 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;
}

View 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

View 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" }

View 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 );
}

View 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;

View 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 }

View 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" }

View file

@ -0,0 +1,3 @@
// { dg-options -std=c++0x }
#include "udlit_system_header"

View 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); }

View file

@ -0,0 +1,4 @@
// { dg-options -std=c++0x }
template<char...>
int operator"" _xyz(unsigned long long); // { dg-error "has invalid argument list" }

View file

@ -0,0 +1,4 @@
// { dg-options -std=c++0x }
template<char...>
int operator"" _abc();

View 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" }

View file

@ -0,0 +1,6 @@
// { dg-options -std=c++0x }
class Foo { };
template<char...>
Foo operator"" _Foo();

View file

@ -0,0 +1,6 @@
#pragma GCC system_header
char
operator"" stdsuffix(char __c)
{ return __c/2; }

View file

@ -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.

View file

@ -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:

View file

@ -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 */

View file

@ -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. */

View file

@ -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);
}