diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index d1c2c49ac85cab68585170f8a7e02eec510933c8..b49e827866b09bcd74668728257ec8a2884d8bf4 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,12 @@
+2011-10-26  Ed Smith-Rowland  <3dw4rd@verizon.net>
+
+	Implement C++11 user-defined literals.
+	* c-common.c (build_userdef_literal): New.
+	* c-common.def: New tree code.
+	* c-common.h (tree_userdef_literal): New tree struct and accessors.
+	* c-lex.c (interpret_float): Add suffix parm.
+	(c_lex_with_flags): Build literal tokens.
+
 2011-10-23  Paolo Carlini  <paolo.carlini@oracle.com>
 
 	PR c++/50841
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index ae18de3929cb28d503505e901d3b34394c67b5ea..2eefe03f390c1f2ac5d4e1643cac58e09ea32818 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -9912,4 +9912,17 @@ c_common_init_ts (void)
   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"
diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def
index c7e01b693ca3673dee8c5437bba76c774753d461..2a7df882d0af2cf007bb41043865d562e17a2b26 100644
--- a/gcc/c-family/c-common.def
+++ b/gcc/c-family/c-common.def
@@ -47,6 +47,12 @@ DEFTREECODE (C_MAYBE_CONST_EXPR, "c_maybe_const_expr", tcc_expression, 2)
    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
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 9818c9ca6828675eae2026076ef76082be8808d0..be9d7295b2a35e6c7e0bfc7ec740c0d28f6f9afd 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1067,4 +1067,27 @@ c_tree_chain_next (tree t)
   return NULL;
 }
 
+/* A suffix-identifier value doublet that represents user-defined literals
+   for C++-0x.  */
+struct GTY(()) tree_userdef_literal {
+  struct tree_base base;
+  tree suffix_id;
+  tree value;
+  tree num_string;
+};
+
+#define USERDEF_LITERAL_SUFFIX_ID(NODE) \
+  (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->suffix_id)
+
+#define USERDEF_LITERAL_VALUE(NODE) \
+  (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->value)
+
+#define USERDEF_LITERAL_NUM_STRING(NODE) \
+  (((struct tree_userdef_literal *)USERDEF_LITERAL_CHECK (NODE))->num_string)
+
+#define USERDEF_LITERAL_TYPE(NODE) \
+  (TREE_TYPE (USERDEF_LITERAL_VALUE (NODE)))
+
+extern tree build_userdef_literal (tree suffix_id, tree value, tree num_string);
+
 #endif /* ! GCC_C_COMMON_H */
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index b151564000cf9e1bcbf68fedd21af0258bf28d2e..baee8eb9799c5a1dea02c823831c999a769a4586 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -45,7 +45,7 @@ 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_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 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags,
 
     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)
 	  {
@@ -332,12 +333,27 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags,
 	    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 suffix_id = get_identifier (suffix);
+	    int len = tok->val.str.len - strlen (suffix);
+	    tree num_string = build_string (len + 1,
+					    (const char *) tok->val.str.text);
+	    TREE_TYPE (num_string) = char_array_type_node;
+	    num_string = fix_string_type (num_string);
+	    char *str = CONST_CAST (char *, TREE_STRING_POINTER (num_string));
+	    str[len] = '\0';
+	    tree literal = build_userdef_literal (suffix_id, *value,
+						  num_string);
+	    *value = literal;
+	  }
       }
       break;
 
@@ -415,6 +431,22 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags,
       }
       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 +454,22 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags,
       *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:
@@ -621,9 +669,10 @@ interpret_integer (const cpp_token *token, unsigned int flags)
 }
 
 /* Interpret TOKEN, a floating point number with FLAGS as classified
-   by cpplib.  */
+   by cpplib.  For C++0X SUFFIX may contain a user-defined literal suffix.  */
 static tree
-interpret_float (const cpp_token *token, unsigned int flags)
+interpret_float (const cpp_token *token, unsigned int flags,
+		 const char *suffix)
 {
   tree type;
   tree const_type;
@@ -702,7 +751,9 @@ interpret_float (const cpp_token *token, unsigned int flags)
      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
     {
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e6a9a90affeef4d4dd3e36dd5a64fce0c133bdca..ee942cab6d6794911e02178729d39d12bee89def 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,29 @@
+2011-10-26  Ed Smith-Rowland  <3dw4rd@verizon.net>
+
+	Implement C++11 user-defined literals.
+	* cp-objcp-common.c: (cp_tree_size) Return size of USERDEF_LITERAL tree.
+	* cp-tree.h: (UDLIT_OP_*, UDLIT_OPER_P): Literal operator
+	name tools. New tree code for user-defined literals.
+	* cxx-pretty-print.h: (pp_cxx_userdef_literal) New.
+	* cxx-pretty-print.c: (pp_cxx_userdef_literal) New.
+	(pp_cxx_primary_expression, pp_cxx_expression): Use it.
+	* decl.c: (cp_tree_node_structure): Return new tree code.
+	(duplicate_decls): Check for raw vs. template operator conflicts.
+	(grokfndecl, grokdeclarator): New checks for literal operators.
+	* error.c: (dump_expr): Warn about user-defined literals
+	in C++98 mode. (dump_function_name): Pretty printing.
+	* mangle.c: (write_literal_operator_name): New.
+	(write_unqualified_id, write_unqualified_name): Use it.
+	* parser.c: (cp_parser_operator): Handle operator"".
+	(cp_parser_userdef_char_literal, cp_parser_userdef_numeric_literal,
+	cp_parser_userdef_string_literal): New.
+	(cp_parser_primary_expression): Handle new user-defined literal tokens
+	with new functions.
+	* semantics.c: (potential_constant_expression_1): Add
+	user-defined literals.
+	* typeck.c (check_raw_literal_operator,
+	check_literal_operator_args): New.
+
 2011-10-26  Paolo Carlini  <paolo.carlini@oracle.com>
 
 	* typeck.c (cp_build_addr_expr_1): Use BASELINK_P.
diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index 035fdcd2f4e40cc4ecbc21d8851a4ea7627506d6..a957a0303acf66f22483294813b7e84d89fd44d2 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -100,6 +100,8 @@ cp_tree_size (enum tree_code code)
 
     case TEMPLATE_INFO:         return sizeof (struct tree_template_info);
 
+    case USERDEF_LITERAL:	return sizeof (struct tree_userdef_literal);
+
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b20e7d1aac581c5b91857072aecf100e48f10e8f..cc12d154a227c8b286ac69d0a68d36e85c1e2100 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -400,7 +400,9 @@ typedef enum cpp0x_warn_str
   /* override controls, override/final */
   CPP0X_OVERRIDE_CONTROLS,
   /* non-static data member initializers */
-  CPP0X_NSDMI
+  CPP0X_NSDMI,
+  /* user defined literals */
+  CPP0X_USER_DEFINED_LITERALS
 } cpp0x_warn_str;
   
 /* The various kinds of operation used by composite_pointer_type. */
@@ -740,6 +742,7 @@ enum cp_tree_node_structure_enum {
   TS_CP_TRAIT_EXPR,
   TS_CP_LAMBDA_EXPR,
   TS_CP_TEMPLATE_INFO,
+  TS_CP_USERDEF_LITERAL,
   LAST_TS_CP_ENUM
 };
 
@@ -765,6 +768,8 @@ union GTY((desc ("cp_tree_node_structure (&%h)"),
     lambda_expression;
   struct tree_template_info GTY ((tag ("TS_CP_TEMPLATE_INFO")))
     template_info;
+  struct tree_userdef_literal GTY ((tag ("TS_CP_USERDEF_LITERAL")))
+    userdef_literal;
 };
 
 
@@ -4228,6 +4233,17 @@ extern GTY(()) VEC(tree,gc) *local_classes;
              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' \
@@ -5759,6 +5775,8 @@ extern tree convert_ptrmem			(tree, tree, bool, bool,
 extern int lvalue_or_else			(tree, enum lvalue_use,
                                                  tsubst_flags_t);
 extern void check_template_keyword		(tree);
+extern bool check_raw_literal_operator		(const_tree decl);
+extern bool check_literal_operator_args		(const_tree, bool *, bool *);
 
 /* in typeck2.c */
 extern void require_complete_eh_spec_types	(tree, tree);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 708afc8cdc2b02d611b1140871e323c94ebb3c5a..55cb64b21e4b09aaf5646c46c3804e1e484e01f6 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -367,6 +367,17 @@ pp_cxx_id_expression (cxx_pretty_printer *pp, tree t)
     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_primary_expression (cxx_pretty_printer *pp, tree t)
       pp_cxx_constant (pp, t);
       break;
 
+    case USERDEF_LITERAL:
+      pp_cxx_userdef_literal (pp, t);
+      break;
+
     case BASELINK:
       t = BASELINK_FUNCTIONS (t);
     case VAR_DECL:
@@ -1024,6 +1039,10 @@ pp_cxx_expression (cxx_pretty_printer *pp, tree t)
       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;
diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h
index d12506e62fe9951f23b137f0d0e03e6d4cba06a6..bb9fec1c1bd0fa54151d57251389a95b5360ab3b 100644
--- a/gcc/cp/cxx-pretty-print.h
+++ b/gcc/cp/cxx-pretty-print.h
@@ -74,5 +74,7 @@ void pp_cxx_canonical_template_parameter (cxx_pretty_printer *, tree);
 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 */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 26e9847f4fd0ebdf0d0086cf888d83dde36d6236..5ba50088684c93e4c0b32ec5ca76050e934749b9 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1203,6 +1203,21 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
       || TREE_TYPE (olddecl) == error_mark_node)
     return error_mark_node;
 
+  if (UDLIT_OPER_P (DECL_NAME (newdecl))
+      && UDLIT_OPER_P (DECL_NAME (olddecl)))
+    {
+      if (TREE_CODE (newdecl) == TEMPLATE_DECL
+	  && TREE_CODE (olddecl) != TEMPLATE_DECL
+	  && check_raw_literal_operator (olddecl))
+	error ("literal operator template %q+D conflicts with"
+	       " raw literal operator %qD", newdecl, olddecl);
+      else if (TREE_CODE (newdecl) != TEMPLATE_DECL
+	       && TREE_CODE (olddecl) == TEMPLATE_DECL
+	       && check_raw_literal_operator (newdecl))
+	error ("raw literal operator %q+D conflicts with"
+	       " literal operator template %qD", newdecl, olddecl);
+    }
+
   if (DECL_P (olddecl)
       && TREE_CODE (newdecl) == FUNCTION_DECL
       && TREE_CODE (olddecl) == FUNCTION_DECL
@@ -7345,6 +7360,47 @@ grokfndecl (tree ctype,
   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
@@ -8536,6 +8592,15 @@ grokdeclarator (const cp_declarator *declarator,
       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))
     {
@@ -13754,6 +13819,7 @@ cp_tree_node_structure (union lang_tree_node * t)
     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;
     }
 }
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index c6110b220fa58d93065b22f1b32a3d5a4af38ff4..544c4d1b7ac2972d2f230193d0a9fc706741c7d5 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1534,6 +1534,8 @@ dump_function_name (tree t, int flags)
     }
   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 @@ dump_expr (tree t, int flags)
       pp_constant (cxx_pp, t);
       break;
 
+    case USERDEF_LITERAL:
+      pp_cxx_userdef_literal (cxx_pp, t);
+      break;
+
     case THROW_EXPR:
       /* While waiting for caret diagnostics, avoid printing
 	 __cxa_allocate_exception, __cxa_throw, and the like.  */
@@ -3233,7 +3239,7 @@ maybe_warn_cpp0x (cpp0x_warn_str str)
 	pedwarn (input_location, OPT_pedantic,
 		 "inline namespaces "
 		 "only available with -std=c++0x or -std=gnu++0x");
-	break;	
+	break;
       case CPP0X_OVERRIDE_CONTROLS:
 	pedwarn (input_location, 0,
 		 "override controls (override/final) "
@@ -3244,8 +3250,13 @@ maybe_warn_cpp0x (cpp0x_warn_str str)
 		 "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 ();
       }
 }
 
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 55851e646b2e169c78d71a79c2dac86a0b0b8de9..8bc26d8b34ff0c58207cdd43c47bf2319b72c514 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -181,6 +181,7 @@ static void write_template_prefix (const tree);
 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_unqualified_id (tree identifier)
 	  }
       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_unqualified_name (const tree decl)
 
 	  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_source_name (tree identifier)
   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
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index a762d9d91847aafa43558f16be1bba65e7e52382..840a30ddf650ab84cc0cdbcd1c4ff6da23ec9ad0 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -225,6 +225,9 @@ static cp_token_cache *cp_token_cache_new
 static void cp_parser_initial_pragma
   (cp_token *);
 
+static tree cp_literal_operator_id
+  (const char *);
+
 /* Manifest constants.  */
 #define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token))
 #define CP_SAVED_TOKEN_STACK 5
@@ -1762,6 +1765,12 @@ static tree cp_parser_identifier
   (cp_parser *);
 static tree cp_parser_string_literal
   (cp_parser *, bool, bool);
+static tree cp_parser_userdef_char_literal
+  (cp_parser *);
+static tree cp_parser_userdef_string_literal
+  (cp_token *);
+static tree cp_parser_userdef_numeric_literal
+  (cp_parser *);
 
 /* Basic concepts [gram.basic]  */
 
@@ -2270,6 +2279,8 @@ static bool cp_parser_error_occurred
   (cp_parser *);
 static bool cp_parser_allow_gnu_extensions_p
   (cp_parser *);
+static bool cp_parser_is_pure_string_literal
+  (cp_token *);
 static bool cp_parser_is_string_literal
   (cp_token *);
 static bool cp_parser_is_keyword
@@ -2290,7 +2301,7 @@ cp_parser_parsing_tentatively (cp_parser* parser)
 /* Returns nonzero if TOKEN is a string literal.  */
 
 static bool
-cp_parser_is_string_literal (cp_token* token)
+cp_parser_is_pure_string_literal (cp_token* token)
 {
   return (token->type == CPP_STRING ||
 	  token->type == CPP_STRING16 ||
@@ -2299,6 +2310,20 @@ cp_parser_is_string_literal (cp_token* token)
 	  token->type == CPP_UTF8STRING);
 }
 
+/* Returns nonzero if TOKEN is a string literal
+   of a user-defined string literal.  */
+
+static bool
+cp_parser_is_string_literal (cp_token* token)
+{
+  return (cp_parser_is_pure_string_literal (token) ||
+	  token->type == CPP_STRING_USERDEF ||
+	  token->type == CPP_STRING16_USERDEF ||
+	  token->type == CPP_STRING32_USERDEF ||
+	  token->type == CPP_WSTRING_USERDEF ||
+	  token->type == CPP_UTF8STRING_USERDEF);
+}
+
 /* Returns nonzero if TOKEN is the indicated KEYWORD.  */
 
 static bool
@@ -3338,7 +3363,11 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
   struct obstack str_ob;
   cpp_string str, istr, *strs;
   cp_token *tok;
-  enum cpp_ttype type;
+  enum cpp_ttype type, curr_type;
+  int have_suffix_p = 0;
+  tree string_tree;
+  tree suffix_id = NULL_TREE;
+  bool curr_tok_is_userdef_p = false;
 
   tok = cp_lexer_peek_token (parser->lexer);
   if (!cp_parser_is_string_literal (tok))
@@ -3347,7 +3376,18 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
       return error_mark_node;
     }
 
-  type = tok->type;
+  if (cpp_userdef_string_p (tok->type))
+    {
+      string_tree = USERDEF_LITERAL_VALUE (tok->u.value);
+      curr_type = cpp_userdef_string_remove_type (tok->type);
+      curr_tok_is_userdef_p = true;
+    }
+  else
+    {
+      string_tree = tok->u.value;
+      curr_type = tok->type;
+    }
+  type = curr_type;
 
   /* Try to avoid the overhead of creating and destroying an obstack
      for the common case of just one string.  */
@@ -3356,10 +3396,19 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
     {
       cp_lexer_consume_token (parser->lexer);
 
-      str.text = (const unsigned char *)TREE_STRING_POINTER (tok->u.value);
-      str.len = TREE_STRING_LENGTH (tok->u.value);
+      str.text = (const unsigned char *)TREE_STRING_POINTER (string_tree);
+      str.len = TREE_STRING_LENGTH (string_tree);
       count = 1;
 
+      if (curr_tok_is_userdef_p)
+	{
+	  suffix_id = USERDEF_LITERAL_SUFFIX_ID (tok->u.value);
+	  have_suffix_p = 1;
+	  curr_type = cpp_userdef_string_remove_type (tok->type);
+	}
+      else
+	curr_type = tok->type;
+
       strs = &str;
     }
   else
@@ -3371,14 +3420,35 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
 	{
 	  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 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 != tok->type)
+	  if (type != curr_type)
 	    {
 	      if (type == CPP_STRING)
-		type = tok->type;
-	      else if (tok->type != CPP_STRING)
+		type = curr_type;
+	      else if (curr_type != CPP_STRING)
 		error_at (tok->location,
 			  "unsupported non-standard concatenation "
 			  "of string literals");
@@ -3387,6 +3457,18 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
 	  obstack_grow (&str_ob, &str, sizeof (cpp_string));
 
 	  tok = cp_lexer_peek_token (parser->lexer);
+	  if (cpp_userdef_string_p (tok->type))
+	    {
+	      string_tree = USERDEF_LITERAL_VALUE (tok->u.value);
+	      curr_type = cpp_userdef_string_remove_type (tok->type);
+	      curr_tok_is_userdef_p = true;
+	    }
+	  else
+	    {
+	      string_tree = tok->u.value;
+	      curr_type = tok->type;
+	      curr_tok_is_userdef_p = false;
+	    }
 	}
       while (cp_parser_is_string_literal (tok));
 
@@ -3424,6 +3506,13 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
 	}
 
       value = fix_string_type (value);
+
+      if (have_suffix_p)
+	{
+	  tree literal = build_userdef_literal (suffix_id, value, NULL_TREE);
+	  tok->u.value = literal;
+	  return cp_parser_userdef_string_literal (tok);
+	}
     }
   else
     /* cpp_interpret_string has issued an error.  */
@@ -3435,6 +3524,186 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
   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 charvec;
+  tree argpack = make_node (NONTYPE_ARGUMENT_PACK);
+  const char *str = TREE_STRING_POINTER (value);
+  int i, len = TREE_STRING_LENGTH (value) - 1;
+  tree argvec = make_tree_vec (1);
+
+  /* Fill in CHARVEC with all of the parameters.  */
+  charvec = make_tree_vec (len);
+  for (i = 0; i < len; ++i)
+    TREE_VEC_ELT (charvec, i) = build_int_cst (char_type_node, str[i]);
+
+  /* Build the argument packs.  */
+  SET_ARGUMENT_PACK_ARGS (argpack, charvec);
+  TREE_TYPE (argpack) = char_type_node;
+
+  TREE_VEC_ELT (argvec, 0) = argpack;
+
+  return argvec;
+}
+
+/* Parse a user-defined numeric constant.  returns a call to a user-defined
+   literal operator.  */
+
+static tree
+cp_parser_userdef_numeric_literal (cp_parser *parser)
+{
+  cp_token *token = NULL;
+  tree literal, suffix_id, value, num_string;
+  tree name, decl;
+  tree result = error_mark_node;
+  VEC(tree,gc) *args;
+
+  token = cp_lexer_consume_token (parser->lexer);
+  literal = token->u.value;
+  suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+  value = USERDEF_LITERAL_VALUE (literal);
+  num_string = USERDEF_LITERAL_NUM_STRING (literal);
+  name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+
+  /* Build up a call to the user-defined operator  */
+  /* Lookup the name we got back from the id-expression.  */
+  /* Try to find the literal operator by finishing the call expression
+     with the numeric argument.  */
+  args = make_tree_vector ();
+  VEC_safe_push (tree, gc, args, value);
+  decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+  if (decl && decl != error_mark_node)
+    {
+      result = finish_call_expr (decl, &args, false, true, tf_none);
+      if (result != error_mark_node)
+	{
+	  release_tree_vector (args);
+	  return result;
+	}
+    }
+  release_tree_vector (args);
+
+  /* If the numeric argument didn't work, look for a raw literal
+     operator taking a const char* argument consisting of the number
+     in string format.  */
+  args = make_tree_vector ();
+  VEC_safe_push (tree, gc, args, num_string);
+  decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+  if (decl && decl != error_mark_node)
+    {
+      result = finish_call_expr (decl, &args, false, true, tf_none);
+      if (result != error_mark_node)
+	{
+	  release_tree_vector (args);
+	  return result;
+	}
+    }
+  release_tree_vector (args);
+
+  /* If the raw literal didn't work, look for a non-type template
+     function with parameter pack char....  Call the function with
+     template parameter characters representing the number.  */
+  args = make_tree_vector ();
+  decl = lookup_function_nonclass (name, args, /*block_p=*/false);
+  if (decl && decl != error_mark_node)
+    {
+      tree tmpl_args = make_char_string_pack (num_string);
+      decl = lookup_template_function (decl, tmpl_args);
+      result = finish_call_expr (decl, &args, false, true, tf_none);
+      if (result != error_mark_node)
+	{
+	  release_tree_vector (args);
+	  return result;
+	}
+    }
+  release_tree_vector (args);
+
+  if (result == error_mark_node)
+    error ("unable to find user-defined numeric literal operator %qD", name);
+
+  return result;
+}
+
+/* Parse a user-defined string constant.  Returns a call to a user-defined
+   literal operator taking a character pointer and the length of the string
+   as arguments.  */
+static tree
+cp_parser_userdef_string_literal (cp_token *token)
+{
+  tree literal, suffix_id, value;
+  tree name, decl;
+  tree result;
+  VEC(tree,gc) *vec;
+  int len;
+
+  literal = token->u.value;
+  suffix_id = USERDEF_LITERAL_SUFFIX_ID (literal);
+  name = cp_literal_operator_id (IDENTIFIER_POINTER (suffix_id));
+  value = USERDEF_LITERAL_VALUE (literal);
+  len = TREE_STRING_LENGTH (value) - 1;
+
+  /* Build up a call to the user-defined operator  */
+  /* Lookup the name we got back from the id-expression.  */
+  vec = make_tree_vector ();
+  VEC_safe_push (tree, gc, vec, value);
+  VEC_safe_push (tree, gc, vec, build_int_cst (size_type_node, len));
+  decl = lookup_function_nonclass (name, vec, /*block_p=*/false);
+  if (!decl || decl == error_mark_node)
+    {
+      error ("unable to find user-defined string literal operator %qD", name);
+      release_tree_vector (vec);
+      return error_mark_node;
+    }
+  result = finish_call_expr (decl, &vec, false, true, tf_none);
+  if (result == error_mark_node)
+    error ("unable to find valid user-defined string literal operator %qD."
+	   "  Possible missing length argument in string literal operator.",
+	   name);
+  release_tree_vector (vec);
+
+  return result;
+}
+
 
 /* Basic concepts [gram.basic]  */
 
@@ -3578,12 +3847,16 @@ cp_parser_primary_expression (cp_parser *parser,
 	   character-literal
 	   floating-literal
 	   string-literal
-	   boolean-literal  */
+	   boolean-literal
+	   pointer-literal
+	   user-defined-literal  */
     case CPP_CHAR:
     case CPP_CHAR16:
     case CPP_CHAR32:
     case CPP_WCHAR:
     case CPP_NUMBER:
+      if (TREE_CODE (token->u.value) == USERDEF_LITERAL)
+	return cp_parser_userdef_numeric_literal (parser);
       token = cp_lexer_consume_token (parser->lexer);
       if (TREE_CODE (token->u.value) == FIXED_CST)
 	{
@@ -3637,11 +3910,22 @@ cp_parser_primary_expression (cp_parser *parser,
 	}
       return token->u.value;
 
+    case CPP_CHAR_USERDEF:
+    case CPP_CHAR16_USERDEF:
+    case CPP_CHAR32_USERDEF:
+    case CPP_WCHAR_USERDEF:
+      return cp_parser_userdef_char_literal (parser);
+
     case CPP_STRING:
     case CPP_STRING16:
     case CPP_STRING32:
     case CPP_WSTRING:
     case CPP_UTF8STRING:
+    case CPP_STRING_USERDEF:
+    case CPP_STRING16_USERDEF:
+    case CPP_STRING32_USERDEF:
+    case CPP_WSTRING_USERDEF:
+    case CPP_UTF8STRING_USERDEF:
       /* ??? Should wide strings be allowed when parser->translate_strings_p
 	 is false (i.e. in attributes)?  If not, we can kill the third
 	 argument to cp_parser_string_literal.  */
@@ -4477,6 +4761,14 @@ cp_parser_unqualified_id (cp_parser* parser,
 	  /* If that didn't work, try a conversion-function-id.  */
 	  if (!cp_parser_parse_definitely (parser))
 	    id = cp_parser_conversion_function_id (parser);
+	  else if (UDLIT_OPER_P (id))
+	    {
+	      /* 17.6.3.3.5  */
+	      const char *name = UDLIT_OP_SUFFIX (id);
+	      if (name[0] != '_' && !in_system_header)
+		warning (0, "literal operator suffixes not preceded by %<_%>"
+			    " are reserved for future standardization");
+	    }
 
 	  return id;
 	}
@@ -5119,7 +5411,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 	/* Restore the saved message.  */
 	parser->type_definition_forbidden_message = saved_message;
 	/* `typeid' may not appear in an integral constant expression.  */
-	if (cp_parser_non_integral_constant_expression(parser, NIC_TYPEID))
+	if (cp_parser_non_integral_constant_expression (parser, NIC_TYPEID))
 	  return error_mark_node;
       }
       break;
@@ -9739,7 +10031,7 @@ cp_parser_declaration (cp_parser* parser)
   /* If the next token is `extern' and the following token is a string
      literal, then we have a linkage specification.  */
   if (token1.keyword == RID_EXTERN
-      && cp_parser_is_string_literal (&token2))
+      && cp_parser_is_pure_string_literal (&token2))
     cp_parser_linkage_specification (parser);
   /* If the next token is `template', then we have either a template
      declaration, an explicit instantiation, or an explicit
@@ -11170,6 +11462,22 @@ cp_parser_operator_function_id (cp_parser* parser)
   return cp_parser_operator (parser);
 }
 
+/* Return an identifier node for a user-defined literal operator.
+   The suffix identifier is chained to the operator name identifier.  */
+
+static tree
+cp_literal_operator_id (const char* name)
+{
+  tree identifier;
+  char *buffer = XNEWVEC (char, strlen (UDLIT_OP_ANSI_PREFIX)
+			      + strlen (name) + 10);
+  sprintf (buffer, UDLIT_OP_ANSI_FORMAT, name);
+  identifier = get_identifier (buffer);
+  /*IDENTIFIER_UDLIT_OPNAME_P (identifier) = 1; If we get a flag someday. */
+
+  return identifier;
+}
+
 /* Parse an operator.
 
    operator:
@@ -11389,6 +11697,37 @@ cp_parser_operator (cp_parser* parser)
       cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
       return ansi_opname (ARRAY_REF);
 
+    case CPP_STRING:
+      if (cxx_dialect == cxx98)
+	maybe_warn_cpp0x (CPP0X_USER_DEFINED_LITERALS);
+      if (TREE_STRING_LENGTH (token->u.value) > 2)
+	{
+	  error ("expected empty string after %<operator%> keyword");
+	  return error_mark_node;
+	}
+      /* Consume the string.  */
+      cp_lexer_consume_token (parser->lexer);
+      /* Look for the suffix identifier.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      if (token->type == CPP_NAME)
+	{
+	  id = cp_parser_identifier (parser);
+	  if (id != error_mark_node)
+	    {
+	      const char *name = IDENTIFIER_POINTER (id);
+	      return cp_literal_operator_id (name);
+	    }
+	}
+      else
+	{
+	  error ("expected suffix identifier");
+	  return error_mark_node;
+	}
+
+    case CPP_STRING_USERDEF:
+      error ("missing space between %<\"\"%> and suffix identifier");
+      return error_mark_node;
+
     default:
       /* Anything else is an error.  */
       break;
@@ -20583,6 +20922,33 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
   /* Finish up.  */
   finish_template_decl (parameter_list);
 
+  /* Check the template arguments for a literal operator template.  */
+  if (decl
+      && (TREE_CODE (decl) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (decl))
+      && UDLIT_OPER_P (DECL_NAME (decl)))
+    {
+      bool ok = true;
+      if (parameter_list == NULL_TREE)
+	ok = false;
+      else
+	{
+	  int num_parms = TREE_VEC_LENGTH (parameter_list);
+	  if (num_parms != 1)
+	    ok = false;
+	  else
+	    {
+	      tree parm_list = TREE_VEC_ELT (parameter_list, 0);
+	      tree parm = INNERMOST_TEMPLATE_PARMS (parm_list);
+	      if (TREE_TYPE (parm) != char_type_node
+		  || !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)))
+		ok = false;
+	    }
+	}
+      if (!ok)
+	error ("literal operator template %qD has invalid parameter list."
+	       "  Expected non-type template argument pack <char...>",
+	       decl);
+    }
   /* Register member declarations.  */
   if (member_p && !friend_p && decl && !DECL_CLASS_TEMPLATE_P (decl))
     finish_member_declaration (decl);
@@ -22891,7 +23257,8 @@ cp_parser_objc_interstitial_code (cp_parser* parser)
   /* 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)
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index ec38a473715f2d8aabe3849c479f51be571461dd..fa8ab9914c3fb459229313d36f8fb7581d8b8a8c 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -7865,6 +7865,7 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
     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:
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 068819ebe870341c37904583f8b1da45fdf9a8ac..59e1357cb0bf272f70973ce33e1a0c5da91119c7 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -8356,3 +8356,121 @@ lvalue_or_else (tree ref, enum lvalue_use use, tsubst_flags_t complain)
   return 1;
 }
 
+/* Return true if a user-defined literal operator is a raw operator.  */
+
+bool
+check_raw_literal_operator (const_tree decl)
+{
+  tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
+  tree argtype;
+  int arity;
+  bool maybe_raw_p = false;
+
+  /* Count the number and type of arguments and check for ellipsis.  */
+  for (argtype = argtypes, arity = 0;
+       argtype && argtype != void_list_node;
+       ++arity, argtype = TREE_CHAIN (argtype))
+    {
+      tree t = TREE_VALUE (argtype);
+
+      if (same_type_p (t, const_string_type_node))
+	maybe_raw_p = true;
+    }
+  if (!argtype)
+    return false; /* Found ellipsis.  */
+
+  if (!maybe_raw_p || arity != 1)
+    return false;
+
+  return true;
+}
+
+
+/* Return true if a user-defined literal operator has one of the allowed
+   argument types.  */
+
+bool
+check_literal_operator_args (const_tree decl,
+			     bool *long_long_unsigned_p, bool *long_double_p)
+{
+  tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
+  if (processing_template_decl)
+    return (argtypes == NULL_TREE
+	    || same_type_p (TREE_VALUE (argtypes), void_type_node));
+  else
+    {
+      tree argtype;
+      int arity;
+      int max_arity = 2;
+      bool found_string_p = false;
+      bool maybe_raw_p = false;
+      bool found_size_p = false;
+      tree const_wchar_ptr_type_node
+	   = build_pointer_type (build_type_variant (wchar_type_node, 1, 0));
+      tree const_char16_ptr_type_node
+	   = build_pointer_type (build_type_variant (char16_type_node, 1, 0));
+      tree const_char32_ptr_type_node
+	   = build_pointer_type (build_type_variant (char32_type_node, 1, 0));
+
+      *long_long_unsigned_p = false;
+      *long_double_p = false;
+
+      /* Count the number and type of arguments and check for ellipsis.  */
+      for (argtype = argtypes, arity = 0;
+	   argtype && argtype != void_list_node;
+	   argtype = TREE_CHAIN (argtype))
+	{
+	  tree t = TREE_VALUE (argtype);
+	  ++arity;
+
+	  if (same_type_p (t, const_string_type_node))
+	    {
+	      found_string_p = true;
+	      maybe_raw_p = true;
+	    }
+	  else if (same_type_p (t, const_wchar_ptr_type_node))
+	    found_string_p = true;
+	  else if (same_type_p (t, const_char16_ptr_type_node))
+	    found_string_p = true;
+	  else if (same_type_p (t, const_char32_ptr_type_node))
+	    found_string_p = true;
+	  else if (same_type_p (t, size_type_node))
+	    {
+	      if (!found_string_p)
+		return false;
+	      found_size_p = true;
+	    }
+	  else if (same_type_p (t, long_long_unsigned_type_node))
+	    {
+	      max_arity = 1;
+	      *long_long_unsigned_p = true;
+	    }
+	  else if (same_type_p (t, long_double_type_node))
+	    {
+	      max_arity = 1;
+	      *long_double_p = true;
+	    }
+	  else if (same_type_p (t, char_type_node))
+	    max_arity = 1;
+	  else if (same_type_p (t, wchar_type_node))
+	    max_arity = 1;
+	  else if (same_type_p (t, char16_type_node))
+	    max_arity = 1;
+	  else if (same_type_p (t, char32_type_node))
+	    max_arity = 1;
+	  else
+	    return false;
+	}
+      if (!argtype)
+	return false; /* Found ellipsis.  */
+
+      if (arity > max_arity)
+	return false;
+
+      if (found_string_p && !maybe_raw_p && !found_size_p)
+	return false;
+
+      return true;
+    }
+}
+
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 868e4b0d204a4086d45389c16542e36b9d14fcf1..e702ae907c2e44bdcfd05b5affd5b163a65bc74f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,38 @@
+2011-10-26  Ed Smith-Rowland  <3dw4rd@verizon.net>
+
+	Implement C++11 user-defined literals.
+	* g++.dg/cpp0x/udlit-addr.C: New.
+	* g++.dg/cpp0x/udlit-args.C: New.
+	* g++.dg/cpp0x/udlit-args-neg.C: New.
+	* g++.dg/cpp0x/udlit-clink-neg.C: New.
+	* g++.dg/cpp0x/udlit-concat.C: New.
+	* g++.dg/cpp0x/udlit-concat-neg.C: New.
+	* g++.dg/cpp0x/udlit-constexpr.C: New.
+	* g++.dg/cpp0x/udlit-cpp98-neg.C: New.
+	* g++.dg/cpp0x/udlit-declare-neg.C: New.
+	* g++.dg/cpp0x/udlit-friend.C: New.
+	* g++.dg/cpp0x/udlit-general.C: New.
+	* g++.dg/cpp0x/udlit-inline.C: New.
+	* g++.dg/cpp0x/udlit-linkage-neg.C: New.
+	* g++.dg/cpp0x/udlit-member-neg.C: New.
+	* g++.dg/cpp0x/udlit-namespace.C: New.
+	* g++.dg/cpp0x/udlit-nofunc-neg.C: New.
+	* g++.dg/cpp0x/udlit-nonempty-str-neg.C: New.
+	* g++.dg/cpp0x/udlit-nospace-neg.C: New.
+	* g++.dg/cpp0x/udlit-nosuffix-neg.C: New.
+	* g++.dg/cpp0x/udlit-nounder-neg.C: New.
+	* g++.dg/cpp0x/udlit-operator-neg.C: New.
+	* g++.dg/cpp0x/udlit-raw-str.C: New.
+	* g++.dg/cpp0x/udlit-shadow-neg.C: New.
+	* g++.dg/cpp0x/udlit-suffix-neg.C: New.
+	* g++.dg/cpp0x/udlit-systemheader.C: New.
+	* g++.dg/cpp0x/udlit-template.C: New.
+	* g++.dg/cpp0x/udlit-tmpl-arg.C: New.
+	* g++.dg/cpp0x/udlit-tmpl-arg-neg.C: New.
+	* g++.dg/cpp0x/udlit-tmpl-parms.C: New.
+	* g++.dg/cpp0x/udlit-tmpl-parms-neg.C: New.
+	* g++.dg/cpp0x/udlit_system_header: New.
+
 2011-10-26  Paolo Carlini  <paolo.carlini@oracle.com>
 
 	PR c++/50870
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-addr.C b/gcc/testsuite/g++.dg/cpp0x/udlit-addr.C
new file mode 100644
index 0000000000000000000000000000000000000000..7d3286e007be4ac4baefb725e6a61c803814cc7e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-addr.C
@@ -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);
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-args-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-args-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..cb924a249bf612627b6a79723758cbe966f3b883
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-args-neg.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-args.C b/gcc/testsuite/g++.dg/cpp0x/udlit-args.C
new file mode 100644
index 0000000000000000000000000000000000000000..ca2039c59d31074aa1e16da1b7761a4bab3454e0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-args.C
@@ -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);
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-clink-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-clink-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..a80e7244afd294f9fc8953d2600e9d26346270fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-clink-neg.C
@@ -0,0 +1,8 @@
+// { dg-options -std=c++0x }
+
+extern "C" {
+
+int
+operator"" _badclinkage(unsigned long long);	// { dg-error "operator with C linkage" }
+
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-concat-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-concat-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..61dc2ab02c6b52d91d2c40dc4d9dc5bb592dd43d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-concat-neg.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-concat.C b/gcc/testsuite/g++.dg/cpp0x/udlit-concat.C
new file mode 100644
index 0000000000000000000000000000000000000000..612bc1d1116cedc3acaf44c692ee4991974b4a2b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-concat.C
@@ -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;
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C b/gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C
new file mode 100644
index 0000000000000000000000000000000000000000..40b0dfac53152e787cb1718fd33f65cae1c3844d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-constexpr.C
@@ -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];
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-cpp98-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-cpp98-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..cb78a2c9c3e3c80e6c9e4b34d9b037803e1b3028
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-cpp98-neg.C
@@ -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 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..7b50c017f01479570658057f082e82228ec11c14
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-embed-quote.C b/gcc/testsuite/g++.dg/cpp0x/udlit-embed-quote.C
new file mode 100644
index 0000000000000000000000000000000000000000..48a2a1b171d05d58056988535224d40dc8240896
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-embed-quote.C
@@ -0,0 +1,34 @@
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+//  Make sure embedded quotes are not a problem for string and char literals.
+
+#include <cstdint>
+#include <cassert>
+
+int operator"" _embedchar(char)
+{ return 41; };
+
+int operator"" _embedstr(const char*, std::size_t len)
+{ return 42 + len; };
+
+void
+test()
+{
+  int i = '\''_embedchar;
+
+  int j = "\""_embedstr;
+  assert(j == 43);
+
+  int k = "foo\""_embedstr;
+  assert(k == 46);
+
+  int l = "\"bar"_embedstr;
+  assert(l == 46);
+}
+
+int
+main()
+{
+  test();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-friend.C b/gcc/testsuite/g++.dg/cpp0x/udlit-friend.C
new file mode 100644
index 0000000000000000000000000000000000000000..b3f3ef8a604d30fe7725e9189ab4bfb625269110
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-friend.C
@@ -0,0 +1,28 @@
+// { dg-options -std=c++0x }
+
+long double
+operator"" _Hertz(long double);
+
+class Foo
+{
+public:
+  Foo() { }
+
+  friend Foo operator"" _Bar(char);
+
+  friend long double
+  operator"" _Hertz(long double omega)
+  { return omega / 6.28318530717958648; }
+};
+
+Foo
+operator"" _Bar(char)
+{ return Foo(); }
+
+Foo f1 = operator"" _Bar('x');
+
+Foo f2 = 'x'_Bar;
+
+long double fm1 = operator"" _Hertz(552.92L);
+
+long double fm2 = 552.92_Hertz;
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-general.C b/gcc/testsuite/g++.dg/cpp0x/udlit-general.C
new file mode 100644
index 0000000000000000000000000000000000000000..9e448ac805014c58c3ce8b122684d404134d2ad7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-general.C
@@ -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); }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-inline.C b/gcc/testsuite/g++.dg/cpp0x/udlit-inline.C
new file mode 100644
index 0000000000000000000000000000000000000000..75032c5767990540f98c07b6212cb7835f9cf3e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-inline.C
@@ -0,0 +1,22 @@
+// { dg-options "-std=c++0x" }
+
+//  Literal operators can be inline.
+
+inline int
+operator"" _thing1(char cc)
+{ return 42 * cc; }
+
+int operator"" _thing2(char cc);
+
+class Foo
+{
+  int
+  friend operator"" _thing2(char cc)
+  { return 42 * cc; }
+};
+
+int i = operator"" _thing1('x');
+int j = 'x'_thing1;
+
+int iF = operator"" _thing2('x');
+int jF = 'x'_thing2;
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-linkage-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-linkage-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..c2ecede8d48d8ed040fadd1ef914ba8d2ea5f01e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-linkage-neg.C
@@ -0,0 +1,7 @@
+// { dg-options -std=c++0x }
+
+extern "C"_badlinkage {	// { dg-error "expected unqualified-id before" }
+
+int foo();
+
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..809df254c0e62e2bec12adc89fcf062aff293a42
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C
@@ -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; }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C b/gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C
new file mode 100644
index 0000000000000000000000000000000000000000..e5d54e519009601ccecb8f589cab41a8f09ccc22
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-namespace.C
@@ -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; }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-nofunc-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-nofunc-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..6ad79b85b1d8b1c61370d380dfb7ceb142248eaf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-nofunc-neg.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..981865f15263c7c6ec4dc0095f0bc6c44c1ee5e9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-nonempty-str-neg.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-nospace-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-nospace-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..2b57637a9168d176c21f3f06f43ea4245295e582
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-nospace-neg.C
@@ -0,0 +1,3 @@
+// { dg-options "-std=c++0x" }
+
+float operator ""_abc(const char*); // { dg-error "missing space between|and suffix identifier" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-nosuffix-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-nosuffix-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..b90635cd0fc3c0a8b5ba43df78039c2179bd08aa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-nosuffix-neg.C
@@ -0,0 +1,5 @@
+// { dg-options -std=c++0x }
+
+char32_t
+operator"" (char32_t C)	// { dg-error "expected suffix identifier" }
+{ return C; }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-nounder-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-nounder-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..2067bbe561f912733a1dc881add318544de182b7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-nounder-neg.C
@@ -0,0 +1,9 @@
+// { dg-options "-std=c++0x" }
+
+// Test user-defined literals.
+// Test warning on declaration without leading underscore.
+
+long double operator"" nounder(long double); // { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" }
+
+template<char...>
+  int operator"" nounder(); // { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..27fdedec766a6225677e80cc47bf45a9bb65e957
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-operator-neg.C
@@ -0,0 +1,42 @@
+// { dg-options "-std=c++0x" }
+
+//  Can't have *both* literal operator template and raw literal operator.
+
+int
+operator"" _abc(const char*)
+  {
+    return 42;
+  }
+
+template<char...>
+  int
+  operator"" _abc() // { dg-error "literal operator template|conflicts with raw literal operator" }
+  {
+    return 13;
+  }
+
+template<char...>
+  int
+  operator"" _def()
+  {
+    return 12;
+  }
+
+int
+operator"" _def(const char*) // { dg-error "raw literal operator|conflicts with literal operator template" }
+  {
+    return 43;
+  }
+
+int
+operator"" _ghi(long double)
+  {
+    return 42;
+  }
+
+template<char...>
+  int
+  operator"" _ghi() // OK
+  {
+    return 13;
+  }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-preproc-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-preproc-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..23633390cf0d494968d91ab9725c8ec4178647df
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-preproc-neg.C
@@ -0,0 +1,9 @@
+// { dg-options "-std=c++0x" }
+
+int
+operator"" _badpreproc(const char *str)
+{ return 0; }
+
+#if 123_badpreproc  //  { dg-error "user-defined literal in preprocessor expression" }
+#  error ("user-defined literal in preprocessor expression")  //  { dg-error "user-defined literal in preprocessor expression" }
+#endif
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..5c399aff5990f3a56fbc6e23de3510ac52bb59c7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-raw-op-string-neg.C
@@ -0,0 +1,8 @@
+// { dg-options "-std=c++0x" }
+
+//  Make sure handing a string to a raw literal generates a sensible error message.
+
+int operator"" _embedraw(const char*)
+{ return 41; };
+
+int k = "Boo!"_embedraw;  //  { dg-error "unable to find valid user-defined string literal operator" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-raw-op.C b/gcc/testsuite/g++.dg/cpp0x/udlit-raw-op.C
new file mode 100644
index 0000000000000000000000000000000000000000..3bbf19cb05c809ffaded7fd1e183fd165364b46d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-raw-op.C
@@ -0,0 +1,21 @@
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+#include <cassert>
+#include <cstring>
+
+int
+operator"" _raw_umber(const char * str)
+{
+  return strlen(str);
+}
+
+int
+main()
+{
+  int i = 0123012301230123012301230123012301230123012301230123012301230123_raw_umber;
+  assert( i == 64 );
+
+  int j = 90123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789_raw_umber;
+  assert( j == 101 );
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-raw-str.C b/gcc/testsuite/g++.dg/cpp0x/udlit-raw-str.C
new file mode 100644
index 0000000000000000000000000000000000000000..e94410fd0619c66bd4ae2eaee8832fec7628f493
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-raw-str.C
@@ -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;
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..6d38252ff2a25a4241bfd2df6d6e7222b678f1ac
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-shadow-neg.C
@@ -0,0 +1,49 @@
+// { dg-options -std=c++0x }
+
+//  Test that the standard suffixes shadow any user-defined suffixes of the same name.
+long double
+operator"" L(long double x)  // { dg-warning "floating point suffix|shadowed by implementation" }
+{ return x; }
+
+unsigned long long int
+operator"" ULL(unsigned long long int k)  // { dg-warning "integer suffix|shadowed by implementation" }
+{ return k; }
+
+long double
+operator"" l(long double x)  // { dg-warning "floating point suffix|shadowed by implementation" }
+{ return x; }
+
+unsigned long long int
+operator"" ull(unsigned long long int k)  // { dg-warning "integer suffix|shadowed by implementation" }
+{ return k; }
+
+//  Namespaces are no hiding place.
+namespace Long
+{
+
+long double
+operator"" L(long double x)  // { dg-warning "integer suffix|shadowed by implementation" }
+{ return x; }
+
+unsigned long long int
+operator"" ULL(unsigned long long int k)  // { dg-warning "integer suffix|shadowed by implementation" }
+{ return k; }
+
+long double
+operator"" l(long double x)  // { dg-warning "integer suffix|shadowed by implementation" }
+{ return x; }
+
+unsigned long long int
+operator"" ull(unsigned long long int k)  // { dg-warning "integer suffix|shadowed by implementation" }
+{ return k; }
+
+}
+
+// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 5 }
+// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 9 }
+// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 13 }
+// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 17 }
+// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 25 }
+// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 29 }
+// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 33 }
+// { dg-warning "literal operator suffixes not preceded by|are reserved for future standardization" "" { target *-*-* } 37 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-suffix-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-suffix-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..56eab01d7365a9512303e0e76b09a6800dcec080
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-suffix-neg.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-systemheader.C b/gcc/testsuite/g++.dg/cpp0x/udlit-systemheader.C
new file mode 100644
index 0000000000000000000000000000000000000000..599c8652a147b4b5ac30443a8ddb78c377fb0cc0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-systemheader.C
@@ -0,0 +1,3 @@
+// { dg-options -std=c++0x }
+
+#include "udlit_system_header"
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-template.C b/gcc/testsuite/g++.dg/cpp0x/udlit-template.C
new file mode 100644
index 0000000000000000000000000000000000000000..6a28f74a22b3bf88febceddd67a993983bb5b733
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-template.C
@@ -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); }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..e8ccb6f545d556bf623d2bc3acefa779cf698970
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg-neg.C
@@ -0,0 +1,4 @@
+// { dg-options -std=c++0x }
+
+template<char...>
+  int operator"" _xyz(unsigned long long);	// { dg-error "has invalid argument list" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg.C
new file mode 100644
index 0000000000000000000000000000000000000000..6324823fabbb147d22edccec419aa04c17352cc6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-arg.C
@@ -0,0 +1,4 @@
+// { dg-options -std=c++0x }
+
+template<char...>
+  int operator"" _abc();
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C
new file mode 100644
index 0000000000000000000000000000000000000000..4dab4d2f6f097c6eca9301f9316a16471621317b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms-neg.C
@@ -0,0 +1,12 @@
+// { dg-options -std=c++0x }
+
+class Foo { };
+
+template<wchar_t...>
+  Foo operator"" _Foo(); // { dg-error "literal operator template|has invalid parameter list" }
+
+template<char>
+  Foo operator"" _Bar(); // { dg-error "literal operator template|has invalid parameter list" }
+
+template<typename... Type>
+  Foo operator"" _Bar(); // { dg-error "literal operator template|has invalid parameter list" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms.C b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms.C
new file mode 100644
index 0000000000000000000000000000000000000000..77456737c70c79923d924011be56316d40578a10
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-tmpl-parms.C
@@ -0,0 +1,6 @@
+// { dg-options -std=c++0x }
+
+class Foo { };
+
+template<char...>
+  Foo operator"" _Foo();
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit_system_header b/gcc/testsuite/g++.dg/cpp0x/udlit_system_header
new file mode 100644
index 0000000000000000000000000000000000000000..d541f24f62ac77037b47b960dab9ff74d3b2b1a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit_system_header
@@ -0,0 +1,6 @@
+
+#pragma GCC system_header
+
+char
+operator"" stdsuffix(char __c)
+{ return __c/2; }
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index 918b8af1daddd106b3e27b0947fa4f8e400d5a8e..5be923ea1f6c7da1e41300213550924efb3ad64c 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,17 @@
+2011-10-26  Ed Smith-Rowland  <3dw4rd@verizon.net>
+
+	Implement C++11 user-defined literals.
+	* expr.c: (cpp_interpret_float_suffix, cpp_interpret_int_suffix,
+	cpp_userdef_string_remove_type, cpp_userdef_string_add_type,
+	cpp_userdef_char_remove_type, cpp_userdef_char_add_type,
+	cpp_userdef_string_p, cpp_userdef_char_p, cpp_get_userdef_suffix): New.
+	(cpp_classify_number): Classify unrecognized tokens as user-defined
+	literals.
+	* include/cpplib.h: Add new tokens for user-defined literals.
+	* init.c: Add new preprocessor flag (cxx11).
+	* lex.c: (lex_string, lex_raw_string): Handle user-defined literals
+	including concatenation and promotion with suffixes.
+
 2011-10-24  Dodji Seketeli  <dodji@redhat.com>
 
 	* line-map.c (linemap_macro_map_lookup): Fix logic.
diff --git a/libcpp/expr.c b/libcpp/expr.c
index 3c36127b54f9c51e8cd1ff80a4d40a5555118ef0..7bbc72d6f26ac1217a4740bd6bdbf28119d6c84f 100644
--- a/libcpp/expr.c
+++ b/libcpp/expr.c
@@ -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 @@ interpret_float_suffix (const uchar *s, size_t len)
 	     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 @@ interpret_int_suffix (const uchar *s, size_t len)
 	     : (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 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
   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 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
       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, user_literals))
+	    {
+	      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 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
       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, user_literals))
+	    {
+	      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.
@@ -539,7 +699,7 @@ cpp_interpret_integer (cpp_reader *pfile, const cpp_token *token,
 	    }
 	}
 
-      if (overflow)
+      if (overflow && !(type & CPP_N_USERDEF))
 	cpp_error (pfile, CPP_DL_PEDWARN,
 		   "integer constant is too large for its type");
       /* If too big to be signed, consider it unsigned.  Only warn for
@@ -748,7 +908,10 @@ eval_token (cpp_reader *pfile, const cpp_token *token)
   switch (token->type)
     {
     case CPP_NUMBER:
-      temp = cpp_classify_number (pfile, token);
+      temp = cpp_classify_number (pfile, token, NULL);
+      if (temp & CPP_N_USERDEF)
+	cpp_error (pfile, CPP_DL_ERROR,
+		   "user-defined literal in preprocessor expression");
       switch (temp & CPP_N_CATEGORY)
 	{
 	case CPP_N_FLOATING:
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 825bf2fc6ff2452b6a5b2d36997151eea41204cb..9582b621ab573b8b8835b79869b52871466ead5d 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -131,6 +131,16 @@ struct _cpp_file;
   TK(OBJC_STRING,	LITERAL) /* @"string" - Objective-C */		\
   TK(HEADER_NAME,	LITERAL) /* <stdio.h> in #include */		\
 									\
+  TK(CHAR_USERDEF,	LITERAL) /* 'char'_suffix - C++-0x */		\
+  TK(WCHAR_USERDEF,	LITERAL) /* L'char'_suffix - C++-0x */		\
+  TK(CHAR16_USERDEF,	LITERAL) /* u'char'_suffix - C++-0x */		\
+  TK(CHAR32_USERDEF,	LITERAL) /* U'char'_suffix - C++-0x */		\
+  TK(STRING_USERDEF,	LITERAL) /* "string"_suffix - C++-0x */		\
+  TK(WSTRING_USERDEF,	LITERAL) /* L"string"_suffix - C++-0x */	\
+  TK(STRING16_USERDEF,	LITERAL) /* u"string"_suffix - C++-0x */	\
+  TK(STRING32_USERDEF,	LITERAL) /* U"string"_suffix - C++-0x */	\
+  TK(UTF8STRING_USERDEF,LITERAL) /* u8"string"_suffix - C++-0x */	\
+									\
   TK(COMMENT,		LITERAL) /* Only if output comments.  */	\
 				 /* SPELL_LITERAL happens to DTRT.  */	\
   TK(MACRO_ARG,		NONE)	 /* Macro argument.  */			\
@@ -414,6 +424,9 @@ struct cpp_options
   /* True for traditional preprocessing.  */
   unsigned char traditional;
 
+  /* Nonzero for C++ 2011 Standard user-defnied literals.  */
+  unsigned char user_literals;
+
   /* Holds the name of the target (execution) character set.  */
   const char *narrow_charset;
 
@@ -829,13 +842,22 @@ struct cpp_num
 #define CPP_N_FRACT	0x100000 /* Fract types.  */
 #define CPP_N_ACCUM	0x200000 /* Accum types.  */
 
+#define CPP_N_USERDEF	0x1000000 /* C++0x user-defined literal.  */
+
 /* Classify a CPP_NUMBER token.  The return value is a combination of
    the flags from the above sets.  */
-extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *);
+extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *,
+				     const char **);
+
+/* Return the classification flags for a float suffix.  */
+extern unsigned int cpp_interpret_float_suffix (const char *, size_t);
+
+/* Return the classification flags for an int suffix.  */
+extern unsigned int cpp_interpret_int_suffix (const char *, size_t);
 
 /* Evaluate a token classified as category CPP_N_INTEGER.  */
 extern cpp_num cpp_interpret_integer (cpp_reader *, const cpp_token *,
-				      unsigned int type);
+				      unsigned int);
 
 /* Sign extend a number, with PRECISION significant bits and all
    others assumed clear, to fill out a cpp_num structure.  */
@@ -1005,4 +1027,20 @@ extern int cpp_read_state (cpp_reader *, const char *, FILE *,
 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 */
diff --git a/libcpp/init.c b/libcpp/init.c
index 6771e638970036d1cdc0db2611e38e8f9c0bf325..99b65ba339e1c3650b52fdc1688d89af855c3f71 100644
--- a/libcpp/init.c
+++ b/libcpp/init.c
@@ -80,22 +80,23 @@ struct lang_flags
   char digraphs;
   char uliterals;
   char rliterals;
+  char user_literals;
 };
 
 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 user_literals */
+  /* 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_set_lang (cpp_reader *pfile, enum c_lang lang)
   CPP_OPTION (pfile, digraphs)			 = l->digraphs;
   CPP_OPTION (pfile, uliterals)			 = l->uliterals;
   CPP_OPTION (pfile, rliterals)			 = l->rliterals;
+  CPP_OPTION (pfile, user_literals)		 = l->user_literals;
 }
 
 /* Initialize library global state.  */
diff --git a/libcpp/lex.c b/libcpp/lex.c
index 896a3bef2c2c732bf19c3babfeadc9e4debab38a..fcec329d8b4970a67de3271e2476c2d8f700a2db 100644
--- a/libcpp/lex.c
+++ b/libcpp/lex.c
@@ -1478,6 +1478,18 @@ lex_raw_string (cpp_reader *pfile, cpp_token *token, const uchar *base,
     }
  break_outer_loop:
 
+  if (CPP_OPTION (pfile, user_literals))
+    {
+      /* Grab user defined literal suffix.  */
+      if (ISIDST (*cur))
+	{
+	  type = cpp_userdef_string_add_type (type);
+	  ++cur;
+	}
+      while (ISIDNUM (*cur))
+	++cur;
+    }
+
   pfile->buffer->cur = cur;
   if (first_buff == NULL)
     create_literal (pfile, token, base, cur - base, type);
@@ -1581,6 +1593,19 @@ lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base)
     cpp_error (pfile, CPP_DL_PEDWARN, "missing terminating %c character",
 	       (int) terminator);
 
+  if (CPP_OPTION (pfile, user_literals))
+    {
+      /* 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);
 }