From: Ed Smith-Rowland <3dw4rd@verizon.net>
To: Jason Merrill <jason@redhat.com>
Cc: gcc-patches <gcc-patches@gcc.gnu.org>
Subject: Re: [C++-11] User defined literals
Date: Mon, 19 Sep 2011 08:33:00 -0000 [thread overview]
Message-ID: <4E76FBBB.6050601@verizon.net> (raw)
In-Reply-To: <4E7008DA.6090703@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 7070 bytes --]
On 09/13/2011 09:52 PM, Jason Merrill wrote:
> Since we're starting to come up on the end of stage 1, I'll go ahead
> and review the current patch even though it isn't finished yet.
> Thanks for all your work on this, it definitely seems to be coming
> together.
>
> On 09/13/2011 10:35 AM, Ed Smith-Rowland wrote:
>> +#define CPP_N_USERDEF 0x1000000 /* C++0x user-defned literal. */
>
> "defined"
Done.
>
>> -extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *);
>> +extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *,
>> + char **ud_suffix);
>> +
>> +/* Return the classification flags for a float suffix. */
>> +unsigned int cpp_interpret_float_suffix (const char *s, size_t len);
>> +
>> +/* Return the classification flags for an int suffix. */
>> +unsigned int cpp_interpret_int_suffix (const char *s, size_t len);
>>
>> /* Evaluate a token classified as category CPP_N_INTEGER. */
>> extern cpp_num cpp_interpret_integer (cpp_reader *, const cpp_token *,
>
> Let's follow the pattern of the existing declarations by adding
> explicit 'extern' and not naming the parameters.
Done.
>
>> @@ -327,6 +327,10 @@ pp_cxx_constant (cxx_pretty_printer *pp, tree t)
>> + case USERDEF_LITERAL:
>> + pp_c_constant (pp_c_base (pp), USERDEF_LITERAL_VALUE (t));
>> + break;
>> @@ -1755,6 +1757,11 @@ dump_expr (tree t, int flags)
>> + case USERDEF_LITERAL:
>> + pp_constant (cxx_pp, USERDEF_LITERAL_VALUE (t));
>> + dump_decl (USERDEF_LITERAL_SUFFIX_ID (t), flags);
>> + break;
>
> These should be the same--or just call pp_cxx_constant from dump_expr.
Done, I think.
>
>> +/* Extract the suffix from a user-defined literal string or char. */
>> +void
>> +cpp_get_userdef_suffix (cpp_string string, char delim, char *suffix)
>> +{
>> + unsigned int len = string.len;
>> + const char *text = (const char *)string.text;
>> + int i;
>> + for (i = len; i > 0; --i)
>> + {
>> + if (text[i - 1] == delim)
>> + break;
>> + }
>> + strncpy (suffix, text + i, len - i);
>> + suffix[len - i] = '\0';
>> +}
>
> Since you're just going to be passing the pointer to get_identifier
> anyway, we don't need to copy the suffix into the pointer. Just
> return a pointer to the start of the suffix.
Done.
>
>> + if (ud_suffix)
>> + *ud_suffix = xstrdup ((const char *)str);
>
> Similarly here.
Done.
>
>> + const char *curr_suffix = NULL;
>> + suffix_id = USERDEF_LITERAL_SUFFIX_ID (tok->u.value);
>> + curr_suffix = IDENTIFIER_POINTER (suffix_id);
>> + if (have_suffix_p == 0)
>> + {
>> + suffix = xstrdup (curr_suffix);
>> + have_suffix_p = 1;
>> + }
>> + else if (have_suffix_p == 1 && strcmp (suffix,
>> curr_suffix) != 0)
>
> And here, you can compare the identifiers with ==, since identifiers
> are unique.
Done.
>
>> + error ("inconsistent user-defined literal suffixes");
>
> Let's print the suffixes involved.
Done.
>
>> + error ("%qD has illegal argument list", decl);
>
> Use "invalid" rather than "illegal".
Done.
>
>> + suffix = UDLIT_OP_SUFFIX (DECL_NAME (decl));
>> + if (long_long_unsigned_p)
>> + {
>> + if (cpp_interpret_int_suffix (suffix, strlen (suffix)))
>> + warning (0, "integer suffix shadowed by
>> implementation");
>> + }
>> + else if (long_double_p)
>> + {
>> + if (cpp_interpret_float_suffix (suffix, strlen (suffix)))
>> + warning (0, "floating point suffix"
>> + " shadowed by implementation");
>> + }
>
> Let's print the suffix as part of the warning.
Done.
>
>> + if (dname
>> + && TREE_CODE (dname) == IDENTIFIER_NODE
>> + && UDLIT_OPER_P (dname)
>> + && innermost_code != cdk_function
>> + && ! (ctype && !declspecs->any_specifiers_p))
>
> I think we can drop the last check, as it only applies to constructors.
Done.
>
>> +/* User-defined literal operator.
>> +DEF_SIMPLE_OPERATOR ("\"\"", USERDEF_LITERAL_EXPR, "ud", 1) */
>
> Are you planning to use this for something?
Removed.
>
>> +/* 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)
>
> There should be a blank line after the comment here and before the
> other new functions, at least in gcc/.
Done in as many of my places as I could find.
>
>> +make_numeric_string(tree value)
>
> This function tries to recreate a printed form for a numeric constant,
> but that's not right; we need the actual source characters, which are
> likely to be different, especially for floating-point numbers. So we
> need to get back to the actual spelling of the token here.
>
> I notice that later in cp_parser_userdef_numeric_literal when calling
> the variadic template version you assume that you have the spelling of
> the token, which is indeed what we want.
Done. I am now storing the numeric string along with the number and the
suffix ID for numeric operators. I'm keeping the numeric value because
we need it too.
>
>> +check_literal_operator_args(const_tree decl,
>
> Space before (.
Done.
>
>> + tree const_char_ptr_type_node
>> + = build_pointer_type(build_type_variant(char_type_node, 1,
>> 0));
>> + 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));
>
> It seems to me that rather than build these up to compare against, it
> it would be faster to check for POINTER_TYPE, then check that the
> pointed-to type is CP_TYPE_CONST_NON_VOLATILE_P, and then compare the
> TYPE_MAIN_VARIANT to char_type_node, etc.
I tried this and couldn't get it to work. I got a bunch of false
negatives and then a crash.
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
>
>> +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C
>> @@ -0,0 +1,16 @@
>> +// { dg-options "-std=c++0x" }
>> +
>> +// Both of these can't have *both* of these.
>> +
>> +int
>> +operator"" _abc(const char*)
>> + {
>> + return 42;
>> + }
>> +
>> +template<char...>
>> + int
>> + operator"" _abc()
>> + {
>> + return 13;
>> + }
>
> Shouldn't this have a dg-error tag somewhere?
I'm working on checking this. I need to test if both
operator"" _foo(char*)
and
template <char...>
_foo();
are declared and error. I'l looking over decl.c for this.
If I can't figure that out I'll take out the test.
>
> Jason
>
Attached are the results to date.
[-- Attachment #2: patch19 --]
[-- Type: text/plain, Size: 67659 bytes --]
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c (revision 178919)
+++ gcc/c-family/c-common.c (working copy)
@@ -9919,4 +9919,17 @@
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"
Index: gcc/c-family/c-lex.c
===================================================================
--- gcc/c-family/c-lex.c (revision 178919)
+++ gcc/c-family/c-lex.c (working copy)
@@ -44,8 +44,8 @@
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_integer (const cpp_token *, unsigned int, const char *);
+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 @@
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)
{
@@ -328,16 +329,27 @@
Set PURE_ZERO to pass this information to the C++ parser. */
if (tok->val.str.len == 1 && *tok->val.str.text == '0')
add_flags = PURE_ZERO;
- *value = interpret_integer (tok, flags);
+ *value = interpret_integer (tok, flags, suffix);
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 num_string = build_string (tok->val.str.len - strlen (suffix),
+ (const char *) tok->val.str.text);
+ TREE_TYPE (num_string) = char_array_type_node;
+ num_string = fix_string_type (num_string);
+ tree literal = build_userdef_literal (get_identifier (suffix),
+ *value, num_string);
+ *value = literal;
+ }
}
break;
@@ -415,6 +427,23 @@
}
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->val.str, '\'', &suffix);
+ 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 +451,23 @@
*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->val.str, '"', &suffix);
+ 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:
@@ -536,9 +582,11 @@
return itk_none;
}
-/* Interpret TOKEN, an integer with FLAGS as classified by cpplib. */
+/* Interpret TOKEN, an integer with FLAGS as classified by cpplib.
+ For C++0X SUFFIX may contain a user-defined literal suffix. */
static tree
-interpret_integer (const cpp_token *token, unsigned int flags)
+interpret_integer (const cpp_token *token, unsigned int flags,
+ const char *suffix)
{
tree value, type;
enum integer_type_kind itk;
@@ -621,9 +669,10 @@
}
/* 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 @@
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
{
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h (revision 178919)
+++ gcc/c-family/c-common.h (working copy)
@@ -1067,4 +1067,27 @@
return NULL;
}
+/* A suffix-identifier value doublet that represents user-defined literals
+ for C++-0x. */
+struct GTY(()) tree_userdef_literal {
+ struct tree_common common;
+ 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 */
Index: gcc/c-family/c-common.def
===================================================================
--- gcc/c-family/c-common.def (revision 178919)
+++ gcc/c-family/c-common.def (working copy)
@@ -47,6 +47,12 @@
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
Index: gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg-neg.C (revision 0)
@@ -0,0 +1,4 @@
+// { dg-options -std=c++0x }
+
+template<char...>
+ int operator"" _xyz(unsigned long long); // { dg-error "has illegal argument list" }
Index: gcc/testsuite/g++.dg/cpp0x/udlit_system_header
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit_system_header (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit_system_header (revision 0)
@@ -0,0 +1,6 @@
+
+#pragma GCC system_header
+
+char
+operator"" stdsuffix(char __c)
+{ return __c/2; }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C (revision 0)
@@ -0,0 +1,16 @@
+// { dg-options "-std=c++0x" }
+
+// Both of these can't have *both* of these.
+
+int
+operator"" _abc(const char*)
+ {
+ return 42;
+ }
+
+template<char...>
+ int
+ operator"" _abc()
+ {
+ return 13;
+ }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C (revision 0)
@@ -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; }
+}
Index: gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C (revision 0)
@@ -0,0 +1,8 @@
+// { dg-options -std=c++0x }
+
+class Foo
+{
+public:
+ Foo() { }
+ int operator"" _Bar(char32_t) { return 42; } // { dg-error "must be a non-member function" }
+};
Index: gcc/testsuite/g++.dg/cpp0x/udlit-args-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-args-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-args-neg.C (revision 0)
@@ -0,0 +1,38 @@
+// { dg-options -std=c++0x }
+
+#include <cstddef>
+
+class Foo { };
+
+Foo
+operator"" _Foo(int *); // { dg-error "has illegal argument list" }
+
+Foo
+operator"" _Foo(unsigned long int); // { dg-error "has illegal argument list" }
+
+Foo
+operator"" _Foo(double); // { dg-error "has illegal argument list" }
+
+Foo
+operator"" _Foo(const float *, std::size_t); // { dg-error "has illegal argument list" }
+
+Foo
+operator"" _Foo(const wchar_t *, int); // { dg-error "has illegal argument list" }
+
+Foo
+operator"" _Foo(const char16_t *); // { dg-error "has illegal argument list" }
+
+Foo
+operator"" _Foo(char...); // { dg-error "has illegal argument list" }
+
+Foo
+operator"" _Foo(unsigned long long int, char); // { dg-error "has illegal argument list" }
+
+Foo
+operator"" _Foo(const char *, std::size_t, int); // { dg-error "has illegal argument list" }
+
+Foo
+operator"" _Foo(long double &); // { dg-error "has illegal argument list" }
+
+Foo
+operator"" _Foo(std::size_t, const char16_t *); // { dg-error "has illegal argument list" }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-cpp98-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-cpp98-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-cpp98-neg.C (revision 0)
@@ -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 }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-suffix-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-suffix-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-suffix-neg.C (revision 0)
@@ -0,0 +1,7 @@
+// { dg-options -std=c++0x }
+
+#include <string>
+
+std::string operator"" 5X(const char*, std::size_t); // { dg-error "expected suffix identifier" }
+
+// { dg-error "expected type-specifier before string constant" "" { target *-*-* } 5 }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C (revision 0)
@@ -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];
Index: gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C (revision 0)
@@ -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 "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 5 }
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 9 }
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 13 }
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 17 }
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 25 }
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 29 }
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 33 }
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 37 }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-nounder-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-nounder-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-nounder-neg.C (revision 0)
@@ -0,0 +1,6 @@
+// { dg-options "-std=c++0x" }
+
+// Test user-defined literals.
+// Test warning on declaration without leading underscore.
+
+long double operator"" nounder(long double); // { dg-warning "suffixes not preceded by|are reserved for future standardization" }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C (revision 0)
@@ -0,0 +1,6 @@
+// { dg-options -std=c++0x }
+
+class Foo { };
+
+template<wchar_t...> // { dg-error "" }
+ Foo operator"" _Foo();
Index: gcc/testsuite/g++.dg/cpp0x/udlit-general.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-general.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-general.C (revision 0)
@@ -0,0 +1,47 @@
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+// Test user-defined literals.
+// Test simple operator declaration and definition.
+
+#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 y)
+{ return std::complex<double>(0.0L, y); }
+
+void
+test1()
+{
+ long double x = operator"" _v(1.2L);
+
+ std::string s = operator"" _w(u"one", 3);
+
+ unsigned u = operator"" _w("Hello, World!");
+ unsigned u2 = operator"" _w("Hello, World!");
+
+ std::complex<double> i = operator"" _i(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*)
+{ return 0U; }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-systemheader.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-systemheader.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-systemheader.C (revision 0)
@@ -0,0 +1,3 @@
+// { dg-options -std=c++0x }
+
+#include "udlit_system_header"
Index: gcc/testsuite/g++.dg/cpp0x/udlit-raw-str.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-raw-str.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-raw-str.C (revision 0)
@@ -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;
Index: gcc/testsuite/g++.dg/cpp0x/udlit-nofunc-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-nofunc-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-nofunc-neg.C (revision 0)
@@ -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" }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-addr.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-addr.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-addr.C (revision 0)
@@ -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);
Index: gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg.C (revision 0)
@@ -0,0 +1,4 @@
+// { dg-options -std=c++0x }
+
+template<char...>
+ int operator"" _abc();
Index: gcc/testsuite/g++.dg/cpp0x/udlit-clink-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-clink-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-clink-neg.C (revision 0)
@@ -0,0 +1,8 @@
+// { dg-options -std=c++0x }
+
+extern "C" {
+
+int
+operator"" _badclinkage(unsigned long long); // { dg-error "operator with C linkage" }
+
+}
Index: gcc/testsuite/g++.dg/cpp0x/udlit-template.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-template.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-template.C (revision 0)
@@ -0,0 +1,25 @@
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+// Test user-defined literals.
+// Test template operator declaration and definition.
+
+template<char...>
+ int operator"" _abc();
+
+int
+test1()
+{
+ int universal_meaning = operator"" _abc<'L','U','E'>();
+ int j = 1234567890_abc;
+}
+
+int
+main()
+{
+ test1();
+}
+
+template<char...>
+ int operator"" _abc()
+ { return 42; }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-args.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-args.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-args.C (revision 0)
@@ -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);
Index: gcc/testsuite/g++.dg/cpp0x/udlit-nosuffix-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-nosuffix-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-nosuffix-neg.C (revision 0)
@@ -0,0 +1,7 @@
+// { dg-options -std=c++0x }
+
+char32_t
+operator"" (char32_t C)
+{ return C; } // { dg-error "expected suffix identifier" }
+
+// { dg-error "expected type-specifier before string constant" "" { target *-*-* } 4 }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C (revision 0)
@@ -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" }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-linkage-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-linkage-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-linkage-neg.C (revision 0)
@@ -0,0 +1,7 @@
+// { dg-options -std=c++0x }
+
+extern "C"_badlinkage { // { dg-error "expected unqualified-id before" }
+
+int foo();
+
+}
Index: gcc/testsuite/g++.dg/cpp0x/udlit-friend.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-friend.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-friend.C (revision 0)
@@ -0,0 +1,10 @@
+// { dg-options -std=c++0x }
+
+class Foo
+{
+public:
+ Foo() { }
+ friend Foo operator"" _Bar(char) { return Foo(); }
+};
+
+Foo f = 'x'_Bar;
Index: gcc/testsuite/g++.dg/cpp0x/udlit-concat-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-concat-neg.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-concat-neg.C (revision 0)
@@ -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" }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms.C (revision 0)
@@ -0,0 +1,6 @@
+// { dg-options -std=c++0x }
+
+class Foo { };
+
+template<char...>
+ Foo operator"" _Foo();
Index: gcc/testsuite/g++.dg/cpp0x/udlit-concat.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-concat.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-concat.C (revision 0)
@@ -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;
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c (revision 178919)
+++ gcc/cp/typeck.c (working copy)
@@ -8321,3 +8321,94 @@
return 1;
}
+
+/* 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_char_ptr_type_node
+ = build_pointer_type(build_type_variant(char_type_node, 1, 0));
+ 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_char_ptr_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;
+ }
+}
+
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c (revision 178919)
+++ gcc/cp/decl.c (working copy)
@@ -7314,7 +7314,48 @@
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
tentative. error_mark_node is replaced later with the BLOCK. */
@@ -8498,6 +8539,15 @@
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))
{
@@ -13746,6 +13796,7 @@
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;
}
}
Index: gcc/cp/error.c
===================================================================
--- gcc/cp/error.c (revision 178919)
+++ gcc/cp/error.c (working copy)
@@ -1533,6 +1533,8 @@
}
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);
@@ -1755,6 +1757,10 @@
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. */
@@ -3230,14 +3236,19 @@
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) "
"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 ();
}
}
Index: gcc/cp/cxx-pretty-print.c
===================================================================
--- gcc/cp/cxx-pretty-print.c (revision 178919)
+++ gcc/cp/cxx-pretty-print.c (working copy)
@@ -367,6 +367,17 @@
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_constant (pp, t);
break;
+ case USERDEF_LITERAL:
+ pp_cxx_userdef_literal (pp, t);
+ break;
+
case BASELINK:
t = BASELINK_FUNCTIONS (t);
case VAR_DECL:
@@ -1023,6 +1038,10 @@
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;
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c (revision 178919)
+++ gcc/cp/semantics.c (working copy)
@@ -7748,6 +7748,7 @@
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:
Index: gcc/cp/cxx-pretty-print.h
===================================================================
--- gcc/cp/cxx-pretty-print.h (revision 178919)
+++ gcc/cp/cxx-pretty-print.h (working copy)
@@ -74,5 +74,7 @@
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 */
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revision 178919)
+++ gcc/cp/parser.c (working copy)
@@ -210,6 +210,8 @@
(cp_lexer *);
static void cp_lexer_rollback_tokens
(cp_lexer *);
+static tree cp_literal_operator_id
+ (const char *);
#ifdef ENABLE_CHECKING
static void cp_lexer_print_token
(FILE *, cp_token *);
@@ -501,20 +503,20 @@
}
else
{
- if (warn_cxx0x_compat
- && C_RID_CODE (token->u.value) >= RID_FIRST_CXX0X
- && C_RID_CODE (token->u.value) <= RID_LAST_CXX0X)
- {
- /* Warn about the C++0x keyword (but still treat it as
- an identifier). */
- warning (OPT_Wc__0x_compat,
- "identifier %qE will become a keyword in C++0x",
- token->u.value);
+ if (warn_cxx0x_compat
+ && C_RID_CODE (token->u.value) >= RID_FIRST_CXX0X
+ && C_RID_CODE (token->u.value) <= RID_LAST_CXX0X)
+ {
+ /* Warn about the C++0x keyword (but still treat it as
+ an identifier). */
+ warning (OPT_Wc__0x_compat,
+ "identifier %qE will become a keyword in C++0x",
+ token->u.value);
- /* Clear out the C_RID_CODE so we don't warn about this
- particular identifier-turned-keyword again. */
- C_SET_RID_CODE (token->u.value, RID_MAX);
- }
+ /* Clear out the C_RID_CODE so we don't warn about this
+ particular identifier-turned-keyword again. */
+ C_SET_RID_CODE (token->u.value, RID_MAX);
+ }
token->ambiguous_p = false;
token->keyword = RID_MAX;
@@ -1528,6 +1530,12 @@
(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] */
@@ -2030,6 +2038,8 @@
(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
@@ -2050,7 +2060,7 @@
/* 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 ||
@@ -2059,6 +2069,20 @@
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
@@ -3098,7 +3122,11 @@
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))
@@ -3107,7 +3135,18 @@
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. */
@@ -3116,10 +3155,19 @@
{
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
@@ -3131,14 +3179,35 @@
{
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");
@@ -3147,6 +3216,18 @@
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));
@@ -3184,6 +3265,13 @@
}
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. */
@@ -3195,7 +3283,183 @@
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 == error_mark_node)
+ {
+ error ("unable to find user-defined literal operator declaration");
+ 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 parmvec;
+ tree argpack = make_node (NONTYPE_ARGUMENT_PACK);
+ const char *str = TREE_STRING_POINTER (value);
+ int i, len = TREE_STRING_LENGTH (value) - 1;
+ /* Do I need to stuff THIS into a tree? */
+ tree argvec = make_tree_vec (1);
+
+ /* Fill in PARMVEC with all of the parameters. */
+ parmvec = make_tree_vec (len);
+ for (i = 0; i < len; ++i)
+ TREE_VEC_ELT (parmvec, i) = build_int_cst (char_type_node, str[i]);
+
+ /* Build the argument packs. */
+ SET_ARGUMENT_PACK_ARGS (argpack, parmvec);
+ TREE_TYPE (argpack) = char_type_node;
+
+ /* Do I need to stuff THIS into a tree? */
+ 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 != 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 != 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 != error_mark_node)
+ {
+ decl = finish_call_expr (decl, &args, false, true, tf_none);
+ if (decl != error_mark_node)
+ {
+ tree tmpl_args = make_char_string_pack (num_string);
+ result = lookup_template_function (decl, tmpl_args);
+ release_tree_vector (args);
+ return result;
+ }
+ }
+ release_tree_vector (args);
+
+ if (result == error_mark_node)
+ error ("unable to find appropriate call for user-defined literal");
+
+ 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 == error_mark_node)
+ {
+ error ("unable to find user-defined literal operator declaration");
+ 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;
+}
+
+
/* Basic concepts [gram.basic] */
/* Parse a translation-unit.
@@ -3338,12 +3602,16 @@
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)
{
@@ -3397,11 +3665,22 @@
}
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. */
@@ -4879,7 +5158,7 @@
/* 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;
@@ -9462,7 +9741,7 @@
/* 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
@@ -10893,6 +11172,22 @@
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:
@@ -11112,6 +11407,35 @@
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);
+ if (id != error_mark_node)
+ {
+ const char *name = IDENTIFIER_POINTER (id);
+
+ /* 17.6.3.3.5 */
+ if (name[0] != '_' && !in_system_header)
+ warning (0, "suffixes not preceded by %<_%> "
+ "are reserved for future standardization");
+
+ return cp_literal_operator_id(name);
+ }
+ else
+ {
+ error ("expected suffix identifier");
+ return error_mark_node;
+ }
+
default:
/* Anything else is an error. */
break;
@@ -22458,7 +22782,8 @@
/* 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)
Index: gcc/cp/cp-objcp-common.c
===================================================================
--- gcc/cp/cp-objcp-common.c (revision 178919)
+++ gcc/cp/cp-objcp-common.c (working copy)
@@ -100,6 +100,8 @@
case TEMPLATE_INFO: return sizeof (struct tree_template_info);
+ case USERDEF_LITERAL: return sizeof (struct tree_userdef_literal);
+
default:
gcc_unreachable ();
}
Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c (revision 178919)
+++ gcc/cp/mangle.c (working copy)
@@ -181,6 +181,7 @@
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_string (mangled_name);
}
+ else if (UDLIT_OPER_P (identifier))
+ write_literal_operator_name (identifier);
else
write_source_name (identifier);
}
@@ -1227,6 +1230,8 @@
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_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
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h (revision 178919)
+++ gcc/cp/cp-tree.h (working copy)
@@ -394,7 +394,9 @@
/* inline namespaces */
CPP0X_INLINE_NAMESPACES,
/* override controls, override/final */
- CPP0X_OVERRIDE_CONTROLS
+ CPP0X_OVERRIDE_CONTROLS,
+ /* user defined literals */
+ CPP0X_USER_DEFINED_LITERALS
} cpp0x_warn_str;
/* The various kinds of operation used by composite_pointer_type. */
@@ -725,6 +727,7 @@
TS_CP_TRAIT_EXPR,
TS_CP_LAMBDA_EXPR,
TS_CP_TEMPLATE_INFO,
+ TS_CP_USERDEF_LITERAL,
LAST_TS_CP_ENUM
};
@@ -750,6 +753,8 @@
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;
};
\f
@@ -4191,6 +4196,17 @@
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' \
@@ -5713,6 +5729,7 @@
extern int lvalue_or_else (tree, enum lvalue_use,
tsubst_flags_t);
extern void check_template_keyword (tree);
+extern bool check_literal_operator_args (const_tree, bool *, bool *);
/* in typeck2.c */
extern void require_complete_eh_spec_types (tree, tree);
Index: libcpp/include/cpplib.h
===================================================================
--- libcpp/include/cpplib.h (revision 178919)
+++ libcpp/include/cpplib.h (working copy)
@@ -131,6 +131,16 @@
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. */ \
@@ -402,6 +412,9 @@
/* True for traditional preprocessing. */
unsigned char traditional;
+ /* Nonzero for the 2011 C++ Standard. */
+ unsigned char cxx11;
+
/* Holds the name of the target (execution) character set. */
const char *narrow_charset;
@@ -817,13 +830,22 @@
#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. */
@@ -993,4 +1015,20 @@
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 void cpp_get_userdef_suffix
+ (cpp_string, char, const char **);
+
#endif /* ! LIBCPP_CPPLIB_H */
Index: libcpp/init.c
===================================================================
--- libcpp/init.c (revision 178919)
+++ libcpp/init.c (working copy)
@@ -80,22 +80,23 @@
char digraphs;
char uliterals;
char rliterals;
+ char cxx11;
};
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 cxx11 */
+ /* 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_OPTION (pfile, digraphs) = l->digraphs;
CPP_OPTION (pfile, uliterals) = l->uliterals;
CPP_OPTION (pfile, rliterals) = l->rliterals;
+ CPP_OPTION (pfile, cxx11) = l->cxx11;
}
/* Initialize library global state. */
Index: libcpp/expr.c
===================================================================
--- libcpp/expr.c (revision 178919)
+++ libcpp/expr.c (working copy)
@@ -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 @@
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,138 @@
: (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. */
+void
+cpp_get_userdef_suffix (cpp_string string, char delim, const char **suffix)
+{
+ unsigned int len = string.len;
+ const char *text = (const char *)string.text;
+ int i;
+ for (i = len; i > 0; --i)
+ {
+ if (text[i - 1] == delim)
+ break;
+ }
+ *suffix = 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 +365,9 @@
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 +498,19 @@
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, cxx11))
+ {
+ 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 +552,19 @@
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, cxx11))
+ {
+ 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.
@@ -748,7 +903,7 @@
switch (token->type)
{
case CPP_NUMBER:
- temp = cpp_classify_number (pfile, token);
+ temp = cpp_classify_number (pfile, token, NULL);
switch (temp & CPP_N_CATEGORY)
{
case CPP_N_FLOATING:
Index: libcpp/lex.c
===================================================================
--- libcpp/lex.c (revision 178919)
+++ libcpp/lex.c (working copy)
@@ -1227,6 +1227,7 @@
token->type = type;
token->val.str.len = len;
token->val.str.text = dest;
+/*printf("\ntoken: %s", token->val.str.text);*/
}
/* Subroutine of lex_raw_string: Append LEN chars from BASE to the buffer
@@ -1478,6 +1479,21 @@
}
break_outer_loop:
+ if (CPP_OPTION (pfile, cxx11))
+ {
+ /* 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;
if (first_buff == NULL)
create_literal (pfile, token, base, cur - base, type);
@@ -1581,6 +1597,21 @@
cpp_error (pfile, CPP_DL_PEDWARN, "missing terminating %c character",
(int) terminator);
+ if (CPP_OPTION (pfile, cxx11))
+ {
+ /* 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);
}
next prev parent reply other threads:[~2011-09-19 8:22 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-09-13 15:36 Ed Smith-Rowland
2011-09-13 16:43 ` Jason Merrill
2011-09-14 8:00 ` Jason Merrill
2011-09-19 8:33 ` Ed Smith-Rowland [this message]
2011-09-19 22:43 ` Jason Merrill
2011-09-20 7:23 ` Ed Smith-Rowland
2011-09-20 21:48 ` Jason Merrill
2011-10-05 15:57 ` Ed Smith-Rowland
2011-10-05 21:24 ` Jason Merrill
2011-10-08 21:38 ` Ed Smith-Rowland
2011-10-09 1:18 ` Jason Merrill
2011-10-09 23:46 ` Ed Smith-Rowland
2011-10-11 19:20 ` Jason Merrill
2011-10-11 17:39 ` Jason Merrill
2011-10-12 6:51 ` Ed Smith-Rowland
2011-10-12 18:49 ` Jason Merrill
2011-10-12 21:12 3dw4rd
2011-10-15 23:13 ` Jason Merrill
2011-10-16 7:59 ` Jason Merrill
2011-10-21 14:56 ` Ed Smith-Rowland
2011-10-21 21:20 ` Tom Tromey
2011-10-21 23:38 ` Jason Merrill
2011-10-23 22:29 ` Ed Smith-Rowland
2011-10-24 15:41 ` Ed Smith-Rowland
2011-10-25 23:38 ` Jason Merrill
2011-10-26 9:16 ` Ed Smith-Rowland
2011-10-26 20:13 ` Jason Merrill
2011-10-27 19:15 ` Ed Smith-Rowland
2011-10-27 19:55 ` Ed Smith-Rowland
2011-10-27 20:37 ` Jason Merrill
2011-10-30 19:10 ` Ed Smith-Rowland
2011-10-31 17:52 ` Jason Merrill
2011-10-25 7:07 ` Ed Smith-Rowland
2011-10-21 17:04 3dw4rd
2011-10-26 20:33 3dw4rd
2011-10-26 20:46 ` Jason Merrill
2011-10-31 17:58 3dw4rd
2011-10-31 20:20 ` Jason Merrill
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4E76FBBB.6050601@verizon.net \
--to=3dw4rd@verizon.net \
--cc=gcc-patches@gcc.gnu.org \
--cc=jason@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).