summaryrefslogtreecommitdiff
path: root/libcpp
diff options
context:
space:
mode:
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2011-10-26 19:30:59 +0000
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2011-10-26 19:30:59 +0000
commit244db24d8ddff5d5788dc1f10c971d815c9b4388 (patch)
tree1d0c22775480b21a84a6024b85f12710e67dd587 /libcpp
parenta60a96f62b663b8dc609fa90feb808ca74956a03 (diff)
downloadgcc-244db24d8ddff5d5788dc1f10c971d815c9b4388.tar.gz
Implement C++11 user-defined literals.
libcpp/ * expr.c: (cpp_interpret_float_suffix, cpp_interpret_int_suffix, cpp_userdef_string_remove_type, cpp_userdef_string_add_type, cpp_userdef_char_remove_type, cpp_userdef_char_add_type, cpp_userdef_string_p, cpp_userdef_char_p, cpp_get_userdef_suffix): New. (cpp_classify_number): Classify unrecognized tokens as user-defined literals. * include/cpplib.h: Add new tokens for user-defined literals. * init.c: Add new preprocessor flag (cxx11). * lex.c: (lex_string, lex_raw_string): Handle user-defined literals including concatenation and promotion with suffixes. c-family/ * c-common.c (build_userdef_literal): New. * c-common.def: New tree code. * c-common.h (tree_userdef_literal): New tree struct and accessors. * c-lex.c (interpret_float): Add suffix parm. (c_lex_with_flags): Build literal tokens. cp/ * cp-objcp-common.c: (cp_tree_size) Return size of USERDEF_LITERAL tree. * cp-tree.h: (UDLIT_OP_*, UDLIT_OPER_P): Literal operator name tools. New tree code for user-defined literals. * cxx-pretty-print.h: (pp_cxx_userdef_literal) New. * cxx-pretty-print.c: (pp_cxx_userdef_literal) New. (pp_cxx_primary_expression, pp_cxx_expression): Use it. * decl.c: (cp_tree_node_structure): Return new tree code. (duplicate_decls): Check for raw vs. template operator conflicts. (grokfndecl, grokdeclarator): New checks for literal operators. * error.c: (dump_expr): Warn about user-defined literals in C++98 mode. (dump_function_name): Pretty printing. * mangle.c: (write_literal_operator_name): New. (write_unqualified_id, write_unqualified_name): Use it. * parser.c: (cp_parser_operator): Handle operator"". (cp_parser_userdef_char_literal, cp_parser_userdef_numeric_literal, cp_parser_userdef_string_literal): New. (cp_parser_primary_expression): Handle new user-defined literal tokens with new functions. * semantics.c: (potential_constant_expression_1): Add user-defined literals. * typeck.c (check_raw_literal_operator, check_literal_operator_args): New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@180536 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libcpp')
-rw-r--r--libcpp/ChangeLog14
-rw-r--r--libcpp/expr.c189
-rw-r--r--libcpp/include/cpplib.h42
-rw-r--r--libcpp/init.c28
-rw-r--r--libcpp/lex.c25
5 files changed, 270 insertions, 28 deletions
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index 918b8af1dad..5be923ea1f6 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,17 @@
+2011-10-26 Ed Smith-Rowland <3dw4rd@verizon.net>
+
+ Implement C++11 user-defined literals.
+ * expr.c: (cpp_interpret_float_suffix, cpp_interpret_int_suffix,
+ cpp_userdef_string_remove_type, cpp_userdef_string_add_type,
+ cpp_userdef_char_remove_type, cpp_userdef_char_add_type,
+ cpp_userdef_string_p, cpp_userdef_char_p, cpp_get_userdef_suffix): New.
+ (cpp_classify_number): Classify unrecognized tokens as user-defined
+ literals.
+ * include/cpplib.h: Add new tokens for user-defined literals.
+ * init.c: Add new preprocessor flag (cxx11).
+ * lex.c: (lex_string, lex_raw_string): Handle user-defined literals
+ including concatenation and promotion with suffixes.
+
2011-10-24 Dodji Seketeli <dodji@redhat.com>
* line-map.c (linemap_macro_map_lookup): Fix logic.
diff --git a/libcpp/expr.c b/libcpp/expr.c
index 3c36127b54f..7bbc72d6f26 100644
--- a/libcpp/expr.c
+++ b/libcpp/expr.c
@@ -1,6 +1,6 @@
/* Parse C expressions for cpplib.
Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
- 2002, 2004, 2008, 2009, 2010 Free Software Foundation.
+ 2002, 2004, 2008, 2009, 2010, 2011 Free Software Foundation.
Contributed by Per Bothner, 1994.
This program is free software; you can redistribute it and/or modify it
@@ -185,6 +185,13 @@ interpret_float_suffix (const uchar *s, size_t len)
q ? CPP_N_MD_Q : CPP_N_DEFAULT));
}
+/* Return the classification flags for a float suffix. */
+unsigned int
+cpp_interpret_float_suffix (const char *s, size_t len)
+{
+ return interpret_float_suffix ((const unsigned char *)s, len);
+}
+
/* Subroutine of cpp_classify_number. S points to an integer suffix
of length LEN, possibly zero. Returns 0 for an invalid suffix, or a
flag vector describing the suffix. */
@@ -219,11 +226,143 @@ interpret_int_suffix (const uchar *s, size_t len)
: (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE));
}
+/* Return the classification flags for an int suffix. */
+unsigned int
+cpp_interpret_int_suffix (const char *s, size_t len)
+{
+ return interpret_int_suffix ((const unsigned char *)s, len);
+}
+
+/* Return the string type corresponding to the the input user-defined string
+ literal type. If the input type is not a user-defined string literal
+ type return the input type. */
+enum cpp_ttype
+cpp_userdef_string_remove_type (enum cpp_ttype type)
+{
+ if (type == CPP_STRING_USERDEF)
+ return CPP_STRING;
+ else if (type == CPP_WSTRING_USERDEF)
+ return CPP_WSTRING;
+ else if (type == CPP_STRING16_USERDEF)
+ return CPP_STRING16;
+ else if (type == CPP_STRING32_USERDEF)
+ return CPP_STRING32;
+ else if (type == CPP_UTF8STRING_USERDEF)
+ return CPP_UTF8STRING;
+ else
+ return type;
+}
+
+/* Return the user-defined string literal type corresponding to the input
+ string type. If the input type is not a string type return the input
+ type. */
+enum cpp_ttype
+cpp_userdef_string_add_type (enum cpp_ttype type)
+{
+ if (type == CPP_STRING)
+ return CPP_STRING_USERDEF;
+ else if (type == CPP_WSTRING)
+ return CPP_WSTRING_USERDEF;
+ else if (type == CPP_STRING16)
+ return CPP_STRING16_USERDEF;
+ else if (type == CPP_STRING32)
+ return CPP_STRING32_USERDEF;
+ else if (type == CPP_UTF8STRING)
+ return CPP_UTF8STRING_USERDEF;
+ else
+ return type;
+}
+
+/* Return the char type corresponding to the the input user-defined char
+ literal type. If the input type is not a user-defined char literal
+ type return the input type. */
+enum cpp_ttype
+cpp_userdef_char_remove_type (enum cpp_ttype type)
+{
+ if (type == CPP_CHAR_USERDEF)
+ return CPP_CHAR;
+ else if (type == CPP_WCHAR_USERDEF)
+ return CPP_WCHAR;
+ else if (type == CPP_CHAR16_USERDEF)
+ return CPP_STRING16;
+ else if (type == CPP_CHAR32_USERDEF)
+ return CPP_STRING32;
+ else
+ return type;
+}
+
+/* Return the user-defined char literal type corresponding to the input
+ char type. If the input type is not a char type return the input
+ type. */
+enum cpp_ttype
+cpp_userdef_char_add_type (enum cpp_ttype type)
+{
+ if (type == CPP_CHAR)
+ return CPP_CHAR_USERDEF;
+ else if (type == CPP_WCHAR)
+ return CPP_WCHAR_USERDEF;
+ else if (type == CPP_CHAR16)
+ return CPP_CHAR16_USERDEF;
+ else if (type == CPP_CHAR32)
+ return CPP_CHAR32_USERDEF;
+ else
+ return type;
+}
+
+/* Return true if the token type is a user-defined string literal. */
+bool
+cpp_userdef_string_p (enum cpp_ttype type)
+{
+ if (type == CPP_STRING_USERDEF
+ || type == CPP_WSTRING_USERDEF
+ || type == CPP_STRING16_USERDEF
+ || type == CPP_STRING32_USERDEF
+ || type == CPP_UTF8STRING_USERDEF)
+ return true;
+ else
+ return false;
+}
+
+/* Return true if the token type is a user-defined char literal. */
+bool
+cpp_userdef_char_p (enum cpp_ttype type)
+{
+ if (type == CPP_CHAR_USERDEF
+ || type == CPP_WCHAR_USERDEF
+ || type == CPP_CHAR16_USERDEF
+ || type == CPP_CHAR32_USERDEF)
+ return true;
+ else
+ return false;
+}
+
+/* Extract the suffix from a user-defined literal string or char. */
+const char *
+cpp_get_userdef_suffix (const cpp_token *tok)
+{
+ unsigned int len = tok->val.str.len;
+ const char *text = (const char *)tok->val.str.text;
+ char delim;
+ unsigned int i;
+ for (i = 0; i < len; ++i)
+ if (text[i] == '\'' || text[i] == '"')
+ break;
+ if (i == len)
+ return text + len;
+ delim = text[i];
+ for (i = len; i > 0; --i)
+ if (text[i - 1] == delim)
+ break;
+ return text + i;
+}
+
/* Categorize numeric constants according to their field (integer,
floating point, or invalid), radix (decimal, octal, hexadecimal),
- and type suffixes. */
+ and type suffixes. In C++0X if UD_SUFFIX is non null it will be
+ assigned any unrecognized suffix for a user-defined literal. */
unsigned int
-cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
+cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
+ const char **ud_suffix)
{
const uchar *str = token->val.str.text;
const uchar *limit;
@@ -231,6 +370,9 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag;
bool seen_digit;
+ if (ud_suffix)
+ *ud_suffix = NULL;
+
/* If the lexer has done its job, length one can only be a single
digit. Fast-path this very common case. */
if (token->val.str.len == 1)
@@ -361,10 +503,19 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
result = interpret_float_suffix (str, limit - str);
if (result == 0)
{
- cpp_error (pfile, CPP_DL_ERROR,
- "invalid suffix \"%.*s\" on floating constant",
- (int) (limit - str), str);
- return CPP_N_INVALID;
+ if (CPP_OPTION (pfile, user_literals))
+ {
+ if (ud_suffix)
+ *ud_suffix = (const char *) str;
+ result = CPP_N_LARGE | CPP_N_USERDEF;
+ }
+ else
+ {
+ cpp_error (pfile, CPP_DL_ERROR,
+ "invalid suffix \"%.*s\" on floating constant",
+ (int) (limit - str), str);
+ return CPP_N_INVALID;
+ }
}
/* Traditional C didn't accept any floating suffixes. */
@@ -406,10 +557,19 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
result = interpret_int_suffix (str, limit - str);
if (result == 0)
{
- cpp_error (pfile, CPP_DL_ERROR,
- "invalid suffix \"%.*s\" on integer constant",
- (int) (limit - str), str);
- return CPP_N_INVALID;
+ if (CPP_OPTION (pfile, user_literals))
+ {
+ if (ud_suffix)
+ *ud_suffix = (const char *) str;
+ result = CPP_N_UNSIGNED | CPP_N_LARGE | CPP_N_USERDEF;
+ }
+ else
+ {
+ cpp_error (pfile, CPP_DL_ERROR,
+ "invalid suffix \"%.*s\" on integer constant",
+ (int) (limit - str), str);
+ return CPP_N_INVALID;
+ }
}
/* Traditional C only accepted the 'L' suffix.
@@ -539,7 +699,7 @@ cpp_interpret_integer (cpp_reader *pfile, const cpp_token *token,
}
}
- if (overflow)
+ if (overflow && !(type & CPP_N_USERDEF))
cpp_error (pfile, CPP_DL_PEDWARN,
"integer constant is too large for its type");
/* If too big to be signed, consider it unsigned. Only warn for
@@ -748,7 +908,10 @@ eval_token (cpp_reader *pfile, const cpp_token *token)
switch (token->type)
{
case CPP_NUMBER:
- temp = cpp_classify_number (pfile, token);
+ temp = cpp_classify_number (pfile, token, NULL);
+ if (temp & CPP_N_USERDEF)
+ cpp_error (pfile, CPP_DL_ERROR,
+ "user-defined literal in preprocessor expression");
switch (temp & CPP_N_CATEGORY)
{
case CPP_N_FLOATING:
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 825bf2fc6ff..9582b621ab5 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -131,6 +131,16 @@ struct _cpp_file;
TK(OBJC_STRING, LITERAL) /* @"string" - Objective-C */ \
TK(HEADER_NAME, LITERAL) /* <stdio.h> in #include */ \
\
+ TK(CHAR_USERDEF, LITERAL) /* 'char'_suffix - C++-0x */ \
+ TK(WCHAR_USERDEF, LITERAL) /* L'char'_suffix - C++-0x */ \
+ TK(CHAR16_USERDEF, LITERAL) /* u'char'_suffix - C++-0x */ \
+ TK(CHAR32_USERDEF, LITERAL) /* U'char'_suffix - C++-0x */ \
+ TK(STRING_USERDEF, LITERAL) /* "string"_suffix - C++-0x */ \
+ TK(WSTRING_USERDEF, LITERAL) /* L"string"_suffix - C++-0x */ \
+ TK(STRING16_USERDEF, LITERAL) /* u"string"_suffix - C++-0x */ \
+ TK(STRING32_USERDEF, LITERAL) /* U"string"_suffix - C++-0x */ \
+ TK(UTF8STRING_USERDEF,LITERAL) /* u8"string"_suffix - C++-0x */ \
+ \
TK(COMMENT, LITERAL) /* Only if output comments. */ \
/* SPELL_LITERAL happens to DTRT. */ \
TK(MACRO_ARG, NONE) /* Macro argument. */ \
@@ -414,6 +424,9 @@ struct cpp_options
/* True for traditional preprocessing. */
unsigned char traditional;
+ /* Nonzero for C++ 2011 Standard user-defnied literals. */
+ unsigned char user_literals;
+
/* Holds the name of the target (execution) character set. */
const char *narrow_charset;
@@ -829,13 +842,22 @@ struct cpp_num
#define CPP_N_FRACT 0x100000 /* Fract types. */
#define CPP_N_ACCUM 0x200000 /* Accum types. */
+#define CPP_N_USERDEF 0x1000000 /* C++0x user-defined literal. */
+
/* Classify a CPP_NUMBER token. The return value is a combination of
the flags from the above sets. */
-extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *);
+extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *,
+ const char **);
+
+/* Return the classification flags for a float suffix. */
+extern unsigned int cpp_interpret_float_suffix (const char *, size_t);
+
+/* Return the classification flags for an int suffix. */
+extern unsigned int cpp_interpret_int_suffix (const char *, size_t);
/* Evaluate a token classified as category CPP_N_INTEGER. */
extern cpp_num cpp_interpret_integer (cpp_reader *, const cpp_token *,
- unsigned int type);
+ unsigned int);
/* Sign extend a number, with PRECISION significant bits and all
others assumed clear, to fill out a cpp_num structure. */
@@ -1005,4 +1027,20 @@ extern int cpp_read_state (cpp_reader *, const char *, FILE *,
extern void cpp_force_token_locations (cpp_reader *, source_location *);
extern void cpp_stop_forcing_token_locations (cpp_reader *);
+/* In expr.c */
+extern enum cpp_ttype cpp_userdef_string_remove_type
+ (enum cpp_ttype type);
+extern enum cpp_ttype cpp_userdef_string_add_type
+ (enum cpp_ttype type);
+extern enum cpp_ttype cpp_userdef_char_remove_type
+ (enum cpp_ttype type);
+extern enum cpp_ttype cpp_userdef_char_add_type
+ (enum cpp_ttype type);
+extern bool cpp_userdef_string_p
+ (enum cpp_ttype type);
+extern bool cpp_userdef_char_p
+ (enum cpp_ttype type);
+extern const char * cpp_get_userdef_suffix
+ (const cpp_token *);
+
#endif /* ! LIBCPP_CPPLIB_H */
diff --git a/libcpp/init.c b/libcpp/init.c
index 6771e638970..99b65ba339e 100644
--- a/libcpp/init.c
+++ b/libcpp/init.c
@@ -80,22 +80,23 @@ struct lang_flags
char digraphs;
char uliterals;
char rliterals;
+ char user_literals;
};
static const struct lang_flags lang_defaults[] =
-{ /* c99 c++ xnum xid std // digr ulit rlit */
- /* GNUC89 */ { 0, 0, 1, 0, 0, 1, 1, 0, 0 },
- /* GNUC99 */ { 1, 0, 1, 0, 0, 1, 1, 1, 1 },
- /* GNUC1X */ { 1, 0, 1, 0, 0, 1, 1, 1, 1 },
- /* STDC89 */ { 0, 0, 0, 0, 1, 0, 0, 0, 0 },
- /* STDC94 */ { 0, 0, 0, 0, 1, 0, 1, 0, 0 },
- /* STDC99 */ { 1, 0, 1, 0, 1, 1, 1, 0, 0 },
- /* STDC1X */ { 1, 0, 1, 0, 1, 1, 1, 1, 0 },
- /* GNUCXX */ { 0, 1, 1, 0, 0, 1, 1, 0, 0 },
- /* CXX98 */ { 0, 1, 1, 0, 1, 1, 1, 0, 0 },
- /* GNUCXX0X */ { 1, 1, 1, 0, 0, 1, 1, 1, 1 },
- /* CXX0X */ { 1, 1, 1, 0, 1, 1, 1, 1, 1 },
- /* ASM */ { 0, 0, 1, 0, 0, 1, 0, 0, 0 }
+{ /* c99 c++ xnum xid std // digr ulit rlit user_literals */
+ /* GNUC89 */ { 0, 0, 1, 0, 0, 1, 1, 0, 0, 0 },
+ /* GNUC99 */ { 1, 0, 1, 0, 0, 1, 1, 1, 1, 0 },
+ /* GNUC1X */ { 1, 0, 1, 0, 0, 1, 1, 1, 1, 0 },
+ /* STDC89 */ { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
+ /* STDC94 */ { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0 },
+ /* STDC99 */ { 1, 0, 1, 0, 1, 1, 1, 0, 0, 0 },
+ /* STDC1X */ { 1, 0, 1, 0, 1, 1, 1, 1, 0, 0 },
+ /* GNUCXX */ { 0, 1, 1, 0, 0, 1, 1, 0, 0, 0 },
+ /* CXX98 */ { 0, 1, 1, 0, 1, 1, 1, 0, 0, 0 },
+ /* GNUCXX0X */ { 1, 1, 1, 0, 0, 1, 1, 1, 1, 1 },
+ /* CXX0X */ { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 },
+ /* ASM */ { 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 }
/* xid should be 1 for GNUC99, STDC99, GNUCXX, CXX98, GNUCXX0X, and
CXX0X when no longer experimental (when all uses of identifiers
in the compiler have been audited for correct handling of
@@ -120,6 +121,7 @@ cpp_set_lang (cpp_reader *pfile, enum c_lang lang)
CPP_OPTION (pfile, digraphs) = l->digraphs;
CPP_OPTION (pfile, uliterals) = l->uliterals;
CPP_OPTION (pfile, rliterals) = l->rliterals;
+ CPP_OPTION (pfile, user_literals) = l->user_literals;
}
/* Initialize library global state. */
diff --git a/libcpp/lex.c b/libcpp/lex.c
index 896a3bef2c2..fcec329d8b4 100644
--- a/libcpp/lex.c
+++ b/libcpp/lex.c
@@ -1478,6 +1478,18 @@ lex_raw_string (cpp_reader *pfile, cpp_token *token, const uchar *base,
}
break_outer_loop:
+ if (CPP_OPTION (pfile, user_literals))
+ {
+ /* Grab user defined literal suffix. */
+ if (ISIDST (*cur))
+ {
+ type = cpp_userdef_string_add_type (type);
+ ++cur;
+ }
+ while (ISIDNUM (*cur))
+ ++cur;
+ }
+
pfile->buffer->cur = cur;
if (first_buff == NULL)
create_literal (pfile, token, base, cur - base, type);
@@ -1581,6 +1593,19 @@ lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base)
cpp_error (pfile, CPP_DL_PEDWARN, "missing terminating %c character",
(int) terminator);
+ if (CPP_OPTION (pfile, user_literals))
+ {
+ /* Grab user defined literal suffix. */
+ if (ISIDST (*cur))
+ {
+ type = cpp_userdef_char_add_type (type);
+ type = cpp_userdef_string_add_type (type);
+ ++cur;
+ }
+ while (ISIDNUM (*cur))
+ ++cur;
+ }
+
pfile->buffer->cur = cur;
create_literal (pfile, token, base, cur - base, type);
}