Greetings,
I am slowly working on user defined literals for C++-0x.
This is my first foray into the C++ front end and I'm stuck.
Anyway, I managed to parse things like
long double
operator"" _foo(long double x) { return 2.0L * x; }
The result is a normal function that I can either call like
operator "" _foo(1.2L);
or just
_foo(1.2L);
The problem is when I parse something like
u"string"w
I want to generate a call to something like
std::string operator"" w(const char16_t*, size_t);
i.e. I want to build a call:
w(u"string", 6);
I have a (not nearly ready for prime time) patch attached. My current
problem is in parser.c cp_parser_primary_expression after the string types.
Thanks for any help you can give,
Ed
Index: gcc/cp/error.c
===================================================================
--- gcc/cp/error.c (revision 164355)
+++ gcc/cp/error.c (working copy)
@@ -3033,7 +3033,12 @@
pedwarn (input_location, OPT_pedantic,
"inline namespaces "
"only available with -std=c++0x or -std=gnu++0x");
- break;
+ 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();
}
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revision 164355)
+++ gcc/cp/parser.c (working copy)
@@ -3579,13 +3579,50 @@
case CPP_STRING32:
case CPP_WSTRING:
case CPP_UTF8STRING:
- /* ??? 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. */
- return cp_parser_string_literal (parser,
- parser->translate_strings_p,
- true);
+ {
+ tree strl;
+ cp_token *next_token;
+ /* ??? 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. */
+ strl = cp_parser_string_literal (parser,
+ parser->translate_strings_p,
+ true);
+
+ next_token = cp_lexer_peek_token (parser->lexer);
+ if (next_token->type == CPP_NAME)
+ {
+ tree identifier;
+ VEC(tree,gc) *vec;
+ int len = TREE_STRING_LENGTH (strl);
+
+ identifier = cp_parser_identifier(parser);
+ if (identifier == error_mark_node)
+ return error_mark_node;
+
+ /* Build up a call to the user-defined operator */
+ vec = make_tree_vector ();
+ VEC_safe_push (tree, gc, vec, strl);
+ VEC_safe_push (tree, gc, vec, build_int_cst (size_type_node, len));
+ identifier = perform_koenig_lookup (identifier, vec,
+ /*include_std=*/false);
+ if (identifier == error_mark_node)
+ {
+ release_tree_vector (vec);
+ error ("unable to find user-defined operator");
+ return error_mark_node;
+ }
+ identifier = finish_call_expr (identifier, &vec, false, true,
+ tf_warning_or_error);
+ release_tree_vector (vec);
+
+ return identifier;
+ }
+ else
+ return strl;
+ }
+
case CPP_OPEN_PAREN:
{
tree expr;
@@ -10927,6 +10964,31 @@
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 an identifier. */
+ id = cp_parser_identifier (parser);
+
+ /* Look for a `('. */
+ token = cp_lexer_peek_token (parser->lexer);
+ if (token->type != CPP_OPEN_PAREN)
+ {
+ error ("expected function declaration");
+ return error_mark_node;
+ }
+
+ return id;
+ }
+
default:
/* Anything else is an error. */
break;
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h (revision 164355)
+++ gcc/cp/cp-tree.h (working copy)
@@ -389,7 +389,9 @@
/* defaulted and deleted functions */
CPP0X_DEFAULTED_DELETED,
/* inline namespaces */
- CPP0X_INLINE_NAMESPACES
+ CPP0X_INLINE_NAMESPACES,
+ /* user defined literals */
+ CPP0X_USER_DEFINED_LITERALS
} cpp0x_warn_str;
/* The various kinds of operation used by composite_pointer_type. */
Index: libcpp/include/cpplib.h
===================================================================
--- libcpp/include/cpplib.h (revision 164355)
+++ libcpp/include/cpplib.h (working copy)
@@ -816,6 +816,8 @@
#define CPP_N_FRACT 0x100000 /* Fract types. */
#define CPP_N_ACCUM 0x200000 /* Accum types. */
+#define CPP_N_USER_DEFINED 0x1000000 /* C++0x user-defned 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 *);
Index: libcpp/expr.c
===================================================================
--- libcpp/expr.c (revision 164355)
+++ libcpp/expr.c (working copy)
@@ -361,10 +361,18 @@
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, lang) == CLK_CXX0X
+ || CPP_OPTION (pfile, lang) == CLK_GNUCXX0X)
+ {
+ result |= CPP_N_USER_DEFINED;
+ }
+ 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 +414,18 @@
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, lang) == CLK_CXX0X
+ || CPP_OPTION (pfile, lang) == CLK_GNUCXX0X)
+ {
+ result |= CPP_N_USER_DEFINED;
+ }
+ 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.
// ./bin_udlit/bin/g++ -std=c++0x -o user_defined_literal user_defined_literal.cpp
#include <iostream>
#include <string>
#include <complex>
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);
namespace Long
{
long double operator"" L(long double);
}
long double loo(long double);
template<char...>
int operator"" _abc();
//double operator"hi" _badword(long double); // user_defined_literal.cpp:23:8: error: expected empty string after 'operator' keyword // IMHO, this could be pedantic.
//double operator"" _baddecl; // user_defined_literal.cpp:25:19: error: expected function declaration
double operator"" _badargs(int, int);
int
main()
{
std::cout << "Explicitly call operators..." << std::endl;
std::cout << operator "" v(1.2L) << std::endl;
std::cout << operator "" w(u"one", 3) << std::endl;
std::cout << operator "" w("12") << std::endl;
std::cout << operator "" _i(2.0) << std::endl;
std::cout << Long::operator "" L(1.2) << std::endl;
std::cout << "Explicitly call functions..." << std::endl;
std::cout << v(1.2) << std::endl;
std::cout << w(u"one", 3) << std::endl;
std::cout << w("12") << std::endl;
std::cout << _i(2.0) << std::endl;
std::cout << Long::L(1.2) << std::endl;
std::cout << "Literals..." << std::endl;
std::cout << 1.2v << std::endl; // calls operator "" w(1.2L)
std::cout << u"one"w << std::endl; // calls operator "" w(u"one", 3)
std::cout << 12w << std::endl; // calls operator "" w("12")
std::cout << 2.0_i << std::endl;
std::cout << loo(1.2) << std::endl;
//std::cout << "two"w << std::endl; // error: no applicable literal operator
}
long double operator"" v(long double x) { return x + 1.0L; }
std::string operator"" w(const char16_t*, size_t) { return std::string(); }
unsigned operator"" w(const char*) { return 0U; }
std::complex<double>
operator"" _i(long double y)
{ return std::complex<double>(0.0L, y); }
namespace Long
{
long double
operator"" L(long double x)
{ return x + 2.0L; }
}
long double
loo(long double x)
{
using Long::L;
return L(x);
}
template<char...>
int operator"" _abc()
{ return 42; }