diff mbox

[C++-11] User defined literals

Message ID 4E8C7DF0.9030809@verizon.net
State New
Headers show

Commit Message

Ed Smith-Rowland Oct. 5, 2011, 3:55 p.m. UTC
On 09/20/2011 04:15 PM, Jason Merrill wrote:
> On 09/19/2011 10:07 PM, Ed Smith-Rowland wrote:
>> On 09/19/2011 05:11 PM, Jason Merrill wrote:
>>> Can't you store the string and the suffix, and then interpret the
>>> number later if you end up calling an operator that takes the value?
>
>> I could and I thought abut it but from the wording (2.14.8 p3 and p4) it
>> looks like the numeric argument gets first try, then raw literal then
>> literal template. I thought I might as well let the preprocessor do the
>> numeric conversion since I'll always check it first.
>
> Fair enough.  We could do the overload resolution before we produce 
> the actual value to be passed, but I guess that's probably not a 
> sufficient optmization to bother with.
>
>> +       error ("user-defined literal operator template %q+D"
>> +              " conflicts with user-defined raw literal operator %q+D",
>> +              newdecl, olddecl);
>
> You should only use + for one of the decls; that sets the source 
> position for the diagnostic.
>
>> +  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 
>> */      \
>
> Could we avoid adding all these additional codes by setting a flag on 
> the token?  It seems odd to have extra codes for char/string literals 
> but not for numbers.
>
>> +       const char *suffix;
>> +       cpp_get_userdef_suffix (tok->val.str, '\'', &suffix);
>
> Let's return the suffix pointer instead of passing in the address of a 
> local variable.  And pass in the token pointer rather than the string 
> and a delimiter; libcpp can figure out which delimiter to use based on 
> the token type.  It could also handle the flag I suggested above so 
> that the front end doesn't need to know about it.
>
> Jason
>
Here is another iteration of the patch.

I tried getting rid of all the codes.
1.  I couldn't even bootstrap the result.
2.  I sort of like the codes - these really are different sort of tokens 
- strings with suffixes.
3.  One could argue that then I should have a CPP_NUMBER_USERDEF token.  
I'm mixed.  On one hand this would be more consistent.  On the other, 
suffixed numbers are an old tried and true token.  This last is why the 
treatment of numbers was different from strings and chars.

I finally figured out template operators.  They work now.

One thing doesn't work.  Earlier I had said that friend declarations 
failed.  Not true.  What fails is defining the function body in the 
class definition.  The function is simply not recorded.  I'm trying to 
track this down but pointers would be helpful.  If I write the function 
body outside the class definition friend works perfectly.

About friends.  The lookup for user-defined literal operators isn't 
ADL.  They are a lot like normal functions because of the suffix-id as 
opposed to operator<< in this regard.  Thus a friend literal operator 
should be accessible both as an explicit operator call and via a 
literal.  Both are tested and except as noted above about inline defs 
the tests pass.

I have some repeated error messages I would like to clean up.  I want 
the missing underscore warning to appear only once.  Again, pointers 
would be helpful.

Basically, the thing works.

Thank you,

Ed

Comments

Jason Merrill Oct. 5, 2011, 9:08 p.m. UTC | #1
On 10/05/2011 11:55 AM, Ed Smith-Rowland wrote:
> +         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);

This is backwards; you want to do INNERMOST_TEMPLATE_PARMS before 
looking at the number of parms or pulling out the one at index 0.

> +struct GTY(()) tree_userdef_literal {
> +  struct tree_common common;

I think you can use tree_base instead of tree_common here, since you 
aren't using TREE_TYPE or TREE_CHAIN.

> One thing doesn't work.  Earlier I had said that friend declarations failed.  Not true.  What fails is defining the function body in the class definition.  The function is simply not recorded.  I'm trying to track this down but pointers would be helpful.  If I write the function body outside the class definition friend works perfectly.

> About friends.  The lookup for user-defined literal operators isn't ADL.  They are a lot like normal functions because of the suffix-id as opposed to operator<< in this regard.  Thus a friend literal operator should be accessible both as an explicit operator call and via a literal.  Both are tested and except as noted above about inline defs the tests pass.

A function that is only declared in a friend declaration can only be 
found by ADL, so that doesn't sound like a failure to me; it sounds like 
it's working the way it should.  However, if you declare the function 
earlier and then define it in the friend declaration it ought to work.

Jason
diff mbox

Patch

Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 179328)
+++ gcc/c-family/c-common.c	(working copy)
@@ -9919,4 +9919,17 @@ 
   MARK_TS_TYPED (EXCESS_PRECISION_EXPR);
 }
 
+/* Build a user-defined numeric literal out of an integer constant type VALUE
+   with identifier SUFFIX.  */
+
+tree
+build_userdef_literal (tree suffix_id, tree value, tree num_string)
+{
+  tree literal = make_node (USERDEF_LITERAL);
+  USERDEF_LITERAL_SUFFIX_ID (literal) = suffix_id;
+  USERDEF_LITERAL_VALUE (literal) = value;
+  USERDEF_LITERAL_NUM_STRING (literal) = num_string;
+  return literal;
+}
+
 #include "gt-c-family-c-common.h"
Index: gcc/c-family/c-lex.c
===================================================================
--- gcc/c-family/c-lex.c	(revision 179328)
+++ 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.h
===================================================================
--- gcc/c-family/c-common.h	(revision 179328)
+++ gcc/c-family/c-common.h	(working copy)
@@ -1067,4 +1067,27 @@ 
   return NULL;
 }
 
+/* A suffix-identifier value doublet that represents user-defined literals
+   for C++-0x.  */
+struct GTY(()) tree_userdef_literal {
+  struct tree_common common;
+  tree suffix_id;
+  tree value;
+  tree num_string;
+};
+
+#define USERDEF_LITERAL_SUFFIX_ID(NODE) \
+  (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->suffix_id)
+
+#define USERDEF_LITERAL_VALUE(NODE) \
+  (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->value)
+
+#define USERDEF_LITERAL_NUM_STRING(NODE) \
+  (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->num_string)
+
+#define USERDEF_LITERAL_TYPE(NODE) \
+  (TREE_TYPE (USERDEF_LITERAL_VALUE (NODE)))
+
+extern tree build_userdef_literal (tree suffix_id, tree value, tree num_string);
+
 #endif /* ! GCC_C_COMMON_H */
Index: gcc/c-family/c-common.def
===================================================================
--- gcc/c-family/c-common.def	(revision 179328)
+++ 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,29 @@ 
+// { 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 "user-defined literal operator template|conflicts with user-defined raw literal operator"}
+  {
+    return 13;
+  }
+
+template<char...>
+  int
+  operator"" _def()
+  {
+    return 12;
+  }
+
+int
+operator"" _def(const char*) // {dg-error "user-defined raw literal operator|conflicts with user-defined literal operator template"}
+  {
+    return 43;
+  }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C	(revision 0)
@@ -0,0 +1,43 @@ 
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+// Test user-defined literals.
+// Test simple operator declaration and definition in namespaces.
+
+#include <cmath>
+#include <limits>
+
+namespace Long
+{
+  long double operator"" _LL(long double);
+}
+
+namespace Short
+{
+  short
+  operator"" _SS(long double x)
+  { return std::fmod(x, static_cast<long double>(std::numeric_limits<short>::max())); }
+}
+
+void
+test1()
+{
+  long double x = Long::operator "" _LL(1.2L);
+
+  using namespace Short;
+  short s = operator"" _SS(1.2L);
+  short s2 = 1.2_SS;
+}
+
+int
+main()
+{
+  test1();
+}
+
+namespace Long
+{
+  long double
+  operator"" _LL(long double x)
+  { return x + 2.0L; }
+}
Index: gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C	(revision 0)
@@ -0,0 +1,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,7 @@ 
+// { dg-options -std=c++0x }
+
+#include <string>
+
+std::string operator"" 5X(const char*, std::size_t);	// { dg-error "expected suffix identifier" }
+
+// { dg-error "expected type-specifier before string constant" "" { target *-*-* } 5 }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C	(revision 0)
@@ -0,0 +1,7 @@ 
+// { dg-options -std=c++0x }
+
+constexpr unsigned long long
+operator"" _grow(unsigned long long n)
+{ return 2 * n; }
+
+double buffer[25_grow];
Index: gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C	(revision 0)
@@ -0,0 +1,49 @@ 
+// { dg-options -std=c++0x }
+
+//  Test that the standard suffixes shadow any user-defined suffixes of the same name.
+long double
+operator"" L(long double x)	// { dg-warning "floating point suffix shadowed by implementation" }
+{ return x; }
+
+unsigned long long int
+operator"" ULL(unsigned long long int k)	// { dg-warning "integer suffix shadowed by implementation" }
+{ return k; }
+
+long double
+operator"" l(long double x)	// { dg-warning "floating point suffix shadowed by implementation" }
+{ return x; }
+
+unsigned long long int
+operator"" ull(unsigned long long int k)	// { dg-warning "integer suffix shadowed by implementation" }
+{ return k; }
+
+//  Namespaces are no hiding place.
+namespace Long
+{
+
+long double
+operator"" L(long double x)	// { dg-warning "integer suffix shadowed by implementation" }
+{ return x; }
+
+unsigned long long int
+operator"" ULL(unsigned long long int k)	// { dg-warning "integer suffix shadowed by implementation" }
+{ return k; }
+
+long double
+operator"" l(long double x)	// { dg-warning "integer suffix shadowed by implementation" }
+{ return x; }
+
+unsigned long long int
+operator"" ull(unsigned long long int k)	// { dg-warning "integer suffix shadowed by implementation" }
+{ return k; }
+
+}
+
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 5 }
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 9 }
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 13 }
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 17 }
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 25 }
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 29 }
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 33 }
+// { dg-warning "suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 37 }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-nounder-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-nounder-neg.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-nounder-neg.C	(revision 0)
@@ -0,0 +1,6 @@ 
+// { dg-options "-std=c++0x" }
+
+// Test user-defined literals.
+// Test warning on declaration without leading underscore.
+
+long double operator"" nounder(long double); // { dg-warning "suffixes not preceded by|are reserved for future standardization" }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C	(revision 0)
@@ -0,0 +1,6 @@ 
+// { dg-options -std=c++0x }
+
+class Foo { };
+
+template<wchar_t...>
+  Foo operator"" _Foo(); // { dg-error "user-defined 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-inline-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-inline-neg.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-inline-neg.C	(revision 0)
@@ -0,0 +1,17 @@ 
+// { dg-options -std=c++0x }
+
+//  Make sure inline literal operator definition in class issn't accepted.
+
+class Foo
+{
+  int
+  operator"" _thing(char cc)
+  { return 42 * cc; }
+};
+
+int
+main()
+{
+  int iF = Foo::operator"" _thing('x');
+  int jF = 'x'_thing;
+}
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,7 @@ 
+// { dg-options -std=c++0x }
+
+char32_t
+operator"" (char32_t C)	// { dg-error "expected suffix identifier" }
+{ return C; }
+
+// { dg-error "expected type-specifier before string constant" "" { target *-*-* } 4 }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C	(revision 0)
@@ -0,0 +1,6 @@ 
+// { dg-options "-std=c++0x" }
+
+// Test user-defined literals.
+// Test error on non-empty string after 'operator' keyword.
+
+double operator"hi" _badword(long double); // { dg-error "expected empty string after" }
Index: gcc/testsuite/g++.dg/cpp0x/udlit-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,20 @@ 
+// { dg-options "-std=c++0x" }
+
+//  Literal operators can be inline.
+
+inline int
+operator"" _thing1(char cc)
+{ return 42 * 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,16 @@ 
+// { dg-options -std=c++0x }
+
+class Foo
+{
+public:
+  Foo() { }
+  friend Foo operator"" _Bar(char);
+};
+
+Foo
+operator"" _Bar(char)
+{ return Foo(); }
+
+Foo f1 = operator"" _Bar('x');
+
+Foo f2 = '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 179328)
+++ gcc/cp/typeck.c	(working copy)
@@ -8334,3 +8334,94 @@ 
   return 1;
 }
 
+
+/* Return true if a user-defined literal operator has one of the allowed
+   argument types.  */
+
+bool
+check_literal_operator_args (const_tree decl,
+			     bool *long_long_unsigned_p, bool *long_double_p)
+{
+  tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
+  if (processing_template_decl)
+    return (argtypes == NULL_TREE
+	    || same_type_p (TREE_VALUE (argtypes), void_type_node));
+  else
+    {
+      tree argtype;
+      int arity;
+      int max_arity = 2;
+      bool found_string_p = false;
+      bool maybe_raw_p = false;
+      bool found_size_p = false;
+      tree const_char_ptr_type_node
+	   = build_pointer_type(build_type_variant(char_type_node, 1, 0));
+      tree const_wchar_ptr_type_node
+	   = build_pointer_type(build_type_variant(wchar_type_node, 1, 0));
+      tree const_char16_ptr_type_node
+	   = build_pointer_type(build_type_variant(char16_type_node, 1, 0));
+      tree const_char32_ptr_type_node
+	   = build_pointer_type(build_type_variant(char32_type_node, 1, 0));
+
+      *long_long_unsigned_p = false;
+      *long_double_p = false;
+
+      /* Count the number and type of arguments and check for ellipsis.  */
+      for (argtype = argtypes, arity = 0;
+	   argtype && argtype != void_list_node;
+	   argtype = TREE_CHAIN (argtype))
+	{
+	  tree t = TREE_VALUE (argtype);
+	  ++arity;
+
+	  if (same_type_p (t, const_char_ptr_type_node))
+	    {
+	      found_string_p = true;
+	      maybe_raw_p = true;
+	    }
+	  else if (same_type_p (t, const_wchar_ptr_type_node))
+	    found_string_p = true;
+	  else if (same_type_p (t, const_char16_ptr_type_node))
+	    found_string_p = true;
+	  else if (same_type_p (t, const_char32_ptr_type_node))
+	    found_string_p = true;
+	  else if (same_type_p (t, size_type_node))
+	    {
+	      if (!found_string_p)
+		return false;
+	      found_size_p = true;
+	    }
+	  else if (same_type_p (t, long_long_unsigned_type_node))
+	    {
+	      max_arity = 1;
+	      *long_long_unsigned_p = true;
+	    }
+	  else if (same_type_p (t, long_double_type_node))
+	    {
+	      max_arity = 1;
+	      *long_double_p = true;
+	    }
+	  else if (same_type_p (t, char_type_node))
+	    max_arity = 1;
+	  else if (same_type_p (t, wchar_type_node))
+	    max_arity = 1;
+	  else if (same_type_p (t, char16_type_node))
+	    max_arity = 1;
+	  else if (same_type_p (t, char32_type_node))
+	    max_arity = 1;
+	  else
+	    return false;
+	}
+      if (!argtype)
+	return false; /* Found ellipsis.  */
+
+      if (arity > max_arity)
+	return false;
+
+      if (found_string_p && !maybe_raw_p && !found_size_p)
+	return false;
+
+      return true;
+    }
+}
+
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 179328)
+++ 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)
+	error ("user-defined literal operator template %q+D"
+	       " conflicts with user-defined raw literal operator %qD",
+	       newdecl, olddecl);
+      else if (TREE_CODE (newdecl) != TEMPLATE_DECL
+	       && TREE_CODE (olddecl) == TEMPLATE_DECL)
+	error ("user-defined raw literal operator %q+D"
+	       " conflicts with user-defined literal operator template %qD",
+	       newdecl, olddecl);
+    }
+
   if (DECL_P (olddecl)
       && TREE_CODE (newdecl) == FUNCTION_DECL
       && TREE_CODE (olddecl) == FUNCTION_DECL
@@ -7333,7 +7348,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.  */
@@ -8518,6 +8574,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))
     {
@@ -13734,6 +13799,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 179328)
+++ 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.  */
@@ -3231,7 +3237,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) "
@@ -3242,8 +3248,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 179328)
+++ gcc/cp/cxx-pretty-print.c	(working copy)
@@ -367,6 +367,17 @@ 
     pp_cxx_unqualified_id (pp, t);
 }
 
+/* user-defined literal:
+      literal ud-suffix  */
+
+void
+pp_cxx_userdef_literal (cxx_pretty_printer *pp, tree t)
+{
+  pp_cxx_constant (pp, USERDEF_LITERAL_VALUE (t));
+  pp_cxx_id_expression (pp, USERDEF_LITERAL_SUFFIX_ID (t));
+}
+
+
 /* primary-expression:
      literal
      this
@@ -413,6 +424,10 @@ 
       pp_cxx_constant (pp, t);
       break;
 
+    case USERDEF_LITERAL:
+      pp_cxx_userdef_literal (pp, t);
+      break;
+
     case BASELINK:
       t = BASELINK_FUNCTIONS (t);
     case VAR_DECL:
@@ -1023,6 +1038,10 @@ 
       pp_cxx_constant (pp, t);
       break;
 
+    case USERDEF_LITERAL:
+      pp_cxx_userdef_literal (pp, t);
+      break;
+
     case RESULT_DECL:
       pp_cxx_unqualified_id (pp, t);
       break;
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(revision 179328)
+++ gcc/cp/semantics.c	(working copy)
@@ -7748,6 +7748,7 @@ 
     case TEMPLATE_PARM_INDEX:
     case TRAIT_EXPR:
     case IDENTIFIER_NODE:
+    case USERDEF_LITERAL:
       /* We can see a FIELD_DECL in a pointer-to-member expression.  */
     case FIELD_DECL:
     case PARM_DECL:
Index: gcc/cp/cxx-pretty-print.h
===================================================================
--- gcc/cp/cxx-pretty-print.h	(revision 179328)
+++ 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 179328)
+++ gcc/cp/parser.c	(working copy)
@@ -210,6 +210,8 @@ 
   (cp_lexer *);
 static void cp_lexer_rollback_tokens
   (cp_lexer *);
+static tree cp_literal_operator_id
+  (const char *);
 #ifdef ENABLE_CHECKING
 static void cp_lexer_print_token
   (FILE *, cp_token *);
@@ -501,20 +503,20 @@ 
 	}
       else
 	{
-          if (warn_cxx0x_compat
-              && C_RID_CODE (token->u.value) >= RID_FIRST_CXX0X
-              && C_RID_CODE (token->u.value) <= RID_LAST_CXX0X)
-            {
-              /* Warn about the C++0x keyword (but still treat it as
-                 an identifier).  */
-              warning (OPT_Wc__0x_compat, 
-                       "identifier %qE will become a keyword in C++0x",
-                       token->u.value);
+	  if (warn_cxx0x_compat
+	      && C_RID_CODE (token->u.value) >= RID_FIRST_CXX0X
+	      && C_RID_CODE (token->u.value) <= RID_LAST_CXX0X)
+	    {
+	      /* Warn about the C++0x keyword (but still treat it as
+		 an identifier).  */
+	      warning (OPT_Wc__0x_compat, 
+		       "identifier %qE will become a keyword in C++0x",
+		       token->u.value);
 
-              /* Clear out the C_RID_CODE so we don't warn about this
-                 particular identifier-turned-keyword again.  */
-              C_SET_RID_CODE (token->u.value, RID_MAX);
-            }
+	      /* Clear out the C_RID_CODE so we don't warn about this
+		 particular identifier-turned-keyword again.  */
+	      C_SET_RID_CODE (token->u.value, RID_MAX);
+	    }
 
 	  token->ambiguous_p = false;
 	  token->keyword = RID_MAX;
@@ -1531,6 +1533,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]  */
 
@@ -2039,6 +2047,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
@@ -2059,7 +2069,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 ||
@@ -2068,6 +2078,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
@@ -3107,7 +3131,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))
@@ -3116,7 +3144,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.  */
@@ -3125,10 +3164,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
@@ -3140,14 +3188,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");
@@ -3156,6 +3225,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));
 
@@ -3193,6 +3274,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.  */
@@ -3204,7 +3292,184 @@ 
   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;
+
+  /*  Do I need to stuff THIS into a tree? */
+  TREE_VEC_ELT (argvec, 0) = argpack;
+
+  return argvec;
+}
+
+/* Parse a user-defined numeric constant.  returns a call to a user-defined
+   literal operator.  */
+static tree
+cp_parser_userdef_numeric_literal (cp_parser *parser)
+{
+  cp_token *token = NULL;
+  tree literal, suffix_id, value, num_string;
+  tree name, decl;
+  tree result = error_mark_node;
+  VEC(tree,gc) *args;
+
+  token = cp_lexer_consume_token (parser->lexer);
+  literal = token->u.value;
+  suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+  value = USERDEF_LITERAL_VALUE (literal);
+  num_string = USERDEF_LITERAL_NUM_STRING (literal);
+  name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+
+  /* Build up a call to the user-defined operator  */
+  /* Lookup the name we got back from the id-expression.  */
+  /* Try to find the literal operator by finishing the call expression
+     with the numeric argument.  */
+  args = make_tree_vector ();
+  VEC_safe_push (tree, gc, args, value);
+  decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+  if (decl && 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_warning_or_error);
+  release_tree_vector (vec);
+
+  return result;
+}
+
+
 /* Basic concepts [gram.basic]  */
 
 /* Parse a translation-unit.
@@ -3347,12 +3612,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)
 	{
@@ -3406,11 +3675,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.  */
@@ -4888,7 +5168,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;
@@ -9471,7 +9751,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
@@ -10902,6 +11182,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:
@@ -11121,6 +11417,35 @@ 
       cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
       return ansi_opname (ARRAY_REF);
 
+    case CPP_STRING:
+      if (cxx_dialect == cxx98)
+	maybe_warn_cpp0x (CPP0X_USER_DEFINED_LITERALS);
+      if (TREE_STRING_LENGTH (token->u.value) > 2)
+	{
+	  error ("expected empty string after %<operator%> keyword");
+	  return error_mark_node;
+	}
+      /* Consume the string.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Look for an identifier.  */
+      id = cp_parser_identifier (parser);
+      if (id != error_mark_node)
+	{
+	  const char *name = IDENTIFIER_POINTER (id);
+
+	  /* 17.6.3.3.5  */
+	  if (name[0] != '_' && !in_system_header)
+	    warning (0, "suffixes not preceded by %<_%> "
+			"are reserved for future standardization");
+
+	  return cp_literal_operator_id(name);
+	}
+      else
+	{
+	  error ("expected suffix identifier");
+	  return error_mark_node;
+	}
+
     default:
       /* Anything else is an error.  */
       break;
@@ -20304,6 +20629,32 @@ 
   /* Finish up.  */
   finish_template_decl (parameter_list);
 
+  /* Check the template arguments for a user-defined 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 ("user-defined 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);
@@ -22605,7 +22956,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 179328)
+++ 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 179328)
+++ 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 179328)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -396,7 +396,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. */
@@ -727,6 +729,7 @@ 
   TS_CP_TRAIT_EXPR,
   TS_CP_LAMBDA_EXPR,
   TS_CP_TEMPLATE_INFO,
+  TS_CP_USERDEF_LITERAL,
   LAST_TS_CP_ENUM
 };
 
@@ -752,6 +755,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;
 };
 
 
@@ -4204,6 +4209,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' \
@@ -5728,6 +5744,7 @@ 
 extern int lvalue_or_else			(tree, enum lvalue_use,
                                                  tsubst_flags_t);
 extern void check_template_keyword		(tree);
+extern bool check_literal_operator_args		(const_tree, bool *, bool *);
 
 /* in typeck2.c */
 extern void require_complete_eh_spec_types	(tree, tree);
Index: libcpp/include/cpplib.h
===================================================================
--- libcpp/include/cpplib.h	(revision 179328)
+++ libcpp/include/cpplib.h	(working copy)
@@ -131,6 +131,16 @@ 
   TK(OBJC_STRING,	LITERAL) /* @"string" - Objective-C */		\
   TK(HEADER_NAME,	LITERAL) /* <stdio.h> in #include */		\
 									\
+  TK(CHAR_USERDEF,	LITERAL) /* 'char'_suffix - C++-0x */		\
+  TK(WCHAR_USERDEF,	LITERAL) /* L'char'_suffix - C++-0x */		\
+  TK(CHAR16_USERDEF,	LITERAL) /* u'char'_suffix - C++-0x */		\
+  TK(CHAR32_USERDEF,	LITERAL) /* U'char'_suffix - C++-0x */		\
+  TK(STRING_USERDEF,	LITERAL) /* "string"_suffix - C++-0x */		\
+  TK(WSTRING_USERDEF,	LITERAL) /* L"string"_suffix - C++-0x */	\
+  TK(STRING16_USERDEF,	LITERAL) /* u"string"_suffix - C++-0x */	\
+  TK(STRING32_USERDEF,	LITERAL) /* U"string"_suffix - C++-0x */	\
+  TK(UTF8STRING_USERDEF,LITERAL) /* u8"string"_suffix - C++-0x */	\
+									\
   TK(COMMENT,		LITERAL) /* Only if output comments.  */	\
 				 /* SPELL_LITERAL happens to DTRT.  */	\
   TK(MACRO_ARG,		NONE)	 /* Macro argument.  */			\
@@ -402,6 +412,9 @@ 
   /* True for traditional preprocessing.  */
   unsigned char traditional;
 
+  /* Nonzero for the 2011 C++ Standard.  */
+  unsigned char cxx11;
+
   /* Holds the name of the target (execution) character set.  */
   const char *narrow_charset;
 
@@ -817,13 +830,22 @@ 
 #define CPP_N_FRACT	0x100000 /* Fract types.  */
 #define CPP_N_ACCUM	0x200000 /* Accum types.  */
 
+#define CPP_N_USERDEF	0x1000000 /* C++0x user-defined literal.  */
+
 /* Classify a CPP_NUMBER token.  The return value is a combination of
    the flags from the above sets.  */
-extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *);
+extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *,
+				     const char **);
 
+/* Return the classification flags for a float suffix.  */
+extern unsigned int cpp_interpret_float_suffix (const char *, size_t);
+
+/* Return the classification flags for an int suffix.  */
+extern unsigned int cpp_interpret_int_suffix (const char *, size_t);
+
 /* Evaluate a token classified as category CPP_N_INTEGER.  */
 extern cpp_num cpp_interpret_integer (cpp_reader *, const cpp_token *,
-				      unsigned int type);
+				      unsigned int);
 
 /* Sign extend a number, with PRECISION significant bits and all
    others assumed clear, to fill out a cpp_num structure.  */
@@ -993,4 +1015,20 @@ 
 extern void cpp_force_token_locations (cpp_reader *, source_location *);
 extern void cpp_stop_forcing_token_locations (cpp_reader *);
 
+/* In expr.c */
+extern enum cpp_ttype cpp_userdef_string_remove_type
+  (enum cpp_ttype type);
+extern enum cpp_ttype cpp_userdef_string_add_type
+  (enum cpp_ttype type);
+extern enum cpp_ttype cpp_userdef_char_remove_type
+  (enum cpp_ttype type);
+extern enum cpp_ttype cpp_userdef_char_add_type
+  (enum cpp_ttype type);
+extern bool cpp_userdef_string_p
+  (enum cpp_ttype type);
+extern bool cpp_userdef_char_p
+  (enum cpp_ttype type);
+extern const char * cpp_get_userdef_suffix
+  (const cpp_token *);
+
 #endif /* ! LIBCPP_CPPLIB_H */
Index: libcpp/init.c
===================================================================
--- libcpp/init.c	(revision 179328)
+++ 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 179328)
+++ 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 179328)
+++ libcpp/lex.c	(working copy)
@@ -1227,6 +1227,7 @@ 
   token->type = type;
   token->val.str.len = len;
   token->val.str.text = dest;
+/*printf("\ntoken: %s", token->val.str.text);*/
 }
 
 /* Subroutine of lex_raw_string: Append LEN chars from BASE to the buffer
@@ -1478,6 +1479,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 +1594,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);
 }