aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r--gcc/cp/parser.c395
1 files changed, 381 insertions, 14 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index a762d9d..840a30d 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -225,6 +225,9 @@ static cp_token_cache *cp_token_cache_new
static void cp_parser_initial_pragma
(cp_token *);
+static tree cp_literal_operator_id
+ (const char *);
+
/* Manifest constants. */
#define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token))
#define CP_SAVED_TOKEN_STACK 5
@@ -1762,6 +1765,12 @@ static tree cp_parser_identifier
(cp_parser *);
static tree cp_parser_string_literal
(cp_parser *, bool, bool);
+static tree cp_parser_userdef_char_literal
+ (cp_parser *);
+static tree cp_parser_userdef_string_literal
+ (cp_token *);
+static tree cp_parser_userdef_numeric_literal
+ (cp_parser *);
/* Basic concepts [gram.basic] */
@@ -2270,6 +2279,8 @@ static bool cp_parser_error_occurred
(cp_parser *);
static bool cp_parser_allow_gnu_extensions_p
(cp_parser *);
+static bool cp_parser_is_pure_string_literal
+ (cp_token *);
static bool cp_parser_is_string_literal
(cp_token *);
static bool cp_parser_is_keyword
@@ -2290,7 +2301,7 @@ cp_parser_parsing_tentatively (cp_parser* parser)
/* Returns nonzero if TOKEN is a string literal. */
static bool
-cp_parser_is_string_literal (cp_token* token)
+cp_parser_is_pure_string_literal (cp_token* token)
{
return (token->type == CPP_STRING ||
token->type == CPP_STRING16 ||
@@ -2299,6 +2310,20 @@ cp_parser_is_string_literal (cp_token* token)
token->type == CPP_UTF8STRING);
}
+/* Returns nonzero if TOKEN is a string literal
+ of a user-defined string literal. */
+
+static bool
+cp_parser_is_string_literal (cp_token* token)
+{
+ return (cp_parser_is_pure_string_literal (token) ||
+ token->type == CPP_STRING_USERDEF ||
+ token->type == CPP_STRING16_USERDEF ||
+ token->type == CPP_STRING32_USERDEF ||
+ token->type == CPP_WSTRING_USERDEF ||
+ token->type == CPP_UTF8STRING_USERDEF);
+}
+
/* Returns nonzero if TOKEN is the indicated KEYWORD. */
static bool
@@ -3338,7 +3363,11 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
struct obstack str_ob;
cpp_string str, istr, *strs;
cp_token *tok;
- enum cpp_ttype type;
+ enum cpp_ttype type, curr_type;
+ int have_suffix_p = 0;
+ tree string_tree;
+ tree suffix_id = NULL_TREE;
+ bool curr_tok_is_userdef_p = false;
tok = cp_lexer_peek_token (parser->lexer);
if (!cp_parser_is_string_literal (tok))
@@ -3347,7 +3376,18 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
return error_mark_node;
}
- type = tok->type;
+ if (cpp_userdef_string_p (tok->type))
+ {
+ string_tree = USERDEF_LITERAL_VALUE (tok->u.value);
+ curr_type = cpp_userdef_string_remove_type (tok->type);
+ curr_tok_is_userdef_p = true;
+ }
+ else
+ {
+ string_tree = tok->u.value;
+ curr_type = tok->type;
+ }
+ type = curr_type;
/* Try to avoid the overhead of creating and destroying an obstack
for the common case of just one string. */
@@ -3356,10 +3396,19 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
{
cp_lexer_consume_token (parser->lexer);
- str.text = (const unsigned char *)TREE_STRING_POINTER (tok->u.value);
- str.len = TREE_STRING_LENGTH (tok->u.value);
+ str.text = (const unsigned char *)TREE_STRING_POINTER (string_tree);
+ str.len = TREE_STRING_LENGTH (string_tree);
count = 1;
+ if (curr_tok_is_userdef_p)
+ {
+ suffix_id = USERDEF_LITERAL_SUFFIX_ID (tok->u.value);
+ have_suffix_p = 1;
+ curr_type = cpp_userdef_string_remove_type (tok->type);
+ }
+ else
+ curr_type = tok->type;
+
strs = &str;
}
else
@@ -3371,14 +3420,35 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
{
cp_lexer_consume_token (parser->lexer);
count++;
- str.text = (const unsigned char *)TREE_STRING_POINTER (tok->u.value);
- str.len = TREE_STRING_LENGTH (tok->u.value);
+ str.text = (const unsigned char *)TREE_STRING_POINTER (string_tree);
+ str.len = TREE_STRING_LENGTH (string_tree);
+
+ if (curr_tok_is_userdef_p)
+ {
+ tree curr_suffix_id = USERDEF_LITERAL_SUFFIX_ID (tok->u.value);
+ if (have_suffix_p == 0)
+ {
+ suffix_id = curr_suffix_id;
+ have_suffix_p = 1;
+ }
+ else if (have_suffix_p == 1
+ && curr_suffix_id != suffix_id)
+ {
+ error ("inconsistent user-defined literal suffixes"
+ " %qD and %qD in string literal",
+ suffix_id, curr_suffix_id);
+ have_suffix_p = -1;
+ }
+ curr_type = cpp_userdef_string_remove_type (tok->type);
+ }
+ else
+ curr_type = tok->type;
- if (type != tok->type)
+ if (type != curr_type)
{
if (type == CPP_STRING)
- type = tok->type;
- else if (tok->type != CPP_STRING)
+ type = curr_type;
+ else if (curr_type != CPP_STRING)
error_at (tok->location,
"unsupported non-standard concatenation "
"of string literals");
@@ -3387,6 +3457,18 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
obstack_grow (&str_ob, &str, sizeof (cpp_string));
tok = cp_lexer_peek_token (parser->lexer);
+ if (cpp_userdef_string_p (tok->type))
+ {
+ string_tree = USERDEF_LITERAL_VALUE (tok->u.value);
+ curr_type = cpp_userdef_string_remove_type (tok->type);
+ curr_tok_is_userdef_p = true;
+ }
+ else
+ {
+ string_tree = tok->u.value;
+ curr_type = tok->type;
+ curr_tok_is_userdef_p = false;
+ }
}
while (cp_parser_is_string_literal (tok));
@@ -3424,6 +3506,13 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
}
value = fix_string_type (value);
+
+ if (have_suffix_p)
+ {
+ tree literal = build_userdef_literal (suffix_id, value, NULL_TREE);
+ tok->u.value = literal;
+ return cp_parser_userdef_string_literal (tok);
+ }
}
else
/* cpp_interpret_string has issued an error. */
@@ -3435,6 +3524,186 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
return value;
}
+/* Parse a user-defined char constant. Returns a call to a user-defined
+ literal operator taking the character as an argument. */
+
+static tree
+cp_parser_userdef_char_literal (cp_parser *parser)
+{
+ cp_token *token = NULL;
+ tree literal, suffix_id, value;
+ tree name, decl;
+ tree result;
+ VEC(tree,gc) *vec;
+
+ token = cp_lexer_consume_token (parser->lexer);
+ literal = token->u.value;
+ suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+ value = USERDEF_LITERAL_VALUE (literal);
+ name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+
+ /* Build up a call to the user-defined operator */
+ /* Lookup the name we got back from the id-expression. */
+ vec = make_tree_vector ();
+ VEC_safe_push (tree, gc, vec, value);
+ decl = lookup_function_nonclass (name, vec, /*block_p=*/false);
+ if (!decl || decl == error_mark_node)
+ {
+ error ("unable to find user-defined character literal operator %qD",
+ name);
+ release_tree_vector (vec);
+ return error_mark_node;
+ }
+ result = finish_call_expr (decl, &vec, false, true, tf_warning_or_error);
+ release_tree_vector (vec);
+
+ return result;
+}
+
+/* A subroutine of cp_parser_userdef_numeric_literal to
+ create a char... template parameter pack from a string node. */
+
+static tree
+make_char_string_pack (tree value)
+{
+ tree charvec;
+ tree argpack = make_node (NONTYPE_ARGUMENT_PACK);
+ const char *str = TREE_STRING_POINTER (value);
+ int i, len = TREE_STRING_LENGTH (value) - 1;
+ tree argvec = make_tree_vec (1);
+
+ /* Fill in CHARVEC with all of the parameters. */
+ charvec = make_tree_vec (len);
+ for (i = 0; i < len; ++i)
+ TREE_VEC_ELT (charvec, i) = build_int_cst (char_type_node, str[i]);
+
+ /* Build the argument packs. */
+ SET_ARGUMENT_PACK_ARGS (argpack, charvec);
+ TREE_TYPE (argpack) = char_type_node;
+
+ TREE_VEC_ELT (argvec, 0) = argpack;
+
+ return argvec;
+}
+
+/* Parse a user-defined numeric constant. returns a call to a user-defined
+ literal operator. */
+
+static tree
+cp_parser_userdef_numeric_literal (cp_parser *parser)
+{
+ cp_token *token = NULL;
+ tree literal, suffix_id, value, num_string;
+ tree name, decl;
+ tree result = error_mark_node;
+ VEC(tree,gc) *args;
+
+ token = cp_lexer_consume_token (parser->lexer);
+ literal = token->u.value;
+ suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+ value = USERDEF_LITERAL_VALUE (literal);
+ num_string = USERDEF_LITERAL_NUM_STRING (literal);
+ name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+
+ /* Build up a call to the user-defined operator */
+ /* Lookup the name we got back from the id-expression. */
+ /* Try to find the literal operator by finishing the call expression
+ with the numeric argument. */
+ args = make_tree_vector ();
+ VEC_safe_push (tree, gc, args, value);
+ decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+ if (decl && decl != error_mark_node)
+ {
+ result = finish_call_expr (decl, &args, false, true, tf_none);
+ if (result != error_mark_node)
+ {
+ release_tree_vector (args);
+ return result;
+ }
+ }
+ release_tree_vector (args);
+
+ /* If the numeric argument didn't work, look for a raw literal
+ operator taking a const char* argument consisting of the number
+ in string format. */
+ args = make_tree_vector ();
+ VEC_safe_push (tree, gc, args, num_string);
+ decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+ if (decl && decl != error_mark_node)
+ {
+ result = finish_call_expr (decl, &args, false, true, tf_none);
+ if (result != error_mark_node)
+ {
+ release_tree_vector (args);
+ return result;
+ }
+ }
+ release_tree_vector (args);
+
+ /* If the raw literal didn't work, look for a non-type template
+ function with parameter pack char.... Call the function with
+ template parameter characters representing the number. */
+ args = make_tree_vector ();
+ decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+ if (decl && decl != error_mark_node)
+ {
+ tree tmpl_args = make_char_string_pack (num_string);
+ decl = lookup_template_function (decl, tmpl_args);
+ result = finish_call_expr (decl, &args, false, true, tf_none);
+ if (result != error_mark_node)
+ {
+ release_tree_vector (args);
+ return result;
+ }
+ }
+ release_tree_vector (args);
+
+ if (result == error_mark_node)
+ error ("unable to find user-defined numeric literal operator %qD", name);
+
+ return result;
+}
+
+/* Parse a user-defined string constant. Returns a call to a user-defined
+ literal operator taking a character pointer and the length of the string
+ as arguments. */
+static tree
+cp_parser_userdef_string_literal (cp_token *token)
+{
+ tree literal, suffix_id, value;
+ tree name, decl;
+ tree result;
+ VEC(tree,gc) *vec;
+ int len;
+
+ literal = token->u.value;
+ suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+ name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+ value = USERDEF_LITERAL_VALUE (literal);
+ len = TREE_STRING_LENGTH (value) - 1;
+
+ /* Build up a call to the user-defined operator */
+ /* Lookup the name we got back from the id-expression. */
+ vec = make_tree_vector ();
+ VEC_safe_push (tree, gc, vec, value);
+ VEC_safe_push (tree, gc, vec, build_int_cst (size_type_node, len));
+ decl = lookup_function_nonclass (name, vec, /*block_p=*/false);
+ if (!decl || decl == error_mark_node)
+ {
+ error ("unable to find user-defined string literal operator %qD", name);
+ release_tree_vector (vec);
+ return error_mark_node;
+ }
+ result = finish_call_expr (decl, &vec, false, true, tf_none);
+ if (result == error_mark_node)
+ error ("unable to find valid user-defined string literal operator %qD."
+ " Possible missing length argument in string literal operator.",
+ name);
+ release_tree_vector (vec);
+
+ return result;
+}
+
/* Basic concepts [gram.basic] */
@@ -3578,12 +3847,16 @@ cp_parser_primary_expression (cp_parser *parser,
character-literal
floating-literal
string-literal
- boolean-literal */
+ boolean-literal
+ pointer-literal
+ user-defined-literal */
case CPP_CHAR:
case CPP_CHAR16:
case CPP_CHAR32:
case CPP_WCHAR:
case CPP_NUMBER:
+ if (TREE_CODE (token->u.value) == USERDEF_LITERAL)
+ return cp_parser_userdef_numeric_literal (parser);
token = cp_lexer_consume_token (parser->lexer);
if (TREE_CODE (token->u.value) == FIXED_CST)
{
@@ -3637,11 +3910,22 @@ cp_parser_primary_expression (cp_parser *parser,
}
return token->u.value;
+ case CPP_CHAR_USERDEF:
+ case CPP_CHAR16_USERDEF:
+ case CPP_CHAR32_USERDEF:
+ case CPP_WCHAR_USERDEF:
+ return cp_parser_userdef_char_literal (parser);
+
case CPP_STRING:
case CPP_STRING16:
case CPP_STRING32:
case CPP_WSTRING:
case CPP_UTF8STRING:
+ case CPP_STRING_USERDEF:
+ case CPP_STRING16_USERDEF:
+ case CPP_STRING32_USERDEF:
+ case CPP_WSTRING_USERDEF:
+ case CPP_UTF8STRING_USERDEF:
/* ??? Should wide strings be allowed when parser->translate_strings_p
is false (i.e. in attributes)? If not, we can kill the third
argument to cp_parser_string_literal. */
@@ -4477,6 +4761,14 @@ cp_parser_unqualified_id (cp_parser* parser,
/* If that didn't work, try a conversion-function-id. */
if (!cp_parser_parse_definitely (parser))
id = cp_parser_conversion_function_id (parser);
+ else if (UDLIT_OPER_P (id))
+ {
+ /* 17.6.3.3.5 */
+ const char *name = UDLIT_OP_SUFFIX (id);
+ if (name[0] != '_' && !in_system_header)
+ warning (0, "literal operator suffixes not preceded by %<_%>"
+ " are reserved for future standardization");
+ }
return id;
}
@@ -5119,7 +5411,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
/* `typeid' may not appear in an integral constant expression. */
- if (cp_parser_non_integral_constant_expression(parser, NIC_TYPEID))
+ if (cp_parser_non_integral_constant_expression (parser, NIC_TYPEID))
return error_mark_node;
}
break;
@@ -9739,7 +10031,7 @@ cp_parser_declaration (cp_parser* parser)
/* If the next token is `extern' and the following token is a string
literal, then we have a linkage specification. */
if (token1.keyword == RID_EXTERN
- && cp_parser_is_string_literal (&token2))
+ && cp_parser_is_pure_string_literal (&token2))
cp_parser_linkage_specification (parser);
/* If the next token is `template', then we have either a template
declaration, an explicit instantiation, or an explicit
@@ -11170,6 +11462,22 @@ cp_parser_operator_function_id (cp_parser* parser)
return cp_parser_operator (parser);
}
+/* Return an identifier node for a user-defined literal operator.
+ The suffix identifier is chained to the operator name identifier. */
+
+static tree
+cp_literal_operator_id (const char* name)
+{
+ tree identifier;
+ char *buffer = XNEWVEC (char, strlen (UDLIT_OP_ANSI_PREFIX)
+ + strlen (name) + 10);
+ sprintf (buffer, UDLIT_OP_ANSI_FORMAT, name);
+ identifier = get_identifier (buffer);
+ /*IDENTIFIER_UDLIT_OPNAME_P (identifier) = 1; If we get a flag someday. */
+
+ return identifier;
+}
+
/* Parse an operator.
operator:
@@ -11389,6 +11697,37 @@ cp_parser_operator (cp_parser* parser)
cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
return ansi_opname (ARRAY_REF);
+ case CPP_STRING:
+ if (cxx_dialect == cxx98)
+ maybe_warn_cpp0x (CPP0X_USER_DEFINED_LITERALS);
+ if (TREE_STRING_LENGTH (token->u.value) > 2)
+ {
+ error ("expected empty string after %<operator%> keyword");
+ return error_mark_node;
+ }
+ /* Consume the string. */
+ cp_lexer_consume_token (parser->lexer);
+ /* Look for the suffix identifier. */
+ token = cp_lexer_peek_token (parser->lexer);
+ if (token->type == CPP_NAME)
+ {
+ id = cp_parser_identifier (parser);
+ if (id != error_mark_node)
+ {
+ const char *name = IDENTIFIER_POINTER (id);
+ return cp_literal_operator_id (name);
+ }
+ }
+ else
+ {
+ error ("expected suffix identifier");
+ return error_mark_node;
+ }
+
+ case CPP_STRING_USERDEF:
+ error ("missing space between %<\"\"%> and suffix identifier");
+ return error_mark_node;
+
default:
/* Anything else is an error. */
break;
@@ -20583,6 +20922,33 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
/* Finish up. */
finish_template_decl (parameter_list);
+ /* Check the template arguments for a literal operator template. */
+ if (decl
+ && (TREE_CODE (decl) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (decl))
+ && UDLIT_OPER_P (DECL_NAME (decl)))
+ {
+ bool ok = true;
+ if (parameter_list == NULL_TREE)
+ ok = false;
+ else
+ {
+ int num_parms = TREE_VEC_LENGTH (parameter_list);
+ if (num_parms != 1)
+ ok = false;
+ else
+ {
+ tree parm_list = TREE_VEC_ELT (parameter_list, 0);
+ tree parm = INNERMOST_TEMPLATE_PARMS (parm_list);
+ if (TREE_TYPE (parm) != char_type_node
+ || !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)))
+ ok = false;
+ }
+ }
+ if (!ok)
+ error ("literal operator template %qD has invalid parameter list."
+ " Expected non-type template argument pack <char...>",
+ decl);
+ }
/* Register member declarations. */
if (member_p && !friend_p && decl && !DECL_CLASS_TEMPLATE_P (decl))
finish_member_declaration (decl);
@@ -22891,7 +23257,8 @@ cp_parser_objc_interstitial_code (cp_parser* parser)
/* If the next token is `extern' and the following token is a string
literal, then we have a linkage specification. */
if (token->keyword == RID_EXTERN
- && cp_parser_is_string_literal (cp_lexer_peek_nth_token (parser->lexer, 2)))
+ && cp_parser_is_pure_string_literal
+ (cp_lexer_peek_nth_token (parser->lexer, 2)))
cp_parser_linkage_specification (parser);
/* Handle #pragma, if any. */
else if (token->type == CPP_PRAGMA)