diff mbox

[C++-0x] User defined literals.

Message ID 4DB59410.4010800@verizon.net
State New
Headers show

Commit Message

Ed Smith-Rowland April 25, 2011, 3:32 p.m. UTC
This patch repairs all the potential spacing and buffer overrun issues 
that I could see.

It is still not ready.
1. I would like to get pretty printing so that only one suffix is 
printed instead of 1.234L_abc or 123456ULL_xyz.
     I know how to do this.
2. Templates don't really work.  This is proving difficult for my little 
brain.

I need to parse this:
123_abc;
and replace it with a call to

operator"" _abc<'1', '2', '3'>();

I can call
operator"" _abc<>();

In other words I can't figure out how to get the template args in.

There's stuff in there getting the template function out of OVERLOAD.
Then I try tsubst.  No dice.

3. I can't get friend to work.  The operator definition doesn't even get 
written.
     I'm deferring this until after I get templates to work.

All the other aspects of this capability work.

Have at it and thank you all for your patience and help.

Ed

Comments

Jason Merrill July 12, 2011, 5:40 p.m. UTC | #1
Hmm, sorry I didn't notice this patch until now.  Please CC me on C++ 
patches, and feel free to ping me if I don't respond promptly.  Thanks 
for working on this!

> 2. Templates don't really work.  This is proving difficult for my little brain.
>
> I need to parse this:
> 123_abc;
> and replace it with a call to
>
> operator"" _abc<'1', '2', '3'>();
>
> I can call
> operator"" _abc<>();
>
> In other words I can't figure out how to get the template args in.
>
> There's stuff in there getting the template function out of OVERLOAD.
> Then I try tsubst.  No dice.

Can you build up a TEMPLATE_ID_EXPR and then let the usual overload 
resolution code do the rest?

> 3. I can't get friend to work.  The operator definition doesn't even get written.
>     I'm deferring this until after I get templates to work.

If you're talking about your udlit-friend.C test, I wouldn't expect that 
to work; friends are only found by argument-dependent lookup, and there 
is no argument of type Foo in the call

  operator""_Bar('x')

> +#define UDLIT_OP_MANGLED_PREFIX "__udlit"

Discussion on the ABI list seems to have settled on

   li <source-name>

as the mangling of a literal operator.

Rather than check lang == CXX0X or GNUCXX0X in libcpp, let's add a C++0x 
flag.

There doesn't seem to be any need for USERDEF_LITERAL to be in the 
language-independent code; bits can go in c-common.h and c-common.def 
rather than tree.h and tree.def, etc.

Thanks,
Jason
Jason Merrill July 12, 2011, 8:56 p.m. UTC | #2
A few more notes:

> +      if (DECL_NAMESPACE_SCOPE_P (decl))
> +       {
> +         if (!check_literal_operator_args(decl,
> +                                        &long_long_unsigned_p, &long_double_p))
> +           {
> +             error ("%qD has illegal argument list", decl);
> +             return NULL_TREE;
> +           }
> +
> +         if (CP_DECL_CONTEXT (decl) == global_namespace)
> +           {
> +             const char *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");
> +               }
> +           }
> +       }

Doesn't the shadowing apply everywhere, not just at file scope?

> +  if (cpp_userdef_string_p (tok->type))
> +    {
> +      string_tree = USERDEF_LITERAL_VALUE (tok->u.value);
> +      tok->type = cpp_userdef_string_remove_type (tok->type);
> +      curr_tok_is_userdef_p = true;
> +    }

It seems like a mistake to change tok->type without changing the value. 
  Why not just set the 'type' local variable appropriately?

> +             const char *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)
...
> +         USERDEF_LITERAL_SUFFIX_ID (literal) = get_identifier (suffix);

Just remember the identifier and compare it with ==.  Identifiers are 
unique.

> +  /* Lookup the name we got back from the id-expression.  */
> +  decl = cp_parser_lookup_name (parser, name,

Maybe use lookup_function_nonclass?

Jason
Ed Smith-Rowland July 17, 2011, 5:01 a.m. UTC | #3
On 07/12/2011 04:56 PM, Jason Merrill wrote:
> A few more notes:
>
>> +      if (DECL_NAMESPACE_SCOPE_P (decl))
>> +       {
>> +         if (!check_literal_operator_args(decl,
>> + &long_long_unsigned_p, &long_double_p))
>> +           {
>> +             error ("%qD has illegal argument list", decl);
>> +             return NULL_TREE;
>> +           }
>> +
>> +         if (CP_DECL_CONTEXT (decl) == global_namespace)
>> +           {
>> +             const char *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");
>> +               }
>> +           }
>> +       }
>
> Doesn't the shadowing apply everywhere, not just at file scope?
Yes, the shadowing should apply everywhere.  What test do I use to get that?
I seem to remember trying something like global_p without success.
>
>> +  if (cpp_userdef_string_p (tok->type))
>> +    {
>> +      string_tree = USERDEF_LITERAL_VALUE (tok->u.value);
>> +      tok->type = cpp_userdef_string_remove_type (tok->type);
>> +      curr_tok_is_userdef_p = true;
>> +    }
>
> It seems like a mistake to change tok->type without changing the 
> value.  Why not just set the 'type' local variable appropriately?
The string lexer is comparing the types of string fragments during 
concatenation to make sure there is no inconsistency (wide vs. narrow, etc.)
The type of string fragment for this purpose is is the string type w/o 
the user-definedness.
Now maybe I should use a *second* local variable, say curr_type, for the 
current fragment.  The variable type stores the initial string type and 
the type
all subsequent fragments must equal.
>
>> +             const char *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)
> ...
>> +         USERDEF_LITERAL_SUFFIX_ID (literal) = get_identifier (suffix);
>
> Just remember the identifier and compare it with ==.  Identifiers are 
> unique.
Done.
>
>> +  /* Lookup the name we got back from the id-expression.  */
>> +  decl = cp_parser_lookup_name (parser, name,
>
> Maybe use lookup_function_nonclass?
I used this and it simplifies things somewhat.  I'm trying to follow a 
crash while parsing friend declared literals.
>
> Jason
>
>
Jason Merrill July 18, 2011, 4:56 a.m. UTC | #4
On 07/17/2011 01:01 AM, Ed Smith-Rowland wrote:
> On 07/12/2011 04:56 PM, Jason Merrill wrote:
>> Doesn't the shadowing apply everywhere, not just at file scope?
> Yes, the shadowing should apply everywhere. What test do I use to get that?
> I seem to remember trying something like global_p without success.

I was thinking just drop the checks of CP_DECL_CONTEXT and 
DECL_NAMESPACE_SCOPE_P.

> Now maybe I should use a *second* local variable, say curr_type, for the
> current fragment.

That works.

>> Rather than check lang == CXX0X or GNUCXX0X in libcpp, let's add a C++0x flag.
> Where would you add the flag?  cpp_token?

In lang_flags in libcpp/init.c, like the c99 flag.

Jason
Ed Smith-Rowland July 20, 2011, 9:32 p.m. UTC | #5
On 07/12/2011 04:56 PM, Jason Merrill wrote:
> A few more notes:
>
>> +      if (DECL_NAMESPACE_SCOPE_P (decl))
>> +       {
>> +         if (!check_literal_operator_args(decl,
>> + &long_long_unsigned_p, &long_double_p))
>> +           {
>> +             error ("%qD has illegal argument list", decl);
>> +             return NULL_TREE;
>> +           }
>> +
>> +         if (CP_DECL_CONTEXT (decl) == global_namespace)
>> +           {
>> +             const char *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");
>> +               }
>> +           }
>> +       }
>
> Doesn't the shadowing apply everywhere, not just at file scope?
>
>> +  if (cpp_userdef_string_p (tok->type))
>> +    {
>> +      string_tree = USERDEF_LITERAL_VALUE (tok->u.value);
>> +      tok->type = cpp_userdef_string_remove_type (tok->type);
>> +      curr_tok_is_userdef_p = true;
>> +    }
>
> It seems like a mistake to change tok->type without changing the 
> value.  Why not just set the 'type' local variable appropriately?
>
>> +             const char *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)
> ...
>> +         USERDEF_LITERAL_SUFFIX_ID (literal) = get_identifier (suffix);
>
> Just remember the identifier and compare it with ==.  Identifiers are 
> unique.
>
>> +  /* Lookup the name we got back from the id-expression.  */
>> +  decl = cp_parser_lookup_name (parser, name,
>
> Maybe use lookup_function_nonclass?
>
> Jason
>
>
I was conflating shadowing because of the preprocessor capturing 
suffixed like F for float and L for long int, etc. (which are captured 
by te preprocessor for those purposes) with allowing two user-specified 
suffixes to be disambiguated with namespaces and using declarations as 
mentioned in the paper.

I removed those tests.

Now I have a real question:  Since a shadowed suffix *cannot* act like 
the user wants no matter what, should I error instead of warn?
Jason Merrill July 20, 2011, 10:09 p.m. UTC | #6
On 07/20/2011 05:32 PM, Ed Smith-Rowland wrote:
> Now I have a real question: Since a shadowed suffix *cannot* act like
> the user wants no matter what, should I error instead of warn?

It doesn't seem any more erroneous than any other suffix without a 
leading underscore, even though it isn't very useful.  But it can still 
be called directly by operator name.

But on a related topic, I think complaining about suffixes without a 
leading underscore should not depend on OPT_pedantic; it should only be 
silenced if in_system_header.

Jason
diff mbox

Patch

Index: gcc/c-family/c-lex.c
===================================================================
--- gcc/c-family/c-lex.c	(revision 172649)
+++ 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);
+	char *suffix = NULL;
+	unsigned int flags = cpp_classify_number (parse_in, tok, &suffix);
 
 	switch (flags & CPP_N_CATEGORY)
 	  {
@@ -328,16 +329,24 @@ 
 	       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 literal = build_userdef_literal ();
+	    USERDEF_LITERAL_SUFFIX_ID (literal) = get_identifier (suffix);
+	    USERDEF_LITERAL_VALUE (literal) = *value;
+	    *value = literal;
+	  }
       }
       break;
 
@@ -415,6 +424,24 @@ 
       }
       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;
+	char *suffix = XNEWVEC (char, tok->val.str.len + 1);
+	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 ();
+	USERDEF_LITERAL_SUFFIX_ID (literal) = get_identifier (suffix);
+	USERDEF_LITERAL_VALUE (literal) = lex_charconst (&temp_tok);
+	*value = literal;
+      }
+      break;
+
     case CPP_CHAR:
     case CPP_WCHAR:
     case CPP_CHAR16:
@@ -422,6 +449,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;
+	char *suffix = XNEWVEC (char, tok->val.str.len + 1);
+	cpp_get_userdef_suffix (tok->val.str, '"', suffix);
+	literal = build_userdef_literal ();
+	USERDEF_LITERAL_SUFFIX_ID (literal) = get_identifier (suffix);
+	USERDEF_LITERAL_VALUE (literal)
+	 = build_string (tok->val.str.len - strlen (suffix), tok->val.str.text);
+	*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/tree.c
===================================================================
--- gcc/tree.c	(revision 172649)
+++ gcc/tree.c	(working copy)
@@ -337,6 +337,7 @@ 
     case OMP_CLAUSE:		return TS_OMP_CLAUSE;
     case OPTIMIZATION_NODE:	return TS_OPTIMIZATION;
     case TARGET_OPTION_NODE:	return TS_TARGET_OPTION;
+    case USERDEF_LITERAL:	return TS_USERDEF_LITERAL;
 
     default:
       gcc_unreachable ();
@@ -394,6 +395,7 @@ 
 	case TS_OMP_CLAUSE:
 	case TS_OPTIMIZATION:
 	case TS_TARGET_OPTION:
+	case TS_USERDEF_LITERAL:
 	  MARK_TS_COMMON (code);
 	  break;
 
@@ -682,6 +684,8 @@ 
 	case OPTIMIZATION_NODE: return sizeof (struct tree_optimization_option);
 	case TARGET_OPTION_NODE: return sizeof (struct tree_target_option);
 
+        case USERDEF_LITERAL:	return sizeof (struct tree_userdef_literal);
+
 	default:
 	  return lang_hooks.tree_size (code);
 	}
@@ -1627,7 +1631,19 @@ 
     }
 }
 
+/* Build a user-defined numeric literal out of an integer constant type VALUE
+   with identifier SUFFIX.  */
 
+tree
+build_userdef_literal (void)
+{
+  tree literal = make_node (USERDEF_LITERAL);
+  USERDEF_LITERAL_SUFFIX_ID (literal) = NULL_TREE;
+  USERDEF_LITERAL_VALUE (literal) = NULL_TREE;
+  return literal;
+}
+
+
 /* Build a BINFO with LEN language slots.  */
 
 tree
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 172649)
+++ gcc/tree.h	(working copy)
@@ -3550,6 +3550,25 @@ 
 /* Return a tree node that encapsulates the current target options.  */
 extern tree build_target_option_node (void);
 
+/* 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;
+};
+
+#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_TYPE(NODE) \
+  (TREE_TYPE (USERDEF_LITERAL_VALUE (NODE)))
+
+extern tree build_userdef_literal		(void);
+
 
 /* Define the overall contents of a tree node.
    It may be any of the structures declared above
@@ -3594,6 +3613,7 @@ 
   struct tree_omp_clause GTY ((tag ("TS_OMP_CLAUSE"))) omp_clause;
   struct tree_optimization_option GTY ((tag ("TS_OPTIMIZATION"))) optimization;
   struct tree_target_option GTY ((tag ("TS_TARGET_OPTION"))) target_option;
+  struct tree_userdef_literal GTY ((tag ("TS_USERDEF_LITERAL"))) userdef_literal;
 };
 
 /* Standard named or nameless data types of the C compiler.  */
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-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.2SS;
+}
+
+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,10 @@ 
+// { dg-options -std=c++0x }
+
+class Foo
+{
+public:
+  Foo() { }
+  int operator"" _Bar(char32_t) { return 42; }	// { dg-error "must be a non-member function" }
+};
+
+int n = 'x'_Bar;	// { dg-error "unable to find user-defined literal operator declaration" }
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,23 @@ 
+// { 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" }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-nounder-pedwarn.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-nounder-pedwarn.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-nounder-pedwarn.C	(revision 0)
@@ -0,0 +1,6 @@ 
+// { dg-options "-std=c++0x -pedantic" }
+
+// 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-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,15 @@ 
+// { dg-options "-std=c++98" }
+
+#include <cstddef>
+
+int
+operator"" mm(long double m)	// { dg-warning "user-defined literals only available with -std=c++0x or -std=gnu++0x" }
+{ return int(1000.0L * m); }
+
+int in = 0.0254mm;	// { dg-error "invalid suffix" }
+
+int
+operator"" Q(const char *, std::size_t)	// { dg-warning "user-defined literals only available with -std=c++0x or -std=gnu++0x" }
+{ return 42; }
+
+int x = "Hello"Q;	// { dg-error "invalid conversion from" "expected" }
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,9 @@ 
+// { dg-options -std=c++0x }
+
+long double
+operator"" L(long double x)
+{ return x; }	// { dg-warning "floating point suffix shadowed by implementation" }
+
+unsigned long long int
+operator"" ULL(unsigned long long int k)
+{ return k; }	// { dg-warning "integer suffix shadowed by implementation" }
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-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-noshadow.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-noshadow.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-noshadow.C	(revision 0)
@@ -0,0 +1,14 @@ 
+// { dg-options -std=c++0x }
+
+namespace Long
+{
+
+long double
+operator"" L(long double x)
+{ return x; }
+
+unsigned long long int
+operator"" ULL(unsigned long long int k)
+{ return k; }
+
+}
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
+main()
+{
+  test1();
+  int j = 1234567890_abc;
+}
+
+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,5 @@ 
+// { dg-options -std=c++0x }
+
+char32_t
+operator"" (char32_t C)
+{ return C; }	// { dg-error "expected suffix identifier" }
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 172649)
+++ gcc/cp/typeck.c	(working copy)
@@ -8262,3 +8262,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 (arity > max_arity)
+	    return false;
+	}
+      if (!argtype)
+	return false; /* Found ellipsis.  */
+
+      if (found_string_p && !maybe_raw_p && !found_size_p)
+	return false;
+
+      return true;
+    }
+}
+
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 172649)
+++ gcc/cp/decl.c	(working copy)
@@ -7121,7 +7121,49 @@ 
   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;
+      /* [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 illegal argument list", decl);
+	      return NULL_TREE;
+	    }
+
+	  if (CP_DECL_CONTEXT (decl) == global_namespace)
+	    {
+	      const char *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");
+		}
+	    }
+	}
+      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.  */
@@ -8228,6 +8270,16 @@ 
       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
+      && ! (ctype && !declspecs->any_specifiers_p))
+    {
+      error ("declaration of %qD as non-function", dname);
+      return error_mark_node;
+    }
 
   /* Anything declared one level down from the top level
      must be one of the parameters of a function
Index: gcc/cp/error.c
===================================================================
--- gcc/cp/error.c	(revision 172649)
+++ gcc/cp/error.c	(working copy)
@@ -1,7 +1,7 @@ 
 /* Call-backs for C++ error reporting.
    This code is non-reentrant.
    Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003,
-   2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
    This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
@@ -1493,6 +1493,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);
 
@@ -1713,6 +1715,11 @@ 
       pp_constant (cxx_pp, t);
       break;
 
+    case USERDEF_LITERAL:
+      pp_constant (cxx_pp, USERDEF_LITERAL_VALUE (t));
+      dump_decl (USERDEF_LITERAL_SUFFIX_ID (t), flags);
+      break;
+
     case THROW_EXPR:
       /* While waiting for caret diagnostics, avoid printing
 	 __cxa_allocate_exception, __cxa_throw, and the like.  */
@@ -3142,9 +3149,14 @@ 
 	pedwarn (input_location, OPT_pedantic,
 		 "inline namespaces "
 		 "only available with -std=c++0x or -std=gnu++0x");
-	break;	
+	break;
+      case CPP0X_USER_DEFINED_LITERALS:
+	pedwarn (input_location, 0,
+		 "user-defined literals "
+		 "only available with -std=c++0x or -std=gnu++0x");
+	break;
       default:
-	gcc_unreachable();
+	gcc_unreachable ();
       }
 }
 
Index: gcc/cp/operators.def
===================================================================
--- gcc/cp/operators.def	(revision 172649)
+++ gcc/cp/operators.def	(working copy)
@@ -153,3 +153,6 @@ 
 
 /* Variadic templates extension. */
 DEF_SIMPLE_OPERATOR ("...", EXPR_PACK_EXPANSION, "sp", 1)
+
+/* User-defined literal operator.
+DEF_SIMPLE_OPERATOR ("\"\"", USERDEF_LITERAL_EXPR, "ud", 1)  */
Index: gcc/cp/cxx-pretty-print.c
===================================================================
--- gcc/cp/cxx-pretty-print.c	(revision 172649)
+++ gcc/cp/cxx-pretty-print.c	(working copy)
@@ -1,6 +1,6 @@ 
 /* Implementation of subroutines for the GNU C++ pretty-printer.
    Copyright (C) 2003, 2004, 2005, 2007, 2008,
-   2009, 2010 Free Software Foundation, Inc.
+   2009, 2010, 2011 Free Software Foundation, Inc.
    Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
 
 This file is part of GCC.
@@ -327,6 +327,10 @@ 
 {
   switch (TREE_CODE (t))
     {
+    case USERDEF_LITERAL:
+      pp_c_constant (pp_c_base (pp), USERDEF_LITERAL_VALUE (t));
+      break;
+
     case STRING_CST:
       {
 	const bool in_parens = PAREN_STRING_LITERAL_P (t);
@@ -407,6 +411,7 @@ 
     case REAL_CST:
     case COMPLEX_CST:
     case STRING_CST:
+    case USERDEF_LITERAL:
       pp_cxx_constant (pp, t);
       break;
 
@@ -1017,6 +1022,7 @@ 
     case INTEGER_CST:
     case REAL_CST:
     case COMPLEX_CST:
+    case USERDEF_LITERAL:
       pp_cxx_constant (pp, t);
       break;
 
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(revision 172649)
+++ gcc/cp/semantics.c	(working copy)
@@ -7399,6 +7399,7 @@ 
     case TEMPLATE_PARM_INDEX:
     case TRAIT_EXPR:
     case IDENTIFIER_NODE:
+    case USERDEF_LITERAL:
       return true;
 
     case PARM_DECL:
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 172649)
+++ gcc/cp/parser.c	(working copy)
@@ -1,6 +1,6 @@ 
 /* C++ Parser.
    Copyright (C) 2000, 2001, 2002, 2003, 2004,
-   2005, 2007, 2008, 2009, 2010  Free Software Foundation, Inc.
+   2005, 2007, 2008, 2009, 2010, 2011  Free Software Foundation, Inc.
    Written by Mark Mitchell <mark@codesourcery.com>.
 
    This file is part of GCC.
@@ -209,6 +209,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 *);
@@ -500,20 +502,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;
@@ -1506,6 +1508,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_parser *, cp_token *);
+static tree cp_parser_userdef_numeric_literal
+  (cp_parser *);
 
 /* Basic concepts [gram.basic]  */
 
@@ -2004,6 +2012,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
@@ -2024,7 +2034,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 ||
@@ -2033,6 +2043,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
@@ -3073,6 +3097,10 @@ 
   cpp_string str, istr, *strs;
   cp_token *tok;
   enum cpp_ttype type;
+  char *suffix = NULL;
+  int have_suffix_p = 0;
+  tree string_tree;
+  bool curr_tok_is_userdef_p = false;
 
   tok = cp_lexer_peek_token (parser->lexer);
   if (!cp_parser_is_string_literal (tok))
@@ -3081,6 +3109,14 @@ 
       return error_mark_node;
     }
 
+  if (cpp_userdef_string_p (tok->type))
+    {
+      string_tree = USERDEF_LITERAL_VALUE (tok->u.value);
+      tok->type = cpp_userdef_string_remove_type (tok->type);
+      curr_tok_is_userdef_p = true;
+    }
+  else
+    string_tree = tok->u.value;
   type = tok->type;
 
   /* Try to avoid the overhead of creating and destroying an obstack
@@ -3090,10 +3126,18 @@ 
     {
       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)
+	{
+	  tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (tok->u.value);
+	  suffix = xstrdup (IDENTIFIER_POINTER (suffix_id));
+	  have_suffix_p = 1;
+	  tok->type = cpp_userdef_string_remove_type (tok->type);
+	}
+
       strs = &str;
     }
   else
@@ -3105,9 +3149,26 @@ 
 	{
 	  cp_lexer_consume_token (parser->lexer);
 	  count++;
-	  str.text = (const unsigned char *)TREE_STRING_POINTER (tok->u.value);
-	  str.len = TREE_STRING_LENGTH (tok->u.value);
+	  str.text = (const unsigned char *)TREE_STRING_POINTER (string_tree);
+	  str.len = TREE_STRING_LENGTH (string_tree);
 
+	  if (curr_tok_is_userdef_p)
+	    {
+	      tree suffix_id = USERDEF_LITERAL_SUFFIX_ID (tok->u.value);
+	      const char *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)
+		{
+		  error ("inconsistent user-defined literal suffixes");
+		  have_suffix_p = -1;
+		}
+	      tok->type = cpp_userdef_string_remove_type (tok->type);
+	    }
+
 	  if (type != tok->type)
 	    {
 	      if (type == CPP_STRING)
@@ -3121,6 +3182,17 @@ 
 	  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);
+	      tok->type = cpp_userdef_string_remove_type (tok->type);
+	      curr_tok_is_userdef_p = true;
+	    }
+	  else
+	    {
+	      string_tree = tok->u.value;
+	      curr_tok_is_userdef_p = false;
+	    }
 	}
       while (cp_parser_is_string_literal (tok));
 
@@ -3158,6 +3230,15 @@ 
 	}
 
       value = fix_string_type (value);
+
+      if (have_suffix_p)
+	{
+	  tree literal = build_userdef_literal ();
+	  USERDEF_LITERAL_SUFFIX_ID (literal) = get_identifier (suffix);
+	  USERDEF_LITERAL_VALUE (literal) = value;
+	  tok->u.value = literal;
+	  return cp_parser_userdef_string_literal (parser, tok);
+	}
     }
   else
     /* cpp_interpret_string has issued an error.  */
@@ -3169,7 +3250,257 @@ 
   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.  */
+  decl = cp_parser_lookup_name (parser, name,
+				none_type,
+				/*is_template=*/false,
+				/*is_namespace=*/false,
+				/*check_dependency=*/true,
+				/*ambig_decls=*/NULL,
+				token->location);
+  if (decl == error_mark_node)
+    {
+      error ("unable to find user-defined literal operator declaration");
+      return error_mark_node;
+    }
+  vec = make_tree_vector ();
+  VEC_safe_push (tree, gc, vec, value);
+  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 cast
+   a number as a string.  */
+static tree
+make_numeric_string(tree value)
+{
+  const int len = 1024;
+  char *str = XNEWVEC (char, len);
+  tree newval = error_mark_node;
+  /* Cast VALUE as a string.  */
+  if (TREE_CODE (value) == INTEGER_CST)
+    {
+      HOST_WIDEST_INT i = TREE_INT_CST_LOW (value);
+      snprintf (str, len, HOST_WIDEST_INT_PRINT_DEC, i);
+      newval = build_string (strlen (str), str);
+    }
+  else if (TREE_CODE (value) == REAL_CST)
+    {
+      unsigned int num_digs = 2 + __LDBL_MANT_DIG__ * 643L / 2136;
+      REAL_VALUE_TYPE d;
+      d = TREE_REAL_CST (value);
+      real_to_decimal (str, &d, len,
+		       /*digits=*/num_digs,
+		       /*crop_trailing_zeros=*/1);
+      newval = build_string (strlen (str), str);
+    }
+  else
+    gcc_unreachable ();
+
+  TREE_TYPE (newval) = char_array_type_node;
+  return newval;
+}
+
+/**/
+static tree
+make_char_string_pack (const char* str)
+{
+  tree parmvec;
+  tree parmtypevec;
+  tree argpack = make_node (NONTYPE_ARGUMENT_PACK);
+  tree argtypepack = cxx_make_type (TYPE_ARGUMENT_PACK);
+  int i, len = strlen (str);
+  /*  Do I need to stuff THIS into a tree?
+  tree argvec = make_tree_vec (1); */
+
+  /* Fill in PARMVEC and PARMTYPEVEC with all of the parameters.  */
+  parmvec = make_tree_vec (len);
+  parmtypevec = make_tree_vec (len);
+  for (i = 0; i < len; ++i)
+    {
+      TREE_VEC_ELT (parmvec, i) = build_int_cst (char_type_node, str[i]);
+      TREE_VEC_ELT (parmtypevec, i) = char_type_node;
+    }
+
+  /* Build the argument packs.  */
+  SET_ARGUMENT_PACK_ARGS (argpack, parmvec);
+  SET_ARGUMENT_PACK_ARGS (argtypepack, parmtypevec);
+  TREE_TYPE (argpack) = argtypepack;
+
+  /*  Do I need to stuff THIS into a tree?
+  TREE_VEC_ELT (argvec, 0) = argpack;
+  return argvec; */
+
+  return argpack;
+}
+
+/* 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;
+  tree name, decl;
+  tree result = error_mark_node;
+  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.  */
+  decl = cp_parser_lookup_name (parser, name,
+				none_type,
+				/*is_template=*/false,
+				/*is_namespace=*/false,
+				/*check_dependency=*/true,
+				/*ambig_decls=*/NULL,
+				token->location);
+  if (decl == error_mark_node)
+    {
+      error ("unable to find user-defined literal operator declaration");
+      return error_mark_node;
+    }
+  else
+    {
+      /*  Try to find the literal operator by finishing the call expression
+	  with the numeric argument.  */
+      vec = make_tree_vector ();
+      VEC_safe_push (tree, gc, vec, value);
+      result = finish_call_expr (decl, &vec, false, true, tf_none);
+      release_tree_vector (vec);
+
+      if (result == error_mark_node)
+	{
+	  /* 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.  */
+	  vec = make_tree_vector ();
+	  value = make_numeric_string (value);
+	  VEC_safe_push (tree, gc, vec, value);
+	  result = finish_call_expr (decl, &vec, false, true, tf_none);
+	  release_tree_vector (vec);
+	}
+
+      if (result == error_mark_node)
+	{
+	  /* 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.  */
+	  decl = cp_parser_lookup_name (parser, name,
+					none_type,
+					/*is_template=*/true,
+					/*is_namespace=*/false,
+					/*check_dependency=*/true,
+					/*ambig_decls=*/NULL,
+					token->location);
+	  if (TREE_CODE (decl) == OVERLOAD
+	      || TREE_CODE (decl) == TEMPLATE_DECL
+              || TREE_CODE (decl) == TEMPLATE_ID_EXPR)
+	    {
+	      tree parm = make_char_string_pack (TREE_STRING_POINTER (value));
+	      tree fn = NULL_TREE;
+
+	      /* The standard does not explicitly indicate whether a name that
+		 names a set of overloaded declarations, some of which are
+		 templates, is a template-name.  However, such a name should
+		 be a template-name; otherwise, there is no way to form a
+		 template-id for the overloaded templates.  */
+	      tree fns = BASELINK_P (decl) ? BASELINK_FUNCTIONS (decl) : decl;
+	      if (TREE_CODE (fns) == OVERLOAD)
+		for (fn = fns; fn; fn = OVL_NEXT (fn))
+		  if (TREE_CODE (OVL_CURRENT (fn)) == TEMPLATE_DECL)
+		    break;
+
+	      if (fn)
+		{
+		  TREE_TYPE (decl) = tsubst (TREE_TYPE (decl), parm, tf_warning_or_error, NULL_TREE);
+		  vec = make_tree_vector ();
+		  result = finish_call_expr (decl, &vec, false, true, tf_none);
+		  release_tree_vector (vec);
+		}
+	      else
+		{
+		  /* The name does not name a template.  */
+		  cp_parser_error (parser, "expected template-name");
+		  result = error_mark_node;
+		}
+	    }
+	}
+    }
+
+  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_parser *parser, 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.  */
+  decl = cp_parser_lookup_name (parser, name,
+				none_type,
+				/*is_template=*/false,
+				/*is_namespace=*/false,
+				/*check_dependency=*/true,
+				/*ambig_decls=*/NULL,
+				token->location);
+  if (decl == error_mark_node)
+    {
+      error ("unable to find user-defined literal operator declaration");
+      return error_mark_node;
+    }
+  vec = make_tree_vector ();
+  VEC_safe_push (tree, gc, vec, value);
+  VEC_safe_push (tree, gc, vec, build_int_cst (size_type_node, len));
+  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.
@@ -3309,12 +3640,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)
 	{
@@ -3368,11 +3703,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.  */
@@ -4803,7 +5149,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;
@@ -9270,7 +9616,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
@@ -10692,6 +11038,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:
@@ -10911,6 +11273,36 @@ 
       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] != '_')
+	    pedwarn (token->location, OPT_pedantic,
+		     "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;
@@ -22049,7 +22441,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/mangle.c
===================================================================
--- gcc/cp/mangle.c	(revision 172649)
+++ 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 *,
@@ -1162,6 +1163,8 @@ 
 	  }
       write_string (mangled_name);
     }
+  else if (UDLIT_OPER_P (identifier))
+    write_literal_operator_name (identifier);
   else
     write_source_name (identifier);
 }
@@ -1215,6 +1218,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;
 
@@ -1274,6 +1279,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 172649)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -395,7 +395,9 @@ 
   /* defaulted and deleted functions */
   CPP0X_DEFAULTED_DELETED,
   /* inline namespaces */
-  CPP0X_INLINE_NAMESPACES
+  CPP0X_INLINE_NAMESPACES,
+  /* user defined literals */
+  CPP0X_USER_DEFINED_LITERALS
 } cpp0x_warn_str;
   
 /* The various kinds of operation used by composite_pointer_type. */
@@ -4135,6 +4137,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 "__udlit"
+#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' \
@@ -5592,6 +5605,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: gcc/lto-streamer-out.c
===================================================================
--- gcc/lto-streamer-out.c	(revision 172649)
+++ gcc/lto-streamer-out.c	(working copy)
@@ -1,6 +1,6 @@ 
 /* Write the GIMPLE representation to a file stream.
 
-   Copyright 2009, 2010 Free Software Foundation, Inc.
+   Copyright 2009, 2010, 2011 Free Software Foundation, Inc.
    Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
    Re-implemented by Diego Novillo <dnovillo@google.com>
 
@@ -1145,6 +1145,15 @@ 
   lto_output_string (ob, ob->main_stream, TRANSLATION_UNIT_LANGUAGE (expr));
 }
 
+/* Write a TS_USERDEF_LITERAL tree in EXPR to OB.  */
+
+static void
+lto_output_ts_userdef_literal_tree_pointers (struct output_block *ob, tree expr)
+{
+  lto_output_tree (ob, USERDEF_LITERAL_SUFFIX_ID (expr), false);
+  lto_output_tree (ob, USERDEF_LITERAL_VALUE (expr), false);
+}
+
 /* Helper for lto_output_tree.  Write all pointer fields in EXPR to output
    block OB.  If REF_P is true, the leaves of EXPR are emitted as
    references.  */
@@ -1230,6 +1239,9 @@ 
 
   if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
     lto_output_ts_translation_unit_decl_tree_pointers (ob, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_USERDEF_LITERAL))
+    lto_output_ts_userdef_literal_tree_pointers (ob, expr);
 }
 
 
Index: gcc/treestruct.def
===================================================================
--- gcc/treestruct.def	(revision 172649)
+++ gcc/treestruct.def	(working copy)
@@ -66,3 +66,4 @@ 
 DEFTREESTRUCT(TS_OMP_CLAUSE, "omp clause")
 DEFTREESTRUCT(TS_OPTIMIZATION, "optimization options")
 DEFTREESTRUCT(TS_TARGET_OPTION, "target options")
+DEFTREESTRUCT(TS_USERDEF_LITERAL, "user defined literal")
Index: gcc/lto-streamer-in.c
===================================================================
--- gcc/lto-streamer-in.c	(revision 172649)
+++ gcc/lto-streamer-in.c	(working copy)
@@ -1,6 +1,6 @@ 
 /* Read the GIMPLE representation from a file stream.
 
-   Copyright 2009, 2010 Free Software Foundation, Inc.
+   Copyright 2009, 2010, 2011 Free Software Foundation, Inc.
    Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
    Re-implemented by Diego Novillo <dnovillo@google.com>
 
@@ -2328,6 +2328,16 @@ 
   VEC_safe_push (tree, gc, all_translation_units, expr);
 }
 
+/* Input a TS_USERDEF_LITERAL tree from IB to DATA_IN into EXPR.  */
+
+static void
+lto_input_ts_userdef_literal_tree_pointers (struct lto_input_block *ib,
+					    struct data_in *data_in, tree expr)
+{
+  USERDEF_LITERAL_SUFFIX_ID (expr) = lto_input_tree (ib, data_in);
+  USERDEF_LITERAL_VALUE (expr) = lto_input_tree (ib, data_in);
+}
+
 /* Helper for lto_input_tree.  Read all pointer fields in EXPR from
    input block IB.  DATA_IN contains tables and descriptors for the
    file being read.  */
@@ -2416,6 +2426,9 @@ 
 
   if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
     lto_input_ts_translation_unit_decl_tree_pointers (ib, data_in, expr);
+
+  if (CODE_CONTAINS_STRUCT (code, TS_USERDEF_LITERAL))
+    lto_input_ts_userdef_literal_tree_pointers (ib, data_in, expr);
 }
 
 
Index: gcc/tree.def
===================================================================
--- gcc/tree.def	(revision 172649)
+++ gcc/tree.def	(working copy)
@@ -1160,6 +1160,10 @@ 
 /* TARGET_OPTION_NODE.  Node to store the target specific options.  */
 DEFTREECODE (TARGET_OPTION_NODE, "target_option_node", tcc_exceptional, 0)
 
+/* Used to represent a user-defined literal.
+   The operands are an IDENTIFIER for the suffix and the VALUE of the literal.  */
+DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 2)
+
 /*
 Local variables:
 mode:c
Index: gcc/lto-streamer.c
===================================================================
--- gcc/lto-streamer.c	(revision 172649)
+++ gcc/lto-streamer.c	(working copy)
@@ -1,7 +1,7 @@ 
 /* Miscellaneous utilities for GIMPLE streaming.  Things that are used
    in both input and output are here.
 
-   Copyright 2009, 2010 Free Software Foundation, Inc.
+   Copyright 2009, 2010, 2011 Free Software Foundation, Inc.
    Contributed by Doug Kwan <dougkwan@google.com>
 
 This file is part of GCC.
@@ -305,6 +305,7 @@ 
   handled_p[TS_OPTIMIZATION] = true;
   handled_p[TS_TARGET_OPTION] = true;
   handled_p[TS_TRANSLATION_UNIT_DECL] = true;
+  handled_p[TS_USERDEF_LITERAL] = true;
 
   /* Anything not marked above will trigger the following assertion.
      If this assertion triggers, it means that there is a new TS_*
Index: libcpp/include/cpplib.h
===================================================================
--- libcpp/include/cpplib.h	(revision 172649)
+++ libcpp/include/cpplib.h	(working copy)
@@ -1,6 +1,6 @@ 
 /* Definitions for CPP library.
    Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005, 2007, 2008, 2009, 2010
+   2004, 2005, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Written by Per Bothner, 1994-95.
 
@@ -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.  */			\
@@ -813,10 +823,19 @@ 
 #define CPP_N_FRACT	0x100000 /* Fract types.  */
 #define CPP_N_ACCUM	0x200000 /* Accum types.  */
 
+#define CPP_N_USERDEF	0x1000000 /* C++0x user-defned literal.  */
+
 /* Classify a CPP_NUMBER token.  The return value is a combination of
    the flags from the above sets.  */
-extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *);
+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 *,
 				      unsigned int type);
@@ -985,4 +1004,20 @@ 
 extern int cpp_read_state (cpp_reader *, const char *, FILE *,
 			   struct save_macro_data *);
 
+/* 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, char *);
+
 #endif /* ! LIBCPP_CPPLIB_H */
Index: libcpp/expr.c
===================================================================
--- libcpp/expr.c	(revision 172649)
+++ 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,139 @@ 
 	     : (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, 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';
+}
+
 /* 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,
+		     char **ud_suffix)
 {
   const uchar *str = token->val.str.text;
   const uchar *limit;
@@ -231,6 +366,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 +499,20 @@ 
       result = interpret_float_suffix (str, limit - str);
       if (result == 0)
 	{
-	  cpp_error (pfile, CPP_DL_ERROR,
-		     "invalid suffix \"%.*s\" on floating constant",
-		     (int) (limit - str), str);
-	  return CPP_N_INVALID;
+	  if (CPP_OPTION (pfile, lang) == CLK_CXX0X
+	   || CPP_OPTION (pfile, lang) == CLK_GNUCXX0X)
+	    {
+	      if (ud_suffix)
+		*ud_suffix = xstrdup ((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 +554,20 @@ 
       result = interpret_int_suffix (str, limit - str);
       if (result == 0)
 	{
-	  cpp_error (pfile, CPP_DL_ERROR,
-		     "invalid suffix \"%.*s\" on integer constant",
-		     (int) (limit - str), str);
-	  return CPP_N_INVALID;
+	  if (CPP_OPTION (pfile, lang) == CLK_CXX0X
+	   || CPP_OPTION (pfile, lang) == CLK_GNUCXX0X)
+	    {
+	      if (ud_suffix)
+		*ud_suffix = xstrdup ((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 +906,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 172649)
+++ libcpp/lex.c	(working copy)
@@ -1226,6 +1226,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
@@ -1483,6 +1484,22 @@ 
     cpp_error_with_line (pfile, CPP_DL_WARNING, saw_NUL, 0,
 	       "null character(s) preserved in literal");
 
+  if (CPP_OPTION(pfile, lang) == CLK_CXX0X
+   || CPP_OPTION(pfile, lang) == CLK_GNUCXX0X)
+    {
+      /* 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);
@@ -1586,6 +1603,22 @@ 
     cpp_error (pfile, CPP_DL_PEDWARN, "missing terminating %c character",
 	       (int) terminator);
 
+  if (CPP_OPTION(pfile, lang) == CLK_CXX0X
+   || CPP_OPTION(pfile, lang) == CLK_GNUCXX0X)
+    {
+      /* 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);
 }