diff options
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r-- | gcc/cp/parser.c | 395 |
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) |