Patchwork [C++0x] User-Defined Literals

login
register
mail settings
Submitter Ed Smith-Rowland
Date April 12, 2011, 2:04 a.m.
Message ID <4DA3B332.4090408@verizon.net>
Download mbox | patch
Permalink /patch/90691/
State New
Headers show

Comments

Ed Smith-Rowland - April 12, 2011, 2:04 a.m.
Greetings,

Here is a new patch for user-defined literals.
* New C preprocessor tokens are defined for numbers, chars, and strings 
with suffixes are defined.  They are lexed as complete tokens.
* The new tokens are passed through the C tokenized to the C++ tokenizer 
and parser and so on.
* There is a new tree code and structure for user defined literals.
* Char type literals are completely finished.
* String type literals are completely finished including concatenation, 
raw literals, etc.
* Numeric literals are *mostly* done (numeric argument operators and the 
raw literal operator (const char *) forms are supported.
* LTO serialization seems to work.  I'm storing the trees in my struct 
rather than refs.
* All the checks (except noted below) for arguments are made.
* All the checks I could find concerning scope and linkage are made.
* Like before I issue a warning if the user-defined suffix for numeric 
types is shadowed by our implementation
   which includes not only the usual standard ones but several 
extensions as well.
* You can't call the suffix as a function anymore (That was an error, 
I'm mangling to __udlit<suffix> now).

There are some issues:
* Friend operators don't work.  Literal operators can't be class members 
but they could be friends.
* The template numeric literals don't work:
    template<char...Char>
     X operator"" QQQ();
   - You *can* explicitly call the operator:
         cout << operator"" QQQ<'A','B','C'>();
   - The template parameters are *not* checked
   - The void argument is *not* checked.
* Someday, we'll want to move Objective-C++ strings into the C++ string 
lexer like it says in the notes.
    I think we'll want to do some minimal surprise thing like *not* 
allow @ strings to have suffixes.
    I can't see a reason someone can't return an @ string from a 
user-defined literal though.

I'm sure there are functional and aesthetic comments that people can make.

Have at it ;-)

Ed Smith-Rowland
Joseph S. Myers - April 12, 2011, 12:19 p.m.
On Mon, 11 Apr 2011, Ed Smith-Rowland wrote:

> +    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[256] = "";
> +	cpp_get_userdef_suffix (tok->val.str, '\'', suffix);

This fixed-length buffer appears to have a buffer overrun vulnerability; 
you must avoid such overruns in the presence of suffixes of arbitrary 
length (up to 2GB, anyway, so don't assume they are short enough to 
allocate on the stack; once you get past values representable in "int" 
there are lots of pre-existing problems including "int" being used for the 
length of a STRING_CST) unless there is some other reason long suffixes 
cannot occur.

> +    case CPP_STRING_USERDEF:
> +    case CPP_WSTRING_USERDEF:
> +    case CPP_STRING16_USERDEF:
> +    case CPP_STRING32_USERDEF:
> +    case CPP_UTF8STRING_USERDEF:
> +      {
> +	tree literal;
> +	char suffix[256] = "";
> +	cpp_get_userdef_suffix (tok->val.str, '"', suffix);

Likewise.

> +    copylen -= strlen(suffix);

Missing space before '('.  There are lots of other spacing problems in 
this patch - spaces missing before '(', or in casts, or spaces present 
where they shouldn't be.

> +  char suffix[256] = "", curr_suffix[256] = "";

More fixed-size buffers that need fixing.

> +	  /* 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.  */
> +	  char str[256] = "";

And yet more.

> +/* 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[256];

And more.

> +static void
> +write_literal_operator_name (tree identifier)
> +{
> +  tree suffix_id;
> +  char buffer[256];

And more.

> +  if (type == CPP_STRING_USERDEF )

And here you have lots of cases of excess space before ')'.

Patch

Index: gcc/c-family/c-lex.c
===================================================================
--- gcc/c-family/c-lex.c	(revision 172287)
+++ 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[256] = "";
+	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[256] = "";
+	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 172287)
+++ 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 ();
@@ -431,6 +432,7 @@ 
 	case TS_OMP_CLAUSE:
 	case TS_OPTIMIZATION:
 	case TS_TARGET_OPTION:
+	case TS_USERDEF_LITERAL:
 	  MARK_TS_COMMON (code);
 	  break;
 
@@ -727,6 +729,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);
 	}
@@ -1671,7 +1675,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 172287)
+++ gcc/tree.h	(working copy)
@@ -3497,6 +3497,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
@@ -3540,6 +3559,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-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-error "floating point suffix shadowed by implementation" }
+
+unsigned long long int
+operator"" ULL(unsigned long long int k)
+{ return k; }	// { dg-error "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 172287)
+++ gcc/cp/typeck.c	(working copy)
@@ -8262,3 +8262,33 @@ 
   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, int * type_index)
+{
+  const_tree type1 = decl;
+  const_tree args1 = TYPE_ARG_TYPES (type1);
+
+  if (!processing_template_decl)
+    {
+      int start = (int) CPTI_USERDEF_LIT_CHAR_PTR_TYPE;
+      int i;
+      for (i = 0; i < 11; ++i)
+	{
+	  const_tree type2 = cp_global_trees[start + i];
+	  const_tree args2 = TYPE_ARG_TYPES (type2);
+	  if (compparms (args1, args2))
+	    {
+	      *type_index = start + i;
+	      return true;
+	    }
+	}
+      return false;
+    }
+  else
+    return (args1 == NULL_TREE || TREE_VALUE (args1) == void_type_node);
+}
+
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 172287)
+++ gcc/cp/decl.c	(working copy)
@@ -3610,6 +3610,45 @@ 
     SET_TYPE_MODE (nullptr_type_node, Pmode);
     record_builtin_type (RID_MAX, "decltype(nullptr)", nullptr_type_node);
     nullptr_node = build_int_cst (nullptr_type_node, 0);
+{
+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));
+
+    userdef_lit_char_ptr_type
+     = build_function_type_list (void_type_node,
+				 const_char_ptr_type_node, NULL_TREE);
+
+    userdef_lit_ull_type
+     = build_function_type_list (void_type_node, long_long_unsigned_type_node,
+				 NULL_TREE);
+    userdef_lit_ldbl_type
+     = build_function_type_list (void_type_node, long_double_type_node,
+				 NULL_TREE);
+
+    userdef_lit_char_type
+     = build_function_type_list (void_type_node, char_type_node, NULL_TREE);
+    userdef_lit_wchar_type
+     = build_function_type_list (void_type_node, wchar_type_node, NULL_TREE);
+    userdef_lit_char16_type
+     = build_function_type_list (void_type_node, char16_type_node, NULL_TREE);
+    userdef_lit_char32_type
+     = build_function_type_list (void_type_node, char32_type_node, NULL_TREE);
+
+    userdef_lit_char_str_type
+     = build_function_type_list (void_type_node, const_char_ptr_type_node,
+				 size_type_node, NULL_TREE);
+    userdef_lit_wchar_str_type
+     = build_function_type_list (void_type_node, const_wchar_ptr_type_node,
+				 size_type_node, NULL_TREE);
+    userdef_lit_char16_str_type
+     = build_function_type_list (void_type_node, const_char16_ptr_type_node,
+				 size_type_node, NULL_TREE);
+    userdef_lit_char32_str_type
+     = build_function_type_list (void_type_node, const_char32_ptr_type_node,
+				 size_type_node, NULL_TREE);
+}
   }
 
   abort_fndecl
@@ -7121,7 +7160,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)))
+    {
+      int type_index = -1;
+      /* [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(TREE_TYPE (decl), &type_index))
+	    {
+	      error ("%qD has illegal argument list", decl);
+	      return NULL_TREE;
+	    }
+
+	  if (CP_DECL_CONTEXT (decl) == global_namespace)
+	    {
+	      const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
+	      char suffix[256] = "";
+              sscanf(name, UDLIT_OP_ANSI_FORMAT, suffix);
+	      if (type_index == CPTI_USERDEF_LIT_ULL_TYPE)
+		{
+		  if (cpp_interpret_int_suffix (suffix, strlen (suffix)))
+		    warning (0, "integer suffix shadowed by implementation");
+		}
+	      else if (type_index == CPTI_USERDEF_LIT_LDBL_TYPE)
+		{
+		  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.  */
@@ -8220,6 +8301,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 172287)
+++ 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,7 +3149,12 @@ 
 	pedwarn (input_location, OPT_pedantic,
 		 "inline namespaces "
 		 "only available with -std=c++0x or -std=gnu++0x");
-	break;	
+	break;
+      case CPP0X_USER_DEFINED_LITERALS:
+	pedwarn (input_location, 0,
+		 "user-defined literals "
+		 "only available with -std=c++0x or -std=gnu++0x");
+	break;
       default:
 	gcc_unreachable();
       }
Index: gcc/cp/operators.def
===================================================================
--- gcc/cp/operators.def	(revision 172287)
+++ 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 172287)
+++ 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 172287)
+++ gcc/cp/semantics.c	(working copy)
@@ -7367,6 +7367,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 172287)
+++ 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]  */
 
@@ -2000,6 +2008,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
@@ -2020,7 +2030,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 ||
@@ -2029,6 +2039,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
@@ -3069,6 +3093,10 @@ 
   cpp_string str, istr, *strs;
   cp_token *tok;
   enum cpp_ttype type;
+  char suffix[256] = "", curr_suffix[256] = "";
+  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))
@@ -3077,6 +3105,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
@@ -3086,10 +3122,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);
+	  strcpy (suffix, IDENTIFIER_POINTER (suffix_id));
+	  have_suffix_p = 1;
+	  tok->type = cpp_userdef_string_remove_type (tok->type);
+	}
+
       strs = &str;
     }
   else
@@ -3101,9 +3145,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);
+	      strcpy (curr_suffix, IDENTIFIER_POINTER (suffix_id));
+	      if (have_suffix_p == 0)
+		{
+		  strcpy(suffix, 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)
@@ -3117,6 +3178,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));
 
@@ -3154,6 +3226,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.  */
@@ -3165,7 +3246,166 @@ 
   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, ambig_decls;
+  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=*/&ambig_decls,
+        			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;
+}
+
+/* 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, ambig_decls;
+  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=*/&ambig_decls,
+        			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.  */
+	  char str[256] = "";
+	  tree newval = error_mark_node;
+	  vec = make_tree_vector ();
+	  /* Cast VALUE as a string.  */
+	  if (TREE_CODE (value) == INTEGER_CST)
+	    {
+	      HOST_WIDEST_INT i = TREE_INT_CST_LOW (value);
+	      sprintf (str, HOST_WIDEST_INT_PRINT_DEC, i);
+	      newval = build_string (strlen(str), str);
+	    }
+	  else if (TREE_CODE (value) == REAL_CST)
+	    {
+	      REAL_VALUE_TYPE d;
+	      d = TREE_REAL_CST (value);
+	      real_to_decimal (str, &d, 256,
+			       /*digits=*/18,
+			       /*crop_trailing_zeros=*/1); /* TODO: Get the right number of DIGITS! */
+	      newval = build_string (strlen(str), str);
+	    }
+	  else
+	    gcc_unreachable ();
+	  TREE_TYPE (newval) = char_array_type_node;
+	  VEC_safe_push (tree, gc, vec, newval);
+	  result = finish_call_expr (decl, &vec, false, true, tf_none);
+	  release_tree_vector (vec);
+	}
+    }
+
+  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, ambig_decls;
+  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=*/&ambig_decls,
+				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.
@@ -3305,12 +3545,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)
 	{
@@ -3364,11 +3608,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.  */
@@ -9181,7 +9436,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
@@ -10603,6 +10858,25 @@ 
   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[256];
+
+  sprintf (buffer, UDLIT_OP_ANSI_FORMAT, name);
+  identifier = get_identifier (buffer);
+  /*IDENTIFIER_UDLIT_OPNAME_P (identifier) = 1; If we get a flag someday. */
+
+  /* Add the suffix identifier.  */
+  TREE_CHAIN (identifier) = get_identifier (name);
+
+  return identifier;
+}
+
 /* Parse an operator.
 
    operator:
@@ -10822,6 +11096,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;
@@ -21946,7 +22250,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 172287)
+++ 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,23 @@ 
   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)
+{
+  tree suffix_id;
+  char buffer[256];
+  const char* suffix;
+  suffix_id = TREE_CHAIN (identifier);
+  suffix = IDENTIFIER_POINTER (suffix_id);
+  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 172287)
+++ 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. */
@@ -794,6 +796,18 @@ 
     CPTI_NULLPTR,
     CPTI_NULLPTR_TYPE,
 
+    CPTI_USERDEF_LIT_CHAR_PTR_TYPE,
+    CPTI_USERDEF_LIT_ULL_TYPE,
+    CPTI_USERDEF_LIT_LDBL_TYPE,
+    CPTI_USERDEF_LIT_CHAR_TYPE,
+    CPTI_USERDEF_LIT_WCHAR_TYPE,
+    CPTI_USERDEF_LIT_CHAR16_TYPE,
+    CPTI_USERDEF_LIT_CHAR32_TYPE,
+    CPTI_USERDEF_LIT_CHAR_STR_TYPE,
+    CPTI_USERDEF_LIT_WCHAR_STR_TYPE,
+    CPTI_USERDEF_LIT_CHAR16_STR_TYPE,
+    CPTI_USERDEF_LIT_CHAR32_STR_TYPE,
+
     CPTI_MAX
 };
 
@@ -831,6 +845,18 @@ 
 #define nullptr_node			cp_global_trees[CPTI_NULLPTR]
 #define nullptr_type_node		cp_global_trees[CPTI_NULLPTR_TYPE]
 
+#define userdef_lit_char_ptr_type	cp_global_trees[CPTI_USERDEF_LIT_CHAR_PTR_TYPE]
+#define userdef_lit_ull_type		cp_global_trees[CPTI_USERDEF_LIT_ULL_TYPE]
+#define userdef_lit_ldbl_type		cp_global_trees[CPTI_USERDEF_LIT_LDBL_TYPE]
+#define userdef_lit_char_type		cp_global_trees[CPTI_USERDEF_LIT_CHAR_TYPE]
+#define userdef_lit_wchar_type		cp_global_trees[CPTI_USERDEF_LIT_WCHAR_TYPE]
+#define userdef_lit_char16_type		cp_global_trees[CPTI_USERDEF_LIT_CHAR16_TYPE]
+#define userdef_lit_char32_type		cp_global_trees[CPTI_USERDEF_LIT_CHAR32_TYPE]
+#define userdef_lit_char_str_type       cp_global_trees[CPTI_USERDEF_LIT_CHAR_STR_TYPE]
+#define userdef_lit_wchar_str_type      cp_global_trees[CPTI_USERDEF_LIT_WCHAR_STR_TYPE]
+#define userdef_lit_char16_str_type     cp_global_trees[CPTI_USERDEF_LIT_CHAR16_STR_TYPE]
+#define userdef_lit_char32_str_type     cp_global_trees[CPTI_USERDEF_LIT_CHAR32_STR_TYPE]
+
 /* We cache these tree nodes so as to call get_identifier less
    frequently.  */
 
@@ -4131,6 +4157,15 @@ 
              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))
+
 #if !defined(NO_DOLLAR_IN_LABEL) || !defined(NO_DOT_IN_LABEL)
 
 #define VTABLE_NAME_P(ID_NODE) (IDENTIFIER_POINTER (ID_NODE)[1] == 'v' \
@@ -5587,6 +5622,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, int *);
 
 /* in typeck2.c */
 extern void require_complete_eh_spec_types	(tree, tree);
Index: gcc/lto-streamer-out.c
===================================================================
--- gcc/lto-streamer-out.c	(revision 172287)
+++ 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 172287)
+++ gcc/treestruct.def	(working copy)
@@ -65,3 +65,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 172287)
+++ 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>
 
@@ -2325,6 +2325,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.  */
@@ -2413,6 +2423,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 172287)
+++ 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 172287)
+++ 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.
@@ -304,6 +304,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 172287)
+++ 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 172287)
+++ 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 + 1] = '\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 172287)
+++ 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);
 }