Index: test/Parser/cxx0x-literal-operators.cpp
===================================================================
--- test/Parser/cxx0x-literal-operators.cpp	(revision 132903)
+++ test/Parser/cxx0x-literal-operators.cpp	(working copy)
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
 
 void operator "" (const char *); // expected-error {{expected identifier}}
-void operator "k" foo(const char *); // expected-error {{string literal after 'operator' must be '""'}}
-void operator "" tester (const char *);
+void operator "k" _foo(const char *); // expected-error {{string literal after 'operator' must be '""'}}
+void operator "" _tester (const char *);
Index: test/SemaCXX/literal-operators.cpp
===================================================================
--- test/SemaCXX/literal-operators.cpp	(revision 132903)
+++ test/SemaCXX/literal-operators.cpp	(working copy)
@@ -3,41 +3,54 @@
 #include <stddef.h>
 
 struct tag {
-  void operator "" tag_bad (const char *); // expected-error {{literal operator 'operator "" tag_bad' must be in a namespace or global scope}}
-  friend void operator "" tag_good (const char *);
+  void operator "" _tag_bad (const char *); // expected-error {{literal operator '_tag_bad' must be in a namespace or global scope}}
+  friend void operator "" _tag_good (const char *);
 };
 
-namespace ns { void operator "" ns_good (const char *); }
+namespace ns { void operator "" _ns_good (const char *); }
 
 // Check extern "C++" declarations
-extern "C++" void operator "" extern_good (const char *);
-extern "C++" { void operator "" extern_good (const char *); }
+extern "C++" void operator "" _extern_good (const char *);
+extern "C++" { void operator "" _extern_good (const char *); }
 
-void fn () { void operator "" fn_bad (const char *); } // expected-error {{literal operator 'operator "" fn_bad' must be in a namespace or global scope}}
+void fn () { void operator "" _fn_bad (const char *); } // expected-error {{literal operator '_fn_bad' must be in a namespace or global scope}}
 
 // One-param declarations (const char * was already checked)
-void operator "" good (char);
-void operator "" good (wchar_t);
-void operator "" good (char16_t);
-void operator "" good (char32_t);
-void operator "" good (unsigned long long);
-void operator "" good (long double);
+void operator "" _good (char);
+void operator "" _good (wchar_t);
+void operator "" _good (char16_t);
+void operator "" _good (char32_t);
+void operator "" _good (unsigned long long);
+void operator "" _good (long double);
 
 // Two-param declarations
-void operator "" good (const char *, size_t);
-void operator "" good (const wchar_t *, size_t);
-void operator "" good (const char16_t *, size_t);
-void operator "" good (const char32_t *, size_t);
+void operator "" _good (const char *, size_t);
+void operator "" _good (const wchar_t *, size_t);
+void operator "" _good (const char16_t *, size_t);
+void operator "" _good (const char32_t *, size_t);
 
 // Check typedef and array equivalences
-void operator "" good (const char[]);
+void operator "" _good (const char[]);
 typedef const char c;
-void operator "" good (c*);
+void operator "" _good (c*);
 
 // Check extra cv-qualifiers
-void operator "" cv_good (volatile const char *, const size_t);
+void operator "" _cv_good (volatile const char *, const size_t);
 
-// Template delcaration (not implemented yet)
-// template <char...> void operator "" good ();
+// Template delcaration
+template <char...> void operator "" _good ();
 
-// FIXME: Test some invalid decls that might crop up.
+// Test some invalid decls
+template<char> void operator "" _k (); // expected-error {{literal operator template '_k' must have a non-type template parameter pack}}
+
+template<int...> void operator "" _y (); // expected-error {{literal operator template '_y' must have a single template parameter of type 'char' in its template parameter list; found 'int'}}
+
+template<char...> void operator "" _rm (int); // expected-error {{literal operator template '_rm' cannot have any parameters}}
+
+template<char..., char> void operator "" _rm (int); // expected-error {{literal operator template '_rm' must have a single template parameter in its template parameter list}}
+
+int operator "" _km (const int *); // expected-error {{literal operator '_km' must have a first parameter of character type, pointer to a character type, 'long double' or 'unsigned long long int'}}
+
+long double operator "" _w (); // expected-error {{literal operator '_w' must have a first parameter of character type, pointer to a character type, 'long double' or 'unsigned long long int'}}
+
+long double operator "" _z (wchar_t *); // expected-error {{string literal operator '_z' requires a second parameter of type 'std::size_t'}}
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 132979)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -3670,10 +3670,26 @@
 
 // C++ literal operators
 def err_literal_operator_outside_namespace : Error<
-  "literal operator %0 must be in a namespace or global scope">;
-// FIXME: This diagnostic sucks
-def err_literal_operator_params : Error<
-  "parameter declaration for literal operator %0 is not valid">;
+  "literal operator '%0' must be in a namespace or global scope">;
+def ext_literal_operator_does_not_start_with_underscore : ExtWarn<
+  "literal operator '%0' has a suffix identifier that does not start with an "
+  "underscore, suffix identifiers that do not start with an underscore are "
+  "reserved for future standardization">;
+def err_literal_operator_template_single_template_parameter : Error<
+  "literal operator template '%0' must have a single template parameter in its template parameter list">;
+def err_literal_operator_template_type_char : Error<
+  "literal operator template '%0' must have a single template parameter of type 'char' in its template parameter list; found %1">;
+def err_literal_operator_template_parameter_pack : Error<
+  "literal operator template '%0' must have a non-type template parameter pack">;
+def err_literal_operator_template_no_parameters : Error<
+  "literal operator template '%0' cannot have any parameters">;
+def err_literal_operator_too_many_parameters : Error<
+  "literal operator '%0' is invalid because it has unexpected parameters">;
+def err_literal_operator_expected_valid_first_parameter : Error<
+  "literal operator '%0' must have a first parameter of character type, pointer"
+  " to a character type, 'long double' or 'unsigned long long int'">;
+def err_literal_operator_string_literal_second_parameter_size_t: Error<
+  "string literal operator '%0' requires a second parameter of type 'std::size_t'">;
 
 // C++ conversion functions
 def err_conv_function_not_member : Error<
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h	(revision 132903)
+++ include/clang/AST/ASTContext.h	(working copy)
@@ -1182,7 +1182,7 @@
   CanQualType getCanonicalParamType(QualType T) const;
 
   /// \brief Determine whether the given types are equivalent.
-  bool hasSameType(QualType T1, QualType T2) {
+  bool hasSameType(QualType T1, QualType T2) const {
     return getCanonicalType(T1) == getCanonicalType(T2);
   }
 
@@ -1202,7 +1202,7 @@
 
   /// \brief Determine whether the given types are equivalent after
   /// cvr-qualifiers have been removed.
-  bool hasSameUnqualifiedType(QualType T1, QualType T2) {
+  bool hasSameUnqualifiedType(QualType T1, QualType T2) const {
     return getCanonicalType(T1).getTypePtr() ==
            getCanonicalType(T2).getTypePtr();
   }
@@ -1249,7 +1249,7 @@
 
   /// \brief Determines whether two calling conventions name the same
   /// calling convention.
-  bool isSameCallConv(CallingConv lcc, CallingConv rcc) {
+  bool isSameCallConv(CallingConv lcc, CallingConv rcc) const {
     return (getCanonicalCallConv(lcc) == getCanonicalCallConv(rcc));
   }
 
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp	(revision 132903)
+++ lib/Sema/SemaDeclCXX.cpp	(working copy)
@@ -7938,94 +7938,163 @@
 /// of this literal operator function is well-formed. If so, returns
 /// false; otherwise, emits appropriate diagnostics and returns true.
 bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
+  llvm::StringRef LiteralSuffixIdentifier =
+    FnDecl->getLiteralIdentifier()->getName();
+
   DeclContext *DC = FnDecl->getDeclContext();
   Decl::Kind Kind = DC->getDeclKind();
   if (Kind != Decl::TranslationUnit && Kind != Decl::Namespace &&
       Kind != Decl::LinkageSpec) {
     Diag(FnDecl->getLocation(), diag::err_literal_operator_outside_namespace)
-      << FnDecl->getDeclName();
+      << LiteralSuffixIdentifier;
     return true;
   }
 
-  bool Valid = false;
+  // C++0x [usrlit.suffix]p1:
+  //   Literal suffix identifiers that do not start with an underscore are
+  //   reserved for future standardization.
+  if (LiteralSuffixIdentifier.front() != '_')
+    Diag(FnDecl->getLocation(),
+         diag::ext_literal_operator_does_not_start_with_underscore)
+      << LiteralSuffixIdentifier;
 
-  // template <char...> type operator "" name() is the only valid template
-  // signature, and the only valid signature with no parameters.
-  if (FnDecl->param_size() == 0) {
-    if (FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate()) {
-      // Must have only one template parameter
-      TemplateParameterList *Params = TpDecl->getTemplateParameters();
-      if (Params->size() == 1) {
-        NonTypeTemplateParmDecl *PmDecl =
-          cast<NonTypeTemplateParmDecl>(Params->getParam(0));
+  // C++0x [over.literal]p2:
+  //   A function template declared with a literal-operator-id is a literal
+  //   operator template.
+  if (FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate()) {
+    // C++0x [over.literal]p5: [...] template-parameter-list shall have a
+    //   single template-parameter
+    TemplateParameterList *Params = TpDecl->getTemplateParameters();
+    if (Params->size() == 1) {
+      NonTypeTemplateParmDecl *PmDecl =
+        cast<NonTypeTemplateParmDecl>(Params->getParam(0));
 
-        // The template parameter must be a char parameter pack.
-        if (PmDecl && PmDecl->isTemplateParameterPack() &&
-            Context.hasSameType(PmDecl->getType(), Context.CharTy))
-          Valid = true;
+      // C++0x [over.literal]p5:
+      //   The declaration of a literal operator template shall have an empty
+      //   parameter-declaration-clause [...]
+      if (FnDecl->getNumParams() > 0) {
+        Diag(FnDecl->getParamDecl(0)->getLocation(),
+             diag::err_literal_operator_template_no_parameters)
+          << LiteralSuffixIdentifier;
+        return true;
       }
+      // C++0x [over.literal]p5:
+      //   [...] that is a non-type template parameter pack [...]
+      if (!PmDecl->isTemplateParameterPack()) {
+        Diag(Params->getRAngleLoc(),
+             diag::err_literal_operator_template_parameter_pack)
+          << LiteralSuffixIdentifier
+          << FixItHint::CreateInsertion(Params->getRAngleLoc(), "...");
+        return true;
+      }
+      // C++0x [over.literal]p5:
+      //   [...] with element type char.
+      if (!Context.hasSameType(PmDecl->getType(), Context.CharTy)) {
+        Diag(PmDecl->getLocation(),
+             diag::err_literal_operator_template_type_char)
+          << LiteralSuffixIdentifier
+          << PmDecl->getType();
+        return true;
+      }
+    } else {
+      // we only want _one_ template parameter!
+      Diag(Params->getRAngleLoc(),
+           diag::err_literal_operator_template_single_template_parameter)
+        << LiteralSuffixIdentifier;
+      return true;
     }
   } else {
-    // Check the first parameter
-    FunctionDecl::param_iterator Param = FnDecl->param_begin();
+    // We are assuming this is a literal operator instead of a literal operator
+    // template because we see that this is not a template function
 
-    QualType T = (*Param)->getType();
+    // C++0x [over.literal]p3:
+    //   The declaration of a literal operator shall have a
+    //   parameter-declaration-clause equivalent to one of the following:
+    //        const char*
+    //        unsigned long long int
+    //        long double
+    //        char
+    //        wchar_t
+    //        char16_t
+    //        char32_t
+    //        const char*, std::size_t
+    //        const wchar_t*, std::size_t
+    //        const char16_t*, std::size_t
+    //        const char32_t*, std::size_t
 
-    // unsigned long long int, long double, and any character type are allowed
-    // as the only parameters.
-    if (Context.hasSameType(T, Context.UnsignedLongLongTy) ||
-        Context.hasSameType(T, Context.LongDoubleTy) ||
-        Context.hasSameType(T, Context.CharTy) ||
-        Context.hasSameType(T, Context.WCharTy) ||
-        Context.hasSameType(T, Context.Char16Ty) ||
-        Context.hasSameType(T, Context.Char32Ty)) {
-      if (++Param == FnDecl->param_end())
-        Valid = true;
-      goto FinishedParams;
+    if (FnDecl->getNumParams() == 0) {
+      Diag(FnDecl->getLocation(),
+           diag::err_literal_operator_expected_valid_first_parameter)
+        << LiteralSuffixIdentifier;
+      return true;
     }
 
-    // Otherwise it must be a pointer to const; let's strip those qualifiers.
-    const PointerType *PT = T->getAs<PointerType>();
-    if (!PT)
-      goto FinishedParams;
-    T = PT->getPointeeType();
-    if (!T.isConstQualified())
-      goto FinishedParams;
-    T = T.getUnqualifiedType();
+    const ParmVarDecl *FirstParam = FnDecl->getParamDecl(0);
+    QualType FirstParamType = FirstParam->getType();
+    const PointerType *PT = FirstParamType->getAs<PointerType>();
+    QualType FirstParamPointeeType;
 
-    // Move on to the second parameter;
-    ++Param;
+    if (PT)
+      FirstParamPointeeType = PT->getPointeeType();
 
-    // If there is no second parameter, the first must be a const char *
-    if (Param == FnDecl->param_end()) {
-      if (Context.hasSameType(T, Context.CharTy))
-        Valid = true;
-      goto FinishedParams;
-    }
+    // is the first param signifying an integer literal, a floating literal or
+    // is it a character literal?
+    if (Context.hasSameType(FirstParamType, Context.UnsignedLongLongTy) ||
+        Context.hasSameType(FirstParamType, Context.LongDoubleTy) ||
+        FirstParamType->isAnyCharacterType()) {
+      if (FnDecl->getNumParams() > 1) {
+        Diag(FnDecl->getLocation(),
+             diag::err_literal_operator_too_many_parameters)
+          << LiteralSuffixIdentifier;
+        return true;
+      }
+    } else if (PT && FirstParamPointeeType->isAnyCharacterType()) {
+      // C++0x [over.literal]p4:
+      //   A raw literal operator is a literal operator with a single parameter
+      //   whose type is const char*.
+      if (FnDecl->getNumParams() == 1 &&
+          FirstParamPointeeType->isCharType()) {
+        // bail out with success
+        return false;
+      }
 
-    // const char *, const wchar_t*, const char16_t*, and const char32_t*
-    // are allowed as the first parameter to a two-parameter function
-    if (!(Context.hasSameType(T, Context.CharTy) ||
-          Context.hasSameType(T, Context.WCharTy) ||
-          Context.hasSameType(T, Context.Char16Ty) ||
-          Context.hasSameType(T, Context.Char32Ty)))
-      goto FinishedParams;
+      // C++0x [lex.ext]p5:
+      //   If L is a user-defined-string-literal, let str be the literal
+      //   without its ud-suffix and let len be the number of code units in str
+      //   (i.e., its length excluding the terminating null character). The
+      //   literal L is treated as a call of the form
+      //
+      //     operator "" X (str, len)
 
-    // The second and final parameter must be an std::size_t
-    T = (*Param)->getType().getUnqualifiedType();
-    if (Context.hasSameType(T, Context.getSizeType()) &&
-        ++Param == FnDecl->param_end())
-      Valid = true;
+      if (FnDecl->getNumParams() < 2) {
+        // expected a second parameter of size_t
+        Diag(FnDecl->getLocation(),
+             diag::err_literal_operator_string_literal_second_parameter_size_t)
+          << LiteralSuffixIdentifier;
+        return true;
+      } else if (FnDecl->getNumParams() > 2) {
+        // expected _only_ two parameters
+        Diag(FnDecl->getLocation(),
+             diag::err_literal_operator_too_many_parameters)
+          << LiteralSuffixIdentifier;
+        return true;
+      } else if (!Context.hasSameUnqualifiedType(Context.getSizeType(),
+            FnDecl->getParamDecl(1)->getType())) {
+        // expected a second parameter of size_t
+        Diag(FnDecl->getLocation(),
+             diag::err_literal_operator_string_literal_second_parameter_size_t)
+          << LiteralSuffixIdentifier;
+        return true;
+      }
+    } else {
+      // unexpected parameter type, expected a character type, ...
+      Diag(FnDecl->getLocation(),
+           diag::err_literal_operator_expected_valid_first_parameter)
+        << LiteralSuffixIdentifier;
+      return true;
+    }
   }
 
-  // FIXME: This diagnostic is absolutely terrible.
-FinishedParams:
-  if (!Valid) {
-    Diag(FnDecl->getLocation(), diag::err_literal_operator_params)
-      << FnDecl->getDeclName();
-    return true;
-  }
-
   return false;
 }
 
Index: lib/AST/DeclarationName.cpp
===================================================================
--- lib/AST/DeclarationName.cpp	(revision 132903)
+++ lib/AST/DeclarationName.cpp	(working copy)
@@ -53,7 +53,7 @@
   void *FETokenInfo;
 };
 
-/// CXXLiberalOperatorName - Contains the actual identifier that makes up the
+/// CXXLiteralOperatorName - Contains the actual identifier that makes up the
 /// name.
 ///
 /// This identifier is stored here rather than directly in DeclarationName so as
