diff mbox

[C++-11] User defined literals

Message ID 4EA18271.6060705@verizon.net
State New
Headers show

Commit Message

Ed Smith-Rowland Oct. 21, 2011, 2:32 p.m. UTC
On 10/15/2011 04:42 PM, Jason Merrill wrote:
> On 10/12/2011 04:58 PM, 3dw4rd@verizon.net wrote:
>> +  tree const_char_ptr_type_node
>> +       = build_pointer_type (build_type_variant (char_type_node, 1, 
>> 0));
>
> You can just use const_string_type_node here.
>
> Jason
>
I made this change.

I also added a test case to make sure that embedded quotes are not a 
problem.
No valid string can begin or end with an escaped quote.  So the string 
delimiter is found by loking for the first quote in the string.
The suffix is found by looking for that same quote from the end of the 
string.

While looking at the embedded string issue I found that if you apply the 
suffix of a raw literal to a string it errors as it should but the error 
complained that there were too many arguments for the function.  This 
was not helpful so I made a nicer error message.

Ed

Comments

Tom Tromey Oct. 21, 2011, 7:55 p.m. UTC | #1
>>>>> "Ed" == Ed Smith-Rowland <3dw4rd@verizon.net> writes:

Ed> +  /* Nonzero for the 2011 C++ Standard.  */
Ed> +  unsigned char cxx11;

I think it would be better if the new field name reflected its purpose,
so something like "user_literals".

Ed> +      if (ISIDST(*cur))
Ed> +	{
Ed> +	  type = cpp_userdef_string_add_type (type);
Ed> +	  ++cur;
Ed> +	}
Ed> +      while (ISIDNUM(*cur))

There are a few spots like this that are missing a space before an open
paren.

Otherwise the libcpp changes seem fine to me.  I don't actually know the
C++0x user-defined literal spec, though, so someone else will have to
review it for correctness against that.

Tom
Jason Merrill Oct. 21, 2011, 9:20 p.m. UTC | #2
I think we're down to minor cosmetic issues:

On 10/21/2011 03:55 PM, Tom Tromey wrote:
> There are a few spots like this that are missing a space before an open
> paren.

> +      if (DECL_LANGUAGE(decl) == lang_c)

Another one.

> -          if (warn_cxx0x_compat
> -              && C_RID_CODE (token->u.value) >= RID_FIRST_CXX0X
> -              && C_RID_CODE (token->u.value) <= RID_LAST_CXX0X)
....

This code doesn't seem to have actually changed, so let's not adjust its 
whitespace.

> +  /* Fill in PARMVEC with all of the parameters.  */
> +  parmvec = make_tree_vec (len);

Let's call it 'charvec'; the characters are template arguments, not 
parameters.

> +/* 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)

Add a blank line between comment and function.

> While looking at the embedded string issue I found that if you apply the suffix of a raw literal to a string it errors as it should but the error complained that there were too many arguments for the function.  This was not helpful so I made a nicer error message.

> +  if (result == error_mark_node)
> +    error ("invalid string literal prefix %<\"%s\"%> for user-defined"
> +          " raw literal operator %qD", TREE_STRING_POINTER (value), name);

I think that we want a combination of the two errors; the new error 
doesn't help the user to fix their code as much.  It should remind them 
that for a string literal the function is called with a length argument 
as well.

> +       error ("literal operator template %qD has invalid parameter list",
> +              decl);

Similarly, this message should say that the parameter list needs to be 
<char...>

>
> +
> +/* Return true if a user-defined literal operator is a raw operator.  */
> +

We don't need the extra newline before the comment.

Should be ready to go with these tweaks.

Jason
Ed Smith-Rowland Oct. 23, 2011, 9:11 p.m. UTC | #3
On 10/21/2011 05:20 PM, Jason Merrill wrote:
> I think we're down to minor cosmetic issues:
>
> On 10/21/2011 03:55 PM, Tom Tromey wrote:
>> There are a few spots like this that are missing a space before an open
>> paren.
>
>> +      if (DECL_LANGUAGE(decl) == lang_c)
>
> Another one.
>
>> -          if (warn_cxx0x_compat
>> - && C_RID_CODE (token->u.value) >= RID_FIRST_CXX0X
>> - && C_RID_CODE (token->u.value) <= RID_LAST_CXX0X)
> ....
>
> This code doesn't seem to have actually changed, so let's not adjust 
> its whitespace.
>
>> +  /* Fill in PARMVEC with all of the parameters.  */
>> +  parmvec = make_tree_vec (len);
>
> Let's call it 'charvec'; the characters are template arguments, not 
> parameters.
>
>> +/* 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)
>
> Add a blank line between comment and function.
>
>> While looking at the embedded string issue I found that if you apply 
>> the suffix of a raw literal to a string it errors as it should but 
>> the error complained that there were too many arguments for the 
>> function.  This was not helpful so I made a nicer error message.
>
>> +  if (result == error_mark_node)
>> +    error ("invalid string literal prefix %<\"%s\"%> for user-defined"
>> +          " raw literal operator %qD", TREE_STRING_POINTER (value), 
>> name);
>
> I think that we want a combination of the two errors; the new error 
> doesn't help the user to fix their code as much.  It should remind 
> them that for a string literal the function is called with a length 
> argument as well.
>
Concerning this error, the only way to get here is to mis-use a raw 
literal operator by giving it a quoted string.  The prefix must be 
interpretable as a number of some kind.  I think I'll tell the user to 
drop the quotes.
The length of a string literal is supplied implicitly by the compiler to 
a string literal operator when a string user defined literal is 
encountered.  The user doesn't explicitly call the operator (not here 
anyway).

>> +       error ("literal operator template %qD has invalid parameter 
>> list",
>> +              decl);
>
> Similarly, this message should say that the parameter list needs to be 
> <char...>
>
>>
>> +
>> +/* Return true if a user-defined literal operator is a raw 
>> operator.  */
>> +
>
> We don't need the extra newline before the comment.
>
> Should be ready to go with these tweaks.
>
> Jason
>
I've made these corrections.  They'll be in the next patch.

Unfortunately, as I was testing raw operators on very long strings I 
observed two things:
1. A bad error - the argument to a raw literal operator must be a 
null-terminated string.
2. If a very long number is given as the prefix to a numeric literal, a 
warning is issued ("integer constant is too large for its type")
If the receiving operator is either the raw operator or the operator 
template then this should not be given.  I anticipate people might like 
to have multi-precision numbers someday, for example.

Before I release another patch I have to fix 1.  The warning might be 
fixed in-tree if that's OK.

Ed
diff mbox

Patch

Index: gcc/c-family/c-lex.c
===================================================================
--- gcc/c-family/c-lex.c	(revision 180284)
+++ 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,22 @@ 
       }
       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);
+	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 +450,22 @@ 
       *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);
+	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 +580,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 +667,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 +749,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.c
===================================================================
--- gcc/c-family/c-common.c	(revision 180284)
+++ gcc/c-family/c-common.c	(working copy)
@@ -9923,4 +9923,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-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 180284)
+++ 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_base base;
+  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 180284)
+++ 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 invalid 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,42 @@ 
+// { dg-options "-std=c++0x" }
+
+//  Can't have *both* literal operator template and raw literal operator.
+
+int
+operator"" _abc(const char*)
+  {
+    return 42;
+  }
+
+template<char...>
+  int
+  operator"" _abc() // { dg-error "literal operator template|conflicts with raw literal operator" }
+  {
+    return 13;
+  }
+
+template<char...>
+  int
+  operator"" _def()
+  {
+    return 12;
+  }
+
+int
+operator"" _def(const char*) // { dg-error "raw literal operator|conflicts with literal operator template" }
+  {
+    return 43;
+  }
+
+int
+operator"" _ghi(long double)
+  {
+    return 42;
+  }
+
+template<char...>
+  int
+  operator"" _ghi() // OK
+  {
+    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-raw-op-string-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C	(revision 0)
@@ -0,0 +1,8 @@ 
+// { dg-options "-std=c++0x" }
+
+//  Make sure handing a string to a raw literal generates a sensible error message.
+
+int operator"" _embedraw(const char*)
+{ return 41; };
+
+int k = "Boo!"_embedraw;  //  { dg-error "invalid string literal prefix|for user-defined raw literal operator" }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-embed-quote.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-embed-quote.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-embed-quote.C	(revision 0)
@@ -0,0 +1,34 @@ 
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+//  Make sure embedded quotes are not a problem for string and char literals.
+
+#include <cstdint>
+#include <cassert>
+
+int operator"" _embedchar(char)
+{ return 41; };
+
+int operator"" _embedstr(const char*, std::size_t len)
+{ return 42 + len; };
+
+void
+test()
+{
+  int i = '\''_embedchar;
+
+  int j = "\""_embedstr;
+  assert(j == 43);
+
+  int k = "foo\""_embedstr;
+  assert(k == 46);
+
+  int l = "\"bar"_embedstr;
+  assert(l == 46);
+}
+
+int
+main()
+{
+  test();
+}
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,15 @@ 
+// { dg-options -std=c++0x }
+
+class Foo
+{
+public:
+  Foo() { }
+  int operator"" _Bar(char32_t);  // { dg-error "must be a non-member function" }
+};
+
+int i = operator"" _Bar(U'x');  // { dg-error "was not declared in this scope" }
+int j = U'x'_Bar;  // { dg-error "unable to find user-defined character literal operator" }
+
+int
+Foo::operator"" _Bar(char32_t)  // { dg-error "must be a non-member function" }
+{ return 42; }
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 invalid argument list" }
+
+Foo
+operator"" _Foo(unsigned long int);	// { dg-error "has invalid argument list" }
+
+Foo
+operator"" _Foo(double);	// { dg-error "has invalid argument list" }
+
+Foo
+operator"" _Foo(const float *, std::size_t);	// { dg-error "has invalid argument list" }
+
+Foo
+operator"" _Foo(const wchar_t *, int);	// { dg-error "has invalid argument list" }
+
+Foo
+operator"" _Foo(const char16_t *);	// { dg-error "has invalid argument list" }
+
+Foo
+operator"" _Foo(char...);	// { dg-error "has invalid argument list" }
+
+Foo
+operator"" _Foo(unsigned long long int, char);	// { dg-error "has invalid argument list" }
+
+Foo
+operator"" _Foo(const char *, std::size_t, int);	// { dg-error "has invalid argument list" }
+
+Foo
+operator"" _Foo(long double &);	// { dg-error "has invalid argument list" }
+
+Foo
+operator"" _Foo(std::size_t, const char16_t *);	// { dg-error "has invalid 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,5 @@ 
+// { dg-options -std=c++0x }
+
+#include <string>
+
+std::string operator"" 5X(const char*, std::size_t);	// { dg-error "expected suffix identifier" }
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 "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 5 }
+// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 9 }
+// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 13 }
+// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 17 }
+// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 25 }
+// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 29 }
+// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 33 }
+// { dg-warning "literal operator 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,9 @@ 
+// { dg-options "-std=c++0x" }
+
+// Test user-defined literals.
+// Test warning on declaration without leading underscore.
+
+long double operator"" nounder(long double); // { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" }
+
+template<char...>
+  int operator"" nounder(); // { dg-warning "literal operator 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,12 @@ 
+// { dg-options -std=c++0x }
+
+class Foo { };
+
+template<wchar_t...>
+  Foo operator"" _Foo(); // { dg-error "literal operator template|has invalid parameter list" }
+
+template<char>
+  Foo operator"" _Bar(); // { dg-error "literal operator template|has invalid parameter list" }
+
+template<typename... Type>
+  Foo operator"" _Bar(); // { dg-error "literal operator template|has invalid parameter list" }
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,52 @@ 
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+// Test user-defined literals.
+// Test simple operator declaration and definition.
+
+#include <cstring>
+#include <string>
+#include <complex>
+#include <cassert>
+
+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);
+  assert(x == 2.2L);
+
+  std::string s = operator"" _w(u"one", 3);
+  assert(s == "boo");
+
+  unsigned u = operator"" _w("Hello, World!");
+  assert(u == 13U);
+
+  std::complex<double> i = operator"" _i(2.0);
+  assert(i == std::complex<double>(0.0, 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* str)
+{ return strlen(str); }
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,51 @@ 
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+// Test user-defined literals.
+// Test template operator declaration and definition.
+
+#include <cassert>
+
+template<char...>
+  int operator"" _abc();
+
+template<>
+  int
+  operator"" _abc<>()
+  { return -1; }
+
+template<>
+  int
+  operator"" _abc<'L','U','E'>()
+  { return 42; }
+
+template<>
+  int
+  operator"" _abc<'6','6','6'>()
+  { return 21; }
+
+int
+test1()
+{
+  int i = operator"" _abc<'1','2','3'>();
+  assert(i == 45);
+  int universal_meaning = operator"" _abc<'L','U','E'>();
+  assert(universal_meaning == 42);
+  int b = operator"" _abc<'6','6','6'>();
+  int z = operator"" _abc<>();
+  assert(z == -1);
+  int j = 123_abc;
+  assert(j == i);
+  int jb = 666_abc;
+  assert(jb == b);
+}
+
+int
+main()
+{
+  test1();
+}
+
+template<char... Chars>
+  int operator"" _abc()
+  { return 42 + sizeof...(Chars); }
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-declare-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C	(revision 0)
@@ -0,0 +1,15 @@ 
+// { dg-options "-std=c++0x" }
+
+//  Check that undeclared literal operator calls and literals give appropriate errors.
+
+int i = operator"" _Bar('x');  // { dg-error "was not declared in this scope" }
+int j = 'x'_Bar;  // { dg-error "unable to find user-defined character literal operator" }
+
+int ii = operator"" _BarCharStr("Howdy, Pardner!");  // { dg-error "was not declared in this scope" }
+int jj = "Howdy, Pardner!"_BarCharStr;  // { dg-error "unable to find user-defined string literal operator" }
+
+unsigned long long iULL = operator"" _BarULL(666ULL);  // { dg-error "was not declared in this scope" }
+unsigned long long jULL = 666_BarULL;  // { dg-error "unable to find user-defined numeric literal operator" }
+
+long double iLD = operator"" _BarLD(666.0L);  // { dg-error "was not declared in this scope" }
+long double jLD = 666.0_BarLD;  // { dg-error "unable to find user-defined numeric literal operator" }
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,5 @@ 
+// { dg-options -std=c++0x }
+
+char32_t
+operator"" (char32_t C)	// { dg-error "expected suffix identifier" }
+{ return C; }
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-nospace-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-nospace-neg.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-nospace-neg.C	(revision 0)
@@ -0,0 +1,3 @@ 
+// { dg-options "-std=c++0x" }
+
+float operator ""_abc(const char*); // { dg-error "missing space between|and suffix identifier" }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-inline.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-inline.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-inline.C	(revision 0)
@@ -0,0 +1,22 @@ 
+// { dg-options "-std=c++0x" }
+
+//  Literal operators can be inline.
+
+inline int
+operator"" _thing1(char cc)
+{ return 42 * cc; }
+
+int operator"" _thing2(char cc);
+
+class Foo
+{
+  int
+  friend operator"" _thing2(char cc)
+  { return 42 * cc; }
+};
+
+int i = operator"" _thing1('x');
+int j = 'x'_thing1;
+
+int iF = operator"" _thing2('x');
+int jF = 'x'_thing2;
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,28 @@ 
+// { dg-options -std=c++0x }
+
+long double
+operator"" _Hertz(long double);
+
+class Foo
+{
+public:
+  Foo() { }
+
+  friend Foo operator"" _Bar(char);
+
+  friend long double
+  operator"" _Hertz(long double omega)
+  { return omega / 6.28318530717958648; }
+};
+
+Foo
+operator"" _Bar(char)
+{ return Foo(); }
+
+Foo f1 = operator"" _Bar('x');
+
+Foo f2 = 'x'_Bar;
+
+long double fm1 = operator"" _Hertz(552.92L);
+
+long double fm2 = 552.92_Hertz;
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 180284)
+++ gcc/cp/typeck.c	(working copy)
@@ -8352,3 +8352,122 @@ 
   return 1;
 }
 
+
+/* Return true if a user-defined literal operator is a raw operator.  */
+
+bool
+check_raw_literal_operator (const_tree decl)
+{
+  tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
+  tree argtype;
+  int arity;
+  bool maybe_raw_p = false;
+
+  /* Count the number and type of arguments and check for ellipsis.  */
+  for (argtype = argtypes, arity = 0;
+       argtype && argtype != void_list_node;
+       ++arity, argtype = TREE_CHAIN (argtype))
+    {
+      tree t = TREE_VALUE (argtype);
+
+      if (same_type_p (t, const_string_type_node))
+	maybe_raw_p = true;
+    }
+  if (!argtype)
+    return false; /* Found ellipsis.  */
+
+  if (!maybe_raw_p || arity != 1)
+    return false;
+
+  return true;
+}
+
+
+/* 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_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_string_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 180284)
+++ gcc/cp/decl.c	(working copy)
@@ -1203,6 +1203,21 @@ 
       || TREE_TYPE (olddecl) == error_mark_node)
     return error_mark_node;
 
+  if (UDLIT_OPER_P (DECL_NAME (newdecl))
+      && UDLIT_OPER_P (DECL_NAME (olddecl)))
+    {
+      if (TREE_CODE (newdecl) == TEMPLATE_DECL
+	  && TREE_CODE (olddecl) != TEMPLATE_DECL
+	  && check_raw_literal_operator (olddecl))
+	error ("literal operator template %q+D conflicts with"
+	       " raw literal operator %qD", newdecl, olddecl);
+      else if (TREE_CODE (newdecl) != TEMPLATE_DECL
+	       && TREE_CODE (olddecl) == TEMPLATE_DECL
+	       && check_raw_literal_operator (newdecl))
+	error ("raw literal operator %q+D conflicts with"
+	       " literal operator template %qD", newdecl, olddecl);
+    }
+
   if (DECL_P (olddecl)
       && TREE_CODE (newdecl) == FUNCTION_DECL
       && TREE_CODE (olddecl) == FUNCTION_DECL
@@ -7343,7 +7358,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.  */
@@ -8534,6 +8590,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))
     {
@@ -13752,6 +13817,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 180284)
+++ gcc/cp/error.c	(working copy)
@@ -1534,6 +1534,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);
 
@@ -1756,6 +1758,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.  */
@@ -3233,7 +3239,7 @@ 
 	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) "
@@ -3244,8 +3250,13 @@ 
 		 "non-static data member initializers "
 		 "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 180284)
+++ 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:
@@ -1024,6 +1039,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 180284)
+++ gcc/cp/semantics.c	(working copy)
@@ -7865,6 +7865,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 180284)
+++ 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 180284)
+++ 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 *);
 static void cp_lexer_print_token
   (FILE *, cp_token *);
 static inline bool cp_lexer_debugging_p
@@ -734,20 +736,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;
@@ -1762,6 +1764,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]  */
 
@@ -2270,6 +2278,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
@@ -2290,7 +2300,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 ||
@@ -2299,6 +2309,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
@@ -3338,7 +3362,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))
@@ -3347,7 +3375,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.  */
@@ -3356,10 +3395,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
@@ -3371,14 +3419,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");
@@ -3387,6 +3456,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));
 
@@ -3424,6 +3505,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.  */
@@ -3435,7 +3523,186 @@ 
   return value;
 }
 
+/* Parse a user-defined char constant.  Returns a call to a user-defined
+   literal operator taking the character as an argument.  */
 
+static tree
+cp_parser_userdef_char_literal (cp_parser *parser)
+{
+  cp_token *token = NULL;
+  tree literal, suffix_id, value;
+  tree name, decl;
+  tree result;
+  VEC(tree,gc) *vec;
+
+  token = cp_lexer_consume_token (parser->lexer);
+  literal = token->u.value;
+  suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+  value = USERDEF_LITERAL_VALUE (literal);
+  name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+
+  /* Build up a call to the user-defined operator  */
+  /* Lookup the name we got back from the id-expression.  */
+  vec = make_tree_vector ();
+  VEC_safe_push (tree, gc, vec, value);
+  decl = lookup_function_nonclass (name, vec, /*block_p=*/false);
+  if (!decl || decl == error_mark_node)
+    {
+      error ("unable to find user-defined character literal operator %qD",
+	     name);
+      release_tree_vector (vec);
+      return error_mark_node;
+    }
+  result = finish_call_expr (decl, &vec, false, true, tf_warning_or_error);
+  release_tree_vector (vec);
+
+  return result;
+}
+
+/* A subroutine of cp_parser_userdef_numeric_literal to
+   create a char... template parameter pack from a string node.  */
+
+static tree
+make_char_string_pack (tree value)
+{
+  tree parmvec;
+  tree argpack = make_node (NONTYPE_ARGUMENT_PACK);
+  const char *str = TREE_STRING_POINTER (value);
+  int i, len = TREE_STRING_LENGTH (value);
+  /*  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;
+
+  TREE_VEC_ELT (argvec, 0) = argpack;
+
+  return argvec;
+}
+
+/* Parse a user-defined numeric constant.  returns a call to a user-defined
+   literal operator.  */
+static tree
+cp_parser_userdef_numeric_literal (cp_parser *parser)
+{
+  cp_token *token = NULL;
+  tree literal, suffix_id, value, num_string;
+  tree name, decl;
+  tree result = error_mark_node;
+  VEC(tree,gc) *args;
+
+  token = cp_lexer_consume_token (parser->lexer);
+  literal = token->u.value;
+  suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+  value = USERDEF_LITERAL_VALUE (literal);
+  num_string = USERDEF_LITERAL_NUM_STRING (literal);
+  name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+
+  /* Build up a call to the user-defined operator  */
+  /* Lookup the name we got back from the id-expression.  */
+  /* Try to find the literal operator by finishing the call expression
+     with the numeric argument.  */
+  args = make_tree_vector ();
+  VEC_safe_push (tree, gc, args, value);
+  decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+  if (decl && decl != error_mark_node)
+    {
+      result = finish_call_expr (decl, &args, false, true, tf_none);
+      if (result != error_mark_node)
+	{
+	  release_tree_vector (args);
+	  return result;
+	}
+    }
+  release_tree_vector (args);
+
+  /* If the numeric argument didn't work, look for a raw literal
+     operator taking a const char* argument consisting of the number
+     in string format.  */
+  args = make_tree_vector ();
+  VEC_safe_push (tree, gc, args, num_string);
+  decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+  if (decl && decl != error_mark_node)
+    {
+      result = finish_call_expr (decl, &args, false, true, tf_none);
+      if (result != error_mark_node)
+	{
+	  release_tree_vector (args);
+	  return result;
+	}
+    }
+  release_tree_vector (args);
+
+  /* If the raw literal didn't work, look for a non-type template
+     function with parameter pack char....  Call the function with
+     template parameter characters representing the number.  */
+  args = make_tree_vector ();
+  decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+  if (decl && decl != error_mark_node)
+    {
+      tree tmpl_args = make_char_string_pack (num_string);
+      decl = lookup_template_function (decl, tmpl_args);
+      result = finish_call_expr (decl, &args, false, true, tf_none);
+      if (result != error_mark_node)
+	{
+	  release_tree_vector (args);
+	  return result;
+	}
+    }
+  release_tree_vector (args);
+
+  if (result == error_mark_node)
+    error ("unable to find user-defined numeric literal operator %qD", name);
+
+  return result;
+}
+
+/* Parse a user-defined string constant.  Returns a call to a user-defined
+   literal operator taking a character pointer and the length of the string
+   as arguments.  */
+static tree
+cp_parser_userdef_string_literal (cp_token *token)
+{
+  tree literal, suffix_id, value;
+  tree name, decl;
+  tree result;
+  VEC(tree,gc) *vec;
+  int len;
+
+  literal = token->u.value;
+  suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+  name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+  value = USERDEF_LITERAL_VALUE (literal);
+  len = TREE_STRING_LENGTH (value) - 1;
+
+  /* Build up a call to the user-defined operator  */
+  /* Lookup the name we got back from the id-expression.  */
+  vec = make_tree_vector ();
+  VEC_safe_push (tree, gc, vec, value);
+  VEC_safe_push (tree, gc, vec, build_int_cst (size_type_node, len));
+  decl = lookup_function_nonclass (name, vec, /*block_p=*/false);
+  if (!decl || decl == error_mark_node)
+    {
+      error ("unable to find user-defined string literal operator %qD", name);
+      release_tree_vector (vec);
+      return error_mark_node;
+    }
+  result = finish_call_expr (decl, &vec, false, true, tf_none);
+  if (result == error_mark_node)
+    error ("invalid string literal prefix %<\"%s\"%> for user-defined"
+	   " raw literal operator %qD", TREE_STRING_POINTER (value), name);
+  release_tree_vector (vec);
+
+  return result;
+}
+
+
 /* Basic concepts [gram.basic]  */
 
 /* Parse a translation-unit.
@@ -3578,12 +3845,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)
 	{
@@ -3637,11 +3908,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.  */
@@ -4477,6 +4759,14 @@ 
 	  /* If that didn't work, try a conversion-function-id.  */
 	  if (!cp_parser_parse_definitely (parser))
 	    id = cp_parser_conversion_function_id (parser);
+	  else if (UDLIT_OPER_P (id))
+	    {
+	      /* 17.6.3.3.5  */
+	      const char *name = UDLIT_OP_SUFFIX (id);
+	      if (name[0] != '_' && !in_system_header)
+		warning (0, "literal operator suffixes not preceded by %<_%>"
+			    " are reserved for future standardization");
+	    }
 
 	  return id;
 	}
@@ -5119,7 +5409,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;
@@ -9739,7 +10029,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
@@ -11170,6 +11460,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:
@@ -11389,6 +11695,37 @@ 
       cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
       return ansi_opname (ARRAY_REF);
 
+    case CPP_STRING:
+      if (cxx_dialect == cxx98)
+	maybe_warn_cpp0x (CPP0X_USER_DEFINED_LITERALS);
+      if (TREE_STRING_LENGTH (token->u.value) > 2)
+	{
+	  error ("expected empty string after %<operator%> keyword");
+	  return error_mark_node;
+	}
+      /* Consume the string.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Look for the suffix identifier.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      if (token->type == CPP_NAME)
+	{
+	  id = cp_parser_identifier (parser);
+	  if (id != error_mark_node)
+	    {
+	      const char *name = IDENTIFIER_POINTER (id);
+	      return cp_literal_operator_id (name);
+	    }
+	}
+      else
+	{
+	  error ("expected suffix identifier");
+	  return error_mark_node;
+	}
+
+    case CPP_STRING_USERDEF:
+      error ("missing space between %<\"\"%> and suffix identifier");
+      return error_mark_node;
+
     default:
       /* Anything else is an error.  */
       break;
@@ -20583,6 +20920,32 @@ 
   /* Finish up.  */
   finish_template_decl (parameter_list);
 
+  /* Check the template arguments for a literal operator template.  */
+  if (decl
+      && (TREE_CODE (decl) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (decl))
+      && UDLIT_OPER_P (DECL_NAME (decl)))
+    {
+      bool ok = true;
+      if (parameter_list == NULL_TREE)
+	ok = false;
+      else
+	{
+	  int num_parms = TREE_VEC_LENGTH (parameter_list);
+	  if (num_parms != 1)
+	    ok = false;
+	  else
+	    {
+	      tree parm_list = TREE_VEC_ELT (parameter_list, 0);
+	      tree parm = INNERMOST_TEMPLATE_PARMS (parm_list);
+	      if (TREE_TYPE (parm) != char_type_node
+		  || !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)))
+		ok = false;
+	    }
+	}
+      if (!ok)
+	error ("literal operator template %qD has invalid parameter list",
+	       decl);
+    }
   /* Register member declarations.  */
   if (member_p && !friend_p && decl && !DECL_CLASS_TEMPLATE_P (decl))
     finish_member_declaration (decl);
@@ -22891,7 +23254,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 180284)
+++ 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 180284)
+++ 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 180284)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -400,7 +400,9 @@ 
   /* override controls, override/final */
   CPP0X_OVERRIDE_CONTROLS,
   /* non-static data member initializers */
-  CPP0X_NSDMI
+  CPP0X_NSDMI,
+  /* user defined literals */
+  CPP0X_USER_DEFINED_LITERALS
 } cpp0x_warn_str;
   
 /* The various kinds of operation used by composite_pointer_type. */
@@ -740,6 +742,7 @@ 
   TS_CP_TRAIT_EXPR,
   TS_CP_LAMBDA_EXPR,
   TS_CP_TEMPLATE_INFO,
+  TS_CP_USERDEF_LITERAL,
   LAST_TS_CP_ENUM
 };
 
@@ -765,6 +768,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;
 };
 
 
@@ -4228,6 +4233,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' \
@@ -5758,6 +5774,8 @@ 
 extern int lvalue_or_else			(tree, enum lvalue_use,
                                                  tsubst_flags_t);
 extern void check_template_keyword		(tree);
+extern bool check_raw_literal_operator		(const_tree decl);
+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 180284)
+++ 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.  */			\
@@ -414,6 +424,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;
 
@@ -829,13 +842,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.  */
@@ -1005,4 +1027,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 const char * cpp_get_userdef_suffix
+  (const cpp_token *);
+
 #endif /* ! LIBCPP_CPPLIB_H */
Index: libcpp/init.c
===================================================================
--- libcpp/init.c	(revision 180284)
+++ 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 180284)
+++ 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,143 @@ 
 	     : (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 @@ 
   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 @@ 
       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 +557,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 +908,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 180284)
+++ libcpp/lex.c	(working copy)
@@ -1478,6 +1478,18 @@ 
     }
  break_outer_loop:
 
+  if (CPP_OPTION (pfile, cxx11))
+    {
+      /* 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 @@ 
     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);
 }